diff options
author | Jarno Rajahalme <jrajahalme@nicira.com> | 2014-05-05 17:40:13 -0400 |
---|---|---|
committer | Pravin B Shelar <pshelar@nicira.com> | 2014-05-22 19:27:36 -0400 |
commit | aed067783e505bf66dcafa8647d08619eb5b1c55 (patch) | |
tree | 272d7ee43bc9dd29ee8c958d32cadc76d4231a3b /net/openvswitch | |
parent | 0e9796b4af9ef490e203158cb738a5a4986eb75c (diff) |
openvswitch: Minimize ovs_flow_cmd_del critical section.
ovs_flow_cmd_del() now allocates reply (if needed) after the flow has
already been removed from the flow table. If the reply allocation
fails, a netlink error is signaled with netlink_set_err(), as is
already done in ovs_flow_cmd_new_or_set() in the similar situation.
Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Diffstat (limited to 'net/openvswitch')
-rw-r--r-- | net/openvswitch/datapath.c | 53 |
1 files changed, 28 insertions, 25 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 949fc7fadaf0..f28beda8426f 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -984,50 +984,53 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) | |||
984 | struct sw_flow_match match; | 984 | struct sw_flow_match match; |
985 | int err; | 985 | int err; |
986 | 986 | ||
987 | if (likely(a[OVS_FLOW_ATTR_KEY])) { | ||
988 | ovs_match_init(&match, &key, NULL); | ||
989 | err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL); | ||
990 | if (unlikely(err)) | ||
991 | return err; | ||
992 | } | ||
993 | |||
987 | ovs_lock(); | 994 | ovs_lock(); |
988 | dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); | 995 | dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); |
989 | if (!dp) { | 996 | if (unlikely(!dp)) { |
990 | err = -ENODEV; | 997 | err = -ENODEV; |
991 | goto unlock; | 998 | goto unlock; |
992 | } | 999 | } |
993 | 1000 | ||
994 | if (!a[OVS_FLOW_ATTR_KEY]) { | 1001 | if (unlikely(!a[OVS_FLOW_ATTR_KEY])) { |
995 | err = ovs_flow_tbl_flush(&dp->table); | 1002 | err = ovs_flow_tbl_flush(&dp->table); |
996 | goto unlock; | 1003 | goto unlock; |
997 | } | 1004 | } |
998 | 1005 | ||
999 | ovs_match_init(&match, &key, NULL); | ||
1000 | err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL); | ||
1001 | if (err) | ||
1002 | goto unlock; | ||
1003 | |||
1004 | flow = ovs_flow_tbl_lookup(&dp->table, &key); | 1006 | flow = ovs_flow_tbl_lookup(&dp->table, &key); |
1005 | if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { | 1007 | if (unlikely(!flow || !ovs_flow_cmp_unmasked_key(flow, &match))) { |
1006 | err = -ENOENT; | 1008 | err = -ENOENT; |
1007 | goto unlock; | 1009 | goto unlock; |
1008 | } | 1010 | } |
1009 | 1011 | ||
1010 | reply = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts), info, | ||
1011 | false); | ||
1012 | if (IS_ERR(reply)) { | ||
1013 | err = PTR_ERR(reply); | ||
1014 | goto unlock; | ||
1015 | } | ||
1016 | |||
1017 | ovs_flow_tbl_remove(&dp->table, flow); | 1012 | ovs_flow_tbl_remove(&dp->table, flow); |
1013 | ovs_unlock(); | ||
1018 | 1014 | ||
1019 | if (reply) { | 1015 | reply = ovs_flow_cmd_alloc_info((const struct sw_flow_actions __force *) flow->sf_acts, |
1020 | err = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, | 1016 | info, false); |
1021 | reply, info->snd_portid, | 1017 | if (likely(reply)) { |
1022 | info->snd_seq, 0, | 1018 | if (likely(!IS_ERR(reply))) { |
1023 | OVS_FLOW_CMD_DEL); | 1019 | rcu_read_lock(); /*To keep RCU checker happy. */ |
1024 | BUG_ON(err < 0); | 1020 | err = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, |
1021 | reply, info->snd_portid, | ||
1022 | info->snd_seq, 0, | ||
1023 | OVS_FLOW_CMD_DEL); | ||
1024 | rcu_read_unlock(); | ||
1025 | BUG_ON(err < 0); | ||
1026 | |||
1027 | ovs_notify(&dp_flow_genl_family, reply, info); | ||
1028 | } else { | ||
1029 | netlink_set_err(sock_net(skb->sk)->genl_sock, 0, 0, PTR_ERR(reply)); | ||
1030 | } | ||
1025 | } | 1031 | } |
1026 | ovs_flow_free(flow, true); | ||
1027 | ovs_unlock(); | ||
1028 | 1032 | ||
1029 | if (reply) | 1033 | ovs_flow_free(flow, true); |
1030 | ovs_notify(&dp_flow_genl_family, reply, info); | ||
1031 | return 0; | 1034 | return 0; |
1032 | unlock: | 1035 | unlock: |
1033 | ovs_unlock(); | 1036 | ovs_unlock(); |