[net-next v1 2/2] net: sched: support hash/classid selecting queue_mapping
flat view
From: <hidden>
Date: 2021-12-06 08:05:35
Subsystem:
networking [general], tc subsystem, the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jamal Hadi Salim, Jiri Pirko, Linus Torvalds
From: Tonghao Zhang <redacted> This patch allows users to select queue_mapping, range from A to B. And users can use skb-hash or cgroup classid to select queues. Then the packets can load balance from A to B queue. $ tc filter ... action skbedit queue_mapping hash-type normal 0 4 "skbedit queue_mapping QUEUE_MAPPING"[0] is enhanced with two flags: SKBEDIT_F_QUEUE_MAPPING_HASH, SKBEDIT_F_QUEUE_MAPPING_CLASSID. The range is an unsigned 8bit value in decimal format. [0]: https://man7.org/linux/man-pages/man8/tc-skbedit.8.html Cc: Jamal Hadi Salim <jhs@mojatatu.com> Cc: Cong Wang <redacted> Cc: Jiri Pirko <jiri@resnulli.us> Cc: "David S. Miller" <davem@davemloft.net> Cc: Jakub Kicinski <kuba@kernel.org> Cc: Jonathan Lemon <redacted> Cc: Eric Dumazet <redacted> Cc: Alexander Lobakin <redacted> Cc: Paolo Abeni <pabeni@redhat.com> Cc: Talal Ahmad <redacted> Cc: Kevin Hao <redacted> Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org> Cc: Kees Cook <redacted> Cc: Kumar Kartikeya Dwivedi <memxor@gmail.com> Cc: Antoine Tenart <atenart@kernel.org> Cc: Wei Wang <redacted> Cc: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Tonghao Zhang <redacted> --- include/net/tc_act/tc_skbedit.h | 1 + include/uapi/linux/tc_act/tc_skbedit.h | 5 +++ net/sched/act_skbedit.c | 48 +++++++++++++++++++++++--- 3 files changed, 50 insertions(+), 4 deletions(-)
diff --git a/include/net/tc_act/tc_skbedit.h b/include/net/tc_act/tc_skbedit.h
index 00bfee70609e..ee96e0fa6566 100644
--- a/include/net/tc_act/tc_skbedit.h
+++ b/include/net/tc_act/tc_skbedit.h@@ -17,6 +17,7 @@ struct tcf_skbedit_params { u32 mark; u32 mask; u16 queue_mapping; + u16 mapping_mod; u16 ptype; struct rcu_head rcu; };
diff --git a/include/uapi/linux/tc_act/tc_skbedit.h b/include/uapi/linux/tc_act/tc_skbedit.h
index 800e93377218..badb58ec84ef 100644
--- a/include/uapi/linux/tc_act/tc_skbedit.h
+++ b/include/uapi/linux/tc_act/tc_skbedit.h@@ -29,6 +29,11 @@ #define SKBEDIT_F_PTYPE 0x8 #define SKBEDIT_F_MASK 0x10 #define SKBEDIT_F_INHERITDSFIELD 0x20 +#define SKBEDIT_F_QUEUE_MAPPING_HASH 0x40 +#define SKBEDIT_F_QUEUE_MAPPING_CLASSID 0x80 + +#define SKBEDIT_F_QUEUE_MAPPING_HASH_MASK (SKBEDIT_F_QUEUE_MAPPING_HASH | \ + SKBEDIT_F_QUEUE_MAPPING_CLASSID) struct tc_skbedit { tc_gen;
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index 940091a7c7f0..9cb65bcce001 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c@@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/skbuff.h> #include <linux/rtnetlink.h> +#include <net/cls_cgroup.h> #include <net/netlink.h> #include <net/pkt_sched.h> #include <net/ip.h>
@@ -23,6 +24,25 @@ static unsigned int skbedit_net_id; static struct tc_action_ops act_skbedit_ops; +static u16 tcf_skbedit_hash(struct tcf_skbedit_params *params, + struct sk_buff *skb) +{ + u16 queue_mapping = params->queue_mapping; + u16 mapping_mod = params->mapping_mod; + u32 hash = 0; + + if (!(params->flags & SKBEDIT_F_QUEUE_MAPPING_HASH_MASK)) + return netdev_cap_txqueue(skb->dev, queue_mapping); + + if (params->flags & SKBEDIT_F_QUEUE_MAPPING_CLASSID) + hash = jhash_1word(task_get_classid(skb), 0); + else if (params->flags & SKBEDIT_F_QUEUE_MAPPING_HASH) + hash = skb_get_hash(skb); + + queue_mapping= (queue_mapping & 0xff) + hash % mapping_mod; + return netdev_cap_txqueue(skb->dev, queue_mapping); +} + static int tcf_skbedit_act(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) {
@@ -57,10 +77,9 @@ static int tcf_skbedit_act(struct sk_buff *skb, const struct tc_action *a, break; } } - if (params->flags & SKBEDIT_F_QUEUE_MAPPING && - skb->dev->real_num_tx_queues > params->queue_mapping) { + if (params->flags & SKBEDIT_F_QUEUE_MAPPING) { skb->tc_skip_txqueue = 1; - skb_set_queue_mapping(skb, params->queue_mapping); + skb_set_queue_mapping(skb, tcf_skbedit_hash(params, skb)); } if (params->flags & SKBEDIT_F_MARK) { skb->mark &= ~params->mask;
@@ -110,6 +129,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, struct tcf_skbedit *d; u32 flags = 0, *priority = NULL, *mark = NULL, *mask = NULL; u16 *queue_mapping = NULL, *ptype = NULL; + u16 mapping_mod = 0; bool exists = false; int ret = 0, err; u32 index;
@@ -157,6 +177,21 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, if (*pure_flags & SKBEDIT_F_INHERITDSFIELD) flags |= SKBEDIT_F_INHERITDSFIELD; + if (*pure_flags & SKBEDIT_F_QUEUE_MAPPING_HASH_MASK) { + u16 max, min; + + if (!queue_mapping) + return -EINVAL; + + max = *queue_mapping >> 8; + min = *queue_mapping & 0xff; + if (max < min) + return -EINVAL; + + mapping_mod = max - min + 1; + flags |= *pure_flags & + SKBEDIT_F_QUEUE_MAPPING_HASH_MASK; + } } parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
@@ -206,8 +241,10 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, params_new->flags = flags; if (flags & SKBEDIT_F_PRIORITY) params_new->priority = *priority; - if (flags & SKBEDIT_F_QUEUE_MAPPING) + if (flags & SKBEDIT_F_QUEUE_MAPPING) { params_new->queue_mapping = *queue_mapping; + params_new->mapping_mod = mapping_mod; + } if (flags & SKBEDIT_F_MARK) params_new->mark = *mark; if (flags & SKBEDIT_F_PTYPE)
@@ -274,6 +311,9 @@ static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a, goto nla_put_failure; if (params->flags & SKBEDIT_F_INHERITDSFIELD) pure_flags |= SKBEDIT_F_INHERITDSFIELD; + if (params->flags & SKBEDIT_F_QUEUE_MAPPING_HASH_MASK) + pure_flags |= params->flags & + SKBEDIT_F_QUEUE_MAPPING_HASH_MASK; if (pure_flags != 0 && nla_put(skb, TCA_SKBEDIT_FLAGS, sizeof(pure_flags), &pure_flags)) goto nla_put_failure;
--
2.27.0