]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
f_flower: Introduce L2TPv3 support
authorWojciech Drewek <wojciech.drewek@intel.com>
Fri, 7 Oct 2022 07:51:01 +0000 (09:51 +0200)
committerDavid Ahern <dsahern@kernel.org>
Sun, 9 Oct 2022 19:54:37 +0000 (13:54 -0600)
Add support for matching on L2TPv3 session ID.
Session ID can be specified only when ip proto was
set to IPPROTO_L2TP.

L2TPv3 might be transported over IP or over UDP,
this implementation is only about L2TPv3 over IP.
IPv6 is also supported, in this case next header
is set to IPPROTO_L2TP.

Example filter:
  # tc filter add dev eth0 ingress prio 1 protocol ip \
      flower \
        ip_proto l2tp \
        l2tpv3_sid 1234 \
        skip_sw \
      action drop

Reviewed-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: Wojciech Drewek <wojciech.drewek@intel.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
man/man8/tc-flower.8
tc/f_flower.c

index 5e486ea31d37f9897281722ed38b21b8956869d2..fc73da93c5c3bead47ca222665d8f6286fcbe021 100644 (file)
@@ -54,7 +54,9 @@ flower \- flow based traffic control filter
 .IR BOS " | "
 .B mpls_ttl
 .IR TTL " | "
-.BR ip_proto " { " tcp " | " udp " | " sctp " | " icmp " | " icmpv6 " | "
+.B l2tpv3_sid
+.IR LSID " | "
+.BR ip_proto " { " tcp " | " udp " | " sctp " | " icmp " | " icmpv6 " | " l2tp " | "
 .IR IP_PROTO " } | "
 .B ip_tos
 .IR MASKED_IP_TOS " | "
@@ -291,11 +293,16 @@ entry.
 .I TTL
 is an unsigned 8 bit value in decimal format.
 .TP
+.BI l2tpv3_sid " LSID"
+Match on L2TPv3 session id field transported over IPv4 or IPv6.
+.I LSID
+is an unsigned 32 bit value in decimal format.
+.TP
 .BI ip_proto " IP_PROTO"
 Match on layer four protocol.
 .I IP_PROTO
 may be
-.BR tcp ", " udp ", " sctp ", " icmp ", " icmpv6
+.BR tcp ", " udp ", " sctp ", " icmp ", " icmpv6 ", " l2tp
 or an unsigned 8bit value in hexadecimal format.
 .TP
 .BI ip_tos " MASKED_IP_TOS"
index 069896a48f332f1a6559b6592361e723e0dbc027..4c0a194836f5b308f121d491bc8e81e8dafcad87 100644 (file)
 #include "tc_util.h"
 #include "rt_names.h"
 
+#ifndef IPPROTO_L2TP
+#define IPPROTO_L2TP 115
+#endif
+
 enum flower_matching_flags {
        FLOWER_IP_FLAGS,
 };
@@ -60,7 +64,7 @@ static void explain(void)
                "                       ppp_proto [ ipv4 | ipv6 | mpls_uc | mpls_mc | PPP_PROTO ]"
                "                       dst_mac MASKED-LLADDR |\n"
                "                       src_mac MASKED-LLADDR |\n"
-               "                       ip_proto [tcp | udp | sctp | icmp | icmpv6 | IP-PROTO ] |\n"
+               "                       ip_proto [tcp | udp | sctp | icmp | icmpv6 | l2tp | IP-PROTO ] |\n"
                "                       ip_tos MASKED-IP_TOS |\n"
                "                       ip_ttl MASKED-IP_TTL |\n"
                "                       mpls LSE-LIST |\n"
@@ -68,6 +72,7 @@ static void explain(void)
                "                       mpls_tc TC |\n"
                "                       mpls_bos BOS |\n"
                "                       mpls_ttl TTL |\n"
+               "                       l2tpv3_sid LSID |\n"
                "                       dst_ip PREFIX |\n"
                "                       src_ip PREFIX |\n"
                "                       dst_port PORT-NUMBER |\n"
@@ -428,6 +433,11 @@ static int flower_parse_ip_proto(char *str, __be16 eth_type, int type,
                if (eth_type != htons(ETH_P_IPV6))
                        goto err;
                ip_proto = IPPROTO_ICMPV6;
+       } else if (!strcmp(str, "l2tp")) {
+               if (eth_type != htons(ETH_P_IP) &&
+                   eth_type != htons(ETH_P_IPV6))
+                       goto err;
+               ip_proto = IPPROTO_L2TP;
        } else {
                ret = get_u8(&ip_proto, str, 16);
                if (ret)
@@ -646,6 +656,27 @@ static int flower_parse_icmp(char *str, __u16 eth_type, __u8 ip_proto,
        return flower_parse_u8(str, value_type, mask_type, NULL, NULL, n);
 }
 
+static int flower_parse_l2tpv3(char *str, __u8 ip_proto,
+                              struct nlmsghdr *n)
+{
+       __be32 sid;
+       int ret;
+
+       if (ip_proto != IPPROTO_L2TP) {
+               fprintf(stderr,
+                       "Can't set \"l2tpv3_sid\" if ip_proto isn't l2tp\n");
+               return -1;
+       }
+       ret = get_be32(&sid, str, 10);
+       if (ret < 0) {
+               fprintf(stderr, "Illegal \"l2tpv3 session id\"\n");
+               return -1;
+       }
+       addattr32(n, MAX_MSG, TCA_FLOWER_KEY_L2TPV3_SID, sid);
+
+       return 0;
+}
+
 static int flower_port_attr_type(__u8 ip_proto, enum flower_endpoint endpoint)
 {
        if (ip_proto == IPPROTO_TCP)
@@ -1840,6 +1871,11 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
                                fprintf(stderr, "Illegal \"icmp code\"\n");
                                return -1;
                        }
+               } else if (!strcmp(*argv, "l2tpv3_sid")) {
+                       NEXT_ARG();
+                       ret = flower_parse_l2tpv3(*argv, ip_proto, n);
+                       if (ret < 0)
+                               return -1;
                } else if (matches(*argv, "arp_tip") == 0) {
                        NEXT_ARG();
                        ret = flower_parse_arp_ip_addr(*argv, eth_type,
@@ -2153,6 +2189,8 @@ static void flower_print_ip_proto(__u8 *p_ip_proto,
                sprintf(out, "icmp");
        else if (ip_proto == IPPROTO_ICMPV6)
                sprintf(out, "icmpv6");
+       else if (ip_proto == IPPROTO_L2TP)
+               sprintf(out, "l2tp");
        else
                sprintf(out, "%02x", ip_proto);
 
@@ -2880,6 +2918,14 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
                flower_print_masked_u8("icmp_code", tb[nl_type],
                                       tb[nl_mask_type], NULL);
 
+       if (tb[TCA_FLOWER_KEY_L2TPV3_SID]) {
+               struct rtattr *attr = tb[TCA_FLOWER_KEY_L2TPV3_SID];
+
+               print_nl();
+               print_uint(PRINT_ANY, "l2tpv3_sid", "  l2tpv3_sid %u",
+                          rta_getattr_be32(attr));
+       }
+
        flower_print_ip4_addr("arp_sip", tb[TCA_FLOWER_KEY_ARP_SIP],
                             tb[TCA_FLOWER_KEY_ARP_SIP_MASK]);
        flower_print_ip4_addr("arp_tip", tb[TCA_FLOWER_KEY_ARP_TIP],