datapath: remove RCU annotation from flow->mask
[sliver-openvswitch.git] / datapath / datapath.c
index 3680391..4330ce3 100644 (file)
@@ -972,9 +972,10 @@ static struct genl_ops dp_packet_genl_ops[] = {
 
 static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats)
 {
+       struct flow_table *table;
        int i;
-       struct flow_table *table = ovsl_dereference(dp->table);
 
+       table = rcu_dereference_check(dp->table, lockdep_ovsl_is_held());
        stats->n_flows = ovs_flow_tbl_count(table);
 
        stats->n_hit = stats->n_missed = stats->n_lost = 0;
@@ -1126,7 +1127,6 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
                                  u32 seq, u32 flags, u8 cmd)
 {
        const int skb_orig_len = skb->len;
-       const struct sw_flow_actions *sf_acts;
        struct nlattr *start;
        struct ovs_flow_stats stats;
        struct ovs_header *ovs_header;
@@ -1135,8 +1135,6 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
        u8 tcp_flags;
        int err;
 
-       sf_acts = ovsl_dereference(flow->sf_acts);
-
        ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family, flags, cmd);
        if (!ovs_header)
                return -EMSGSIZE;
@@ -1158,8 +1156,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
        if (!nla)
                goto nla_put_failure;
 
-       err = ovs_flow_to_nlattrs(&flow->key,
-                       &ovsl_dereference(flow->mask)->key, skb);
+       err = ovs_flow_to_nlattrs(&flow->key, &flow->mask->key, skb);
        if (err)
                goto error;
 
@@ -1197,6 +1194,11 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
         */
        start = nla_nest_start(skb, OVS_FLOW_ATTR_ACTIONS);
        if (start) {
+               const struct sw_flow_actions *sf_acts;
+
+               sf_acts = rcu_dereference_check(flow->sf_acts,
+                                               lockdep_ovsl_is_held());
+
                err = actions_to_attr(sf_acts->actions, sf_acts->actions_len, skb);
                if (!err)
                        nla_nest_end(skb, start);
@@ -1247,7 +1249,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr **a = info->attrs;
        struct ovs_header *ovs_header = info->userhdr;
-       struct sw_flow_key key;
+       struct sw_flow_key key, masked_key;
        struct sw_flow *flow = NULL;
        struct sw_flow_mask mask;
        struct sk_buff *reply;
@@ -1275,9 +1277,13 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                if (IS_ERR(acts))
                        goto error;
 
-               error = validate_and_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &key,  0, &acts);
-               if (error)
+               ovs_flow_key_mask(&masked_key, &key, &mask);
+               error = validate_and_copy_actions(a[OVS_FLOW_ATTR_ACTIONS],
+                                                 &masked_key, 0, &acts);
+               if (error) {
+                       OVS_NLERR("Flow actions may not be safe on all matching packets.\n");
                        goto err_kfree;
+               }
        } else if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW) {
                error = -EINVAL;
                goto error;
@@ -1320,6 +1326,9 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                }
                clear_stats(flow);
 
+               flow->key = masked_key;
+               flow->unmasked_key = key;
+
                /* Make sure mask is unique in the system */
                mask_p = ovs_sw_flow_mask_find(table, &mask);
                if (!mask_p) {
@@ -1333,11 +1342,11 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                }
 
                ovs_sw_flow_mask_add_ref(mask_p);
-               rcu_assign_pointer(flow->mask, mask_p);
+               flow->mask = mask_p;
                rcu_assign_pointer(flow->sf_acts, acts);
 
                /* Put flow in bucket. */
-               ovs_flow_insert(table, flow, &key, match.range.end);
+               ovs_flow_insert(table, flow);
 
                reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid,
                                                info->snd_seq, OVS_FLOW_CMD_NEW);
@@ -1358,8 +1367,10 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 
                /* The unmasked key has to be the same for flow updates. */
                error = -EINVAL;
-               if (!ovs_flow_cmp_unmasked_key(flow, &key, match.range.end))
+               if (!ovs_flow_cmp_unmasked_key(flow, &key, match.range.end)) {
+                       OVS_NLERR("Flow modification message rejected, unmasked key does not match.\n");
                        goto err_unlock_ovs;
+               }
 
                /* Update actions. */
                old_acts = ovsl_dereference(flow->sf_acts);
@@ -1407,8 +1418,10 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
        struct sw_flow_match match;
        int err;
 
-       if (!a[OVS_FLOW_ATTR_KEY])
+       if (!a[OVS_FLOW_ATTR_KEY]) {
+               OVS_NLERR("Flow get message rejected, Key attribute missing.\n");
                return -EINVAL;
+       }
 
        ovs_match_init(&match, &key, NULL);
        err = ovs_match_from_nlattrs(&match, a[OVS_FLOW_ATTR_KEY], NULL);
@@ -1507,15 +1520,14 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
        struct datapath *dp;
        struct flow_table *table;
 
-       ovs_lock();
+       rcu_read_lock();
        dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
        if (!dp) {
-               ovs_unlock();
+               rcu_read_unlock();
                return -ENODEV;
        }
 
-       table = ovsl_dereference(dp->table);
-
+       table = rcu_dereference(dp->table);
        for (;;) {
                struct sw_flow *flow;
                u32 bucket, obj;
@@ -1535,7 +1547,7 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
                cb->args[0] = bucket;
                cb->args[1] = obj;
        }
-       ovs_unlock();
+       rcu_read_unlock();
        return skb->len;
 }
 
@@ -1741,7 +1753,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
                goto err_destroy_local_port;
 
        ovs_net = net_generic(ovs_dp_get_net(dp), ovs_net_id);
-       list_add_tail(&dp->list_node, &ovs_net->dps);
+       list_add_tail_rcu(&dp->list_node, &ovs_net->dps);
 
        ovs_unlock();
 
@@ -1779,7 +1791,7 @@ static void __dp_destroy(struct datapath *dp)
                                ovs_dp_detach_port(vport);
        }
 
-       list_del(&dp->list_node);
+       list_del_rcu(&dp->list_node);
 
        /* OVSP_LOCAL is datapath internal port. We need to make sure that
         * all port in datapath are destroyed first before freeing datapath.
@@ -1896,8 +1908,8 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
        int skip = cb->args[0];
        int i = 0;
 
-       ovs_lock();
-       list_for_each_entry(dp, &ovs_net->dps, list_node) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(dp, &ovs_net->dps, list_node) {
                if (i >= skip &&
                    ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).portid,
                                         cb->nlh->nlmsg_seq, NLM_F_MULTI,
@@ -1905,7 +1917,7 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
                        break;
                i++;
        }
-       ovs_unlock();
+       rcu_read_unlock();
 
        cb->args[0] = i;
 
@@ -2445,6 +2457,8 @@ static struct pernet_operations ovs_net_ops = {
        .size = sizeof(struct ovs_net),
 };
 
+DEFINE_COMPAT_PNET_REG_FUNC(device);
+
 static int __init dp_init(void)
 {
        int err;