|
|
4aca6e |
From 0263aa84af6519d1dc057329e895275d34a0f595 Mon Sep 17 00:00:00 2001
|
|
|
4aca6e |
From: Phil Sutter <psutter@redhat.com>
|
|
|
4aca6e |
Date: Fri, 17 Mar 2017 13:23:32 +0100
|
|
|
4aca6e |
Subject: [PATCH] tc/cls_flower: Classify packet in ip tunnels
|
|
|
4aca6e |
|
|
|
4aca6e |
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1422629
|
|
|
4aca6e |
Upstream Status: iproute2.git commit bb9b63b18e85f
|
|
|
4aca6e |
|
|
|
4aca6e |
commit bb9b63b18e85f17e618469ecb139e78ca5a4a4fc
|
|
|
4aca6e |
Author: Amir Vadai <amir@vadai.me>
|
|
|
4aca6e |
Date: Fri Dec 2 13:25:14 2016 +0200
|
|
|
4aca6e |
|
|
|
4aca6e |
tc/cls_flower: Classify packet in ip tunnels
|
|
|
4aca6e |
|
|
|
4aca6e |
Introduce classifying by metadata extracted by the tunnel device.
|
|
|
4aca6e |
Outer header fields - source/dest ip and tunnel id, are extracted from
|
|
|
4aca6e |
the metadata when classifying.
|
|
|
4aca6e |
|
|
|
4aca6e |
For example, the following will add a filter on the ingress Qdisc of shared
|
|
|
4aca6e |
vxlan device named 'vxlan0'. To forward packets with outer src ip
|
|
|
4aca6e |
11.11.0.2, dst ip 11.11.0.1 and tunnel id 11. The packets will be
|
|
|
4aca6e |
forwarded to tap device 'vnet0':
|
|
|
4aca6e |
|
|
|
4aca6e |
$ tc filter add dev vxlan0 protocol ip parent ffff: \
|
|
|
4aca6e |
flower \
|
|
|
4aca6e |
enc_src_ip 11.11.0.2 \
|
|
|
4aca6e |
enc_dst_ip 11.11.0.1 \
|
|
|
4aca6e |
enc_key_id 11 \
|
|
|
4aca6e |
dst_ip 11.11.11.1 \
|
|
|
4aca6e |
action mirred egress redirect dev vnet0
|
|
|
4aca6e |
|
|
|
4aca6e |
Signed-off-by: Amir Vadai <amir@vadai.me>
|
|
|
4aca6e |
---
|
|
|
4aca6e |
man/man8/tc-flower.8 | 17 ++++++++++-
|
|
|
4aca6e |
tc/f_flower.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++--
|
|
|
4aca6e |
2 files changed, 95 insertions(+), 4 deletions(-)
|
|
|
4aca6e |
|
|
|
4aca6e |
diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
|
|
|
4aca6e |
index 16ef261..dd35649 100644
|
|
|
4aca6e |
--- a/man/man8/tc-flower.8
|
|
|
4aca6e |
+++ b/man/man8/tc-flower.8
|
|
|
4aca6e |
@@ -34,7 +34,11 @@ flower \- flow based traffic control filter
|
|
|
4aca6e |
.BR dst_ip " | " src_ip " } { "
|
|
|
4aca6e |
.IR ipv4_address " | " ipv6_address " } | { "
|
|
|
4aca6e |
.BR dst_port " | " src_port " } "
|
|
|
4aca6e |
-.IR port_number " }"
|
|
|
4aca6e |
+.IR port_number " } | "
|
|
|
4aca6e |
+.B enc_key_id
|
|
|
4aca6e |
+.IR KEY-ID " | {"
|
|
|
4aca6e |
+.BR enc_dst_ip " | " enc_src_ip " } { "
|
|
|
4aca6e |
+.IR ipv4_address " | " ipv6_address " } | "
|
|
|
4aca6e |
.SH DESCRIPTION
|
|
|
4aca6e |
The
|
|
|
4aca6e |
.B flower
|
|
|
4aca6e |
@@ -112,6 +116,17 @@ which has to be specified in beforehand.
|
|
|
4aca6e |
Match on layer 4 protocol source or destination port number. Only available for
|
|
|
4aca6e |
.BR ip_proto " values " udp " and " tcp ,
|
|
|
4aca6e |
which has to be specified in beforehand.
|
|
|
4aca6e |
+.TP
|
|
|
4aca6e |
+.BI enc_key_id " NUMBER"
|
|
|
4aca6e |
+.TQ
|
|
|
4aca6e |
+.BI enc_dst_ip " ADDRESS"
|
|
|
4aca6e |
+.TQ
|
|
|
4aca6e |
+.BI enc_src_ip " ADDRESS"
|
|
|
4aca6e |
+Match on IP tunnel metadata. Key id
|
|
|
4aca6e |
+.I NUMBER
|
|
|
4aca6e |
+is a 32 bit tunnel key id (e.g. VNI for VXLAN tunnel).
|
|
|
4aca6e |
+.I ADDRESS
|
|
|
4aca6e |
+must be a valid IPv4 or IPv6 address.
|
|
|
4aca6e |
.SH NOTES
|
|
|
4aca6e |
As stated above where applicable, matches of a certain layer implicitly depend
|
|
|
4aca6e |
on the matches of the next lower layer. Precisely, layer one and two matches (
|
|
|
4aca6e |
diff --git a/tc/f_flower.c b/tc/f_flower.c
|
|
|
4aca6e |
index 75e64ae..36963c5 100644
|
|
|
4aca6e |
--- a/tc/f_flower.c
|
|
|
4aca6e |
+++ b/tc/f_flower.c
|
|
|
4aca6e |
@@ -41,7 +41,10 @@ static void explain(void)
|
|
|
4aca6e |
" dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
|
|
|
4aca6e |
" src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
|
|
|
4aca6e |
" dst_port PORT-NUMBER |\n"
|
|
|
4aca6e |
- " src_port PORT-NUMBER }\n"
|
|
|
4aca6e |
+ " src_port PORT-NUMBER |\n"
|
|
|
4aca6e |
+ " enc_dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
|
|
|
4aca6e |
+ " enc_src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"
|
|
|
4aca6e |
+ " enc_key_id [ KEY-ID ] }\n"
|
|
|
4aca6e |
" FILTERID := X:Y:Z\n"
|
|
|
4aca6e |
" ACTION-SPEC := ... look at individual actions\n"
|
|
|
4aca6e |
"\n"
|
|
|
4aca6e |
@@ -125,8 +128,9 @@ static int flower_parse_ip_addr(char *str, __be16 eth_type,
|
|
|
4aca6e |
family = AF_INET;
|
|
|
4aca6e |
} else if (eth_type == htons(ETH_P_IPV6)) {
|
|
|
4aca6e |
family = AF_INET6;
|
|
|
4aca6e |
+ } else if (!eth_type) {
|
|
|
4aca6e |
+ family = AF_UNSPEC;
|
|
|
4aca6e |
} else {
|
|
|
4aca6e |
- fprintf(stderr, "Illegal \"eth_type\" for ip address\n");
|
|
|
4aca6e |
return -1;
|
|
|
4aca6e |
}
|
|
|
4aca6e |
|
|
|
4aca6e |
@@ -134,8 +138,10 @@ static int flower_parse_ip_addr(char *str, __be16 eth_type,
|
|
|
4aca6e |
if (ret)
|
|
|
4aca6e |
return -1;
|
|
|
4aca6e |
|
|
|
4aca6e |
- if (addr.family != family)
|
|
|
4aca6e |
+ if (family && (addr.family != family)) {
|
|
|
4aca6e |
+ fprintf(stderr, "Illegal \"eth_type\" for ip address\n");
|
|
|
4aca6e |
return -1;
|
|
|
4aca6e |
+ }
|
|
|
4aca6e |
|
|
|
4aca6e |
addattr_l(n, MAX_MSG, addr.family == AF_INET ? addr4_type : addr6_type,
|
|
|
4aca6e |
addr.data, addr.bytelen);
|
|
|
4aca6e |
@@ -197,6 +203,18 @@ static int flower_parse_port(char *str, __u8 ip_port, bool is_src,
|
|
|
4aca6e |
return 0;
|
|
|
4aca6e |
}
|
|
|
4aca6e |
|
|
|
4aca6e |
+static int flower_parse_key_id(const char *str, int type, struct nlmsghdr *n)
|
|
|
4aca6e |
+{
|
|
|
4aca6e |
+ int ret;
|
|
|
4aca6e |
+ __be32 key_id;
|
|
|
4aca6e |
+
|
|
|
4aca6e |
+ ret = get_be32(&key_id, str, 10);
|
|
|
4aca6e |
+ if (!ret)
|
|
|
4aca6e |
+ addattr32(n, MAX_MSG, type, key_id);
|
|
|
4aca6e |
+
|
|
|
4aca6e |
+ return ret;
|
|
|
4aca6e |
+}
|
|
|
4aca6e |
+
|
|
|
4aca6e |
static int flower_parse_opt(struct filter_util *qu, char *handle,
|
|
|
4aca6e |
int argc, char **argv, struct nlmsghdr *n)
|
|
|
4aca6e |
{
|
|
|
4aca6e |
@@ -355,6 +373,38 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
|
|
|
4aca6e |
fprintf(stderr, "Illegal \"src_port\"\n");
|
|
|
4aca6e |
return -1;
|
|
|
4aca6e |
}
|
|
|
4aca6e |
+ } else if (matches(*argv, "enc_dst_ip") == 0) {
|
|
|
4aca6e |
+ NEXT_ARG();
|
|
|
4aca6e |
+ ret = flower_parse_ip_addr(*argv, 0,
|
|
|
4aca6e |
+ TCA_FLOWER_KEY_ENC_IPV4_DST,
|
|
|
4aca6e |
+ TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
|
|
|
4aca6e |
+ TCA_FLOWER_KEY_ENC_IPV6_DST,
|
|
|
4aca6e |
+ TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
|
|
|
4aca6e |
+ n);
|
|
|
4aca6e |
+ if (ret < 0) {
|
|
|
4aca6e |
+ fprintf(stderr, "Illegal \"enc_dst_ip\"\n");
|
|
|
4aca6e |
+ return -1;
|
|
|
4aca6e |
+ }
|
|
|
4aca6e |
+ } else if (matches(*argv, "enc_src_ip") == 0) {
|
|
|
4aca6e |
+ NEXT_ARG();
|
|
|
4aca6e |
+ ret = flower_parse_ip_addr(*argv, 0,
|
|
|
4aca6e |
+ TCA_FLOWER_KEY_ENC_IPV4_SRC,
|
|
|
4aca6e |
+ TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
|
|
|
4aca6e |
+ TCA_FLOWER_KEY_ENC_IPV6_SRC,
|
|
|
4aca6e |
+ TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
|
|
|
4aca6e |
+ n);
|
|
|
4aca6e |
+ if (ret < 0) {
|
|
|
4aca6e |
+ fprintf(stderr, "Illegal \"enc_src_ip\"\n");
|
|
|
4aca6e |
+ return -1;
|
|
|
4aca6e |
+ }
|
|
|
4aca6e |
+ } else if (matches(*argv, "enc_key_id") == 0) {
|
|
|
4aca6e |
+ NEXT_ARG();
|
|
|
4aca6e |
+ ret = flower_parse_key_id(*argv,
|
|
|
4aca6e |
+ TCA_FLOWER_KEY_ENC_KEY_ID, n);
|
|
|
4aca6e |
+ if (ret < 0) {
|
|
|
4aca6e |
+ fprintf(stderr, "Illegal \"enc_key_id\"\n");
|
|
|
4aca6e |
+ return -1;
|
|
|
4aca6e |
+ }
|
|
|
4aca6e |
} else if (matches(*argv, "action") == 0) {
|
|
|
4aca6e |
NEXT_ARG();
|
|
|
4aca6e |
ret = parse_action(&argc, &argv, TCA_FLOWER_ACT, n);
|
|
|
4aca6e |
@@ -515,6 +565,13 @@ static void flower_print_port(FILE *f, char *name, struct rtattr *attr)
|
|
|
4aca6e |
fprintf(f, "\n %s %d", name, rta_getattr_be16(attr));
|
|
|
4aca6e |
}
|
|
|
4aca6e |
|
|
|
4aca6e |
+static void flower_print_key_id(FILE *f, const char *name,
|
|
|
4aca6e |
+ struct rtattr *attr)
|
|
|
4aca6e |
+{
|
|
|
4aca6e |
+ if (attr)
|
|
|
4aca6e |
+ fprintf(f, "\n %s %d", name, rta_getattr_be32(attr));
|
|
|
4aca6e |
+}
|
|
|
4aca6e |
+
|
|
|
4aca6e |
static int flower_print_opt(struct filter_util *qu, FILE *f,
|
|
|
4aca6e |
struct rtattr *opt, __u32 handle)
|
|
|
4aca6e |
{
|
|
|
4aca6e |
@@ -580,6 +637,25 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
|
|
|
4aca6e |
flower_print_port(f, "src_port",
|
|
|
4aca6e |
tb[flower_port_attr_type(ip_proto, true)]);
|
|
|
4aca6e |
|
|
|
4aca6e |
+ flower_print_ip_addr(f, "enc_dst_ip",
|
|
|
4aca6e |
+ tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] ?
|
|
|
4aca6e |
+ htons(ETH_P_IP) : htons(ETH_P_IPV6),
|
|
|
4aca6e |
+ tb[TCA_FLOWER_KEY_ENC_IPV4_DST],
|
|
|
4aca6e |
+ tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK],
|
|
|
4aca6e |
+ tb[TCA_FLOWER_KEY_ENC_IPV6_DST],
|
|
|
4aca6e |
+ tb[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]);
|
|
|
4aca6e |
+
|
|
|
4aca6e |
+ flower_print_ip_addr(f, "enc_src_ip",
|
|
|
4aca6e |
+ tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] ?
|
|
|
4aca6e |
+ htons(ETH_P_IP) : htons(ETH_P_IPV6),
|
|
|
4aca6e |
+ tb[TCA_FLOWER_KEY_ENC_IPV4_SRC],
|
|
|
4aca6e |
+ tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK],
|
|
|
4aca6e |
+ tb[TCA_FLOWER_KEY_ENC_IPV6_SRC],
|
|
|
4aca6e |
+ tb[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]);
|
|
|
4aca6e |
+
|
|
|
4aca6e |
+ flower_print_key_id(f, "enc_key_id",
|
|
|
4aca6e |
+ tb[TCA_FLOWER_KEY_ENC_KEY_ID]);
|
|
|
4aca6e |
+
|
|
|
4aca6e |
if (tb[TCA_FLOWER_FLAGS]) {
|
|
|
4aca6e |
__u32 flags = rta_getattr_u32(tb[TCA_FLOWER_FLAGS]);
|
|
|
4aca6e |
|
|
|
4aca6e |
--
|
|
|
4aca6e |
1.8.3.1
|
|
|
4aca6e |
|