diff mbox series

[RFC,net-next,1/6] openvswitch: exclude kernel flow key from upcalls

Message ID 20221122140307.705112-2-aconole@redhat.com
State New
Headers show
Series Allow excluding sw flow key from upcalls | expand

Commit Message

Aaron Conole Nov. 22, 2022, 2:03 p.m. UTC
When processing upcall commands, two groups of data are available to
userspace for processing: the actual packet data and the kernel
sw flow key data.  The inclusion of the flow key allows the userspace
avoid running through the dissection again.

However, the userspace can choose to ignore the flow key data, as is
the case in some ovs-vswitchd upcall processing.  For these messages,
having the flow key data merely adds additional data to the upcall
pipeline without any actual gain.  Userspace simply throws the data
away anyway.

Introduce a new feature OVS_DP_F_EXCLUDE_UPCALL_FLOW_KEY which signals
that the userspace doesn't want upcalls included with specific class
of message (for example MISS messages).  The associated attribute
OVS_DP_ATTR_EXCLUDE_CMDS tells which specific commands to omit via a
bitmask.

A test will be added to showcase using the feature.

Signed-off-by: Aaron Conole <aconole@redhat.com>
---
 include/uapi/linux/openvswitch.h |  6 ++++++
 net/openvswitch/datapath.c       | 26 ++++++++++++++++++++++----
 net/openvswitch/datapath.h       |  2 ++
 3 files changed, 30 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h
index 94066f87e9ee..238e62ecba46 100644
--- a/include/uapi/linux/openvswitch.h
+++ b/include/uapi/linux/openvswitch.h
@@ -95,6 +95,9 @@  enum ovs_datapath_attr {
 				     * per-cpu dispatch mode
 				     */
 	OVS_DP_ATTR_IFINDEX,
+	OVS_DP_ATTR_EXCLUDE_CMDS,	/* u32 mask of OVS_PACKET_CMDs for
+					 * omitting FLOW_KEY attribute
+					 */
 	__OVS_DP_ATTR_MAX
 };
 
@@ -138,6 +141,9 @@  struct ovs_vport_stats {
 /* Allow per-cpu dispatch of upcalls */
 #define OVS_DP_F_DISPATCH_UPCALL_PER_CPU	(1 << 3)
 
+/* Drop Flow key data from upcall packet cmds */
+#define OVS_DP_F_EXCLUDE_UPCALL_FLOW_KEY	(1 << 4)
+
 /* Fixed logical ports. */
 #define OVSP_LOCAL      ((__u32)0)
 
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 861dfb8daf4a..6afde7de492c 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -470,9 +470,13 @@  static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
 	}
 	upcall->dp_ifindex = dp_ifindex;
 
-	err = ovs_nla_put_key(key, key, OVS_PACKET_ATTR_KEY, false, user_skb);
-	if (err)
-		goto out;
+	if (!(dp->user_features & OVS_DP_F_EXCLUDE_UPCALL_FLOW_KEY) ||
+	    !(dp->upcall_exclude_cmds & (1U << upcall_info->cmd))) {
+		err = ovs_nla_put_key(key, key, OVS_PACKET_ATTR_KEY, false,
+				      user_skb);
+		if (err)
+			goto out;
+	}
 
 	if (upcall_info->userdata)
 		__nla_put(user_skb, OVS_PACKET_ATTR_USERDATA,
@@ -1526,6 +1530,7 @@  static size_t ovs_dp_cmd_msg_size(void)
 	msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_USER_FEATURES */
 	msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_MASKS_CACHE_SIZE */
 	msgsize += nla_total_size(sizeof(u32) * nr_cpu_ids); /* OVS_DP_ATTR_PER_CPU_PIDS */
+	msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_EXCLUDE_CMDS */
 
 	return msgsize;
 }
@@ -1574,6 +1579,10 @@  static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb,
 			goto nla_put_failure;
 	}
 
+	if (nla_put_u32(skb, OVS_DP_ATTR_EXCLUDE_CMDS,
+			dp->upcall_exclude_cmds))
+		goto nla_put_failure;
+
 	genlmsg_end(skb, ovs_header);
 	return 0;
 
@@ -1684,7 +1693,8 @@  static int ovs_dp_change(struct datapath *dp, struct nlattr *a[])
 		if (user_features & ~(OVS_DP_F_VPORT_PIDS |
 				      OVS_DP_F_UNALIGNED |
 				      OVS_DP_F_TC_RECIRC_SHARING |
-				      OVS_DP_F_DISPATCH_UPCALL_PER_CPU))
+				      OVS_DP_F_DISPATCH_UPCALL_PER_CPU |
+				      OVS_DP_F_EXCLUDE_UPCALL_FLOW_KEY))
 			return -EOPNOTSUPP;
 
 #if !IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
@@ -1705,6 +1715,14 @@  static int ovs_dp_change(struct datapath *dp, struct nlattr *a[])
 
 	dp->user_features = user_features;
 
+	if (dp->user_features & OVS_DP_F_EXCLUDE_UPCALL_FLOW_KEY) {
+		if (!a[OVS_DP_ATTR_EXCLUDE_CMDS])
+			return -EINVAL;
+
+		dp->upcall_exclude_cmds =
+			nla_get_u32(a[OVS_DP_ATTR_EXCLUDE_CMDS]);
+	}
+
 	if (dp->user_features & OVS_DP_F_DISPATCH_UPCALL_PER_CPU &&
 	    a[OVS_DP_ATTR_PER_CPU_PIDS]) {
 		/* Upcall Netlink Port IDs have been updated */
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
index 0cd29971a907..3c951e25509e 100644
--- a/net/openvswitch/datapath.h
+++ b/net/openvswitch/datapath.h
@@ -101,6 +101,8 @@  struct datapath {
 
 	u32 max_headroom;
 
+	u32 upcall_exclude_cmds;
+
 	/* Switch meters. */
 	struct dp_meter_table meter_tbl;