From 29b7968926edb6256aaa1f699ad4f40041281856 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 16 May 2016 11:13:05 -0700 Subject: [PATCH 1/4] add tc_ife.h --- include/linux/tc_act/tc_ife.h | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 include/linux/tc_act/tc_ife.h diff --git a/include/linux/tc_act/tc_ife.h b/include/linux/tc_act/tc_ife.h new file mode 100644 index 00000000..d648ff66 --- /dev/null +++ b/include/linux/tc_act/tc_ife.h @@ -0,0 +1,38 @@ +#ifndef __UAPI_TC_IFE_H +#define __UAPI_TC_IFE_H + +#include +#include + +#define TCA_ACT_IFE 25 +/* Flag bits for now just encoding/decoding; mutually exclusive */ +#define IFE_ENCODE 1 +#define IFE_DECODE 0 + +struct tc_ife { + tc_gen; + __u16 flags; +}; + +/*XXX: We need to encode the total number of bytes consumed */ +enum { + TCA_IFE_UNSPEC, + TCA_IFE_PARMS, + TCA_IFE_TM, + TCA_IFE_DMAC, + TCA_IFE_SMAC, + TCA_IFE_TYPE, + TCA_IFE_METALST, + __TCA_IFE_MAX +}; +#define TCA_IFE_MAX (__TCA_IFE_MAX - 1) + +#define IFE_META_SKBMARK 1 +#define IFE_META_HASHID 2 +#define IFE_META_PRIO 3 +#define IFE_META_QMAP 4 +/*Can be overridden at runtime by module option*/ +#define __IFE_META_MAX 5 +#define IFE_META_MAX (__IFE_META_MAX - 1) + +#endif From d3e511223fc5042f181332622ea97ae617cc73bc Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sat, 7 May 2016 09:35:23 -0400 Subject: [PATCH 2/4] tc: introduce IFE action This action allows for a sending side to encapsulate arbitrary metadata which is decapsulated by the receiving end. The sender runs in encoding mode and the receiver in decode mode. Both sender and receiver must specify the same ethertype. At some point we hope to have a registered ethertype and we'll then provide a default so the user doesnt have to specify it. For now we enforce the user specify it. Described in netdev01 paper: "Distributing Linux Traffic Control Classifier-Action Subsystem" Authors: Jamal Hadi Salim and Damascene M. Joachimpillai Also refer to IETF draft-ietf-forces-interfelfb-04.txt Lets show example usage where we encode icmp from a sender towards a receiver with an skbmark of 17; both sender and receiver use ethertype of 0xdead to interop. YYYY: Lets start with Receiver-side policy config: xxx: add an ingress qdisc sudo tc qdisc add dev $ETH ingress xxx: any packets with ethertype 0xdead will be subjected to ife decoding xxx: we then restart the classification so we can match on icmp at prio 3 sudo $TC filter add dev $ETH parent ffff: prio 2 protocol 0xdead \ u32 match u32 0 0 flowid 1:1 \ action ife decode reclassify xxx: on restarting the classification from above if it was an icmp xxx: packet, then match it here and continue to the next rule at prio 4 xxx: which will match based on skb mark of 17 sudo tc filter add dev $ETH parent ffff: prio 3 protocol ip \ u32 match ip protocol 1 0xff flowid 1:1 \ action continue xxx: match on skbmark of 0x11 (decimal 17) and accept sudo tc filter add dev $ETH parent ffff: prio 4 protocol ip \ handle 0x11 fw flowid 1:1 \ action ok xxx: Lets show the decoding policy sudo tc -s filter ls dev $ETH parent ffff: protocol 0xdead xxx: filter pref 2 u32 filter pref 2 u32 fh 800: ht divisor 1 filter pref 2 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 (rule hit 0 success 0) match 00000000/00000000 at 0 (success 0 ) action order 1: ife decode action reclassify type 0x0 allow mark allow prio index 11 ref 1 bind 1 installed 45 sec used 45 sec Action statistics: Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 xxx: Observe that above lists all metadatum it can decode. Typically these submodules will already be compiled into a monolithic kernel or loaded as modules YYYY: Lets show the sender side now .. xxx: Add an egress qdisc on the sender netdev sudo tc qdisc add dev $ETH root handle 1: prio xxx: xxx: Match all icmp packets to 192.168.122.237/24, then xxx: tag the packet with skb mark of decimal 17, then xxx: Encode it with: xxx: ethertype 0xdead xxx: add skb->mark to whitelist of metadatum to send xxx: rewrite target dst MAC address to 02:15:15:15:15:15 xxx: sudo $TC filter add dev $ETH parent 1: protocol ip prio 10 u32 \ match ip dst 192.168.122.237/24 \ match ip protocol 1 0xff \ flowid 1:2 \ action skbedit mark 17 \ action ife encode \ type 0xDEAD \ allow mark \ dst 02:15:15:15:15:15 xxx: Lets show the encoding policy filter pref 10 u32 filter pref 10 u32 fh 800: ht divisor 1 filter pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:2 (rule hit 118 success 0) match c0a87a00/ffffff00 at 16 (success 0 ) match 00010000/00ff0000 at 8 (success 0 ) action order 1: skbedit mark 17 index 11 ref 1 bind 1 installed 3 sec used 3 sec Action statistics: Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 action order 2: ife encode action pipe type 0xDEAD allow mark dst 02:15:15:15:15:15 index 12 ref 1 bind 1 installed 3 sec used 3 sec Action statistics: Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 xxx: Now test by sending ping from sender to destination Signed-off-by: Jamal Hadi Salim --- tc/Makefile | 1 + tc/m_ife.c | 341 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 342 insertions(+) create mode 100644 tc/m_ife.c diff --git a/tc/Makefile b/tc/Makefile index f5bea877..20f51100 100644 --- a/tc/Makefile +++ b/tc/Makefile @@ -43,6 +43,7 @@ TCMODULES += m_gact.o TCMODULES += m_mirred.o TCMODULES += m_nat.o TCMODULES += m_pedit.o +TCMODULES += m_ife.o TCMODULES += m_skbedit.o TCMODULES += m_csum.o TCMODULES += m_simple.o diff --git a/tc/m_ife.c b/tc/m_ife.c new file mode 100644 index 00000000..839e370a --- /dev/null +++ b/tc/m_ife.c @@ -0,0 +1,341 @@ +/* + * m_ife.c IFE actions module + * + * This program is free software; you can distribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: J Hadi Salim (jhs@mojatatu.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt_names.h" +#include "utils.h" +#include "tc_util.h" +#include + +static void ife_explain(void) +{ + fprintf(stderr, + "Usage:... ife {decode|encode} {ALLOW|USE} [dst DMAC] [src SMAC] [type TYPE] [CONTROL] [index INDEX]\n"); + fprintf(stderr, + "\tALLOW := Encode direction. Allows encoding specified metadata\n" + "\t\t e.g \"allow mark\"\n" + "\tUSE := Encode direction. Enforce Static encoding of specified metadata\n" + "\t\t e.g \"use mark 0x12\"\n" + "\tDMAC := 6 byte Destination MAC address to encode\n" + "\tSMAC := optional 6 byte Source MAC address to encode\n" + "\tTYPE := optional 16 bit ethertype to encode\n" + "\tCONTROL := reclassify|pipe|drop|continue|ok\n" + "\tINDEX := optional IFE table index value used\n"); + fprintf(stderr, "encode is used for sending IFE packets\n"); + fprintf(stderr, "decode is used for receiving IFE packets\n"); +} + +static void ife_usage(void) +{ + ife_explain(); + exit(-1); +} + +static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, + int tca_id, struct nlmsghdr *n) +{ + int argc = *argc_p; + char **argv = *argv_p; + int ok = 0; + struct tc_ife p; + struct rtattr *tail; + struct rtattr *tail2; + char dbuf[ETH_ALEN]; + char sbuf[ETH_ALEN]; + __u16 ife_type = 0; + __u32 ife_prio = 0; + __u32 ife_prio_v = 0; + __u32 ife_mark = 0; + __u32 ife_mark_v = 0; + char *daddr = NULL; + char *saddr = NULL; + + memset(&p, 0, sizeof(p)); + p.action = TC_ACT_PIPE; /* good default */ + + if (argc <= 0) + return -1; + + while (argc > 0) { + if (matches(*argv, "ife") == 0) { + NEXT_ARG(); + continue; + } else if (matches(*argv, "decode") == 0) { + p.flags = IFE_DECODE; /* readability aid */ + ok++; + } else if (matches(*argv, "encode") == 0) { + p.flags = IFE_ENCODE; + ok++; + } else if (matches(*argv, "allow") == 0) { + NEXT_ARG(); + if (matches(*argv, "mark") == 0) { + ife_mark = IFE_META_SKBMARK; + } else if (matches(*argv, "prio") == 0) { + ife_prio = IFE_META_PRIO; + } else { + fprintf(stderr, "Illegal meta define <%s>\n", + *argv); + return -1; + } + } else if (matches(*argv, "use") == 0) { + NEXT_ARG(); + if (matches(*argv, "mark") == 0) { + NEXT_ARG(); + if (get_u32(&ife_mark_v, *argv, 0)) + invarg("ife mark val is invalid", + *argv); + } else if (matches(*argv, "prio") == 0) { + NEXT_ARG(); + if (get_u32(&ife_prio_v, *argv, 0)) + invarg("ife prio val is invalid", + *argv); + } else { + fprintf(stderr, "Illegal meta use type <%s>\n", + *argv); + return -1; + } + } else if (matches(*argv, "type") == 0) { + NEXT_ARG(); + if (get_u16(&ife_type, *argv, 0)) + invarg("ife type is invalid", *argv); + fprintf(stderr, "IFE type 0x%x\n", ife_type); + } else if (matches(*argv, "dst") == 0) { + NEXT_ARG(); + daddr = *argv; + if (sscanf(daddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + dbuf, dbuf + 1, dbuf + 2, + dbuf + 3, dbuf + 4, dbuf + 5) != 6) { + fprintf(stderr, "Invalid mac address %s\n", + daddr); + } + fprintf(stderr, "dst MAC address <%s>\n", daddr); + + } else if (matches(*argv, "src") == 0) { + NEXT_ARG(); + saddr = *argv; + if (sscanf(saddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + sbuf, sbuf + 1, sbuf + 2, + sbuf + 3, sbuf + 4, sbuf + 5) != 6) { + fprintf(stderr, "Invalid mac address %s\n", + saddr); + } + fprintf(stderr, "src MAC address <%s>\n", saddr); + } else if (matches(*argv, "help") == 0) { + ife_usage(); + } else { + break; + } + + argc--; + argv++; + } + + if (argc) { + if (matches(*argv, "reclassify") == 0) { + p.action = TC_ACT_RECLASSIFY; + argc--; + argv++; + } else if (matches(*argv, "pipe") == 0) { + p.action = TC_ACT_PIPE; + argc--; + argv++; + } else if (matches(*argv, "drop") == 0 || + matches(*argv, "shot") == 0) { + p.action = TC_ACT_SHOT; + argc--; + argv++; + } else if (matches(*argv, "continue") == 0) { + p.action = TC_ACT_UNSPEC; + argc--; + argv++; + } else if (matches(*argv, "pass") == 0) { + p.action = TC_ACT_OK; + argc--; + argv++; + } + } + + if (argc) { + if (matches(*argv, "index") == 0) { + NEXT_ARG(); + if (get_u32(&p.index, *argv, 10)) { + fprintf(stderr, "ife: Illegal \"index\"\n"); + return -1; + } + argc--; + argv++; + } + } + + if (!ok) { + fprintf(stderr, "IFE requires decode/encode specified\n"); + ife_usage(); + } + + tail = NLMSG_TAIL(n); + addattr_l(n, MAX_MSG, tca_id, NULL, 0); + addattr_l(n, MAX_MSG, TCA_IFE_PARMS, &p, sizeof(p)); + + if (!(p.flags & IFE_ENCODE)) + goto skip_encode; + + if (daddr) + addattr_l(n, MAX_MSG, TCA_IFE_DMAC, dbuf, ETH_ALEN); + if (ife_type) + addattr_l(n, MAX_MSG, TCA_IFE_TYPE, &ife_type, 2); + if (saddr) + addattr_l(n, MAX_MSG, TCA_IFE_SMAC, sbuf, ETH_ALEN); + + tail2 = NLMSG_TAIL(n); + addattr_l(n, MAX_MSG, TCA_IFE_METALST, NULL, 0); + if (ife_mark || ife_mark_v) { + if (ife_mark_v) + addattr_l(n, MAX_MSG, IFE_META_SKBMARK, &ife_mark_v, 4); + else + addattr_l(n, MAX_MSG, IFE_META_SKBMARK, NULL, 0); + } + if (ife_prio || ife_prio_v) { + if (ife_prio_v) + addattr_l(n, MAX_MSG, IFE_META_PRIO, &ife_prio_v, 4); + else + addattr_l(n, MAX_MSG, IFE_META_PRIO, NULL, 0); + } + + tail2->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail2; + +skip_encode: + tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail; + + *argc_p = argc; + *argv_p = argv; + return 0; +} + +static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg) +{ + struct tc_ife *p = NULL; + struct rtattr *tb[TCA_IFE_MAX + 1]; + __u16 ife_type = 0; + __u32 mmark = 0; + __u32 mhash = 0; + __u32 mprio = 0; + int has_optional = 0; + SPRINT_BUF(b1); + SPRINT_BUF(b2); + + if (arg == NULL) + return -1; + + parse_rtattr_nested(tb, TCA_IFE_MAX, arg); + + if (tb[TCA_IFE_PARMS] == NULL) { + fprintf(f, "[NULL ife parameters]"); + return -1; + } + p = RTA_DATA(tb[TCA_IFE_PARMS]); + + fprintf(f, "ife %s action %s ", + (p->flags & IFE_ENCODE) ? "encode" : "decode", + action_n2a(p->action, b1, sizeof(b1))); + + if (tb[TCA_IFE_TYPE]) { + ife_type = rta_getattr_u16(tb[TCA_IFE_TYPE]); + has_optional = 1; + fprintf(f, "type 0x%X ", ife_type); + } + + if (has_optional) + fprintf(f, "\n\t "); + + if (tb[TCA_IFE_METALST]) { + struct rtattr *metalist[IFE_META_MAX + 1]; + int len = 0; + + parse_rtattr_nested(metalist, IFE_META_MAX, + tb[TCA_IFE_METALST]); + + if (metalist[IFE_META_SKBMARK]) { + len = RTA_PAYLOAD(metalist[IFE_META_SKBMARK]); + if (len) { + mmark = rta_getattr_u32(metalist[IFE_META_SKBMARK]); + fprintf(f, "use mark %d ", mmark); + } else + fprintf(f, "allow mark "); + } + + if (metalist[IFE_META_HASHID]) { + len = RTA_PAYLOAD(metalist[IFE_META_HASHID]); + if (len) { + mhash = rta_getattr_u32(metalist[IFE_META_HASHID]); + fprintf(f, "use hash %d ", mhash); + } else + fprintf(f, "allow hash "); + } + + if (metalist[IFE_META_PRIO]) { + len = RTA_PAYLOAD(metalist[IFE_META_PRIO]); + if (len) { + mprio = rta_getattr_u32(metalist[IFE_META_PRIO]); + fprintf(f, "use prio %d ", mprio); + } else + fprintf(f, "allow prio "); + } + + } + + if (tb[TCA_IFE_DMAC]) { + has_optional = 1; + fprintf(f, "dst %s ", + ll_addr_n2a(RTA_DATA(tb[TCA_IFE_DMAC]), + RTA_PAYLOAD(tb[TCA_IFE_DMAC]), 0, b2, + sizeof(b2))); + + } + + if (tb[TCA_IFE_SMAC]) { + has_optional = 1; + fprintf(f, "src %s ", + ll_addr_n2a(RTA_DATA(tb[TCA_IFE_SMAC]), + RTA_PAYLOAD(tb[TCA_IFE_SMAC]), 0, b2, + sizeof(b2))); + } + + fprintf(f, "\n\t index %d ref %d bind %d", p->index, p->refcnt, + p->bindcnt); + if (show_stats) { + if (tb[TCA_IFE_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_IFE_TM]); + + print_tm(f, tm); + } + } + + fprintf(f, "\n"); + + return 0; +} + +struct action_util ife_action_util = { + .id = "ife", + .parse_aopt = parse_ife, + .print_aopt = print_ife, +}; From 43726b750a398323a6becdfbea45ae502a180ea8 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sat, 7 May 2016 09:39:36 -0400 Subject: [PATCH 3/4] tc: don't ignore ok as an action branch This is what used to happen before: tc filter add dev tap1 parent ffff: protocol 0xfefe prio 10 \ u32 match u32 0 0 flowid 1:16 \ action ife decode allow mark ok tc -s filter ls dev tap1 parent ffff: filter protocol [65278] pref 10 u32 filter protocol [65278] pref 10 u32 fh 800: ht divisor 1 filter protocol [65278] pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:16 match 00000000/00000000 at 0 action order 1: ife decode action pipe index 2 ref 1 bind 1 installed 4 sec used 4 sec type: 0x0 Metadata: allow mark Action statistics: Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 action order 2: gact action pass random type none pass val 0 index 1 ref 1 bind 1 installed 4 sec used 4 sec Action statistics: Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 Note the extra action added at the end.. Signed-off-by: Jamal Hadi Salim --- tc/m_connmark.c | 3 ++- tc/m_csum.c | 3 ++- tc/m_ife.c | 3 ++- tc/m_mirred.c | 3 ++- tc/m_nat.c | 3 ++- tc/m_pedit.c | 3 ++- tc/m_skbedit.c | 3 ++- tc/m_vlan.c | 3 ++- 8 files changed, 16 insertions(+), 8 deletions(-) diff --git a/tc/m_connmark.c b/tc/m_connmark.c index b1c7d3af..143d75de 100644 --- a/tc/m_connmark.c +++ b/tc/m_connmark.c @@ -99,7 +99,8 @@ parse_connmark(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, sel.action = TC_ACT_UNSPEC; argc--; argv++; - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { sel.action = TC_ACT_OK; argc--; argv++; diff --git a/tc/m_csum.c b/tc/m_csum.c index 36181fa1..fb1183a9 100644 --- a/tc/m_csum.c +++ b/tc/m_csum.c @@ -140,7 +140,8 @@ parse_csum(struct action_util *a, int *argc_p, sel.action = TC_ACT_UNSPEC; argc--; argv++; - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { sel.action = TC_ACT_OK; argc--; argv++; diff --git a/tc/m_ife.c b/tc/m_ife.c index 839e370a..ed01ff72 100644 --- a/tc/m_ife.c +++ b/tc/m_ife.c @@ -167,7 +167,8 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, p.action = TC_ACT_UNSPEC; argc--; argv++; - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { p.action = TC_ACT_OK; argc--; argv++; diff --git a/tc/m_mirred.c b/tc/m_mirred.c index e7e69dfc..64aad4d2 100644 --- a/tc/m_mirred.c +++ b/tc/m_mirred.c @@ -172,7 +172,8 @@ parse_egress(struct action_util *a, int *argc_p, char ***argv_p, } else if (matches(*argv, "continue") == 0) { p.action = TC_POLICE_UNSPEC; NEXT_ARG(); - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { p.action = TC_POLICE_OK; NEXT_ARG(); } diff --git a/tc/m_nat.c b/tc/m_nat.c index 4b90121c..4d1b1edf 100644 --- a/tc/m_nat.c +++ b/tc/m_nat.c @@ -135,7 +135,8 @@ parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct sel.action = TC_ACT_UNSPEC; argc--; argv++; - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { sel.action = TC_ACT_OK; argc--; argv++; diff --git a/tc/m_pedit.c b/tc/m_pedit.c index 2a94dfba..a539b68b 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -495,7 +495,8 @@ parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, stru } else if (matches(*argv, "continue") == 0) { sel.sel.action = TC_ACT_UNSPEC; NEXT_ARG(); - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { sel.sel.action = TC_ACT_OK; NEXT_ARG(); } diff --git a/tc/m_skbedit.c b/tc/m_skbedit.c index 180b9cbd..9ba288c0 100644 --- a/tc/m_skbedit.c +++ b/tc/m_skbedit.c @@ -114,7 +114,8 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, } else if (matches(*argv, "continue") == 0) { sel.action = TC_ACT_UNSPEC; NEXT_ARG(); - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { sel.action = TC_ACT_OK; NEXT_ARG(); } diff --git a/tc/m_vlan.c b/tc/m_vlan.c index 3233d207..c2684461 100644 --- a/tc/m_vlan.c +++ b/tc/m_vlan.c @@ -119,7 +119,8 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, parm.action = TC_ACT_UNSPEC; argc--; argv++; - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { parm.action = TC_ACT_OK; argc--; argv++; From fdf1bdd0f14db7b465d93ec09e45e5da70b1c582 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sun, 8 May 2016 11:02:06 -0400 Subject: [PATCH 4/4] tc simple action update and breakage Brings it closer to more serious actions (adding branching and allowing for late binding) Unfortunately this breaks old syntax of the simple action. But because simple is a pedagogical example unlikely to be used in production environments (i.e its role is to serve as an example on how to write actions), then this is ok. New syntax for simple has new keyword "sdata". Example usage is: sudo tc actions add action simple sdata "foobar" index 1 or tc filter add dev $DEV parent ffff: protocol ip prio 1 u32\ match ip dst 17.0.0.1/32 flowid 1:10 action simple sdata "foobar" Signed-off-by: Jamal Hadi Salim --- tc/m_simple.c | 72 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/tc/m_simple.c b/tc/m_simple.c index e167ccae..feba61b5 100644 --- a/tc/m_simple.c +++ b/tc/m_simple.c @@ -81,9 +81,10 @@ #endif static void explain(void) { - fprintf(stderr, "Usage: ... simple STRING\n" - "STRING being an arbitrary string\n" - "example: \"simple blah\"\n"); + fprintf(stderr, "Usage:... simple [sdata STRING] [CONTROL] [index INDEX]\n"); + fprintf(stderr, "\tSTRING being an arbitrary string\n" + "\tCONTROL := reclassify|pipe|drop|continue|ok\n" + "\tINDEX := optional index value used\n"); } static void usage(void) @@ -99,25 +100,64 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct tc_defact sel = {}; int argc = *argc_p; char **argv = *argv_p; - int ok = 0; + int ok = 0, maybe_bind = 0; struct rtattr *tail; char *simpdata = NULL; - while (argc > 0) { if (matches(*argv, "simple") == 0) { NEXT_ARG(); + } else if (matches(*argv, "sdata") == 0) { + NEXT_ARG(); + ok += 1; simpdata = *argv; - ok = 1; argc--; argv++; - break; } else if (matches(*argv, "help") == 0) { usage(); } else { break; } + } + if (argc) { + if (matches(*argv, "reclassify") == 0) { + sel.action = TC_ACT_RECLASSIFY; + argc--; + argv++; + } else if (matches(*argv, "pipe") == 0) { + sel.action = TC_ACT_PIPE; + argc--; + argv++; + } else if (matches(*argv, "drop") == 0 || + matches(*argv, "shot") == 0) { + sel.action = TC_ACT_SHOT; + argc--; + argv++; + } else if (matches(*argv, "continue") == 0) { + sel.action = TC_ACT_UNSPEC; + argc--; + argv++; + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { + sel.action = TC_ACT_OK; + argc--; + argv++; + } + } + + if (argc) { + if (matches(*argv, "index") == 0) { + NEXT_ARG(); + if (get_u32(&sel.index, *argv, 10)) { + fprintf(stderr, "simple: Illegal \"index\"\n", + *argv); + return -1; + } + ok += 1; + argc--; + argv++; + } } if (!ok) { @@ -125,30 +165,20 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, return -1; } - if (argc) { - if (matches(*argv, "index") == 0) { - NEXT_ARG(); - if (get_u32(&sel.index, *argv, 10)) { - fprintf(stderr, "simple: Illegal \"index\"\n"); - return -1; - } - argc--; - argv++; - } - } - - if (strlen(simpdata) > (SIMP_MAX_DATA - 1)) { + if (simpdata && (strlen(simpdata) > (SIMP_MAX_DATA - 1))) { fprintf(stderr, "simple: Illegal string len %zu <%s>\n", strlen(simpdata), simpdata); return -1; } + sel.action = TC_ACT_PIPE; tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); addattr_l(n, MAX_MSG, TCA_DEF_PARMS, &sel, sizeof(sel)); - addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA); + if (simpdata) + addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA); tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; *argc_p = argc;