From: Pieter Jansen van Vuuren
Allow matching on options in Geneve tunnel headers.
The options can be described in the form
CLASS:TYPE:DATA/CLASS_MASK:TYPE_MASK:DATA_MASK, where CLASS is
represented as a 16bit hexadecimal value, TYPE as an 8bit
hexadecimal value and DATA as a variable length hexadecimal value.
e.g.
# ip link add name geneve0 type geneve dstport 0 external
# tc qdisc add dev geneve0 ingress
# tc filter add dev geneve0 protocol ip parent : \
flower \
enc_src_ip 10.0.99.192 \
enc_dst_ip 10.0.99.193 \
enc_key_id 11 \
geneve_opts 0102:80:1122334421314151/:ff: \
ip_proto udp \
action mirred egress redirect dev eth1
Signed-off-by: Pieter Jansen van Vuuren
Signed-off-by: Simon Horman
---
man/man8/tc-flower.8 | 13 ++-
tc/f_flower.c| 282 +++
2 files changed, 294 insertions(+), 1 deletion(-)
diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
index 305d7efe046a..8be8882592ea 100644
--- a/man/man8/tc-flower.8
+++ b/man/man8/tc-flower.8
@@ -80,6 +80,8 @@ flower \- flow based traffic control filter
.IR TOS " | "
.B enc_ttl
.IR TTL " | "
+.B geneve_opts
+.IR OPTIONS " | "
.BR ip_flags
.IR IP_FLAGS
.SH DESCRIPTION
@@ -283,6 +285,8 @@ bits is assumed.
.BI enc_tos " NUMBER"
.TQ
.BI enc_ttl " NUMBER"
+.TQ
+.BI geneve_opts " OPTIONS"
Match on IP tunnel metadata. Key id
.I NUMBER
is a 32 bit tunnel key id (e.g. VNI for VXLAN tunnel).
@@ -295,7 +299,14 @@ is a 16 bit UDP dst port. Tos
.I NUMBER
is an 8 bit tos (dscp+ecn) value, ttl
.I NUMBER
-is an 8 bit time-to-live value.
+is an 8 bit time-to-live value. geneve_opts
+.I OPTIONS
+must be a valid list of comma-separated geneve options where each option
+consists of a key optionally followed by a slash and corresponding mask. If
+the masks is missing, \fBtc\fR assumes a full-length match. The options can
+be described in the form CLASS:TYPE:DATA/CLASS_MASK:TYPE_MASK:DATA_MASK,
+where CLASS is represented as a 16bit hexadecimal value, TYPE as an 8bit
+hexadecimal value and DATA as a variable length hexadecimal value.
.TP
.BI ip_flags " IP_FLAGS"
.I IP_FLAGS
diff --git a/tc/f_flower.c b/tc/f_flower.c
index 59e5f572c542..4a8fb984a35a 100644
--- a/tc/f_flower.c
+++ b/tc/f_flower.c
@@ -79,6 +79,7 @@ static void explain(void)
" enc_key_id [ KEY-ID ] |\n"
" enc_tos MASKED-IP_TOS |\n"
" enc_ttl MASKED-IP_TTL |\n"
+ " geneve_opts MASKED-OPTIONS |\n"
" ip_flags IP-FLAGS | \n"
" enc_dst_port [ port_number ] }\n"
" FILTERID := X:Y:Z\n"
@@ -589,6 +590,179 @@ static int flower_parse_enc_port(char *str, int type,
struct nlmsghdr *n)
return 0;
}
+static int flower_parse_geneve_opts(char *str, struct nlmsghdr *n)
+{
+ struct rtattr *nest;
+ char *token;
+ int i, err;
+
+ nest = addattr_nest(n, MAX_MSG, TCA_FLOWER_KEY_ENC_OPTS_GENEVE);
+
+ i = 1;
+ token = strsep(, ":");
+ while (token) {
+ switch (i) {
+ case TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS:
+ {
+ __be16 opt_class;
+
+ if (!strlen(token))
+ break;
+ err = get_be16(_class, token, 16);
+ if (err)
+ return err;
+
+ addattr16(n, MAX_MSG, i, opt_class);
+ break;
+ }
+ case TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE:
+ {
+ __u8 opt_type;
+
+ if (!strlen(token))
+ break;
+ err = get_u8(_type, token, 16);
+ if (err)
+ return err;
+
+ addattr8(n, MAX_MSG, i, opt_type);
+ break;
+ }
+ case TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA:
+ {
+ size_t token_len = strlen(token);
+ __u8 *opts;
+
+ if (!token_len)
+ break;
+ opts = malloc(token_len / 2);
+ if (!opts)
+ return -1;
+ if (hex2mem(token, opts, token_len / 2) < 0) {
+ free(opts);
+ return -1;
+ }
+ addattr_l(n, MAX_MSG, i, opts, token_len / 2);
+ free(opts);
+
+ break;
+ }
+ default:
+ fprintf(stderr, "Unknown \"geneve_opts\" type\n");
+