diff options
author | Jarno Rajahalme <jrajahalme@nicira.com> | 2014-05-05 12:59:40 -0400 |
---|---|---|
committer | Pravin B Shelar <pshelar@nicira.com> | 2014-05-22 19:27:34 -0400 |
commit | be52c9e96a6657d117bb0ec6e11438fb246af5c7 (patch) | |
tree | 92764c69b9c3cda7a6263dd5163caeea57a6e815 /net/openvswitch/datapath.c | |
parent | 1139e241ec436b9e9610c7a33ac5c6657f87fda1 (diff) |
openvswitch: Avoid assigning a NULL pointer to flow actions.
Flow SET can accept an empty set of actions, with the intended
semantics of leaving existing actions unmodified. This seems to have
been brokin after OVS 1.7, as we have assigned the flow's actions
pointer to NULL in this case, but we never check for the NULL pointer
later on. This patch restores the intended behavior and documents it
in the include/linux/openvswitch.h.
Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Diffstat (limited to 'net/openvswitch/datapath.c')
-rw-r--r-- | net/openvswitch/datapath.c | 14 |
1 files changed, 8 insertions, 6 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 8867d7e2d65b..90a1e5e66287 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -810,6 +810,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
810 | goto err_kfree; | 810 | goto err_kfree; |
811 | } | 811 | } |
812 | } else if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW) { | 812 | } else if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW) { |
813 | /* OVS_FLOW_CMD_NEW must have actions. */ | ||
813 | error = -EINVAL; | 814 | error = -EINVAL; |
814 | goto error; | 815 | goto error; |
815 | } | 816 | } |
@@ -849,8 +850,6 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
849 | reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW); | 850 | reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW); |
850 | } else { | 851 | } else { |
851 | /* We found a matching flow. */ | 852 | /* We found a matching flow. */ |
852 | struct sw_flow_actions *old_acts; | ||
853 | |||
854 | /* Bail out if we're not allowed to modify an existing flow. | 853 | /* Bail out if we're not allowed to modify an existing flow. |
855 | * We accept NLM_F_CREATE in place of the intended NLM_F_EXCL | 854 | * We accept NLM_F_CREATE in place of the intended NLM_F_EXCL |
856 | * because Generic Netlink treats the latter as a dump | 855 | * because Generic Netlink treats the latter as a dump |
@@ -866,11 +865,14 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
866 | if (!ovs_flow_cmp_unmasked_key(flow, &match)) | 865 | if (!ovs_flow_cmp_unmasked_key(flow, &match)) |
867 | goto err_unlock_ovs; | 866 | goto err_unlock_ovs; |
868 | 867 | ||
869 | /* Update actions. */ | 868 | /* Update actions, if present. */ |
870 | old_acts = ovsl_dereference(flow->sf_acts); | 869 | if (acts) { |
871 | rcu_assign_pointer(flow->sf_acts, acts); | 870 | struct sw_flow_actions *old_acts; |
872 | ovs_nla_free_flow_actions(old_acts); | ||
873 | 871 | ||
872 | old_acts = ovsl_dereference(flow->sf_acts); | ||
873 | rcu_assign_pointer(flow->sf_acts, acts); | ||
874 | ovs_nla_free_flow_actions(old_acts); | ||
875 | } | ||
874 | reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW); | 876 | reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW); |
875 | 877 | ||
876 | /* Clear stats. */ | 878 | /* Clear stats. */ |