From: Jarno Rajahalme Date: Sat, 29 Mar 2014 22:52:32 +0000 (-0700) Subject: datapath: Build flow cmd netlink reply only if needed. X-Git-Tag: sliver-openvswitch-2.2.90-1~6^2~9 X-Git-Url: http://git.onelab.eu/?p=sliver-openvswitch.git;a=commitdiff_plain;h=afad3556357e08a3001b9edafcbc267c2e42b715 datapath: Build flow cmd netlink reply only if needed. Use netlink_has_listeners() and NLM_F_ECHO flag to determine if a reply is needed or not for OVS_FLOW_CMD_NEW, OVS_FLOW_CMD_SET, or OVS_FLOW_CMD_DEL. Currently, OVS userspace does not request a reply for OVS_FLOW_CMD_NEW, but usually does for OVS_FLOW_CMD_DEL, as stats may have changed. Signed-off-by: Jarno Rajahalme Signed-off-by: Pravin B Shelar --- diff --git a/datapath/datapath.c b/datapath/datapath.c index 93f8e36e9..d1b015552 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -64,6 +64,15 @@ int ovs_net_id __read_mostly; +/* Check if need to build a reply message. + * OVS userspace sets the NLM_F_ECHO flag if it needs the reply. */ +static bool ovs_must_notify(struct genl_info *info, + const struct genl_multicast_group *grp) +{ + return info->nlhdr->nlmsg_flags & NLM_F_ECHO || + netlink_has_listeners(genl_info_net(info)->genl_sock, grp->id); +} + static void ovs_notify(struct sk_buff *skb, struct genl_info *info, struct genl_multicast_group *grp) { @@ -747,27 +756,37 @@ error: /* Must be called with ovs_mutex. */ static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow, - struct genl_info *info) + struct genl_info *info, + bool always) { + struct sk_buff *skb; size_t len; + if (!always && !ovs_must_notify(info, &ovs_dp_flow_multicast_group)) + return NULL; + len = ovs_flow_cmd_msg_size(ovsl_dereference(flow->sf_acts)); - return genlmsg_new_unicast(len, info, GFP_KERNEL); + skb = genlmsg_new_unicast(len, info, GFP_KERNEL); + + if (!skb) + return ERR_PTR(-ENOMEM); + + return skb; } /* Must be called with ovs_mutex. */ static struct sk_buff *ovs_flow_cmd_build_info(struct sw_flow *flow, struct datapath *dp, struct genl_info *info, - u8 cmd) + u8 cmd, bool always) { struct sk_buff *skb; int retval; - skb = ovs_flow_cmd_alloc_info(flow, info); - if (!skb) - return ERR_PTR(-ENOMEM); + skb = ovs_flow_cmd_alloc_info(flow, info, always); + if (!skb || IS_ERR(skb)) + return skb; retval = ovs_flow_cmd_fill_info(flow, dp, skb, info->snd_portid, info->snd_seq, 0, cmd); @@ -851,7 +870,8 @@ 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); + reply = ovs_flow_cmd_build_info(flow, dp, info, + OVS_FLOW_CMD_NEW, false); } else { /* We found a matching flow. */ /* Bail out if we're not allowed to modify an existing flow. @@ -877,7 +897,8 @@ 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); + reply = ovs_flow_cmd_build_info(flow, dp, info, + OVS_FLOW_CMD_NEW, false); /* Clear stats. */ if (a[OVS_FLOW_ATTR_CLEAR]) @@ -885,11 +906,14 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) } 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: @@ -936,7 +960,7 @@ 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, true); if (IS_ERR(reply)) { err = PTR_ERR(reply); goto unlock; @@ -983,22 +1007,26 @@ 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; + reply = ovs_flow_cmd_alloc_info(flow, info, false); + if (IS_ERR(reply)) { + err = PTR_ERR(reply); 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); + 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();