diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8 index 16ef2617..dd356491 100644 --- a/man/man8/tc-flower.8 +++ b/man/man8/tc-flower.8 @@ -34,7 +34,11 @@ flower \- flow based traffic control filter .BR dst_ip " | " src_ip " } { " .IR ipv4_address " | " ipv6_address " } | { " .BR dst_port " | " src_port " } " -.IR port_number " }" +.IR port_number " } | " +.B enc_key_id +.IR KEY-ID " | {" +.BR enc_dst_ip " | " enc_src_ip " } { " +.IR ipv4_address " | " ipv6_address " } | " .SH DESCRIPTION The .B flower @@ -112,6 +116,17 @@ which has to be specified in beforehand. Match on layer 4 protocol source or destination port number. Only available for .BR ip_proto " values " udp " and " tcp , which has to be specified in beforehand. +.TP +.BI enc_key_id " NUMBER" +.TQ +.BI enc_dst_ip " ADDRESS" +.TQ +.BI enc_src_ip " ADDRESS" +Match on IP tunnel metadata. Key id +.I NUMBER +is a 32 bit tunnel key id (e.g. VNI for VXLAN tunnel). +.I ADDRESS +must be a valid IPv4 or IPv6 address. .SH NOTES As stated above where applicable, matches of a certain layer implicitly depend on the matches of the next lower layer. Precisely, layer one and two matches ( diff --git a/tc/f_flower.c b/tc/f_flower.c index e132974e..7e7f4c92 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -41,7 +41,10 @@ static void explain(void) " dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n" " src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n" " dst_port PORT-NUMBER |\n" - " src_port PORT-NUMBER }\n" + " src_port PORT-NUMBER |\n" + " enc_dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n" + " enc_src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n" + " enc_key_id [ KEY-ID ] }\n" " FILTERID := X:Y:Z\n" " ACTION-SPEC := ... look at individual actions\n" "\n" @@ -125,8 +128,9 @@ static int flower_parse_ip_addr(char *str, __be16 eth_type, family = AF_INET; } else if (eth_type == htons(ETH_P_IPV6)) { family = AF_INET6; + } else if (!eth_type) { + family = AF_UNSPEC; } else { - fprintf(stderr, "Illegal \"eth_type\" for ip address\n"); return -1; } @@ -134,8 +138,10 @@ static int flower_parse_ip_addr(char *str, __be16 eth_type, if (ret) return -1; - if (addr.family != family) + if (family && (addr.family != family)) { + fprintf(stderr, "Illegal \"eth_type\" for ip address\n"); return -1; + } addattr_l(n, MAX_MSG, addr.family == AF_INET ? addr4_type : addr6_type, addr.data, addr.bytelen); @@ -197,6 +203,18 @@ static int flower_parse_port(char *str, __u8 ip_port, bool is_src, return 0; } +static int flower_parse_key_id(const char *str, int type, struct nlmsghdr *n) +{ + int ret; + __be32 key_id; + + ret = get_be32(&key_id, str, 10); + if (!ret) + addattr32(n, MAX_MSG, type, key_id); + + return ret; +} + static int flower_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) { @@ -354,6 +372,38 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, fprintf(stderr, "Illegal \"src_port\"\n"); return -1; } + } else if (matches(*argv, "enc_dst_ip") == 0) { + NEXT_ARG(); + ret = flower_parse_ip_addr(*argv, 0, + TCA_FLOWER_KEY_ENC_IPV4_DST, + TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, + TCA_FLOWER_KEY_ENC_IPV6_DST, + TCA_FLOWER_KEY_ENC_IPV6_DST_MASK, + n); + if (ret < 0) { + fprintf(stderr, "Illegal \"enc_dst_ip\"\n"); + return -1; + } + } else if (matches(*argv, "enc_src_ip") == 0) { + NEXT_ARG(); + ret = flower_parse_ip_addr(*argv, 0, + TCA_FLOWER_KEY_ENC_IPV4_SRC, + TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, + TCA_FLOWER_KEY_ENC_IPV6_SRC, + TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK, + n); + if (ret < 0) { + fprintf(stderr, "Illegal \"enc_src_ip\"\n"); + return -1; + } + } else if (matches(*argv, "enc_key_id") == 0) { + NEXT_ARG(); + ret = flower_parse_key_id(*argv, + TCA_FLOWER_KEY_ENC_KEY_ID, n); + if (ret < 0) { + fprintf(stderr, "Illegal \"enc_key_id\"\n"); + return -1; + } } else if (matches(*argv, "action") == 0) { NEXT_ARG(); ret = parse_action(&argc, &argv, TCA_FLOWER_ACT, n); @@ -514,6 +564,13 @@ static void flower_print_port(FILE *f, char *name, struct rtattr *attr) fprintf(f, "\n %s %d", name, rta_getattr_be16(attr)); } +static void flower_print_key_id(FILE *f, const char *name, + struct rtattr *attr) +{ + if (attr) + fprintf(f, "\n %s %d", name, rta_getattr_be32(attr)); +} + static int flower_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 handle) { @@ -579,6 +636,25 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, flower_print_port(f, "src_port", tb[flower_port_attr_type(ip_proto, true)]); + flower_print_ip_addr(f, "enc_dst_ip", + tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] ? + htons(ETH_P_IP) : htons(ETH_P_IPV6), + tb[TCA_FLOWER_KEY_ENC_IPV4_DST], + tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK], + tb[TCA_FLOWER_KEY_ENC_IPV6_DST], + tb[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]); + + flower_print_ip_addr(f, "enc_src_ip", + tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] ? + htons(ETH_P_IP) : htons(ETH_P_IPV6), + tb[TCA_FLOWER_KEY_ENC_IPV4_SRC], + tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK], + tb[TCA_FLOWER_KEY_ENC_IPV6_SRC], + tb[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]); + + flower_print_key_id(f, "enc_key_id", + tb[TCA_FLOWER_KEY_ENC_KEY_ID]); + if (tb[TCA_FLOWER_FLAGS]) { __u32 flags = rta_getattr_u32(tb[TCA_FLOWER_FLAGS]);