Blame SOURCES/0036-tc-flower-Add-matching-on-conntrack-info.patch

0ac2f3
From b60d960c65c6aa5695ecf1c71b18790ca0cb475c Mon Sep 17 00:00:00 2001
0ac2f3
From: Andrea Claudi <aclaudi@redhat.com>
0ac2f3
Date: Tue, 9 Jun 2020 15:45:56 +0200
0ac2f3
Subject: [PATCH] tc: flower: Add matching on conntrack info
0ac2f3
0ac2f3
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1844637
0ac2f3
Upstream Status: iproute2.git commit 2fffb1c03056e
0ac2f3
0ac2f3
commit 2fffb1c03056e71d49d623f7ca460883fa6110a6
0ac2f3
Author: Paul Blakey <paulb@mellanox.com>
0ac2f3
Date:   Thu Jul 11 11:14:27 2019 +0300
0ac2f3
0ac2f3
    tc: flower: Add matching on conntrack info
0ac2f3
0ac2f3
    Matches on conntrack state, zone, mark, and label.
0ac2f3
0ac2f3
    Signed-off-by: Paul Blakey <paulb@mellanox.com>
0ac2f3
    Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
0ac2f3
    Signed-off-by: Yossi Kuperman <yossiku@mellanox.com>
0ac2f3
    Acked-by: Jiri Pirko <jiri@mellanox.com>
0ac2f3
    Acked-by: Roi Dayan <roid@mellanox.com>
0ac2f3
    Signed-off-by: David Ahern <dsahern@gmail.com>
0ac2f3
---
0ac2f3
 man/man8/tc-flower.8 |  35 ++++++
0ac2f3
 tc/f_flower.c        | 276 ++++++++++++++++++++++++++++++++++++++++++-
0ac2f3
 2 files changed, 310 insertions(+), 1 deletion(-)
0ac2f3
0ac2f3
diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
0ac2f3
index f41b0f7f1ef13..0f95f303f23b7 100644
0ac2f3
--- a/man/man8/tc-flower.8
0ac2f3
+++ b/man/man8/tc-flower.8
0ac2f3
@@ -295,6 +295,41 @@ bits is assumed.
0ac2f3
 .TQ
0ac2f3
 .BI enc_ttl " NUMBER"
0ac2f3
 .TQ
0ac2f3
+.BR
0ac2f3
+.TP
0ac2f3
+.BI ct_state " CT_STATE"
0ac2f3
+.TQ
0ac2f3
+.BI ct_zone " CT_MASKED_ZONE"
0ac2f3
+.TQ
0ac2f3
+.BI ct_mark " CT_MASKED_MARK"
0ac2f3
+.TQ
0ac2f3
+.BI ct_label " CT_MASKED_LABEL"
0ac2f3
+Matches on connection tracking info
0ac2f3
+.RS
0ac2f3
+.TP
0ac2f3
+.I CT_STATE
0ac2f3
+Match the connection state, and can ne combination of [{+|-}flag] flags, where flag can be one of
0ac2f3
+.RS
0ac2f3
+.TP
0ac2f3
+trk - Tracked connection.
0ac2f3
+.TP
0ac2f3
+new - New connection.
0ac2f3
+.TP
0ac2f3
+est - Established connection.
0ac2f3
+.TP
0ac2f3
+Example: +trk+est
0ac2f3
+.RE
0ac2f3
+.TP
0ac2f3
+.I CT_MASKED_ZONE
0ac2f3
+Match the connection zone, and can be masked.
0ac2f3
+.TP
0ac2f3
+.I CT_MASKED_MARK
0ac2f3
+32bit match on the connection mark, and can be masked.
0ac2f3
+.TP
0ac2f3
+.I CT_MASKED_LABEL
0ac2f3
+128bit match on the connection label, and can be masked.
0ac2f3
+.RE
0ac2f3
+.TP
0ac2f3
 .BI geneve_opts " OPTIONS"
0ac2f3
 .TQ
0ac2f3
 .BI vxlan_opts " OPTIONS"
0ac2f3
diff --git a/tc/f_flower.c b/tc/f_flower.c
0ac2f3
index 691541ec59d4c..0a6eaa0df94ce 100644
0ac2f3
--- a/tc/f_flower.c
0ac2f3
+++ b/tc/f_flower.c
0ac2f3
@@ -84,9 +84,14 @@ static void explain(void)
0ac2f3
 		"			vxlan_opts MASKED-OPTIONS |\n"
0ac2f3
 		"                       erspan_opts MASKED-OPTIONS |\n"
0ac2f3
 		"			ip_flags IP-FLAGS | \n"
0ac2f3
-		"			enc_dst_port [ port_number ] }\n"
0ac2f3
+		"			enc_dst_port [ port_number ] |\n"
0ac2f3
+		"			ct_state MASKED_CT_STATE |\n"
0ac2f3
+		"			ct_label MASKED_CT_LABEL |\n"
0ac2f3
+		"			ct_mark MASKED_CT_MARK |\n"
0ac2f3
+		"			ct_zone MASKED_CT_ZONE }\n"
0ac2f3
 		"	FILTERID := X:Y:Z\n"
0ac2f3
 		"	MASKED_LLADDR := { LLADDR | LLADDR/MASK | LLADDR/BITS }\n"
0ac2f3
+		"	MASKED_CT_STATE := combination of {+|-} and flags trk,est,new\n"
0ac2f3
 		"	ACTION-SPEC := ... look at individual actions\n"
0ac2f3
 		"\n"
0ac2f3
 		"NOTE:	CLASSID, IP-PROTO are parsed as hexadecimal input.\n"
0ac2f3
@@ -216,6 +221,159 @@ static int flower_parse_matching_flags(char *str,
0ac2f3
 	return 0;
0ac2f3
 }
0ac2f3
 
0ac2f3
+static int flower_parse_u16(char *str, int value_type, int mask_type,
0ac2f3
+			    struct nlmsghdr *n)
0ac2f3
+{
0ac2f3
+	__u16 value, mask;
0ac2f3
+	char *slash;
0ac2f3
+
0ac2f3
+	slash = strchr(str, '/');
0ac2f3
+	if (slash)
0ac2f3
+		*slash = '\0';
0ac2f3
+
0ac2f3
+	if (get_u16(&value, str, 0))
0ac2f3
+		return -1;
0ac2f3
+
0ac2f3
+	if (slash) {
0ac2f3
+		if (get_u16(&mask, slash + 1, 0))
0ac2f3
+			return -1;
0ac2f3
+	} else {
0ac2f3
+		mask = UINT16_MAX;
0ac2f3
+	}
0ac2f3
+
0ac2f3
+	addattr16(n, MAX_MSG, value_type, value);
0ac2f3
+	addattr16(n, MAX_MSG, mask_type, mask);
0ac2f3
+
0ac2f3
+	return 0;
0ac2f3
+}
0ac2f3
+
0ac2f3
+static int flower_parse_u32(char *str, int value_type, int mask_type,
0ac2f3
+			    struct nlmsghdr *n)
0ac2f3
+{
0ac2f3
+	__u32 value, mask;
0ac2f3
+	char *slash;
0ac2f3
+
0ac2f3
+	slash = strchr(str, '/');
0ac2f3
+	if (slash)
0ac2f3
+		*slash = '\0';
0ac2f3
+
0ac2f3
+	if (get_u32(&value, str, 0))
0ac2f3
+		return -1;
0ac2f3
+
0ac2f3
+	if (slash) {
0ac2f3
+		if (get_u32(&mask, slash + 1, 0))
0ac2f3
+			return -1;
0ac2f3
+	} else {
0ac2f3
+		mask = UINT32_MAX;
0ac2f3
+	}
0ac2f3
+
0ac2f3
+	addattr32(n, MAX_MSG, value_type, value);
0ac2f3
+	addattr32(n, MAX_MSG, mask_type, mask);
0ac2f3
+
0ac2f3
+	return 0;
0ac2f3
+}
0ac2f3
+
0ac2f3
+static int flower_parse_ct_mark(char *str, struct nlmsghdr *n)
0ac2f3
+{
0ac2f3
+	return flower_parse_u32(str,
0ac2f3
+				TCA_FLOWER_KEY_CT_MARK,
0ac2f3
+				TCA_FLOWER_KEY_CT_MARK_MASK,
0ac2f3
+				n);
0ac2f3
+}
0ac2f3
+
0ac2f3
+static int flower_parse_ct_zone(char *str, struct nlmsghdr *n)
0ac2f3
+{
0ac2f3
+	return flower_parse_u16(str,
0ac2f3
+				TCA_FLOWER_KEY_CT_ZONE,
0ac2f3
+				TCA_FLOWER_KEY_CT_ZONE_MASK,
0ac2f3
+				n);
0ac2f3
+}
0ac2f3
+
0ac2f3
+static int flower_parse_ct_labels(char *str, struct nlmsghdr *n)
0ac2f3
+{
0ac2f3
+#define LABELS_SIZE	16
0ac2f3
+	uint8_t labels[LABELS_SIZE], lmask[LABELS_SIZE];
0ac2f3
+	char *slash, *mask = NULL;
0ac2f3
+	size_t slen, slen_mask = 0;
0ac2f3
+
0ac2f3
+	slash = index(str, '/');
0ac2f3
+	if (slash) {
0ac2f3
+		*slash = 0;
0ac2f3
+		mask = slash + 1;
0ac2f3
+		slen_mask = strlen(mask);
0ac2f3
+	}
0ac2f3
+
0ac2f3
+	slen = strlen(str);
0ac2f3
+	if (slen > LABELS_SIZE * 2 || slen_mask > LABELS_SIZE * 2) {
0ac2f3
+		char errmsg[128];
0ac2f3
+
0ac2f3
+		snprintf(errmsg, sizeof(errmsg),
0ac2f3
+				"%zd Max allowed size %d",
0ac2f3
+				slen, LABELS_SIZE*2);
0ac2f3
+		invarg(errmsg, str);
0ac2f3
+	}
0ac2f3
+
0ac2f3
+	if (hex2mem(str, labels, slen / 2) < 0)
0ac2f3
+		invarg("labels must be a hex string\n", str);
0ac2f3
+	addattr_l(n, MAX_MSG, TCA_FLOWER_KEY_CT_LABELS, labels, slen / 2);
0ac2f3
+
0ac2f3
+	if (mask) {
0ac2f3
+		if (hex2mem(mask, lmask, slen_mask / 2) < 0)
0ac2f3
+			invarg("labels mask must be a hex string\n", mask);
0ac2f3
+	} else {
0ac2f3
+		memset(lmask, 0xff, sizeof(lmask));
0ac2f3
+		slen_mask = sizeof(lmask) * 2;
0ac2f3
+	}
0ac2f3
+	addattr_l(n, MAX_MSG, TCA_FLOWER_KEY_CT_LABELS_MASK, lmask,
0ac2f3
+		  slen_mask / 2);
0ac2f3
+
0ac2f3
+	return 0;
0ac2f3
+}
0ac2f3
+
0ac2f3
+static struct flower_ct_states {
0ac2f3
+	char *str;
0ac2f3
+	int flag;
0ac2f3
+} flower_ct_states[] = {
0ac2f3
+	{ "trk", TCA_FLOWER_KEY_CT_FLAGS_TRACKED },
0ac2f3
+	{ "new", TCA_FLOWER_KEY_CT_FLAGS_NEW },
0ac2f3
+	{ "est", TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED },
0ac2f3
+};
0ac2f3
+
0ac2f3
+static int flower_parse_ct_state(char *str, struct nlmsghdr *n)
0ac2f3
+{
0ac2f3
+	int flags = 0, mask = 0,  len, i;
0ac2f3
+	bool p;
0ac2f3
+
0ac2f3
+	while (*str != '\0') {
0ac2f3
+		if (*str == '+')
0ac2f3
+			p = true;
0ac2f3
+		else if (*str == '-')
0ac2f3
+			p = false;
0ac2f3
+		else
0ac2f3
+			return -1;
0ac2f3
+
0ac2f3
+		for (i = 0; i < ARRAY_SIZE(flower_ct_states); i++) {
0ac2f3
+			len = strlen(flower_ct_states[i].str);
0ac2f3
+			if (strncmp(str + 1, flower_ct_states[i].str, len))
0ac2f3
+				continue;
0ac2f3
+
0ac2f3
+			if (p)
0ac2f3
+				flags |= flower_ct_states[i].flag;
0ac2f3
+			mask |= flower_ct_states[i].flag;
0ac2f3
+			break;
0ac2f3
+		}
0ac2f3
+
0ac2f3
+		if (i == ARRAY_SIZE(flower_ct_states))
0ac2f3
+			return -1;
0ac2f3
+
0ac2f3
+		str += len + 1;
0ac2f3
+	}
0ac2f3
+
0ac2f3
+	addattr16(n, MAX_MSG, TCA_FLOWER_KEY_CT_STATE, flags);
0ac2f3
+	addattr16(n, MAX_MSG, TCA_FLOWER_KEY_CT_STATE_MASK, mask);
0ac2f3
+	return 0;
0ac2f3
+}
0ac2f3
+
0ac2f3
 static int flower_parse_ip_proto(char *str, __be16 eth_type, int type,
0ac2f3
 				 __u8 *p_ip_proto, struct nlmsghdr *n)
0ac2f3
 {
0ac2f3
@@ -1077,6 +1235,34 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
0ac2f3
 			flags |= TCA_CLS_FLAGS_SKIP_HW;
0ac2f3
 		} else if (matches(*argv, "skip_sw") == 0) {
0ac2f3
 			flags |= TCA_CLS_FLAGS_SKIP_SW;
0ac2f3
+		} else if (matches(*argv, "ct_state") == 0) {
0ac2f3
+			NEXT_ARG();
0ac2f3
+			ret = flower_parse_ct_state(*argv, n);
0ac2f3
+			if (ret < 0) {
0ac2f3
+				fprintf(stderr, "Illegal \"ct_state\"\n");
0ac2f3
+				return -1;
0ac2f3
+			}
0ac2f3
+		} else if (matches(*argv, "ct_zone") == 0) {
0ac2f3
+			NEXT_ARG();
0ac2f3
+			ret = flower_parse_ct_zone(*argv, n);
0ac2f3
+			if (ret < 0) {
0ac2f3
+				fprintf(stderr, "Illegal \"ct_zone\"\n");
0ac2f3
+				return -1;
0ac2f3
+			}
0ac2f3
+		} else if (matches(*argv, "ct_mark") == 0) {
0ac2f3
+			NEXT_ARG();
0ac2f3
+			ret = flower_parse_ct_mark(*argv, n);
0ac2f3
+			if (ret < 0) {
0ac2f3
+				fprintf(stderr, "Illegal \"ct_mark\"\n");
0ac2f3
+				return -1;
0ac2f3
+			}
0ac2f3
+		} else if (matches(*argv, "ct_label") == 0) {
0ac2f3
+			NEXT_ARG();
0ac2f3
+			ret = flower_parse_ct_labels(*argv, n);
0ac2f3
+			if (ret < 0) {
0ac2f3
+				fprintf(stderr, "Illegal \"ct_label\"\n");
0ac2f3
+				return -1;
0ac2f3
+			}
0ac2f3
 		} else if (matches(*argv, "indev") == 0) {
0ac2f3
 			NEXT_ARG();
0ac2f3
 			if (check_ifname(*argv))
0ac2f3
@@ -1783,6 +1969,85 @@ static void flower_print_tcp_flags(const char *name, struct rtattr *flags_attr,
0ac2f3
 	print_string(PRINT_ANY, name, namefrm, out);
0ac2f3
 }
0ac2f3
 
0ac2f3
+static void flower_print_ct_state(struct rtattr *flags_attr,
0ac2f3
+				  struct rtattr *mask_attr)
0ac2f3
+{
0ac2f3
+	SPRINT_BUF(out);
0ac2f3
+	uint16_t state;
0ac2f3
+	uint16_t state_mask;
0ac2f3
+	size_t done = 0;
0ac2f3
+	int i;
0ac2f3
+
0ac2f3
+	if (!flags_attr)
0ac2f3
+		return;
0ac2f3
+
0ac2f3
+	state = rta_getattr_u16(flags_attr);
0ac2f3
+	if (mask_attr)
0ac2f3
+		state_mask = rta_getattr_u16(mask_attr);
0ac2f3
+	else
0ac2f3
+		state_mask = UINT16_MAX;
0ac2f3
+
0ac2f3
+	for (i = 0; i < ARRAY_SIZE(flower_ct_states); i++) {
0ac2f3
+		if (!(state_mask & flower_ct_states[i].flag))
0ac2f3
+			continue;
0ac2f3
+
0ac2f3
+		if (state & flower_ct_states[i].flag)
0ac2f3
+			done += sprintf(out + done, "+%s",
0ac2f3
+					flower_ct_states[i].str);
0ac2f3
+		else
0ac2f3
+			done += sprintf(out + done, "-%s",
0ac2f3
+					flower_ct_states[i].str);
0ac2f3
+	}
0ac2f3
+
0ac2f3
+	print_string(PRINT_ANY, "ct_state", "\n  ct_state %s", out);
0ac2f3
+}
0ac2f3
+
0ac2f3
+static void flower_print_ct_label(struct rtattr *attr,
0ac2f3
+				  struct rtattr *mask_attr)
0ac2f3
+{
0ac2f3
+	const unsigned char *str;
0ac2f3
+	bool print_mask = false;
0ac2f3
+	int data_len, i;
0ac2f3
+	SPRINT_BUF(out);
0ac2f3
+	char *p;
0ac2f3
+
0ac2f3
+	if (!attr)
0ac2f3
+		return;
0ac2f3
+
0ac2f3
+	data_len = RTA_PAYLOAD(attr);
0ac2f3
+	hexstring_n2a(RTA_DATA(attr), data_len, out, sizeof(out));
0ac2f3
+	p = out + data_len*2;
0ac2f3
+
0ac2f3
+	data_len = RTA_PAYLOAD(attr);
0ac2f3
+	str = RTA_DATA(mask_attr);
0ac2f3
+	if (data_len != 16)
0ac2f3
+		print_mask = true;
0ac2f3
+	for (i = 0; !print_mask && i < data_len; i++) {
0ac2f3
+		if (str[i] != 0xff)
0ac2f3
+			print_mask = true;
0ac2f3
+	}
0ac2f3
+	if (print_mask) {
0ac2f3
+		*p++ = '/';
0ac2f3
+		hexstring_n2a(RTA_DATA(mask_attr), data_len, p,
0ac2f3
+			      sizeof(out)-(p-out));
0ac2f3
+		p += data_len*2;
0ac2f3
+	}
0ac2f3
+	*p = '\0';
0ac2f3
+
0ac2f3
+	print_string(PRINT_ANY, "ct_label", "\n  ct_label %s", out);
0ac2f3
+}
0ac2f3
+
0ac2f3
+static void flower_print_ct_zone(struct rtattr *attr,
0ac2f3
+				 struct rtattr *mask_attr)
0ac2f3
+{
0ac2f3
+	print_masked_u16("ct_zone", attr, mask_attr);
0ac2f3
+}
0ac2f3
+
0ac2f3
+static void flower_print_ct_mark(struct rtattr *attr,
0ac2f3
+				 struct rtattr *mask_attr)
0ac2f3
+{
0ac2f3
+	print_masked_u32("ct_mark", attr, mask_attr);
0ac2f3
+}
0ac2f3
 
0ac2f3
 static void flower_print_key_id(const char *name, struct rtattr *attr)
0ac2f3
 {
0ac2f3
@@ -2218,6 +2483,15 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
0ac2f3
 				    tb[TCA_FLOWER_KEY_FLAGS],
0ac2f3
 				    tb[TCA_FLOWER_KEY_FLAGS_MASK]);
0ac2f3
 
0ac2f3
+	flower_print_ct_state(tb[TCA_FLOWER_KEY_CT_STATE],
0ac2f3
+			      tb[TCA_FLOWER_KEY_CT_STATE_MASK]);
0ac2f3
+	flower_print_ct_zone(tb[TCA_FLOWER_KEY_CT_ZONE],
0ac2f3
+			     tb[TCA_FLOWER_KEY_CT_ZONE_MASK]);
0ac2f3
+	flower_print_ct_mark(tb[TCA_FLOWER_KEY_CT_MARK],
0ac2f3
+			     tb[TCA_FLOWER_KEY_CT_MARK_MASK]);
0ac2f3
+	flower_print_ct_label(tb[TCA_FLOWER_KEY_CT_LABELS],
0ac2f3
+			      tb[TCA_FLOWER_KEY_CT_LABELS_MASK]);
0ac2f3
+
0ac2f3
 	close_json_object();
0ac2f3
 
0ac2f3
 	if (tb[TCA_FLOWER_FLAGS]) {
0ac2f3
-- 
0ac2f3
2.26.2
0ac2f3