[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAPpH65ymT_peXCvG5+fKYD0ZpNk5=M-=-4Hp9BiXqVBu66cz=g@mail.gmail.com>
Date: Wed, 1 Jul 2020 11:17:56 +0200
From: Andrea Claudi <aclaudi@...hat.com>
To: Guillaume Nault <gnault@...hat.com>
Cc: Stephen Hemminger <stephen@...workplumber.org>,
linux-netdev <netdev@...r.kernel.org>
Subject: Re: [PATCH iproute2] tc: flower: support multiple MPLS LSE match
On Fri, Jun 19, 2020 at 12:51 PM Guillaume Nault <gnault@...hat.com> wrote:
>
> Add the new "mpls" keyword that can be used to match MPLS fields in
> arbitrary Label Stack Entries.
> LSEs are introduced by the "lse" keyword and followed by LSE options:
> "depth", "label", "tc", "bos" and "ttl". The depth is manadtory, the
> other options are optionals.
>
> For example, the following filter drops MPLS packets having two labels,
> where the first label is 21 and has TTL 64 and the second label is 22:
>
> $ tc filter add dev ethX ingress proto mpls_uc flower mpls \
> lse depth 1 label 21 ttl 64 \
> lse depth 2 label 22 bos 1 \
> action drop
>
> Signed-off-by: Guillaume Nault <gnault@...hat.com>
> ---
> man/man8/tc-flower.8 | 73 +++++++++++++-
> tc/f_flower.c | 221 +++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 292 insertions(+), 2 deletions(-)
>
> diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
> index 4d32ff1b..693be571 100644
> --- a/man/man8/tc-flower.8
> +++ b/man/man8/tc-flower.8
> @@ -46,6 +46,8 @@ flower \- flow based traffic control filter
> .IR PRIORITY " | "
> .BR cvlan_ethtype " { " ipv4 " | " ipv6 " | "
> .IR ETH_TYPE " } | "
> +.B mpls
> +.IR LSE_LIST " | "
> .B mpls_label
> .IR LABEL " | "
> .B mpls_tc
> @@ -96,7 +98,24 @@ flower \- flow based traffic control filter
> }
> .IR OPTIONS " | "
> .BR ip_flags
> -.IR IP_FLAGS
> +.IR IP_FLAGS " }"
> +
> +.ti -8
> +.IR LSE_LIST " := [ " LSE_LIST " ] " LSE
> +
> +.ti -8
> +.IR LSE " := "
> +.B lse depth
> +.IR DEPTH " { "
> +.B label
> +.IR LABEL " | "
> +.B tc
> +.IR TC " | "
> +.B bos
> +.IR BOS " | "
> +.B ttl
> +.IR TTL " }"
> +
> .SH DESCRIPTION
> The
> .B flower
> @@ -182,6 +201,56 @@ Match on QinQ layer three protocol.
> may be either
> .BR ipv4 ", " ipv6
> or an unsigned 16bit value in hexadecimal format.
> +
> +.TP
> +.BI mpls " LSE_LIST"
> +Match on the MPLS label stack.
> +.I LSE_LIST
> +is a list of Label Stack Entries, each introduced by the
> +.BR lse " keyword."
> +This option can't be used together with the standalone
> +.BR mpls_label ", " mpls_tc ", " mpls_bos " and " mpls_ttl " options."
> +.RS
> +.TP
> +.BI lse " LSE_OPTIONS"
> +Match on an MPLS Label Stack Entry.
> +.I LSE_OPTIONS
> +is a list of options that describe the properties of the LSE to match.
> +.RS
> +.TP
> +.BI depth " DEPTH"
> +The depth of the Label Stack Entry to consider. Depth starts at 1 (the
> +outermost Label Stack Entry). The maximum usable depth may be limitted by the
limited
> +kernel. This option is mandatory.
> +.I DEPTH
> +is an unsigned 8 bit value in decimal format.
> +.TP
> +.BI label " LABEL"
> +Match on the MPLS Label field at the specified
> +.BR depth .
> +.I LABEL
> +is an unsigned 20 bit value in decimal format.
> +.TP
> +.BI tc " TC"
> +Match on the MPLS Traffic Class field at the specified
> +.BR depth .
> +.I TC
> +is an unsigned 3 bit value in decimal format.
> +.TP
> +.BI bos " BOS"
> +Match on the MPLS Bottom Of Stack field at the specified
> +.BR depth .
> +.I BOS
> +is a 1 bit value in decimal format.
> +.TP
> +.BI ttl " TTL"
> +Match on the MPLS Time To Live field at the specified
> +.BR depth .
> +.I TTL
> +is an unsigned 8 bit value in decimal format.
> +.RE
> +.RE
> +
> .TP
> .BI mpls_label " LABEL"
> Match the label id in the outermost MPLS label stack entry.
> @@ -393,7 +462,7 @@ on the matches of the next lower layer. Precisely, layer one and two matches
> (\fBindev\fR, \fBdst_mac\fR and \fBsrc_mac\fR)
> have no dependency,
> MPLS and layer three matches
> -(\fBmpls_label\fR, \fBmpls_tc\fR, \fBmpls_bos\fR, \fBmpls_ttl\fR,
> +(\fBmpls\fR, \fBmpls_label\fR, \fBmpls_tc\fR, \fBmpls_bos\fR, \fBmpls_ttl\fR,
> \fBip_proto\fR, \fBdst_ip\fR, \fBsrc_ip\fR, \fBarp_tip\fR, \fBarp_sip\fR,
> \fBarp_op\fR, \fBarp_tha\fR, \fBarp_sha\fR and \fBip_flags\fR)
> depend on the
> diff --git a/tc/f_flower.c b/tc/f_flower.c
> index fc136911..00c919fd 100644
> --- a/tc/f_flower.c
> +++ b/tc/f_flower.c
> @@ -59,6 +59,7 @@ static void explain(void)
> " ip_proto [tcp | udp | sctp | icmp | icmpv6 | IP-PROTO ] |\n"
> " ip_tos MASKED-IP_TOS |\n"
> " ip_ttl MASKED-IP_TTL |\n"
> + " mpls LSE-LIST |\n"
> " mpls_label LABEL |\n"
> " mpls_tc TC |\n"
> " mpls_bos BOS |\n"
> @@ -89,6 +90,8 @@ static void explain(void)
> " ct_label MASKED_CT_LABEL |\n"
> " ct_mark MASKED_CT_MARK |\n"
> " ct_zone MASKED_CT_ZONE }\n"
> + " LSE-LIST := [ LSE-LIST ] LSE\n"
> + " LSE := lse depth DEPTH { label LABEL | tc TC | bos BOS | ttl TTL }\n"
> " FILTERID := X:Y:Z\n"
> " MASKED_LLADDR := { LLADDR | LLADDR/MASK | LLADDR/BITS }\n"
> " MASKED_CT_STATE := combination of {+|-} and flags trk,est,new\n"
> @@ -1199,11 +1202,127 @@ static int flower_parse_enc_opts_erspan(char *str, struct nlmsghdr *n)
> return 0;
> }
>
> +static int flower_parse_mpls_lse(int *argc_p, char ***argv_p,
> + struct nlmsghdr *nlh)
> +{
> + struct rtattr *lse_attr;
> + char **argv = *argv_p;
> + int argc = *argc_p;
> + __u8 depth = 0;
> + int ret;
> +
> + lse_attr = addattr_nest(nlh, MAX_MSG,
> + TCA_FLOWER_KEY_MPLS_OPTS_LSE | NLA_F_NESTED);
> +
> + while (argc > 0) {
> + if (matches(*argv, "depth") == 0) {
> + NEXT_ARG();
> + ret = get_u8(&depth, *argv, 10);
> + if (ret < 0 || depth < 1) {
> + fprintf(stderr, "Illegal \"depth\"\n");
> + return -1;
> + }
> + addattr8(nlh, MAX_MSG,
> + TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH, depth);
> + } else if (matches(*argv, "label") == 0) {
> + __u32 label;
> +
> + NEXT_ARG();
> + ret = get_u32(&label, *argv, 10);
> + if (ret < 0 ||
> + label & ~(MPLS_LS_LABEL_MASK >> MPLS_LS_LABEL_SHIFT)) {
> + fprintf(stderr, "Illegal \"label\"\n");
> + return -1;
> + }
> + addattr32(nlh, MAX_MSG,
> + TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL, label);
> + } else if (matches(*argv, "tc") == 0) {
> + __u8 tc;
> +
> + NEXT_ARG();
> + ret = get_u8(&tc, *argv, 10);
> + if (ret < 0 ||
> + tc & ~(MPLS_LS_TC_MASK >> MPLS_LS_TC_SHIFT)) {
> + fprintf(stderr, "Illegal \"tc\"\n");
> + return -1;
> + }
> + addattr8(nlh, MAX_MSG, TCA_FLOWER_KEY_MPLS_OPT_LSE_TC,
> + tc);
> + } else if (matches(*argv, "bos") == 0) {
> + __u8 bos;
> +
> + NEXT_ARG();
> + ret = get_u8(&bos, *argv, 10);
> + if (ret < 0 || bos & ~(MPLS_LS_S_MASK >> MPLS_LS_S_SHIFT)) {
> + fprintf(stderr, "Illegal \"bos\"\n");
> + return -1;
> + }
> + addattr8(nlh, MAX_MSG, TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS,
> + bos);
> + } else if (matches(*argv, "ttl") == 0) {
> + __u8 ttl;
> +
> + NEXT_ARG();
> + ret = get_u8(&ttl, *argv, 10);
> + if (ret < 0 || ttl & ~(MPLS_LS_TTL_MASK >> MPLS_LS_TTL_SHIFT)) {
> + fprintf(stderr, "Illegal \"ttl\"\n");
> + return -1;
> + }
> + addattr8(nlh, MAX_MSG, TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL,
> + ttl);
> + } else {
> + break;
> + }
> + argc--; argv++;
> + }
> +
> + if (!depth) {
> + missarg("depth");
> + return -1;
> + }
> +
> + addattr_nest_end(nlh, lse_attr);
> +
> + *argc_p = argc;
> + *argv_p = argv;
> +
> + return 0;
> +}
> +
> +static int flower_parse_mpls(int *argc_p, char ***argv_p, struct nlmsghdr *nlh)
> +{
> + struct rtattr *mpls_attr;
> + char **argv = *argv_p;
> + int argc = *argc_p;
> +
> + mpls_attr = addattr_nest(nlh, MAX_MSG,
> + TCA_FLOWER_KEY_MPLS_OPTS | NLA_F_NESTED);
> +
> + while (argc > 0) {
> + if (matches(*argv, "lse") == 0) {
> + NEXT_ARG();
> + if (flower_parse_mpls_lse(&argc, &argv, nlh) < 0)
> + return -1;
> + } else {
> + break;
> + }
> + }
This can probably be simplified to:
while (argc > 0 && matches(*argv, "lse") == 0) {
NEXT_ARG();
if (flower_parse_mpls_lse(&argc, &argv, nlh) < 0)
return -1;
}
> +
> + addattr_nest_end(nlh, mpls_attr);
> +
> + *argc_p = argc;
> + *argv_p = argv;
> +
> + return 0;
> +}
> +
> static int flower_parse_opt(struct filter_util *qu, char *handle,
> int argc, char **argv, struct nlmsghdr *n)
> {
> int ret;
> struct tcmsg *t = NLMSG_DATA(n);
> + bool mpls_format_old = false;
> + bool mpls_format_new = false;
> struct rtattr *tail;
> __be16 eth_type = TC_H_MIN(t->tcm_info);
> __be16 vlan_ethtype = 0;
> @@ -1381,6 +1500,23 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
> &cvlan_ethtype, n);
> if (ret < 0)
> return -1;
> + } else if (matches(*argv, "mpls") == 0) {
> + NEXT_ARG();
> + if (eth_type != htons(ETH_P_MPLS_UC) &&
> + eth_type != htons(ETH_P_MPLS_MC)) {
> + fprintf(stderr,
> + "Can't set \"mpls\" if ethertype isn't MPLS\n");
> + return -1;
> + }
> + if (mpls_format_old) {
> + fprintf(stderr,
> + "Can't set \"mpls\" if \"mpls_label\", \"mpls_tc\", \"mpls_bos\" or \"mpls_ttl\" is set\n");
> + return -1;
> + }
> + mpls_format_new = true;
> + if (flower_parse_mpls(&argc, &argv, n) < 0)
> + return -1;
> + continue;
> } else if (matches(*argv, "mpls_label") == 0) {
> __u32 label;
>
> @@ -1391,6 +1527,12 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
> "Can't set \"mpls_label\" if ethertype isn't MPLS\n");
> return -1;
> }
> + if (mpls_format_new) {
> + fprintf(stderr,
> + "Can't set \"mpls_label\" if \"mpls\" is set\n");
> + return -1;
> + }
> + mpls_format_old = true;
> ret = get_u32(&label, *argv, 10);
> if (ret < 0 || label & ~(MPLS_LS_LABEL_MASK >> MPLS_LS_LABEL_SHIFT)) {
> fprintf(stderr, "Illegal \"mpls_label\"\n");
> @@ -1407,6 +1549,12 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
> "Can't set \"mpls_tc\" if ethertype isn't MPLS\n");
> return -1;
> }
> + if (mpls_format_new) {
> + fprintf(stderr,
> + "Can't set \"mpls_tc\" if \"mpls\" is set\n");
> + return -1;
> + }
> + mpls_format_old = true;
> ret = get_u8(&tc, *argv, 10);
> if (ret < 0 || tc & ~(MPLS_LS_TC_MASK >> MPLS_LS_TC_SHIFT)) {
> fprintf(stderr, "Illegal \"mpls_tc\"\n");
> @@ -1423,6 +1571,12 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
> "Can't set \"mpls_bos\" if ethertype isn't MPLS\n");
> return -1;
> }
> + if (mpls_format_new) {
> + fprintf(stderr,
> + "Can't set \"mpls_bos\" if \"mpls\" is set\n");
> + return -1;
> + }
> + mpls_format_old = true;
> ret = get_u8(&bos, *argv, 10);
> if (ret < 0 || bos & ~(MPLS_LS_S_MASK >> MPLS_LS_S_SHIFT)) {
> fprintf(stderr, "Illegal \"mpls_bos\"\n");
> @@ -1439,6 +1593,12 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
> "Can't set \"mpls_ttl\" if ethertype isn't MPLS\n");
> return -1;
> }
> + if (mpls_format_new) {
> + fprintf(stderr,
> + "Can't set \"mpls_ttl\" if \"mpls\" is set\n");
> + return -1;
> + }
> + mpls_format_old = true;
> ret = get_u8(&ttl, *argv, 10);
> if (ret < 0 || ttl & ~(MPLS_LS_TTL_MASK >> MPLS_LS_TTL_SHIFT)) {
> fprintf(stderr, "Illegal \"mpls_ttl\"\n");
> @@ -2316,6 +2476,66 @@ static void flower_print_u32(const char *name, struct rtattr *attr)
> print_uint(PRINT_ANY, name, namefrm, rta_getattr_u32(attr));
> }
>
> +static void flower_print_mpls_opt_lse(const char *name, struct rtattr *lse)
> +{
> + struct rtattr *tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX + 1];
> + struct rtattr *attr;
> +
> + if (lse->rta_type != (TCA_FLOWER_KEY_MPLS_OPTS_LSE | NLA_F_NESTED)) {
> + fprintf(stderr, "rta_type 0x%x, expecting 0x%x (0x%x & 0x%x)\n",
> + lse->rta_type,
> + TCA_FLOWER_KEY_MPLS_OPTS_LSE & NLA_F_NESTED,
> + TCA_FLOWER_KEY_MPLS_OPTS_LSE, NLA_F_NESTED);
> + return;
> + }
> +
> + parse_rtattr(tb, TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX, RTA_DATA(lse),
> + RTA_PAYLOAD(lse));
> +
> + print_nl();
> + open_json_array(PRINT_ANY, name);
> + attr = tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH];
> + if (attr)
> + print_hhu(PRINT_ANY, "depth", " depth %u",
> + rta_getattr_u8(attr));
> + attr = tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL];
> + if (attr)
> + print_uint(PRINT_ANY, "label", " label %u",
> + rta_getattr_u32(attr));
> + attr = tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TC];
> + if (attr)
> + print_hhu(PRINT_ANY, "tc", " tc %u", rta_getattr_u8(attr));
> + attr = tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS];
> + if (attr)
> + print_hhu(PRINT_ANY, "bos", " bos %u", rta_getattr_u8(attr));
> + attr = tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL];
> + if (attr)
> + print_hhu(PRINT_ANY, "ttl", " ttl %u", rta_getattr_u8(attr));
> + close_json_array(PRINT_JSON, NULL);
> +}
> +
> +static void flower_print_mpls_opts(const char *name, struct rtattr *attr)
> +{
> + struct rtattr *lse;
> + int rem;
> +
> + if (!attr || !(attr->rta_type & NLA_F_NESTED))
> + return;
> +
> + print_nl();
> + open_json_array(PRINT_ANY, name);
> + rem = RTA_PAYLOAD(attr);
> + lse = RTA_DATA(attr);
> + while (RTA_OK(lse, rem)) {
> + flower_print_mpls_opt_lse(" lse", lse);
> + lse = RTA_NEXT(lse, rem);
> + };
> + if (rem)
> + fprintf(stderr, "!!!Deficit %d, rta_len=%d\n",
> + rem, lse->rta_len);
> + close_json_array(PRINT_JSON, NULL);
> +}
> +
> static void flower_print_arp_op(const char *name,
> struct rtattr *op_attr,
> struct rtattr *mask_attr)
> @@ -2430,6 +2650,7 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
> flower_print_ip_attr("ip_ttl", tb[TCA_FLOWER_KEY_IP_TTL],
> tb[TCA_FLOWER_KEY_IP_TTL_MASK]);
>
> + flower_print_mpls_opts(" mpls", tb[TCA_FLOWER_KEY_MPLS_OPTS]);
> flower_print_u32("mpls_label", tb[TCA_FLOWER_KEY_MPLS_LABEL]);
> flower_print_u8("mpls_tc", tb[TCA_FLOWER_KEY_MPLS_TC]);
> flower_print_u8("mpls_bos", tb[TCA_FLOWER_KEY_MPLS_BOS]);
> --
> 2.21.3
>
Powered by blists - more mailing lists