Skip to content

Commit fb5d1e9

Browse files
Jarno RajahalmePravin B Shelar
authored andcommitted
openvswitch: 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 <[email protected]> Signed-off-by: Pravin B Shelar <[email protected]>
1 parent bb6f9a7 commit fb5d1e9

File tree

1 file changed

+48
-22
lines changed

1 file changed

+48
-22
lines changed

net/openvswitch/datapath.c

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@
6262

6363
int ovs_net_id __read_mostly;
6464

65+
/* Check if need to build a reply message.
66+
* OVS userspace sets the NLM_F_ECHO flag if it needs the reply. */
67+
static bool ovs_must_notify(struct genl_info *info,
68+
const struct genl_multicast_group *grp)
69+
{
70+
return info->nlhdr->nlmsg_flags & NLM_F_ECHO ||
71+
netlink_has_listeners(genl_info_net(info)->genl_sock, 0);
72+
}
73+
6574
static void ovs_notify(struct genl_family *family,
6675
struct sk_buff *skb, struct genl_info *info)
6776
{
@@ -746,27 +755,36 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
746755

747756
/* Must be called with ovs_mutex. */
748757
static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow,
749-
struct genl_info *info)
758+
struct genl_info *info,
759+
bool always)
750760
{
761+
struct sk_buff *skb;
751762
size_t len;
752763

764+
if (!always && !ovs_must_notify(info, &ovs_dp_flow_multicast_group))
765+
return NULL;
766+
753767
len = ovs_flow_cmd_msg_size(ovsl_dereference(flow->sf_acts));
754768

755-
return genlmsg_new_unicast(len, info, GFP_KERNEL);
769+
skb = genlmsg_new_unicast(len, info, GFP_KERNEL);
770+
if (!skb)
771+
return ERR_PTR(-ENOMEM);
772+
773+
return skb;
756774
}
757775

758776
/* Must be called with ovs_mutex. */
759777
static struct sk_buff *ovs_flow_cmd_build_info(struct sw_flow *flow,
760778
struct datapath *dp,
761779
struct genl_info *info,
762-
u8 cmd)
780+
u8 cmd, bool always)
763781
{
764782
struct sk_buff *skb;
765783
int retval;
766784

767-
skb = ovs_flow_cmd_alloc_info(flow, info);
768-
if (!skb)
769-
return ERR_PTR(-ENOMEM);
785+
skb = ovs_flow_cmd_alloc_info(flow, info, always);
786+
if (!skb || IS_ERR(skb))
787+
return skb;
770788

771789
retval = ovs_flow_cmd_fill_info(flow, dp, skb, info->snd_portid,
772790
info->snd_seq, 0, cmd);
@@ -850,7 +868,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
850868
goto err_flow_free;
851869
}
852870

853-
reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW);
871+
reply = ovs_flow_cmd_build_info(flow, dp, info,
872+
OVS_FLOW_CMD_NEW, false);
854873
} else {
855874
/* We found a matching flow. */
856875
/* Bail out if we're not allowed to modify an existing flow.
@@ -876,19 +895,23 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
876895
rcu_assign_pointer(flow->sf_acts, acts);
877896
ovs_nla_free_flow_actions(old_acts);
878897
}
879-
reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW);
898+
reply = ovs_flow_cmd_build_info(flow, dp, info,
899+
OVS_FLOW_CMD_NEW, false);
880900

881901
/* Clear stats. */
882902
if (a[OVS_FLOW_ATTR_CLEAR])
883903
ovs_flow_stats_clear(flow);
884904
}
885905
ovs_unlock();
886906

887-
if (!IS_ERR(reply))
888-
ovs_notify(&dp_flow_genl_family, reply, info);
889-
else
890-
genl_set_err(&dp_flow_genl_family, sock_net(skb->sk), 0,
891-
0, PTR_ERR(reply));
907+
if (reply) {
908+
if (!IS_ERR(reply))
909+
ovs_notify(&dp_flow_genl_family, reply, info);
910+
else
911+
genl_set_err(&dp_flow_genl_family, sock_net(skb->sk), 0,
912+
0, PTR_ERR(reply));
913+
}
914+
892915
return 0;
893916

894917
err_flow_free:
@@ -935,7 +958,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
935958
goto unlock;
936959
}
937960

938-
reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW);
961+
reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW, true);
939962
if (IS_ERR(reply)) {
940963
err = PTR_ERR(reply);
941964
goto unlock;
@@ -982,22 +1005,25 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
9821005
goto unlock;
9831006
}
9841007

985-
reply = ovs_flow_cmd_alloc_info(flow, info);
986-
if (!reply) {
987-
err = -ENOMEM;
1008+
reply = ovs_flow_cmd_alloc_info(flow, info, false);
1009+
if (IS_ERR(reply)) {
1010+
err = PTR_ERR(reply);
9881011
goto unlock;
9891012
}
9901013

9911014
ovs_flow_tbl_remove(&dp->table, flow);
9921015

993-
err = ovs_flow_cmd_fill_info(flow, dp, reply, info->snd_portid,
994-
info->snd_seq, 0, OVS_FLOW_CMD_DEL);
995-
BUG_ON(err < 0);
996-
1016+
if (reply) {
1017+
err = ovs_flow_cmd_fill_info(flow, dp, reply, info->snd_portid,
1018+
info->snd_seq, 0,
1019+
OVS_FLOW_CMD_DEL);
1020+
BUG_ON(err < 0);
1021+
}
9971022
ovs_flow_free(flow, true);
9981023
ovs_unlock();
9991024

1000-
ovs_notify(&dp_flow_genl_family, reply, info);
1025+
if (reply)
1026+
ovs_notify(&dp_flow_genl_family, reply, info);
10011027
return 0;
10021028
unlock:
10031029
ovs_unlock();

0 commit comments

Comments
 (0)