Userspace already sets NLM_F_ECHO when it wants a reply, make use of
it.

For set and del, OVS userspace only sets the NLM_F_ECHO if stats are
needed back.  So, we minimize the data sent back by only responding
with key and stats for ovs_flow_cmd_new, ovs_flow_cmd_set, and
ovs_flow_cmd_del.

When not returning actions, we can allocate the reply (if requested)
before finding the flow, i.e., before locking anything.  We make use
of this in following patches.

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

diff --git a/datapath/datapath.c b/datapath/datapath.c
index f045fe4..9fdb447 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -639,21 +639,26 @@ static struct genl_multicast_group 
ovs_dp_flow_multicast_group = {
        .name = OVS_FLOW_MCGROUP
 };
 
-static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts)
+static size_t ovs_flow_cmd_msg_size(const struct sw_flow *flow, u64 what)
 {
        return NLMSG_ALIGN(sizeof(struct ovs_header))
                + nla_total_size(key_attr_size()) /* OVS_FLOW_ATTR_KEY */
-               + nla_total_size(key_attr_size()) /* OVS_FLOW_ATTR_MASK */
-               + 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 */
+               + (what & 1 << OVS_FLOW_ATTR_MASK
+                  ? nla_total_size(key_attr_size()) : 0)
+               + (what & 1 << OVS_FLOW_ATTR_STATS
+                  ? nla_total_size(sizeof(struct ovs_flow_stats))
+                  + nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */
+                  + nla_total_size(8) /* OVS_FLOW_ATTR_USED */
+                  : 0)
+               + (what & 1 << OVS_FLOW_ATTR_ACTIONS
+                  ? 
nla_total_size(ovsl_dereference(flow->sf_acts)->actions_len)
+                  : 0);
 }
 
 /* Called with ovs_mutex. */
 static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
                                  struct sk_buff *skb, u32 portid,
-                                 u32 seq, u32 flags, u8 cmd)
+                                 u32 seq, u32 flags, u8 cmd, u64 what)
 {
        const int skb_orig_len = skb->len;
        struct nlattr *start;
@@ -670,7 +675,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, 
struct datapath *dp,
 
        ovs_header->dp_ifindex = get_dpifindex(dp);
 
-       /* Fill flow key. */
+       /* Fill flow key. Not optional. */
        nla = nla_nest_start(skb, OVS_FLOW_ATTR_KEY);
        if (!nla)
                goto nla_put_failure;
@@ -680,28 +685,32 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, 
struct datapath *dp,
                goto error;
        nla_nest_end(skb, nla);
 
-       nla = nla_nest_start(skb, OVS_FLOW_ATTR_MASK);
-       if (!nla)
-               goto nla_put_failure;
+       if (what & 1 << OVS_FLOW_ATTR_MASK) {
+               nla = nla_nest_start(skb, OVS_FLOW_ATTR_MASK);
+               if (!nla)
+                       goto nla_put_failure;
 
-       err = ovs_nla_put_flow(&flow->key, &flow->mask->key, skb);
-       if (err)
-               goto error;
+               err = ovs_nla_put_flow(&flow->key, &flow->mask->key, skb);
+               if (err)
+                       goto error;
 
-       nla_nest_end(skb, nla);
+               nla_nest_end(skb, nla);
+       }
 
-       ovs_flow_stats_get(flow, &stats, &used, &tcp_flags);
-       if (used &&
-           nla_put_u64(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used)))
-               goto nla_put_failure;
+       if (what & 1 << OVS_FLOW_ATTR_STATS) {
+               ovs_flow_stats_get(flow, &stats, &used, &tcp_flags);
+               if (used &&
+                   nla_put_u64(skb, OVS_FLOW_ATTR_USED, 
ovs_flow_used_time(used)))
+                       goto nla_put_failure;
 
-       if (stats.n_packets &&
-           nla_put(skb, OVS_FLOW_ATTR_STATS, sizeof(struct ovs_flow_stats), 
&stats))
-               goto nla_put_failure;
+               if (stats.n_packets &&
+                   nla_put(skb, OVS_FLOW_ATTR_STATS, sizeof(struct 
ovs_flow_stats), &stats))
+                       goto nla_put_failure;
 
-       if ((u8)ntohs(tcp_flags) &&
-            nla_put_u8(skb, OVS_FLOW_ATTR_TCP_FLAGS, (u8)ntohs(tcp_flags)))
-               goto nla_put_failure;
+               if ((u8)ntohs(tcp_flags) &&
+                   nla_put_u8(skb, OVS_FLOW_ATTR_TCP_FLAGS, 
(u8)ntohs(tcp_flags)))
+                       goto nla_put_failure;
+       }
 
        /* If OVS_FLOW_ATTR_ACTIONS doesn't fit, skip dumping the actions if
         * this is the first flow to be dumped into 'skb'.  This is unusual for
@@ -713,25 +722,26 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, 
struct datapath *dp,
         * 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 (what & 1 << OVS_FLOW_ATTR_ACTIONS) {
+               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:
@@ -741,30 +751,29 @@ error:
        return err;
 }
 
+/* 'flow' will be dereferenced only if '(what & 1 << OVS_FLOW_ATTR_ACTIONS)'. 
*/
 static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow,
-                                              struct genl_info *info)
+                                              struct genl_info *info,
+                                              u64 what)
 {
-       size_t len;
-
-       len = ovs_flow_cmd_msg_size(ovsl_dereference(flow->sf_acts));
-
-       return genlmsg_new_unicast(len, info, GFP_KERNEL);
+       return genlmsg_new_unicast(ovs_flow_cmd_msg_size(flow, what),
+                                  info, GFP_KERNEL);
 }
 
 static struct sk_buff *ovs_flow_cmd_build_info(struct sw_flow *flow,
                                               struct datapath *dp,
                                               struct genl_info *info,
-                                              u8 cmd)
+                                              u8 cmd, u64 what)
 {
        struct sk_buff *skb;
        int retval;
 
-       skb = ovs_flow_cmd_alloc_info(flow, info);
+       skb = ovs_flow_cmd_alloc_info(flow, info, what);
        if (!skb)
                return ERR_PTR(-ENOMEM);
 
        retval = ovs_flow_cmd_fill_info(flow, dp, skb, info->snd_portid,
-                                       info->snd_seq, 0, cmd);
+                                       info->snd_seq, 0, cmd, what);
        BUG_ON(retval < 0);
        return skb;
 }
@@ -776,7 +785,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, 
struct genl_info *info)
        struct sw_flow_key key, masked_key;
        struct sw_flow *flow = NULL;
        struct sw_flow_mask mask;
-       struct sk_buff *reply;
+       struct sk_buff *reply = NULL;
        struct datapath *dp;
        struct sw_flow_actions *acts = NULL;
        struct sw_flow_match match;
@@ -845,7 +854,10 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, 
struct genl_info *info)
                        goto err_flow_free;
                }
 
-               reply = ovs_flow_cmd_build_info(flow, dp, info, 
OVS_FLOW_CMD_NEW);
+               if (info->nlhdr->nlmsg_flags & NLM_F_ECHO)
+                       reply = ovs_flow_cmd_build_info(flow, dp, info,
+                                                       OVS_FLOW_CMD_NEW,
+                                                       1 << 
OVS_FLOW_ATTR_STATS);
        } else {
                /* We found a matching flow. */
                struct sw_flow_actions *old_acts;
@@ -873,19 +885,23 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, 
struct genl_info *info)
                rcu_assign_pointer(flow->sf_acts, acts);
                ovs_nla_free_flow_actions(old_acts);
 
-               reply = ovs_flow_cmd_build_info(flow, dp, info, 
OVS_FLOW_CMD_NEW);
-
+               if (info->nlhdr->nlmsg_flags & NLM_F_ECHO)
+                       reply = ovs_flow_cmd_build_info(flow, dp, info,
+                                                       OVS_FLOW_CMD_NEW,
+                                                       1 << 
OVS_FLOW_ATTR_STATS);
                /* Clear stats. */
                if (a[OVS_FLOW_ATTR_CLEAR])
                        ovs_flow_stats_clear(flow);
        }
        ovs_unlock();
 
-       if (!IS_ERR(reply))
-               ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
-       else
-               netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
-                               ovs_dp_flow_multicast_group.id, PTR_ERR(reply));
+       if (reply) {
+               if (!IS_ERR(reply))
+                       ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
+               else
+                       netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
+                                       ovs_dp_flow_multicast_group.id, 
PTR_ERR(reply));
+       }
        return 0;
 
 err_flow_free:
@@ -932,7 +948,10 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct 
genl_info *info)
                goto unlock;
        }
 
-       reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW);
+       reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW,
+                                       1 << OVS_FLOW_ATTR_MASK |
+                                       1 << OVS_FLOW_ATTR_STATS |
+                                       1 << OVS_FLOW_ATTR_ACTIONS);
        if (IS_ERR(reply)) {
                err = PTR_ERR(reply);
                goto unlock;
@@ -950,7 +969,7 @@ static int ovs_flow_cmd_del(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 sk_buff *reply;
+       struct sk_buff *reply = NULL;
        struct sw_flow *flow;
        struct datapath *dp;
        struct sw_flow_match match;
@@ -979,22 +998,27 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct 
genl_info *info)
                goto unlock;
        }
 
-       reply = ovs_flow_cmd_alloc_info(flow, info);
-       if (!reply) {
-               err = -ENOMEM;
-               goto unlock;
+       if (info->nlhdr->nlmsg_flags & NLM_F_ECHO) {
+               reply = ovs_flow_cmd_alloc_info(flow, info,
+                                               1 << OVS_FLOW_ATTR_STATS);
+               if (!reply) {
+                       err = -ENOMEM;
+                       goto unlock;
+               }
        }
-
        ovs_flow_tbl_remove(&dp->table, flow);
 
-       err = ovs_flow_cmd_fill_info(flow, dp, reply, info->snd_portid,
-                                    info->snd_seq, 0, OVS_FLOW_CMD_DEL);
-       BUG_ON(err < 0);
-
+       if (reply) {
+               err = ovs_flow_cmd_fill_info(flow, dp, reply, info->snd_portid,
+                                            info->snd_seq, 0, OVS_FLOW_CMD_DEL,
+                                            1 << OVS_FLOW_ATTR_STATS);
+               BUG_ON(err < 0);
+       }
        ovs_flow_free(flow, true);
        ovs_unlock();
 
-       ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
+       if (reply)
+               ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
        return 0;
 unlock:
        ovs_unlock();
@@ -1028,7 +1052,10 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct 
netlink_callback *cb)
                if (ovs_flow_cmd_fill_info(flow, dp, skb,
                                           NETLINK_CB(cb->skb).portid,
                                           cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                                          OVS_FLOW_CMD_NEW) < 0)
+                                          OVS_FLOW_CMD_NEW,
+                                          1 << OVS_FLOW_ATTR_MASK |
+                                          1 << OVS_FLOW_ATTR_STATS |
+                                          1 << OVS_FLOW_ATTR_ACTIONS) < 0)
                        break;
 
                cb->args[0] = bucket;
-- 
1.7.10.4

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

Reply via email to