[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20180630100133.14645-1-jianbol@mellanox.com>
Date: Sat, 30 Jun 2018 10:01:33 +0000
From: Jianbo Liu <jianbol@...lanox.com>
To: netdev@...r.kernel.org, davem@...emloft.net, jiri@...nulli.us
Cc: Jianbo Liu <jianbol@...lanox.com>
Subject: [PATCH iproute2/net-next] tc: flower: Add support for QinQ
To support matching on both outer and inner vlan headers,
we add new cvlan_id/cvlan_prio/cvlan_ethtype for inner vlan header.
Example:
# tc filter add dev eth0 protocol 802.1ad parent ffff: \
flower vlan_id 1000 vlan_ethtype 802.1q \
cvlan_id 100 cvlan_ethtype ipv4 \
action vlan pop \
action vlan pop \
action mirred egress redirect dev eth1
# tc filter show dev eth0 ingress
filter protocol 802.1ad pref 1 flower chain 0
filter protocol 802.1ad pref 1 flower chain 0 handle 0x1
vlan_id 1000
vlan_ethtype 802.1Q
cvlan_id 100
cvlan_ethtype ip
eth_type ipv4
in_hw
Signed-off-by: Jianbo Liu <jianbol@...lanox.com>
Acked-by: Jiri Pirko <jiri@...lanox.com>
---
include/uapi/linux/pkt_cls.h | 4 ++
man/man8/tc-flower.8 | 23 ++++++++++
tc/f_flower.c | 103 ++++++++++++++++++++++++++++++++++++++-----
3 files changed, 118 insertions(+), 12 deletions(-)
diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
index be05e66..e7f7c52 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -468,6 +468,10 @@ enum {
TCA_FLOWER_KEY_IP_TTL, /* u8 */
TCA_FLOWER_KEY_IP_TTL_MASK, /* u8 */
+ TCA_FLOWER_KEY_CVLAN_ID, /* be16 */
+ TCA_FLOWER_KEY_CVLAN_PRIO, /* u8 */
+ TCA_FLOWER_KEY_CVLAN_ETH_TYPE, /* be16 */
+
__TCA_FLOWER_MAX,
};
diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
index a561443..c684652 100644
--- a/man/man8/tc-flower.8
+++ b/man/man8/tc-flower.8
@@ -32,6 +32,12 @@ flower \- flow based traffic control filter
.IR PRIORITY " | "
.BR vlan_ethtype " { " ipv4 " | " ipv6 " | "
.IR ETH_TYPE " } | "
+.B cvlan_id
+.IR VID " | "
+.B cvlan_prio
+.IR PRIORITY " | "
+.BR cvlan_ethtype " { " ipv4 " | " ipv6 " | "
+.IR ETH_TYPE " } | "
.B mpls_label
.IR LABEL " | "
.B mpls_tc
@@ -132,6 +138,23 @@ Match on layer three protocol.
.I VLAN_ETH_TYPE
may be either
.BR ipv4 ", " ipv6
+or an unsigned 16bit value in hexadecimal format. To match on QinQ packet, it must be 802.1Q or 802.1AD.
+.TP
+.BI cvlan_id " VID"
+Match on QinQ inner vlan tag id.
+.I VID
+is an unsigned 12bit value in decimal format.
+.TP
+.BI cvlan_prio " PRIORITY"
+Match on QinQ inner vlan tag priority.
+.I PRIORITY
+is an unsigned 3bit value in decimal format.
+.TP
+.BI cvlan_ethtype " VLAN_ETH_TYPE"
+Match on QinQ layer three protocol.
+.I VLAN_ETH_TYPE
+may be either
+.BR ipv4 ", " ipv6
or an unsigned 16bit value in hexadecimal format.
.TP
.BI mpls_label " LABEL"
diff --git a/tc/f_flower.c b/tc/f_flower.c
index ba8eb66..71f2bc1 100644
--- a/tc/f_flower.c
+++ b/tc/f_flower.c
@@ -50,6 +50,9 @@ static void explain(void)
" vlan_id VID |\n"
" vlan_prio PRIORITY |\n"
" vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"
+ " cvlan_id VID |\n"
+ " cvlan_prio PRIORITY |\n"
+ " cvlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"
" dst_mac MASKED-LLADDR |\n"
" src_mac MASKED-LLADDR |\n"
" ip_proto [tcp | udp | sctp | icmp | icmpv6 | IP-PROTO ] |\n"
@@ -128,15 +131,21 @@ err:
return err;
}
+static bool eth_type_vlan(__be16 ethertype)
+{
+ return ethertype == htons(ETH_P_8021Q) ||
+ ethertype == htons(ETH_P_8021AD);
+}
+
static int flower_parse_vlan_eth_type(char *str, __be16 eth_type, int type,
__be16 *p_vlan_eth_type,
struct nlmsghdr *n)
{
__be16 vlan_eth_type;
- if (eth_type != htons(ETH_P_8021Q)) {
- fprintf(stderr,
- "Can't set \"vlan_ethtype\" if ethertype isn't 802.1Q\n");
+ if (!eth_type_vlan(eth_type)) {
+ fprintf(stderr, "Can't set \"%s\" if ethertype isn't 802.1Q or 802.1AD\n",
+ type == TCA_FLOWER_KEY_VLAN_ETH_TYPE ? "vlan_ethtype" : "cvlan_ethtype");
return -1;
}
@@ -586,6 +595,7 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
struct rtattr *tail;
__be16 eth_type = TC_H_MIN(t->tcm_info);
__be16 vlan_ethtype = 0;
+ __be16 cvlan_ethtype = 0;
__u8 ip_proto = 0xff;
__u32 flags = 0;
__u32 mtf = 0;
@@ -661,9 +671,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
__u16 vid;
NEXT_ARG();
- if (eth_type != htons(ETH_P_8021Q)) {
- fprintf(stderr,
- "Can't set \"vlan_id\" if ethertype isn't 802.1Q\n");
+ if (!eth_type_vlan(eth_type)) {
+ fprintf(stderr, "Can't set \"vlan_id\" if ethertype isn't 802.1Q or 802.1AD\n");
return -1;
}
ret = get_u16(&vid, *argv, 10);
@@ -676,9 +685,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
__u8 vlan_prio;
NEXT_ARG();
- if (eth_type != htons(ETH_P_8021Q)) {
- fprintf(stderr,
- "Can't set \"vlan_prio\" if ethertype isn't 802.1Q\n");
+ if (!eth_type_vlan(eth_type)) {
+ fprintf(stderr, "Can't set \"vlan_prio\" if ethertype isn't 802.1Q or 802.1AD\n");
return -1;
}
ret = get_u8(&vlan_prio, *argv, 10);
@@ -695,6 +703,42 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
&vlan_ethtype, n);
if (ret < 0)
return -1;
+ } else if (matches(*argv, "cvlan_id") == 0) {
+ __u16 vid;
+
+ NEXT_ARG();
+ if (!eth_type_vlan(vlan_ethtype)) {
+ fprintf(stderr, "Can't set \"cvlan_id\" if inner vlan ethertype isn't 802.1Q or 802.1AD\n");
+ return -1;
+ }
+ ret = get_u16(&vid, *argv, 10);
+ if (ret < 0 || vid & ~0xfff) {
+ fprintf(stderr, "Illegal \"cvlan_id\"\n");
+ return -1;
+ }
+ addattr16(n, MAX_MSG, TCA_FLOWER_KEY_CVLAN_ID, vid);
+ } else if (matches(*argv, "cvlan_prio") == 0) {
+ __u8 cvlan_prio;
+
+ NEXT_ARG();
+ if (!eth_type_vlan(vlan_ethtype)) {
+ fprintf(stderr, "Can't set \"cvlan_prio\" if inner vlan ethertype isn't 802.1Q or 802.1AD\n");
+ return -1;
+ }
+ ret = get_u8(&cvlan_prio, *argv, 10);
+ if (ret < 0 || cvlan_prio & ~0x7) {
+ fprintf(stderr, "Illegal \"cvlan_prio\"\n");
+ return -1;
+ }
+ addattr8(n, MAX_MSG,
+ TCA_FLOWER_KEY_CVLAN_PRIO, cvlan_prio);
+ } else if (matches(*argv, "cvlan_ethtype") == 0) {
+ NEXT_ARG();
+ ret = flower_parse_vlan_eth_type(*argv, vlan_ethtype,
+ TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
+ &cvlan_ethtype, n);
+ if (ret < 0)
+ return -1;
} else if (matches(*argv, "mpls_label") == 0) {
__u32 label;
@@ -781,7 +825,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
}
} else if (matches(*argv, "ip_proto") == 0) {
NEXT_ARG();
- ret = flower_parse_ip_proto(*argv, vlan_ethtype ?
+ ret = flower_parse_ip_proto(*argv, cvlan_ethtype ?
+ cvlan_ethtype : vlan_ethtype ?
vlan_ethtype : eth_type,
TCA_FLOWER_KEY_IP_PROTO,
&ip_proto, n);
@@ -811,7 +856,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
}
} else if (matches(*argv, "dst_ip") == 0) {
NEXT_ARG();
- ret = flower_parse_ip_addr(*argv, vlan_ethtype ?
+ ret = flower_parse_ip_addr(*argv, cvlan_ethtype ?
+ cvlan_ethtype : vlan_ethtype ?
vlan_ethtype : eth_type,
TCA_FLOWER_KEY_IPV4_DST,
TCA_FLOWER_KEY_IPV4_DST_MASK,
@@ -824,7 +870,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
}
} else if (matches(*argv, "src_ip") == 0) {
NEXT_ARG();
- ret = flower_parse_ip_addr(*argv, vlan_ethtype ?
+ ret = flower_parse_ip_addr(*argv, cvlan_ethtype ?
+ cvlan_ethtype : vlan_ethtype ?
vlan_ethtype : eth_type,
TCA_FLOWER_KEY_IPV4_SRC,
TCA_FLOWER_KEY_IPV4_SRC_MASK,
@@ -1374,6 +1421,38 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
rta_getattr_u8(attr));
}
+ if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) {
+ SPRINT_BUF(buf);
+ struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE];
+
+ print_string(PRINT_ANY, "vlan_ethtype", "\n vlan_ethtype %s",
+ ll_proto_n2a(rta_getattr_u16(attr),
+ buf, sizeof(buf)));
+ }
+
+ if (tb[TCA_FLOWER_KEY_CVLAN_ID]) {
+ struct rtattr *attr = tb[TCA_FLOWER_KEY_CVLAN_ID];
+
+ print_uint(PRINT_ANY, "cvlan_id", "\n cvlan_id %u",
+ rta_getattr_u16(attr));
+ }
+
+ if (tb[TCA_FLOWER_KEY_CVLAN_PRIO]) {
+ struct rtattr *attr = tb[TCA_FLOWER_KEY_CVLAN_PRIO];
+
+ print_uint(PRINT_ANY, "cvlan_prio", "\n cvlan_prio %d",
+ rta_getattr_u8(attr));
+ }
+
+ if (tb[TCA_FLOWER_KEY_CVLAN_ETH_TYPE]) {
+ SPRINT_BUF(buf);
+ struct rtattr *attr = tb[TCA_FLOWER_KEY_CVLAN_ETH_TYPE];
+
+ print_string(PRINT_ANY, "cvlan_ethtype", "\n cvlan_ethtype %s",
+ ll_proto_n2a(rta_getattr_u16(attr),
+ buf, sizeof(buf)));
+ }
+
flower_print_eth_addr("dst_mac", tb[TCA_FLOWER_KEY_ETH_DST],
tb[TCA_FLOWER_KEY_ETH_DST_MASK]);
flower_print_eth_addr("src_mac", tb[TCA_FLOWER_KEY_ETH_SRC],
--
2.9.5
Powered by blists - more mailing lists