net/sched: Enable tc skb ext allocation on chain miss only when needed
authorPaul Blakey <paulb@nvidia.com>
Thu, 3 Feb 2022 08:44:30 +0000 (10:44 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sat, 5 Feb 2022 10:12:53 +0000 (10:12 +0000)
Currently tc skb extension is used to send miss info from
tc to ovs datapath module, and driver to tc. For the tc to ovs
miss it is currently always allocated even if it will not
be used by ovs datapath (as it depends on a requested feature).

Export the static key which is used by openvswitch module to
guard this code path as well, so it will be skipped if ovs
datapath doesn't need it. Enable this code path once
ovs datapath needs it.

Signed-off-by: Paul Blakey <paulb@nvidia.com>
Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/pkt_cls.h
net/openvswitch/datapath.c
net/openvswitch/datapath.h
net/openvswitch/flow.c
net/sched/cls_api.c

index 676cb8ea9e15cae4b098b461918ea0ff49d97768..a3b57a93228a7f9d1f85596c6252489e1dd2066d 100644 (file)
@@ -1028,4 +1028,15 @@ struct tc_fifo_qopt_offload {
        };
 };
 
+#ifdef CONFIG_NET_CLS_ACT
+DECLARE_STATIC_KEY_FALSE(tc_skb_ext_tc);
+void tc_skb_ext_tc_enable(void);
+void tc_skb_ext_tc_disable(void);
+#define tc_skb_ext_tc_enabled() static_branch_unlikely(&tc_skb_ext_tc)
+#else /* CONFIG_NET_CLS_ACT */
+static inline void tc_skb_ext_tc_enable(void) { }
+static inline void tc_skb_ext_tc_disable(void) { }
+#define tc_skb_ext_tc_enabled() false
+#endif
+
 #endif
index 67ad08320886bac67071eb2e3d87531733b2ab9f..7e8a39a356271760be552dc5715ac162efac5901 100644 (file)
@@ -37,6 +37,7 @@
 #include <net/genetlink.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
+#include <net/pkt_cls.h>
 
 #include "datapath.h"
 #include "flow.h"
@@ -1601,8 +1602,6 @@ static void ovs_dp_reset_user_features(struct sk_buff *skb,
        dp->user_features = 0;
 }
 
-DEFINE_STATIC_KEY_FALSE(tc_recirc_sharing_support);
-
 static int ovs_dp_set_upcall_portids(struct datapath *dp,
                              const struct nlattr *ids)
 {
@@ -1657,7 +1656,7 @@ u32 ovs_dp_get_upcall_portid(const struct datapath *dp, uint32_t cpu_id)
 
 static int ovs_dp_change(struct datapath *dp, struct nlattr *a[])
 {
-       u32 user_features = 0;
+       u32 user_features = 0, old_features = dp->user_features;
        int err;
 
        if (a[OVS_DP_ATTR_USER_FEATURES]) {
@@ -1696,10 +1695,12 @@ static int ovs_dp_change(struct datapath *dp, struct nlattr *a[])
                        return err;
        }
 
-       if (dp->user_features & OVS_DP_F_TC_RECIRC_SHARING)
-               static_branch_enable(&tc_recirc_sharing_support);
-       else
-               static_branch_disable(&tc_recirc_sharing_support);
+       if ((dp->user_features & OVS_DP_F_TC_RECIRC_SHARING) &&
+           !(old_features & OVS_DP_F_TC_RECIRC_SHARING))
+               tc_skb_ext_tc_enable();
+       else if (!(dp->user_features & OVS_DP_F_TC_RECIRC_SHARING) &&
+                (old_features & OVS_DP_F_TC_RECIRC_SHARING))
+               tc_skb_ext_tc_disable();
 
        return 0;
 }
@@ -1839,6 +1840,9 @@ static void __dp_destroy(struct datapath *dp)
        struct flow_table *table = &dp->table;
        int i;
 
+       if (dp->user_features & OVS_DP_F_TC_RECIRC_SHARING)
+               tc_skb_ext_tc_disable();
+
        for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
                struct vport *vport;
                struct hlist_node *n;
index fcfe6cb464417e4a015e8e933330493b84f9f42c..0cd29971a907cabe1436703e90386889e77a14d8 100644 (file)
@@ -253,8 +253,6 @@ static inline struct datapath *get_dp(struct net *net, int dp_ifindex)
 extern struct notifier_block ovs_dp_device_notifier;
 extern struct genl_family dp_vport_genl_family;
 
-DECLARE_STATIC_KEY_FALSE(tc_recirc_sharing_support);
-
 void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key);
 void ovs_dp_detach_port(struct vport *);
 int ovs_dp_upcall(struct datapath *, struct sk_buff *,
index 02096f2ec678468ae92e19538c2b30cea6d21e92..f6cd24fd530c8d2e9e90d06b34299c50a3d19d95 100644 (file)
@@ -34,6 +34,7 @@
 #include <net/mpls.h>
 #include <net/ndisc.h>
 #include <net/nsh.h>
+#include <net/pkt_cls.h>
 #include <net/netfilter/nf_conntrack_zones.h>
 
 #include "conntrack.h"
@@ -895,7 +896,7 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
        key->mac_proto = res;
 
 #if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
-       if (static_branch_unlikely(&tc_recirc_sharing_support)) {
+       if (tc_skb_ext_tc_enabled()) {
                tc_ext = skb_ext_find(skb, TC_SKB_EXT);
                key->recirc_id = tc_ext ? tc_ext->chain : 0;
                OVS_CB(skb)->mru = tc_ext ? tc_ext->mru : 0;
index 5f0f346b576fc0f52a5b8de21758af5425285c2c..ff1e6b474fef7de0fc90c878bd773e5d14cb4ea0 100644 (file)
@@ -49,6 +49,23 @@ static LIST_HEAD(tcf_proto_base);
 /* Protects list of registered TC modules. It is pure SMP lock. */
 static DEFINE_RWLOCK(cls_mod_lock);
 
+#ifdef CONFIG_NET_CLS_ACT
+DEFINE_STATIC_KEY_FALSE(tc_skb_ext_tc);
+EXPORT_SYMBOL(tc_skb_ext_tc);
+
+void tc_skb_ext_tc_enable(void)
+{
+       static_branch_inc(&tc_skb_ext_tc);
+}
+EXPORT_SYMBOL(tc_skb_ext_tc_enable);
+
+void tc_skb_ext_tc_disable(void)
+{
+       static_branch_dec(&tc_skb_ext_tc);
+}
+EXPORT_SYMBOL(tc_skb_ext_tc_disable);
+#endif
+
 static u32 destroy_obj_hashfn(const struct tcf_proto *tp)
 {
        return jhash_3words(tp->chain->index, tp->prio,
@@ -1615,19 +1632,21 @@ int tcf_classify(struct sk_buff *skb,
        ret = __tcf_classify(skb, tp, orig_tp, res, compat_mode,
                             &last_executed_chain);
 
-       /* If we missed on some chain */
-       if (ret == TC_ACT_UNSPEC && last_executed_chain) {
-               struct tc_skb_cb *cb = tc_skb_cb(skb);
-
-               ext = tc_skb_ext_alloc(skb);
-               if (WARN_ON_ONCE(!ext))
-                       return TC_ACT_SHOT;
-               ext->chain = last_executed_chain;
-               ext->mru = cb->mru;
-               ext->post_ct = cb->post_ct;
-               ext->post_ct_snat = cb->post_ct_snat;
-               ext->post_ct_dnat = cb->post_ct_dnat;
-               ext->zone = cb->zone;
+       if (tc_skb_ext_tc_enabled()) {
+               /* If we missed on some chain */
+               if (ret == TC_ACT_UNSPEC && last_executed_chain) {
+                       struct tc_skb_cb *cb = tc_skb_cb(skb);
+
+                       ext = tc_skb_ext_alloc(skb);
+                       if (WARN_ON_ONCE(!ext))
+                               return TC_ACT_SHOT;
+                       ext->chain = last_executed_chain;
+                       ext->mru = cb->mru;
+                       ext->post_ct = cb->post_ct;
+                       ext->post_ct_snat = cb->post_ct_snat;
+                       ext->post_ct_dnat = cb->post_ct_dnat;
+                       ext->zone = cb->zone;
+               }
        }
 
        return ret;