Blame SOURCES/0114-tc-cls_flower-Classify-packet-in-ip-tunnels.patch

4aca6e
From 0263aa84af6519d1dc057329e895275d34a0f595 Mon Sep 17 00:00:00 2001
4aca6e
From: Phil Sutter <psutter@redhat.com>
4aca6e
Date: Fri, 17 Mar 2017 13:23:32 +0100
4aca6e
Subject: [PATCH] tc/cls_flower: Classify packet in ip tunnels
4aca6e
4aca6e
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1422629
4aca6e
Upstream Status: iproute2.git commit bb9b63b18e85f
4aca6e
4aca6e
commit bb9b63b18e85f17e618469ecb139e78ca5a4a4fc
4aca6e
Author: Amir Vadai <amir@vadai.me>
4aca6e
Date:   Fri Dec 2 13:25:14 2016 +0200
4aca6e
4aca6e
    tc/cls_flower: Classify packet in ip tunnels
4aca6e
4aca6e
    Introduce classifying by metadata extracted by the tunnel device.
4aca6e
    Outer header fields - source/dest ip and tunnel id, are extracted from
4aca6e
    the metadata when classifying.
4aca6e
4aca6e
    For example, the following will add a filter on the ingress Qdisc of shared
4aca6e
    vxlan device named 'vxlan0'. To forward packets with outer src ip
4aca6e
    11.11.0.2, dst ip 11.11.0.1 and tunnel id 11. The packets will be
4aca6e
    forwarded to tap device 'vnet0':
4aca6e
4aca6e
    $ tc filter add dev vxlan0 protocol ip parent ffff: \
4aca6e
        flower \
4aca6e
          enc_src_ip 11.11.0.2 \
4aca6e
          enc_dst_ip 11.11.0.1 \
4aca6e
          enc_key_id 11 \
4aca6e
          dst_ip 11.11.11.1 \
4aca6e
        action mirred egress redirect dev vnet0
4aca6e
4aca6e
    Signed-off-by: Amir Vadai <amir@vadai.me>
4aca6e
---
4aca6e
 man/man8/tc-flower.8 | 17 ++++++++++-
4aca6e
 tc/f_flower.c        | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++--
4aca6e
 2 files changed, 95 insertions(+), 4 deletions(-)
4aca6e
4aca6e
diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
4aca6e
index 16ef261..dd35649 100644
4aca6e
--- a/man/man8/tc-flower.8
4aca6e
+++ b/man/man8/tc-flower.8
4aca6e
@@ -34,7 +34,11 @@ flower \- flow based traffic control filter
4aca6e
 .BR dst_ip " | " src_ip " } { "
4aca6e
 .IR ipv4_address " | " ipv6_address " } | { "
4aca6e
 .BR dst_port " | " src_port " } "
4aca6e
-.IR port_number " }"
4aca6e
+.IR port_number " } | "
4aca6e
+.B enc_key_id
4aca6e
+.IR KEY-ID " | {"
4aca6e
+.BR enc_dst_ip " | " enc_src_ip " } { "
4aca6e
+.IR ipv4_address " | " ipv6_address " } | "
4aca6e
 .SH DESCRIPTION
4aca6e
 The
4aca6e
 .B flower
4aca6e
@@ -112,6 +116,17 @@ which has to be specified in beforehand.
4aca6e
 Match on layer 4 protocol source or destination port number. Only available for
4aca6e
 .BR ip_proto " values " udp " and " tcp ,
4aca6e
 which has to be specified in beforehand.
4aca6e
+.TP
4aca6e
+.BI enc_key_id " NUMBER"
4aca6e
+.TQ
4aca6e
+.BI enc_dst_ip " ADDRESS"
4aca6e
+.TQ
4aca6e
+.BI enc_src_ip " ADDRESS"
4aca6e
+Match on IP tunnel metadata. Key id
4aca6e
+.I NUMBER
4aca6e
+is a 32 bit tunnel key id (e.g. VNI for VXLAN tunnel).
4aca6e
+.I ADDRESS
4aca6e
+must be a valid IPv4 or IPv6 address.
4aca6e
 .SH NOTES
4aca6e
 As stated above where applicable, matches of a certain layer implicitly depend
4aca6e
 on the matches of the next lower layer. Precisely, layer one and two matches (
4aca6e
diff --git a/tc/f_flower.c b/tc/f_flower.c
4aca6e
index 75e64ae..36963c5 100644
4aca6e
--- a/tc/f_flower.c
4aca6e
+++ b/tc/f_flower.c
4aca6e
@@ -41,7 +41,10 @@ static void explain(void)
4aca6e
 		"                       dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
4aca6e
 		"                       src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
4aca6e
 		"                       dst_port PORT-NUMBER |\n"
4aca6e
-		"                       src_port PORT-NUMBER }\n"
4aca6e
+		"                       src_port PORT-NUMBER |\n"
4aca6e
+		"                       enc_dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
4aca6e
+		"                       enc_src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
4aca6e
+		"                       enc_key_id [ KEY-ID ] }\n"
4aca6e
 		"       FILTERID := X:Y:Z\n"
4aca6e
 		"       ACTION-SPEC := ... look at individual actions\n"
4aca6e
 		"\n"
4aca6e
@@ -125,8 +128,9 @@ static int flower_parse_ip_addr(char *str, __be16 eth_type,
4aca6e
 		family = AF_INET;
4aca6e
 	} else if (eth_type == htons(ETH_P_IPV6)) {
4aca6e
 		family = AF_INET6;
4aca6e
+	} else if (!eth_type) {
4aca6e
+		family = AF_UNSPEC;
4aca6e
 	} else {
4aca6e
-		fprintf(stderr, "Illegal \"eth_type\" for ip address\n");
4aca6e
 		return -1;
4aca6e
 	}
4aca6e
 
4aca6e
@@ -134,8 +138,10 @@ static int flower_parse_ip_addr(char *str, __be16 eth_type,
4aca6e
 	if (ret)
4aca6e
 		return -1;
4aca6e
 
4aca6e
-	if (addr.family != family)
4aca6e
+	if (family && (addr.family != family)) {
4aca6e
+		fprintf(stderr, "Illegal \"eth_type\" for ip address\n");
4aca6e
 		return -1;
4aca6e
+	}
4aca6e
 
4aca6e
 	addattr_l(n, MAX_MSG, addr.family == AF_INET ? addr4_type : addr6_type,
4aca6e
 		  addr.data, addr.bytelen);
4aca6e
@@ -197,6 +203,18 @@ static int flower_parse_port(char *str, __u8 ip_port, bool is_src,
4aca6e
 	return 0;
4aca6e
 }
4aca6e
 
4aca6e
+static int flower_parse_key_id(const char *str, int type, struct nlmsghdr *n)
4aca6e
+{
4aca6e
+	int ret;
4aca6e
+	__be32 key_id;
4aca6e
+
4aca6e
+	ret = get_be32(&key_id, str, 10);
4aca6e
+	if (!ret)
4aca6e
+		addattr32(n, MAX_MSG, type, key_id);
4aca6e
+
4aca6e
+	return ret;
4aca6e
+}
4aca6e
+
4aca6e
 static int flower_parse_opt(struct filter_util *qu, char *handle,
4aca6e
 			    int argc, char **argv, struct nlmsghdr *n)
4aca6e
 {
4aca6e
@@ -355,6 +373,38 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
4aca6e
 				fprintf(stderr, "Illegal \"src_port\"\n");
4aca6e
 				return -1;
4aca6e
 			}
4aca6e
+		} else if (matches(*argv, "enc_dst_ip") == 0) {
4aca6e
+			NEXT_ARG();
4aca6e
+			ret = flower_parse_ip_addr(*argv, 0,
4aca6e
+						   TCA_FLOWER_KEY_ENC_IPV4_DST,
4aca6e
+						   TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
4aca6e
+						   TCA_FLOWER_KEY_ENC_IPV6_DST,
4aca6e
+						   TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
4aca6e
+						   n);
4aca6e
+			if (ret < 0) {
4aca6e
+				fprintf(stderr, "Illegal \"enc_dst_ip\"\n");
4aca6e
+				return -1;
4aca6e
+			}
4aca6e
+		} else if (matches(*argv, "enc_src_ip") == 0) {
4aca6e
+			NEXT_ARG();
4aca6e
+			ret = flower_parse_ip_addr(*argv, 0,
4aca6e
+						   TCA_FLOWER_KEY_ENC_IPV4_SRC,
4aca6e
+						   TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
4aca6e
+						   TCA_FLOWER_KEY_ENC_IPV6_SRC,
4aca6e
+						   TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
4aca6e
+						   n);
4aca6e
+			if (ret < 0) {
4aca6e
+				fprintf(stderr, "Illegal \"enc_src_ip\"\n");
4aca6e
+				return -1;
4aca6e
+			}
4aca6e
+		} else if (matches(*argv, "enc_key_id") == 0) {
4aca6e
+			NEXT_ARG();
4aca6e
+			ret = flower_parse_key_id(*argv,
4aca6e
+						  TCA_FLOWER_KEY_ENC_KEY_ID, n);
4aca6e
+			if (ret < 0) {
4aca6e
+				fprintf(stderr, "Illegal \"enc_key_id\"\n");
4aca6e
+				return -1;
4aca6e
+			}
4aca6e
 		} else if (matches(*argv, "action") == 0) {
4aca6e
 			NEXT_ARG();
4aca6e
 			ret = parse_action(&argc, &argv, TCA_FLOWER_ACT, n);
4aca6e
@@ -515,6 +565,13 @@ static void flower_print_port(FILE *f, char *name, struct rtattr *attr)
4aca6e
 	fprintf(f, "\n  %s %d", name, rta_getattr_be16(attr));
4aca6e
 }
4aca6e
 
4aca6e
+static void flower_print_key_id(FILE *f, const char *name,
4aca6e
+				struct rtattr *attr)
4aca6e
+{
4aca6e
+	if (attr)
4aca6e
+		fprintf(f, "\n  %s %d", name, rta_getattr_be32(attr));
4aca6e
+}
4aca6e
+
4aca6e
 static int flower_print_opt(struct filter_util *qu, FILE *f,
4aca6e
 			    struct rtattr *opt, __u32 handle)
4aca6e
 {
4aca6e
@@ -580,6 +637,25 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
4aca6e
 	flower_print_port(f, "src_port",
4aca6e
 			  tb[flower_port_attr_type(ip_proto, true)]);
4aca6e
 
4aca6e
+	flower_print_ip_addr(f, "enc_dst_ip",
4aca6e
+			     tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] ?
4aca6e
+			     htons(ETH_P_IP) : htons(ETH_P_IPV6),
4aca6e
+			     tb[TCA_FLOWER_KEY_ENC_IPV4_DST],
4aca6e
+			     tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK],
4aca6e
+			     tb[TCA_FLOWER_KEY_ENC_IPV6_DST],
4aca6e
+			     tb[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]);
4aca6e
+
4aca6e
+	flower_print_ip_addr(f, "enc_src_ip",
4aca6e
+			     tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] ?
4aca6e
+			     htons(ETH_P_IP) : htons(ETH_P_IPV6),
4aca6e
+			     tb[TCA_FLOWER_KEY_ENC_IPV4_SRC],
4aca6e
+			     tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK],
4aca6e
+			     tb[TCA_FLOWER_KEY_ENC_IPV6_SRC],
4aca6e
+			     tb[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]);
4aca6e
+
4aca6e
+	flower_print_key_id(f, "enc_key_id",
4aca6e
+			    tb[TCA_FLOWER_KEY_ENC_KEY_ID]);
4aca6e
+
4aca6e
 	if (tb[TCA_FLOWER_FLAGS]) {
4aca6e
 		__u32 flags = rta_getattr_u32(tb[TCA_FLOWER_FLAGS]);
4aca6e
 
4aca6e
-- 
4aca6e
1.8.3.1
4aca6e