Hello!
This is the try number two.
What was changed:
- Added selectable choice in Kconfig file (thanks Jamal!)
- Don't abuse tc_u32_sel to not break backward compatibility (thanks Patrick!).
Stephen, do you have any comments on iproute2 part? I know it's not perfect but this is the best way, I think. "u32 match mark vvvv mmmm" it's intuitive but breaks a little the levels, "u32 mark vvvv mmmm" it's ok but not intuitive....
If you want I can rewrite it if you want.
Thank you for your time.
Signed-off-by: Catalin(ux aka Dino) <catab at umbrella.ro>
--- Catalin(ux aka Dino) BOIE catab at deuroconsult.ro http://kernel.umbrella.ro/
--- linux.orig/net/sched/Kconfig 2004-10-19 00:55:06.000000000 +0300 +++ linux/net/sched/Kconfig 2004-11-09 12:47:36.000000000 +0200 @@ -334,6 +334,18 @@ config NET_CLS_IND Requires a new iproute2 You MUST NOT turn this on if you dont have an update iproute2. +config CLS_U32_MARK + bool "Use nfmark as a key in U32 classifier" + depends on NET_CLS_U32 + help + This allows you to match mark in a u32 filter. + Example: + tc filter add dev eth0 protocol ip parent 1:0 prio 5 u32 \ + match mark 0x0090 0xffff \ + match ip dst 4.4.4.4 \ + flowid 1:90 + You must use a new iproute2 to use this feature. + config NET_CLS_RSVP tristate "Special RSVP classifier" depends on NET_CLS && NET_QOS --- linux.orig/net/sched/cls_u32.c 2004-10-19 00:53:45.000000000 +0300 +++ linux/net/sched/cls_u32.c 2004-11-09 13:56:42.000000000 +0200 @@ -27,6 +27,7 @@ * JHS: We should remove the CONFIG_NET_CLS_IND from here * eventually when the meta match extension is made available * + * nfmark match added by Catalin(ux aka Dino) BOIE <catab at umbrella.ro> */ #include <asm/uaccess.h> @@ -57,6 +58,13 @@ #include <net/pkt_sched.h> +struct tc_u32_mark +{ + __u32 val; + __u32 mask; + __u32 success; +}; + struct tc_u_knode { struct tc_u_knode *next; @@ -78,6 +86,9 @@ struct tc_u_knode #ifdef CONFIG_CLS_U32_PERF struct tc_u32_pcnt *pf; #endif +#ifdef CONFIG_CLS_U32_MARK + struct tc_u32_mark mark; +#endif struct tc_u32_sel sel; }; @@ -139,6 +150,16 @@ next_knode: n->pf->rcnt +=1; j = 0; #endif + +#ifdef CONFIG_CLS_U32_MARK + if ((skb->nfmark & n->mark.mask) != n->mark.val) { + n = n->next; + goto next_knode; + } else { + n->mark.success++; + } +#endif + for (i = n->sel.nkeys; i>0; i--, key++) { if ((*(u32*)(ptr+key->off+(off2&key->offmask))^key->val)&key->mask) { @@ -615,6 +636,7 @@ static int u32_change(struct tcf_proto * struct tc_u_hnode *ht; struct tc_u_knode *n; struct tc_u32_sel *s; + struct tc_u32_mark *mark; struct rtattr *opt = tca[TCA_OPTIONS-1]; struct rtattr *tb[TCA_U32_MAX]; u32 htid; @@ -718,6 +740,16 @@ static int u32_change(struct tcf_proto * } n->fshift = i; } + +#ifdef CONFIG_CLS_U32_MARK + if (tb[TCA_U32_MARK-1] == 0 || + RTA_PAYLOAD(tb[TCA_U32_MARK-1]) < sizeof(struct tc_u32_mark)) + return -EINVAL; + mark = RTA_DATA(tb[TCA_U32_MARK-1]); + memcpy(&n->mark, mark, sizeof(struct tc_u32_mark)); + n->mark.success = 0; +#endif + err = u32_set_parms(tp->q, base, ht, n, tb, tca[TCA_RATE-1]); if (err == 0) { struct tc_u_knode **ins; @@ -805,6 +837,12 @@ static int u32_dump(struct tcf_proto *tp RTA_PUT(skb, TCA_U32_CLASSID, 4, &n->res.classid); if (n->ht_down) RTA_PUT(skb, TCA_U32_LINK, 4, &n->ht_down->handle); + +#ifdef CONFIG_CLS_U32_MARK + if (n->mark.val || n->mark.mask) + RTA_PUT(skb, TCA_U32_MARK, sizeof(n->mark), &n->mark); +#endif + #ifdef CONFIG_NET_CLS_ACT /* again for backward compatible mode - we want * to work with both old and new modes of entering --- linux.orig/include/linux/pkt_cls.h 2004-10-19 00:53:07.000000000 +0300 +++ linux/include/linux/pkt_cls.h 2004-11-09 09:50:45.000000000 +0200 @@ -190,6 +190,7 @@ enum TCA_U32_ACT, TCA_U32_INDEV, TCA_U32_PCNT, + TCA_U32_MARK, __TCA_U32_MAX };
--- iproute2-2.6.9/tc/f_u32.c.orig 2004-11-04 15:38:53.000000000 +0200 +++ iproute2-2.6.9/tc/f_u32.c 2004-11-09 13:59:00.000000000 +0200 @@ -7,6 +7,7 @@ * 2 of the License, or (at your option) any later version. * * Authors: Alexey Kuznetsov, <kuznet@xxxxxxxxxxxxx> + * Match mark added by Catalin(ux aka Dino) BOIE <catab at umbrella.ro> [5 nov 2004] * */ @@ -33,7 +34,7 @@ static void explain(void) fprintf(stderr, "or u32 divisor DIVISOR\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n"); - fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} } SAMPLE_ARGS\n"); + fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark } SAMPLE_ARGS\n"); fprintf(stderr, " FILTERID := X:Y:Z\n"); } @@ -590,9 +591,42 @@ done: return res; } +static int parse_mark(int *argc_p, char ***argv_p, struct nlmsghdr *n) +{ + int res = -1; + int argc = *argc_p; + char **argv = *argv_p; + struct tc_u32_mark mark; + + if (argc <= 1) + return -1; + + if (get_u32(&mark.val, *argv, 0)) { + fprintf(stderr, "Illegal \"mark\" value\n"); + return -1; + } + NEXT_ARG(); + + if (get_u32(&mark.mask, *argv, 0)) { + fprintf(stderr, "Illegal \"mark\" mask\n"); + return -1; + } + NEXT_ARG(); + + if ((mark.val & mark.mask) != mark.val) { + fprintf(stderr, "Illegal \"mark\" (impossible combination)\n"); + return -1; + } + addattr_l(n, MAX_MSG, TCA_U32_MARK, &mark, sizeof(mark)); + res = 0; + + *argc_p = argc; + *argv_p = argv; + return res; +} -static int parse_selector(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) +static int parse_selector(int *argc_p, char ***argv_p, struct tc_u32_sel *sel, struct nlmsghdr *n) { int argc = *argc_p; char **argv = *argv_p; @@ -641,6 +675,12 @@ static int parse_selector(int *argc_p, c res = parse_icmp(&argc, &argv, sel); goto done; } + if (matches(*argv, "mark") == 0) { + NEXT_ARG(); + res = parse_mark(&argc, &argv, n); + goto done; + } + return -1; done: @@ -760,7 +800,7 @@ static int u32_parse_opt(struct filter_u while (argc > 0) { if (matches(*argv, "match") == 0) { NEXT_ARG(); - if (parse_selector(&argc, &argv, &sel.sel)) { + if (parse_selector(&argc, &argv, &sel.sel, n)) { fprintf(stderr, "Illegal \"match\"\n"); return -1; } @@ -839,7 +879,7 @@ static int u32_parse_opt(struct filter_u struct tc_u32_key keys[4]; } sel2; NEXT_ARG(); - if (parse_selector(&argc, &argv, &sel2.sel)) { + if (parse_selector(&argc, &argv, &sel2.sel, n)) { fprintf(stderr, "Illegal \"sample\"\n"); return -1; } @@ -964,11 +1004,22 @@ static int u32_print_opt(struct filter_u pf = RTA_DATA(tb[TCA_U32_PCNT]); } + if (sel && show_stats && NULL != pf) + fprintf(f, " (rule hit %llu success %llu)",pf->rcnt,pf->rhit); + + if (tb[TCA_U32_MARK]) { + struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]); + if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) { + fprintf(f, "\n Invalid mark (kernel&iproute2 mismatch)\n"); + } else { + fprintf(f, "\n mark 0x%04x 0x%04x (success %d)", + mark->val, mark->mask, mark->success); + } + } + if (sel) { int i; struct tc_u32_key *key = sel->keys; - if (show_stats && NULL != pf) - fprintf(f, " (rule hit %llu success %llu)",pf->rcnt,pf->rhit); if (sel->nkeys) { for (i=0; i<sel->nkeys; i++, key++) { fprintf(f, "\n match %08x/%08x at %s%d", --- iproute2-2.6.9/include/linux/pkt_cls.h.orig 2004-11-04 15:42:27.000000000 +0200 +++ iproute2-2.6.9/include/linux/pkt_cls.h 2004-11-09 13:58:15.000000000 +0200 @@ -190,6 +190,7 @@ enum TCA_U32_ACT, TCA_U32_INDEV, TCA_U32_PCNT, + TCA_U32_MARK, __TCA_U32_MAX }; @@ -224,6 +225,14 @@ struct tc_u32_pcnt __u64 rhit; __u64 kcnts[0]; }; + +struct tc_u32_mark +{ + __u32 val; + __u32 mask; + __u32 success; +}; + /* Flags */ #define TC_U32_TERMINAL 1