Fix null pointer dereference when a delete flow command is executed.
authorJustin Pettit <jpettit@nicira.com>
Fri, 19 Dec 2008 20:49:09 +0000 (12:49 -0800)
committerJustin Pettit <jpettit@nicira.com>
Fri, 19 Dec 2008 20:49:09 +0000 (12:49 -0800)
A set of missing parentheses was causing an attempt to send a Flow End
message even if no flow existed.  The code to send the Flow End message
would try to access data in the flow and cause a kernel panic.

datapath/table-hash.c
datapath/table-linear.c

index a8c965e..2951722 100644 (file)
@@ -102,8 +102,10 @@ static int table_hash_modify(struct sw_table *swt,
 }
 
 /* Caller must update n_flows. */
-static int do_delete(struct sw_flow **bucket, struct sw_flow *flow)
+static int do_delete(struct datapath *dp, struct sw_flow **bucket, 
+                       struct sw_flow *flow, enum nx_flow_end_reason reason)
 {
+       dp_send_flow_end(dp, flow, reason);
        rcu_assign_pointer(*bucket, NULL);
        flow_deferred_free(flow);
        return 1;
@@ -123,9 +125,8 @@ static int table_hash_delete(struct datapath *dp, struct sw_table *swt,
                struct sw_flow **bucket = find_bucket(swt, key);
                struct sw_flow *flow = *bucket;
                if (flow && flow_keys_equal(&flow->key, key)
-                               && flow_has_out_port(flow, out_port))
-                       count = do_delete(bucket, flow);
-                       dp_send_flow_end(dp, flow, NXFER_DELETE);
+                               && flow_has_out_port(flow, out_port)) 
+                       count = do_delete(dp, bucket, flow, NXFER_DELETE);
        } else {
                unsigned int i;
 
@@ -134,8 +135,7 @@ static int table_hash_delete(struct datapath *dp, struct sw_table *swt,
                        struct sw_flow *flow = *bucket;
                        if (flow && flow_matches_desc(&flow->key, key, strict)
                                        && flow_has_out_port(flow, out_port))
-                               count += do_delete(bucket, flow);
-                               dp_send_flow_end(dp, flow, NXFER_DELETE);
+                               count = do_delete(dp, bucket, flow, NXFER_DELETE);
                }
        }
        th->n_flows -= count;
@@ -155,8 +155,7 @@ static int table_hash_timeout(struct datapath *dp, struct sw_table *swt)
                if (flow) {
                        int reason = flow_timeout(flow);
                        if (reason >= 0) {
-                               count += do_delete(bucket, flow); 
-                               dp_send_flow_end(dp, flow, reason);
+                               count += do_delete(dp, bucket, flow, reason); 
                        }
                }
        }
index 3026a68..1d5e186 100644 (file)
@@ -90,8 +90,10 @@ static int table_linear_modify(struct sw_table *swt,
        return count;
 }
 
-static int do_delete(struct sw_table *swt, struct sw_flow *flow) 
+static int do_delete(struct datapath *dp, struct sw_table *swt, 
+                       struct sw_flow *flow, enum nx_flow_end_reason reason) 
 {
+       dp_send_flow_end(dp, flow, reason);
        list_del_rcu(&flow->node);
        list_del_rcu(&flow->iter_node);
        flow_deferred_free(flow);
@@ -110,8 +112,7 @@ static int table_linear_delete(struct datapath *dp, struct sw_table *swt,
                if (flow_matches_desc(&flow->key, key, strict)
                                && flow_has_out_port(flow, out_port)
                                && (!strict || (flow->priority == priority)))
-                       count += do_delete(swt, flow);
-                       dp_send_flow_end(dp, flow, NXFER_DELETE);
+                       count += do_delete(dp, swt, flow, NXFER_DELETE);
        }
        tl->n_flows -= count;
        return count;
@@ -127,8 +128,7 @@ static int table_linear_timeout(struct datapath *dp, struct sw_table *swt)
        list_for_each_entry (flow, &tl->flows, node) {
                int reason = flow_timeout(flow);
                if (reason >= 0) {
-                       count += do_delete(swt, flow);
-                       dp_send_flow_end(dp, flow, reason);
+                       count += do_delete(dp, swt, flow, reason);
                }
        }
        tl->n_flows -= count;