Not returning the actions from flow delete allows the reply (if any) be
allocated before taking the lock, and failing out properly if no memory
is available.

It seems that userspace has no plausable use for the actions in a flow
delete reply, so this should be OK.

Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com>
---
 datapath/datapath.c |   64 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 35 insertions(+), 29 deletions(-)

diff --git a/datapath/datapath.c b/datapath/datapath.c
index 9e86ec8..da07f9d 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -664,7 +664,7 @@ static size_t ovs_flow_cmd_msg_size(const struct 
sw_flow_actions *acts)
                + nla_total_size(sizeof(struct ovs_flow_stats)) /* 
OVS_FLOW_ATTR_STATS */
                + nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */
                + nla_total_size(8) /* OVS_FLOW_ATTR_USED */
-               + nla_total_size(acts->actions_len); /* OVS_FLOW_ATTR_ACTIONS */
+               + (acts ? nla_total_size(acts->actions_len) : 0); /* 
OVS_FLOW_ATTR_ACTIONS */
 }
 
 /* Called with ovs_mutex or RCU read lock. */
@@ -730,25 +730,26 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, 
int dp_ifindex,
         * This can only fail for dump operations because the skb is always
         * properly sized for single flows.
         */
-       start = nla_nest_start(skb, OVS_FLOW_ATTR_ACTIONS);
-       if (start) {
-               const struct sw_flow_actions *sf_acts;
-
-               sf_acts = rcu_dereference_ovsl(flow->sf_acts);
-
-               err = ovs_nla_put_actions(sf_acts->actions,
-                                         sf_acts->actions_len, skb);
-               if (!err)
-                       nla_nest_end(skb, start);
-               else {
-                       if (skb_orig_len)
-                               goto error;
-
-                       nla_nest_cancel(skb, start);
-               }
-       } else if (skb_orig_len)
-               goto nla_put_failure;
-
+       if (cmd != OVS_FLOW_CMD_DEL) {
+               start = nla_nest_start(skb, OVS_FLOW_ATTR_ACTIONS);
+               if (start) {
+                       const struct sw_flow_actions *sf_acts;
+
+                       sf_acts = rcu_dereference_ovsl(flow->sf_acts);
+
+                       err = ovs_nla_put_actions(sf_acts->actions,
+                                                 sf_acts->actions_len, skb);
+                       if (!err)
+                               nla_nest_end(skb, start);
+                       else {
+                               if (skb_orig_len)
+                                       goto error;
+
+                               nla_nest_cancel(skb, start);
+                       }
+               } else if (skb_orig_len)
+                       goto nla_put_failure;
+       }
        return genlmsg_end(skb, ovs_header);
 
 nla_put_failure:
@@ -992,6 +993,12 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct 
genl_info *info)
                        return err;
        }
 
+       if (ovs_build_reply(info, &ovs_dp_flow_multicast_group)) {
+               reply = ovs_flow_cmd_alloc_info(NULL, info);
+               if (!reply)
+                       return -ENOMEM;
+       }
+
        ovs_lock();
        dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
        if (!dp) {
@@ -1011,20 +1018,19 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct 
genl_info *info)
        ovs_flow_tbl_remove(&dp->table, flow);
        ovs_unlock();
 
-       if (ovs_build_reply(info, &ovs_dp_flow_multicast_group)) {
-               /* XXX: We may skip sending a response if kernel is out of
-                  memory.  We could do the allocation before locking if we did
-                  not need to return the actions (which are useless in this
-                  case anyway). */
-               reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex,
-                                               info, OVS_FLOW_CMD_DEL);
-               if (!IS_ERR(reply))
-                       ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
+       if (reply) {
+               err = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex,
+                                            reply, info->snd_portid,
+                                            info->snd_seq, 0,
+                                            OVS_FLOW_CMD_DEL);
+               BUG_ON(err < 0);
+               ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
        }
        ovs_flow_free(flow, true);
        return 0;
 
 ovs_unlock:
+       kfree_skb(reply);
        ovs_unlock();
        return err;
 }
-- 
1.7.10.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to