From: Eli Britstein Date: Wed, 20 Nov 2019 12:42:45 +0000 (+0200) Subject: tc: flower: support masked port destination and source match X-Git-Tag: v5.5.0~48 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=482fd40adfe80bdfc4408bd35b988099072e6352;p=thirdparty%2Fiproute2.git tc: flower: support masked port destination and source match Extend destination and source port match to support masks, accepting both decimal and hexadecimal formats. Also add missing documentation to synopsis in manpage. $ tc qdisc add dev eth0 ingress $ tc filter add dev eth0 protocol ip parent ffff: prio 1 flower skip_hw \ ip_proto tcp dst_port 1234/0xff00 action drop $ tc -s filter show dev eth0 parent ffff: filter protocol ip pref 1 flower chain 0 filter protocol ip pref 1 flower chain 0 handle 0x1 eth_type ipv4 ip_proto tcp dst_port 1234/0xff00 skip_hw not_in_hw action order 1: gact action drop random type none pass val 0 index 1 ref 1 bind 1 installed 26 sec used 26 sec Action statistics: Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 $ tc -p -j filter show dev eth0 parent ffff: "options": { "keys": { "dst_port": 1234, "dst_port_mask": 65280 ... Signed-off-by: Eli Britstein Reviewed-by: Roi Dayan Acked-by: Jiri Pirko Signed-off-by: David Ahern --- diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8 index 04ee19476..eb9eb5f0b 100644 --- a/man/man8/tc-flower.8 +++ b/man/man8/tc-flower.8 @@ -57,7 +57,7 @@ flower \- flow based traffic control filter .BR dst_ip " | " src_ip " } " .IR PREFIX " | { " .BR dst_port " | " src_port " } { " -.IR port_number " | " +.IR MASKED_NUMBER " | " .IR min_port_number-max_port_number " } | " .B tcp_flags .IR MASKED_TCP_FLAGS " | " @@ -221,12 +221,13 @@ must be a valid IPv4 or IPv6 address, depending on the \fBprotocol\fR option to tc filter, optionally followed by a slash and the prefix length. If the prefix is missing, \fBtc\fR assumes a full-length host match. .TP -.IR \fBdst_port " { " NUMBER " | " " MIN_VALUE-MAX_VALUE " } +.IR \fBdst_port " { " MASKED_NUMBER " | " " MIN_VALUE-MAX_VALUE " } .TQ -.IR \fBsrc_port " { " NUMBER " | " " MIN_VALUE-MAX_VALUE " } -Match on layer 4 protocol source or destination port number. Alternatively, the -mininum and maximum values can be specified to match on a range of layer 4 -protocol source or destination port numbers. Only available for +.IR \fBsrc_port " { " MASKED_NUMBER " | " " MIN_VALUE-MAX_VALUE " } +Match on layer 4 protocol source or destination port number, with an +optional mask. Alternatively, the mininum and maximum values can be +specified to match on a range of layer 4 protocol source or destination +port numbers. Only available for .BR ip_proto " values " udp ", " tcp " and " sctp which have to be specified in beforehand. .TP diff --git a/tc/f_flower.c b/tc/f_flower.c index 69de6a807..a193c0eca 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -637,6 +637,27 @@ static int flower_port_attr_type(__u8 ip_proto, enum flower_endpoint endpoint) return -1; } +static int flower_port_attr_mask_type(__u8 ip_proto, + enum flower_endpoint endpoint) +{ + switch (ip_proto) { + case IPPROTO_TCP: + return endpoint == FLOWER_ENDPOINT_SRC ? + TCA_FLOWER_KEY_TCP_SRC_MASK : + TCA_FLOWER_KEY_TCP_DST_MASK; + case IPPROTO_UDP: + return endpoint == FLOWER_ENDPOINT_SRC ? + TCA_FLOWER_KEY_UDP_SRC_MASK : + TCA_FLOWER_KEY_UDP_DST_MASK; + case IPPROTO_SCTP: + return endpoint == FLOWER_ENDPOINT_SRC ? + TCA_FLOWER_KEY_SCTP_SRC_MASK : + TCA_FLOWER_KEY_SCTP_DST_MASK; + default: + return -1; + } +} + static int flower_port_range_attr_type(__u8 ip_proto, enum flower_endpoint type, __be16 *min_port_type, __be16 *max_port_type) @@ -681,13 +702,17 @@ static int flower_parse_port(char *str, __u8 ip_proto, enum flower_endpoint endpoint, struct nlmsghdr *n) { + char *slash = NULL; __be16 min = 0; __be16 max = 0; int ret; ret = parse_range(str, &min, &max); - if (ret) - return -1; + if (ret) { + slash = strchr(str, '/'); + if (!slash) + return -1; + } if (min && max) { __be16 min_port_type, max_port_type; @@ -702,13 +727,24 @@ static int flower_parse_port(char *str, __u8 ip_proto, addattr16(n, MAX_MSG, min_port_type, min); addattr16(n, MAX_MSG, max_port_type, max); - } else if (min && !max) { + } else if (slash || (min && !max)) { int type; type = flower_port_attr_type(ip_proto, endpoint); if (type < 0) return -1; - addattr16(n, MAX_MSG, type, min); + + if (!slash) { + addattr16(n, MAX_MSG, type, min); + } else { + int mask_type; + + mask_type = flower_port_attr_mask_type(ip_proto, + endpoint); + if (mask_type < 0) + return -1; + return flower_parse_u16(str, type, mask_type, n, true); + } } else { return -1; } @@ -1715,15 +1751,10 @@ static void flower_print_ip4_addr(char *name, struct rtattr *addr_attr, addr_attr, mask_attr, 0, 0); } -static void flower_print_port(char *name, struct rtattr *attr) +static void flower_print_port(char *name, struct rtattr *attr, + struct rtattr *mask_attr) { - SPRINT_BUF(namefrm); - - if (!attr) - return; - - sprintf(namefrm,"\n %s %%u", name); - print_hu(PRINT_ANY, name, namefrm, rta_getattr_be16(attr)); + print_masked_be16(name, attr, mask_attr, true); } static void flower_print_port_range(char *name, struct rtattr *min_attr, @@ -2129,11 +2160,13 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, tb[TCA_FLOWER_KEY_IPV6_SRC_MASK]); nl_type = flower_port_attr_type(ip_proto, FLOWER_ENDPOINT_DST); + nl_mask_type = flower_port_attr_mask_type(ip_proto, FLOWER_ENDPOINT_DST); if (nl_type >= 0) - flower_print_port("dst_port", tb[nl_type]); + flower_print_port("dst_port", tb[nl_type], tb[nl_mask_type]); nl_type = flower_port_attr_type(ip_proto, FLOWER_ENDPOINT_SRC); + nl_mask_type = flower_port_attr_mask_type(ip_proto, FLOWER_ENDPOINT_SRC); if (nl_type >= 0) - flower_print_port("src_port", tb[nl_type]); + flower_print_port("src_port", tb[nl_type], tb[nl_mask_type]); if (!flower_port_range_attr_type(ip_proto, FLOWER_ENDPOINT_DST, &min_port_type, &max_port_type)) @@ -2193,7 +2226,8 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, flower_print_key_id("enc_key_id", tb[TCA_FLOWER_KEY_ENC_KEY_ID]); - flower_print_port("enc_dst_port", tb[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]); + flower_print_port("enc_dst_port", tb[TCA_FLOWER_KEY_ENC_UDP_DST_PORT], + tb[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]); flower_print_ip_attr("enc_tos", tb[TCA_FLOWER_KEY_ENC_IP_TOS], tb[TCA_FLOWER_KEY_ENC_IP_TOS_MASK]);