net:sched: add action inheritdsfield to skbedit
authorQiaobin Fu <qiaobinf@bu.edu>
Sun, 1 Jul 2018 19:16:27 +0000 (15:16 -0400)
committerDavid S. Miller <davem@davemloft.net>
Wed, 4 Jul 2018 12:27:42 +0000 (21:27 +0900)
The new action inheritdsfield copies the field DS of
IPv4 and IPv6 packets into skb->priority. This enables
later classification of packets based on the DS field.

v5:
*Update the drop counter for TC_ACT_SHOT

v4:
*Not allow setting flags other than the expected ones.

*Allow dumping the pure flags.

v3:
*Use optional flags, so that it won't break old versions of tc.

*Allow users to set both SKBEDIT_F_PRIORITY and SKBEDIT_F_INHERITDSFIELD flags.

v2:
*Fix the style issue

*Move the code from skbmod to skbedit

Original idea by Jamal Hadi Salim <jhs@mojatatu.com>

Signed-off-by: Qiaobin Fu <qiaobinf@bu.edu>
Reviewed-by: Michel Machado <michel@digirati.com.br>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Acked-by: Davide Caratti <dcaratti@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/tc_act/tc_skbedit.h
net/sched/act_skbedit.c

index fbcfe27a4e6c4173553fe675655f86c2e4f51045..6de6071ebed605f3165ad49eca2ac645b4cff5a9 100644 (file)
@@ -30,6 +30,7 @@
 #define SKBEDIT_F_MARK                 0x4
 #define SKBEDIT_F_PTYPE                        0x8
 #define SKBEDIT_F_MASK                 0x10
+#define SKBEDIT_F_INHERITDSFIELD       0x20
 
 struct tc_skbedit {
        tc_gen;
@@ -45,6 +46,7 @@ enum {
        TCA_SKBEDIT_PAD,
        TCA_SKBEDIT_PTYPE,
        TCA_SKBEDIT_MASK,
+       TCA_SKBEDIT_FLAGS,
        __TCA_SKBEDIT_MAX
 };
 #define TCA_SKBEDIT_MAX (__TCA_SKBEDIT_MAX - 1)
index 6138d1d71900b561f50578bf22110902bb488bf4..dfaf5d8028dda324ddfee2cc63a2fd03fd9c90ee 100644 (file)
@@ -23,6 +23,9 @@
 #include <linux/rtnetlink.h>
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/dsfield.h>
 
 #include <linux/tc_act/tc_skbedit.h>
 #include <net/tc_act/tc_skbedit.h>
@@ -41,6 +44,25 @@ static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a,
 
        if (d->flags & SKBEDIT_F_PRIORITY)
                skb->priority = d->priority;
+       if (d->flags & SKBEDIT_F_INHERITDSFIELD) {
+               int wlen = skb_network_offset(skb);
+
+               switch (tc_skb_protocol(skb)) {
+               case htons(ETH_P_IP):
+                       wlen += sizeof(struct iphdr);
+                       if (!pskb_may_pull(skb, wlen))
+                               goto err;
+                       skb->priority = ipv4_get_dsfield(ip_hdr(skb)) >> 2;
+                       break;
+
+               case htons(ETH_P_IPV6):
+                       wlen += sizeof(struct ipv6hdr);
+                       if (!pskb_may_pull(skb, wlen))
+                               goto err;
+                       skb->priority = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2;
+                       break;
+               }
+       }
        if (d->flags & SKBEDIT_F_QUEUE_MAPPING &&
            skb->dev->real_num_tx_queues > d->queue_mapping)
                skb_set_queue_mapping(skb, d->queue_mapping);
@@ -53,6 +75,11 @@ static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a,
 
        spin_unlock(&d->tcf_lock);
        return d->tcf_action;
+
+err:
+       d->tcf_qstats.drops++;
+       spin_unlock(&d->tcf_lock);
+       return TC_ACT_SHOT;
 }
 
 static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
@@ -62,6 +89,7 @@ static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
        [TCA_SKBEDIT_MARK]              = { .len = sizeof(u32) },
        [TCA_SKBEDIT_PTYPE]             = { .len = sizeof(u16) },
        [TCA_SKBEDIT_MASK]              = { .len = sizeof(u32) },
+       [TCA_SKBEDIT_FLAGS]             = { .len = sizeof(u64) },
 };
 
 static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
@@ -114,6 +142,13 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
                mask = nla_data(tb[TCA_SKBEDIT_MASK]);
        }
 
+       if (tb[TCA_SKBEDIT_FLAGS] != NULL) {
+               u64 *pure_flags = nla_data(tb[TCA_SKBEDIT_FLAGS]);
+
+               if (*pure_flags & SKBEDIT_F_INHERITDSFIELD)
+                       flags |= SKBEDIT_F_INHERITDSFIELD;
+       }
+
        parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
 
        exists = tcf_idr_check(tn, parm->index, a, bind);
@@ -178,6 +213,7 @@ static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a,
                .action  = d->tcf_action,
        };
        struct tcf_t t;
+       u64 pure_flags = 0;
 
        if (nla_put(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt))
                goto nla_put_failure;
@@ -196,6 +232,11 @@ static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a,
        if ((d->flags & SKBEDIT_F_MASK) &&
            nla_put_u32(skb, TCA_SKBEDIT_MASK, d->mask))
                goto nla_put_failure;
+       if (d->flags & SKBEDIT_F_INHERITDSFIELD)
+               pure_flags |= SKBEDIT_F_INHERITDSFIELD;
+       if (pure_flags != 0 &&
+           nla_put(skb, TCA_SKBEDIT_FLAGS, sizeof(pure_flags), &pure_flags))
+               goto nla_put_failure;
 
        tcf_tm_dump(&t, &d->tcf_tm);
        if (nla_put_64bit(skb, TCA_SKBEDIT_TM, sizeof(t), &t, TCA_SKBEDIT_PAD))