From 54549fa07c9ad748ffa9ecf6865c12641cd71329 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 17 Mar 2017 13:21:33 +0100 Subject: [PATCH] tc: flower: Introduce vlan support Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1422629 Upstream Status: iproute2.git commit 745d91726006f Conflicts: Context changes due to missing commit 32a121cba2579 ("tc: code cleanup"). commit 745d91726006fcaa9006f491f9a596c4025cecf7 Author: Hadar Hen Zion Date: Thu Sep 1 09:45:47 2016 +0300 tc: flower: Introduce vlan support Classification according to vlan id and vlan priority. Example script that adds vlan filter: # add ingress qdisc tc qdisc add dev ens4f0 ingress # add a flower filter with vlan id and priority classification tc filter add dev ens4f0 protocol 802.1Q parent ffff: \ flower \ indev ens4f0 \ vlan_ethtype ipv4 \ vlan_id 100 \ vlan_prio 3 \ action vlan pop Signed-off-by: Hadar Hen Zion Acked-by: Jiri Pirko --- man/man8/tc-flower.8 | 25 ++++++++++++++++- tc/f_flower.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 99 insertions(+), 4 deletions(-) diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8 index 9ae10e6..74f7664 100644 --- a/man/man8/tc-flower.8 +++ b/man/man8/tc-flower.8 @@ -23,7 +23,13 @@ flower \- flow based traffic control filter .R " | { " .BR dst_mac " | " src_mac " } " .IR mac_address " | " -.BR eth_type " { " ipv4 " | " ipv6 " | " +.BR eth_type " { " ipv4 " | " ipv6 " | " 802.1Q " | " +.IR ETH_TYPE " } | " +.B vlan_id +.IR VID " | " +.B vlan_prio +.IR PRIORITY " | " +.BR vlan_eth_type " { " ipv4 " | " ipv6 " | " .IR ETH_TYPE " } | " .BR ip_proto " { " tcp " | " udp " | " .IR IP_PROTO " } | { " @@ -70,6 +76,23 @@ Do not process filter by hardware. Match on source or destination MAC address. .TP .BI eth_type " ETH_TYPE" +Match on the next protocol. +.I ETH_TYPE +may be either +.BR ipv4 , ipv6 , 802.1Q , +or an unsigned 16bit value in hexadecimal format. +.TP +.BI vlan_id " VID" +Match on vlan tag id. +.I VID +is an unsigned 12bit value in decimal format. +.TP +.BI vlan_prio " priority" +Match on vlan tag priority. +.I PRIORITY +is an unsigned 3bit value in decimal format. +.TP +.BI vlan_eth_type " VLAN_ETH_TYPE" Match on layer three protocol. .I ETH_TYPE may be either diff --git a/tc/f_flower.c b/tc/f_flower.c index 01527c8..dec7d9d 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "utils.h" #include "tc_util.h" @@ -30,6 +31,9 @@ static void explain(void) fprintf(stderr, "\n"); fprintf(stderr, "Where: MATCH-LIST := [ MATCH-LIST ] MATCH\n"); fprintf(stderr, " MATCH := { indev DEV-NAME | \n"); + fprintf(stderr, " vlan_id VID |\n"); + fprintf(stderr, " vlan_prio PRIORITY |\n"); + fprintf(stderr, " vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"); fprintf(stderr, " dst_mac MAC-ADDR | \n"); fprintf(stderr, " src_mac MAC-ADDR | \n"); fprintf(stderr, " [ipv4 | ipv6 ] | \n"); @@ -61,6 +65,23 @@ static int flower_parse_eth_addr(char *str, int addr_type, int mask_type, return 0; } +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"); + return -1; + } + + if (ll_proto_a2n(&vlan_eth_type, str)) + invarg("invalid vlan_ethtype", str); + addattr16(n, MAX_MSG, type, vlan_eth_type); + *p_vlan_eth_type = vlan_eth_type; + return 0; +} + static int flower_parse_ip_proto(char *str, __be16 eth_type, int type, __u8 *p_ip_proto, struct nlmsghdr *n) { @@ -167,6 +188,7 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, struct tcmsg *t = NLMSG_DATA(n); struct rtattr *tail; __be16 eth_type = TC_H_MIN(t->tcm_info); + __be16 vlan_ethtype = 0; __u8 ip_proto = 0xff; __u32 flags = 0; @@ -209,6 +231,41 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, memset(ifname, 0, sizeof(ifname)); strncpy(ifname, *argv, sizeof(ifname) - 1); addattrstrz(n, MAX_MSG, TCA_FLOWER_INDEV, ifname); + } else if (matches(*argv, "vlan_id") == 0) { + __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"); + return -1; + } + ret = get_u16(&vid, *argv, 10); + if (ret < 0 || vid & ~0xfff) { + fprintf(stderr, "Illegal \"vlan_id\"\n"); + return -1; + } + addattr16(n, MAX_MSG, TCA_FLOWER_KEY_VLAN_ID, vid); + } else if (matches(*argv, "vlan_prio") == 0) { + __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"); + return -1; + } + ret = get_u8(&vlan_prio, *argv, 10); + if (ret < 0 || vlan_prio & ~0x7) { + fprintf(stderr, "Illegal \"vlan_prio\"\n"); + return -1; + } + addattr8(n, MAX_MSG, TCA_FLOWER_KEY_VLAN_PRIO, vlan_prio); + } else if (matches(*argv, "vlan_ethtype") == 0) { + NEXT_ARG(); + ret = flower_parse_vlan_eth_type(*argv, eth_type, + TCA_FLOWER_KEY_VLAN_ETH_TYPE, + &vlan_ethtype, n); + if (ret < 0) + return -1; } else if (matches(*argv, "dst_mac") == 0) { NEXT_ARG(); ret = flower_parse_eth_addr(*argv, @@ -231,7 +288,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, eth_type, + ret = flower_parse_ip_proto(*argv, vlan_ethtype ? + vlan_ethtype : eth_type, TCA_FLOWER_KEY_IP_PROTO, &ip_proto, n); if (ret < 0) { @@ -240,7 +298,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, eth_type, + ret = flower_parse_ip_addr(*argv, vlan_ethtype ? + vlan_ethtype : eth_type, TCA_FLOWER_KEY_IPV4_DST, TCA_FLOWER_KEY_IPV4_DST_MASK, TCA_FLOWER_KEY_IPV6_DST, @@ -252,7 +311,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, eth_type, + ret = flower_parse_ip_addr(*argv, vlan_ethtype ? + vlan_ethtype : eth_type, TCA_FLOWER_KEY_IPV4_SRC, TCA_FLOWER_KEY_IPV4_SRC_MASK, TCA_FLOWER_KEY_IPV6_SRC, @@ -478,6 +538,18 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, fprintf(f, "\n indev %s", rta_getattr_str(attr)); } + if (tb[TCA_FLOWER_KEY_VLAN_ID]) { + struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_ID]; + + fprintf(f, "\n vlan_id %d", rta_getattr_u16(attr)); + } + + if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) { + struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_PRIO]; + + fprintf(f, "\n vlan_prio %d", rta_getattr_u8(attr)); + } + flower_print_eth_addr(f, "dst_mac", tb[TCA_FLOWER_KEY_ETH_DST], tb[TCA_FLOWER_KEY_ETH_DST_MASK]); flower_print_eth_addr(f, "src_mac", tb[TCA_FLOWER_KEY_ETH_SRC], -- 1.8.3.1