naccyde / rpms / iproute

Forked from rpms/iproute 9 months ago
Clone

Blame SOURCES/0046-tc-flower-Add-support-for-QinQ.patch

7e752c
From b485126fd0a84a09f3d61bb4d634011be92fb6a4 Mon Sep 17 00:00:00 2001
7e752c
From: Andrea Claudi <aclaudi@redhat.com>
7e752c
Date: Wed, 29 May 2019 18:28:17 +0200
7e752c
Subject: [PATCH] tc: flower: Add support for QinQ
7e752c
MIME-Version: 1.0
7e752c
Content-Type: text/plain; charset=UTF-8
7e752c
Content-Transfer-Encoding: 8bit
7e752c
7e752c
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1615928
7e752c
Upstream Status: iproute2.git commit 1f0a5dfd388cd
7e752c
7e752c
commit 1f0a5dfd388cd5c25f6a24247667e04b2346e568
7e752c
Author: Jianbo Liu <jianbol@mellanox.com>
7e752c
Date:   Sat Jun 30 10:01:33 2018 +0000
7e752c
7e752c
    tc: flower: Add support for QinQ
7e752c
7e752c
    To support matching on both outer and inner vlan headers,
7e752c
    we add new cvlan_id/cvlan_prio/cvlan_ethtype for inner vlan header.
7e752c
7e752c
    Example:
7e752c
    # tc filter add dev eth0 protocol 802.1ad parent ffff: \
7e752c
        flower vlan_id 1000 vlan_ethtype 802.1q \
7e752c
            cvlan_id 100 cvlan_ethtype ipv4 \
7e752c
        action vlan pop \
7e752c
        action vlan pop \
7e752c
        action mirred egress redirect dev eth1
7e752c
7e752c
    # tc filter show dev eth0 ingress
7e752c
    filter protocol 802.1ad pref 1 flower chain 0
7e752c
    filter protocol 802.1ad pref 1 flower chain 0 handle 0x1
7e752c
      vlan_id 1000
7e752c
      vlan_ethtype 802.1Q
7e752c
      cvlan_id 100
7e752c
      cvlan_ethtype ip
7e752c
      eth_type ipv4
7e752c
      in_hw
7e752c
7e752c
    Signed-off-by: Jianbo Liu <jianbol@mellanox.com>
7e752c
    Acked-by: Jiri Pirko <jiri@mellanox.com>
7e752c
    Signed-off-by: David Ahern <dsahern@gmail.com>
7e752c
---
7e752c
 man/man8/tc-flower.8 |  23 ++++++++++
7e752c
 tc/f_flower.c        | 103 ++++++++++++++++++++++++++++++++++++++-----
7e752c
 2 files changed, 114 insertions(+), 12 deletions(-)
7e752c
7e752c
diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
7e752c
index 276b5271cf013..8be8882592eaa 100644
7e752c
--- a/man/man8/tc-flower.8
7e752c
+++ b/man/man8/tc-flower.8
7e752c
@@ -34,6 +34,12 @@ flower \- flow based traffic control filter
7e752c
 .IR PRIORITY " | "
7e752c
 .BR vlan_ethtype " { " ipv4 " | " ipv6 " | "
7e752c
 .IR ETH_TYPE " } | "
7e752c
+.B cvlan_id
7e752c
+.IR VID " | "
7e752c
+.B cvlan_prio
7e752c
+.IR PRIORITY " | "
7e752c
+.BR cvlan_ethtype " { " ipv4 " | " ipv6 " | "
7e752c
+.IR ETH_TYPE " } | "
7e752c
 .B mpls_label
7e752c
 .IR LABEL " | "
7e752c
 .B mpls_tc
7e752c
@@ -145,6 +151,23 @@ Match on layer three protocol.
7e752c
 .I VLAN_ETH_TYPE
7e752c
 may be either
7e752c
 .BR ipv4 ", " ipv6
7e752c
+or an unsigned 16bit value in hexadecimal format. To match on QinQ packet, it must be 802.1Q or 802.1AD.
7e752c
+.TP
7e752c
+.BI cvlan_id " VID"
7e752c
+Match on QinQ inner vlan tag id.
7e752c
+.I VID
7e752c
+is an unsigned 12bit value in decimal format.
7e752c
+.TP
7e752c
+.BI cvlan_prio " PRIORITY"
7e752c
+Match on QinQ inner vlan tag priority.
7e752c
+.I PRIORITY
7e752c
+is an unsigned 3bit value in decimal format.
7e752c
+.TP
7e752c
+.BI cvlan_ethtype " VLAN_ETH_TYPE"
7e752c
+Match on QinQ layer three protocol.
7e752c
+.I VLAN_ETH_TYPE
7e752c
+may be either
7e752c
+.BR ipv4 ", " ipv6
7e752c
 or an unsigned 16bit value in hexadecimal format.
7e752c
 .TP
7e752c
 .BI mpls_label " LABEL"
7e752c
diff --git a/tc/f_flower.c b/tc/f_flower.c
7e752c
index 43102c86d1597..634bb81af7dbb 100644
7e752c
--- a/tc/f_flower.c
7e752c
+++ b/tc/f_flower.c
7e752c
@@ -50,6 +50,9 @@ static void explain(void)
7e752c
 		"                       vlan_id VID |\n"
7e752c
 		"                       vlan_prio PRIORITY |\n"
7e752c
 		"                       vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"
7e752c
+		"                       cvlan_id VID |\n"
7e752c
+		"                       cvlan_prio PRIORITY |\n"
7e752c
+		"                       cvlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"
7e752c
 		"                       dst_mac MASKED-LLADDR |\n"
7e752c
 		"                       src_mac MASKED-LLADDR |\n"
7e752c
 		"                       ip_proto [tcp | udp | sctp | icmp | icmpv6 | IP-PROTO ] |\n"
7e752c
@@ -131,15 +134,21 @@ err:
7e752c
 	return err;
7e752c
 }
7e752c
 
7e752c
+static bool eth_type_vlan(__be16 ethertype)
7e752c
+{
7e752c
+	return ethertype == htons(ETH_P_8021Q) ||
7e752c
+	       ethertype == htons(ETH_P_8021AD);
7e752c
+}
7e752c
+
7e752c
 static int flower_parse_vlan_eth_type(char *str, __be16 eth_type, int type,
7e752c
 				      __be16 *p_vlan_eth_type,
7e752c
 				      struct nlmsghdr *n)
7e752c
 {
7e752c
 	__be16 vlan_eth_type;
7e752c
 
7e752c
-	if (eth_type != htons(ETH_P_8021Q)) {
7e752c
-		fprintf(stderr,
7e752c
-			"Can't set \"vlan_ethtype\" if ethertype isn't 802.1Q\n");
7e752c
+	if (!eth_type_vlan(eth_type)) {
7e752c
+		fprintf(stderr, "Can't set \"%s\" if ethertype isn't 802.1Q or 802.1AD\n",
7e752c
+			type == TCA_FLOWER_KEY_VLAN_ETH_TYPE ? "vlan_ethtype" : "cvlan_ethtype");
7e752c
 		return -1;
7e752c
 	}
7e752c
 
7e752c
@@ -762,6 +771,7 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
7e752c
 	struct rtattr *tail;
7e752c
 	__be16 eth_type = TC_H_MIN(t->tcm_info);
7e752c
 	__be16 vlan_ethtype = 0;
7e752c
+	__be16 cvlan_ethtype = 0;
7e752c
 	__u8 ip_proto = 0xff;
7e752c
 	__u32 flags = 0;
7e752c
 	__u32 mtf = 0;
7e752c
@@ -839,9 +849,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
7e752c
 			__u16 vid;
7e752c
 
7e752c
 			NEXT_ARG();
7e752c
-			if (eth_type != htons(ETH_P_8021Q)) {
7e752c
-				fprintf(stderr,
7e752c
-					"Can't set \"vlan_id\" if ethertype isn't 802.1Q\n");
7e752c
+			if (!eth_type_vlan(eth_type)) {
7e752c
+				fprintf(stderr, "Can't set \"vlan_id\" if ethertype isn't 802.1Q or 802.1AD\n");
7e752c
 				return -1;
7e752c
 			}
7e752c
 			ret = get_u16(&vid, *argv, 10);
7e752c
@@ -854,9 +863,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
7e752c
 			__u8 vlan_prio;
7e752c
 
7e752c
 			NEXT_ARG();
7e752c
-			if (eth_type != htons(ETH_P_8021Q)) {
7e752c
-				fprintf(stderr,
7e752c
-					"Can't set \"vlan_prio\" if ethertype isn't 802.1Q\n");
7e752c
+			if (!eth_type_vlan(eth_type)) {
7e752c
+				fprintf(stderr, "Can't set \"vlan_prio\" if ethertype isn't 802.1Q or 802.1AD\n");
7e752c
 				return -1;
7e752c
 			}
7e752c
 			ret = get_u8(&vlan_prio, *argv, 10);
7e752c
@@ -873,6 +881,42 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
7e752c
 						 &vlan_ethtype, n);
7e752c
 			if (ret < 0)
7e752c
 				return -1;
7e752c
+		} else if (matches(*argv, "cvlan_id") == 0) {
7e752c
+			__u16 vid;
7e752c
+
7e752c
+			NEXT_ARG();
7e752c
+			if (!eth_type_vlan(vlan_ethtype)) {
7e752c
+				fprintf(stderr, "Can't set \"cvlan_id\" if inner vlan ethertype isn't 802.1Q or 802.1AD\n");
7e752c
+				return -1;
7e752c
+			}
7e752c
+			ret = get_u16(&vid, *argv, 10);
7e752c
+			if (ret < 0 || vid & ~0xfff) {
7e752c
+				fprintf(stderr, "Illegal \"cvlan_id\"\n");
7e752c
+				return -1;
7e752c
+			}
7e752c
+			addattr16(n, MAX_MSG, TCA_FLOWER_KEY_CVLAN_ID, vid);
7e752c
+		} else if (matches(*argv, "cvlan_prio") == 0) {
7e752c
+			__u8 cvlan_prio;
7e752c
+
7e752c
+			NEXT_ARG();
7e752c
+			if (!eth_type_vlan(vlan_ethtype)) {
7e752c
+				fprintf(stderr, "Can't set \"cvlan_prio\" if inner vlan ethertype isn't 802.1Q or 802.1AD\n");
7e752c
+				return -1;
7e752c
+			}
7e752c
+			ret = get_u8(&cvlan_prio, *argv, 10);
7e752c
+			if (ret < 0 || cvlan_prio & ~0x7) {
7e752c
+				fprintf(stderr, "Illegal \"cvlan_prio\"\n");
7e752c
+				return -1;
7e752c
+			}
7e752c
+			addattr8(n, MAX_MSG,
7e752c
+				 TCA_FLOWER_KEY_CVLAN_PRIO, cvlan_prio);
7e752c
+		} else if (matches(*argv, "cvlan_ethtype") == 0) {
7e752c
+			NEXT_ARG();
7e752c
+			ret = flower_parse_vlan_eth_type(*argv, vlan_ethtype,
7e752c
+						 TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
7e752c
+						 &cvlan_ethtype, n);
7e752c
+			if (ret < 0)
7e752c
+				return -1;
7e752c
 		} else if (matches(*argv, "mpls_label") == 0) {
7e752c
 			__u32 label;
7e752c
 
7e752c
@@ -959,7 +1003,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
7e752c
 			}
7e752c
 		} else if (matches(*argv, "ip_proto") == 0) {
7e752c
 			NEXT_ARG();
7e752c
-			ret = flower_parse_ip_proto(*argv, vlan_ethtype ?
7e752c
+			ret = flower_parse_ip_proto(*argv, cvlan_ethtype ?
7e752c
+						    cvlan_ethtype : vlan_ethtype ?
7e752c
 						    vlan_ethtype : eth_type,
7e752c
 						    TCA_FLOWER_KEY_IP_PROTO,
7e752c
 						    &ip_proto, n);
7e752c
@@ -989,7 +1034,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
7e752c
 			}
7e752c
 		} else if (matches(*argv, "dst_ip") == 0) {
7e752c
 			NEXT_ARG();
7e752c
-			ret = flower_parse_ip_addr(*argv, vlan_ethtype ?
7e752c
+			ret = flower_parse_ip_addr(*argv, cvlan_ethtype ?
7e752c
+						   cvlan_ethtype : vlan_ethtype ?
7e752c
 						   vlan_ethtype : eth_type,
7e752c
 						   TCA_FLOWER_KEY_IPV4_DST,
7e752c
 						   TCA_FLOWER_KEY_IPV4_DST_MASK,
7e752c
@@ -1002,7 +1048,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
7e752c
 			}
7e752c
 		} else if (matches(*argv, "src_ip") == 0) {
7e752c
 			NEXT_ARG();
7e752c
-			ret = flower_parse_ip_addr(*argv, vlan_ethtype ?
7e752c
+			ret = flower_parse_ip_addr(*argv, cvlan_ethtype ?
7e752c
+						   cvlan_ethtype : vlan_ethtype ?
7e752c
 						   vlan_ethtype : eth_type,
7e752c
 						   TCA_FLOWER_KEY_IPV4_SRC,
7e752c
 						   TCA_FLOWER_KEY_IPV4_SRC_MASK,
7e752c
@@ -1678,6 +1725,38 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
7e752c
 			   rta_getattr_u8(attr));
7e752c
 	}
7e752c
 
7e752c
+	if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) {
7e752c
+		SPRINT_BUF(buf);
7e752c
+		struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE];
7e752c
+
7e752c
+		print_string(PRINT_ANY, "vlan_ethtype", "\n  vlan_ethtype %s",
7e752c
+			     ll_proto_n2a(rta_getattr_u16(attr),
7e752c
+			     buf, sizeof(buf)));
7e752c
+	}
7e752c
+
7e752c
+	if (tb[TCA_FLOWER_KEY_CVLAN_ID]) {
7e752c
+		struct rtattr *attr = tb[TCA_FLOWER_KEY_CVLAN_ID];
7e752c
+
7e752c
+		print_uint(PRINT_ANY, "cvlan_id", "\n  cvlan_id %u",
7e752c
+			   rta_getattr_u16(attr));
7e752c
+	}
7e752c
+
7e752c
+	if (tb[TCA_FLOWER_KEY_CVLAN_PRIO]) {
7e752c
+		struct rtattr *attr = tb[TCA_FLOWER_KEY_CVLAN_PRIO];
7e752c
+
7e752c
+		print_uint(PRINT_ANY, "cvlan_prio", "\n  cvlan_prio %d",
7e752c
+			   rta_getattr_u8(attr));
7e752c
+	}
7e752c
+
7e752c
+	if (tb[TCA_FLOWER_KEY_CVLAN_ETH_TYPE]) {
7e752c
+		SPRINT_BUF(buf);
7e752c
+		struct rtattr *attr = tb[TCA_FLOWER_KEY_CVLAN_ETH_TYPE];
7e752c
+
7e752c
+		print_string(PRINT_ANY, "cvlan_ethtype", "\n  cvlan_ethtype %s",
7e752c
+			     ll_proto_n2a(rta_getattr_u16(attr),
7e752c
+			     buf, sizeof(buf)));
7e752c
+	}
7e752c
+
7e752c
 	flower_print_eth_addr("dst_mac", tb[TCA_FLOWER_KEY_ETH_DST],
7e752c
 			      tb[TCA_FLOWER_KEY_ETH_DST_MASK]);
7e752c
 	flower_print_eth_addr("src_mac", tb[TCA_FLOWER_KEY_ETH_SRC],
7e752c
-- 
7e752c
2.20.1
7e752c