All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH iproute2 net-next 0/3] support for vxlan vni filtering
@ 2022-05-01  0:12 Roopa Prabhu
  2022-05-01  0:12 ` [PATCH iproute2 net-next 1/3] bridge: vxlan device vnifilter support Roopa Prabhu
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Roopa Prabhu @ 2022-05-01  0:12 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, stephen, razor

This series adds bridge command to manage
recently added vnifilter on a collect metadata
vxlan (external) device. Also includes per vni stats
support.

examples:
$bridge vni add dev vxlan0 vni 400

$bridge vni add dev vxlan0 vni 200 group 239.1.1.101

$bridge vni del dev vxlan0 vni 400

$bridge vni show

$bridge -s vni show


Nikolay Aleksandrov (1):
  bridge: vni: add support for stats dumping

Roopa Prabhu (2):
  bridge: vxlan device vnifilter support
  ip: iplink_vxlan: add support to set vnifiltering flag on vxlan device

 bridge/Makefile       |   2 +-
 bridge/br_common.h    |   2 +
 bridge/bridge.c       |   1 +
 bridge/monitor.c      |  28 ++-
 bridge/vni.c          | 439 ++++++++++++++++++++++++++++++++++++++++++
 include/libnetlink.h  |   9 +
 ip/iplink_vxlan.c     |  23 ++-
 lib/libnetlink.c      |  20 ++
 man/man8/bridge.8     |  77 +++++++-
 man/man8/ip-link.8.in |   9 +
 10 files changed, 606 insertions(+), 4 deletions(-)
 create mode 100644 bridge/vni.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH iproute2 net-next 1/3] bridge: vxlan device vnifilter support
  2022-05-01  0:12 [PATCH iproute2 net-next 0/3] support for vxlan vni filtering Roopa Prabhu
@ 2022-05-01  0:12 ` Roopa Prabhu
  2022-05-01  0:12 ` [PATCH iproute2 net-next 2/3] ip: iplink_vxlan: add support to set vnifiltering flag on vxlan device Roopa Prabhu
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Roopa Prabhu @ 2022-05-01  0:12 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, stephen, razor

This patch adds bridge command to manage
recently added vnifilter on a collect metadata
vxlan device.

examples:
$bridge vni add dev vxlan0 vni 400

$bridge vni add dev vxlan0 vni 200 group 239.1.1.101

$bridge vni del dev vxlan0 vni 400

$bridge vni show

$bridge -s vni show

Signed-off-by: Roopa Prabhu <roopa@nvidia.com>
---
 bridge/Makefile      |   2 +-
 bridge/br_common.h   |   2 +
 bridge/bridge.c      |   1 +
 bridge/monitor.c     |  28 +++-
 bridge/vni.c         | 380 +++++++++++++++++++++++++++++++++++++++++++
 include/libnetlink.h |   8 +
 lib/libnetlink.c     |  18 ++
 man/man8/bridge.8    |  77 ++++++++-
 8 files changed, 513 insertions(+), 3 deletions(-)
 create mode 100644 bridge/vni.c

diff --git a/bridge/Makefile b/bridge/Makefile
index c6b7d08d..01f8a455 100644
--- a/bridge/Makefile
+++ b/bridge/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-BROBJ = bridge.o fdb.o monitor.o link.o mdb.o vlan.o
+BROBJ = bridge.o fdb.o monitor.o link.o mdb.o vlan.o vni.o
 
 include ../config.mk
 
diff --git a/bridge/br_common.h b/bridge/br_common.h
index 610e83f6..841f0594 100644
--- a/bridge/br_common.h
+++ b/bridge/br_common.h
@@ -14,6 +14,7 @@ void print_stp_state(__u8 state);
 int parse_stp_state(const char *arg);
 int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor,
 		   bool global_only);
+int print_vnifilter_rtm(struct nlmsghdr *n, void *arg, bool monitor);
 void br_print_router_port_stats(struct rtattr *pattr);
 
 int do_fdb(int argc, char **argv);
@@ -21,6 +22,7 @@ int do_mdb(int argc, char **argv);
 int do_monitor(int argc, char **argv);
 int do_vlan(int argc, char **argv);
 int do_link(int argc, char **argv);
+int do_vni(int argc, char **argv);
 
 extern int preferred_family;
 extern int show_stats;
diff --git a/bridge/bridge.c b/bridge/bridge.c
index f3a4f08f..704be50c 100644
--- a/bridge/bridge.c
+++ b/bridge/bridge.c
@@ -58,6 +58,7 @@ static const struct cmd {
 	{ "fdb",	do_fdb },
 	{ "mdb",	do_mdb },
 	{ "vlan",	do_vlan },
+	{ "vni",	do_vni },
 	{ "monitor",	do_monitor },
 	{ "help",	do_help },
 	{ 0 }
diff --git a/bridge/monitor.c b/bridge/monitor.c
index 845e221a..2784e93e 100644
--- a/bridge/monitor.c
+++ b/bridge/monitor.c
@@ -31,10 +31,20 @@ static int prefix_banner;
 
 static void usage(void)
 {
-	fprintf(stderr, "Usage: bridge monitor [file | link | fdb | mdb | vlan | all]\n");
+	fprintf(stderr, "Usage: bridge monitor [file | link | fdb | mdb | vlan | vni | all]\n");
 	exit(-1);
 }
 
+static int print_tunnel_rtm(struct nlmsghdr *n, void *arg, bool monitor)
+{
+	struct tunnel_msg *tmsg = NLMSG_DATA(n);
+
+	if (tmsg->family == PF_BRIDGE)
+		return print_vnifilter_rtm(n, arg, monitor);
+
+	return 0;
+}
+
 static int accept_msg(struct rtnl_ctrl_data *ctrl,
 		      struct nlmsghdr *n, void *arg)
 {
@@ -73,6 +83,12 @@ static int accept_msg(struct rtnl_ctrl_data *ctrl,
 			fprintf(fp, "[VLAN]");
 		return print_vlan_rtm(n, arg, true, false);
 
+	case RTM_NEWTUNNEL:
+	case RTM_DELTUNNEL:
+		if (prefix_banner)
+			fprintf(fp, "[TUNNEL]");
+		return print_tunnel_rtm(n, arg, true);
+
 	default:
 		return 0;
 	}
@@ -86,6 +102,7 @@ int do_monitor(int argc, char **argv)
 	int lneigh = 0;
 	int lmdb = 0;
 	int lvlan = 0;
+	int lvni = 0;
 
 	rtnl_close(&rth);
 
@@ -105,9 +122,13 @@ int do_monitor(int argc, char **argv)
 		} else if (matches(*argv, "vlan") == 0) {
 			lvlan = 1;
 			groups = 0;
+		} else if (matches(*argv, "vni") == 0) {
+			lvni = 1;
+			groups = 0;
 		} else if (strcmp(*argv, "all") == 0) {
 			groups = ~RTMGRP_TC;
 			lvlan = 1;
+			lvni = 1;
 			prefix_banner = 1;
 		} else if (matches(*argv, "help") == 0) {
 			usage();
@@ -151,6 +172,11 @@ int do_monitor(int argc, char **argv)
 		exit(1);
 	}
 
+	if (lvni && rtnl_add_nl_group(&rth, RTNLGRP_TUNNEL) < 0) {
+		fprintf(stderr, "Failed to add bridge vni group to list\n");
+		exit(1);
+	}
+
 	ll_init_map(&rth);
 
 	if (rtnl_listen(&rth, accept_msg, stdout) < 0)
diff --git a/bridge/vni.c b/bridge/vni.c
new file mode 100644
index 00000000..65939b34
--- /dev/null
+++ b/bridge/vni.c
@@ -0,0 +1,380 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Command to manage vnifiltering on a vxlan device
+ *
+ * Authors:     Roopa Prabhu <roopa@nvidia.com>
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <linux/if_link.h>
+#include <linux/if_bridge.h>
+#include <linux/if_ether.h>
+
+#include "json_print.h"
+#include "libnetlink.h"
+#include "br_common.h"
+#include "utils.h"
+
+static unsigned int filter_index;
+
+#define VXLAN_ID_LEN 15
+
+#define __stringify_1(x...) #x
+#define __stringify(x...) __stringify_1(x)
+
+static void usage(void)
+{
+	fprintf(stderr,
+		"Usage: bridge vni { add | del } vni VNI\n"
+		"		[ { group | remote } IP_ADDRESS ]\n"
+	        "		[ dev DEV ]\n"
+		"       bridge vni { show }\n"
+		"\n"
+		"Where:	VNI	:= 0-16777215\n"
+	       );
+	exit(-1);
+}
+
+static int parse_vni_filter(const char *argv, struct nlmsghdr *n, int reqsize,
+			    inet_prefix *group)
+{
+	char *vnilist = strdupa(argv);
+	char *vni = strtok(vnilist, ",");
+	int group_type = AF_UNSPEC;
+	struct rtattr *nlvlist_e;
+	char *v;
+	int i;
+
+	if (group && is_addrtype_inet(group))
+		group_type = (group->family == AF_INET) ?  VXLAN_VNIFILTER_ENTRY_GROUP :
+						     VXLAN_VNIFILTER_ENTRY_GROUP6;
+
+	for (i = 0; vni; i++) {
+		__u32 vni_start = 0, vni_end = 0;
+
+		v = strchr(vni, '-');
+		if (v) {
+			*v = '\0';
+			v++;
+			vni_start = atoi(vni);
+			vni_end = atoi(v);
+		} else {
+			vni_start = atoi(vni);
+		}
+		nlvlist_e = addattr_nest(n, reqsize, VXLAN_VNIFILTER_ENTRY |
+					 NLA_F_NESTED);
+		addattr32(n, 1024, VXLAN_VNIFILTER_ENTRY_START, vni_start);
+		if (vni_end)
+			addattr32(n, 1024, VXLAN_VNIFILTER_ENTRY_END, vni_end);
+		if (group)
+			addattr_l(n, 1024, group_type, group->data, group->bytelen);
+		addattr_nest_end(n, nlvlist_e);
+		vni = strtok(NULL, ",");
+	}
+
+	return 0;
+}
+
+static int vni_modify(int cmd, int argc, char **argv)
+{
+	struct {
+		struct nlmsghdr	n;
+		struct tunnel_msg	tmsg;
+		char			buf[1024];
+	} req = {
+		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tunnel_msg)),
+		.n.nlmsg_flags = NLM_F_REQUEST,
+		.n.nlmsg_type = cmd,
+		.tmsg.family = PF_BRIDGE,
+	};
+	bool group_present = false;
+	inet_prefix daddr;
+	char *vni = NULL;
+	char *d = NULL;
+
+	while (argc > 0) {
+		if (strcmp(*argv, "dev") == 0) {
+			NEXT_ARG();
+			d = *argv;
+		} else if (strcmp(*argv, "vni") == 0) {
+			NEXT_ARG();
+			if (vni)
+				invarg("duplicate vni", *argv);
+			vni = *argv;
+		} else if (!matches(*argv, "group")) {
+			if (group_present)
+				invarg("duplicate group", *argv);
+			if (is_addrtype_inet_not_multi(&daddr)) {
+				fprintf(stderr, "vxlan: both group and remote");
+				fprintf(stderr, " cannot be specified\n");
+				return -1;
+			}
+			NEXT_ARG();
+			get_addr(&daddr, *argv, AF_UNSPEC);
+			if (!is_addrtype_inet_multi(&daddr))
+				invarg("invalid group address", *argv);
+			group_present = true;
+		} else if (!matches(*argv, "remote")) {
+			if (group_present)
+				invarg("duplicate group", *argv);
+			NEXT_ARG();
+			get_addr(&daddr, *argv, AF_UNSPEC);
+			group_present = true;
+		} else {
+			if (matches(*argv, "help") == 0)
+				NEXT_ARG();
+		}
+		argc--; argv++;
+	}
+
+	if (d == NULL || vni == NULL) {
+		fprintf(stderr, "Device and VNI ID are required arguments.\n");
+		return -1;
+	}
+
+	if (!vni && group_present) {
+		fprintf(stderr, "Group can only be specified with a vni\n");
+		return -1;
+	}
+
+	if (vni)
+		parse_vni_filter(vni, &req.n, sizeof(req),
+				 (group_present ? &daddr : NULL));
+
+	req.tmsg.ifindex = ll_name_to_index(d);
+	if (req.tmsg.ifindex == 0) {
+		fprintf(stderr, "Cannot find vxlan device \"%s\"\n", d);
+		return -1;
+	}
+
+	if (rtnl_talk(&rth, &req.n, NULL) < 0)
+		return -1;
+
+	return 0;
+}
+
+static void open_vni_port(int ifi_index, const char *fmt)
+{
+	open_json_object(NULL);
+	print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname",
+			   "%-" __stringify(IFNAMSIZ) "s  ",
+			   ll_index_to_name(ifi_index));
+	open_json_array(PRINT_JSON, "vnis");
+}
+
+static void close_vni_port(void)
+{
+	close_json_array(PRINT_JSON, NULL);
+	close_json_object();
+}
+
+static void print_range(const char *name, __u32 start, __u32 id)
+{
+	char end[64];
+
+	snprintf(end, sizeof(end), "%sEnd", name);
+
+	print_uint(PRINT_ANY, name, " %u", start);
+	if (start != id)
+		print_uint(PRINT_ANY, end, "-%-14u ", id);
+
+}
+
+static void print_vni(struct rtattr *t, int ifindex)
+{
+	struct rtattr *ttb[VXLAN_VNIFILTER_ENTRY_MAX+1];
+	__u32 vni_start = 0;
+	__u32 vni_end = 0;
+
+	parse_rtattr_flags(ttb, VXLAN_VNIFILTER_ENTRY_MAX, RTA_DATA(t),
+			   RTA_PAYLOAD(t), NLA_F_NESTED);
+
+	if (ttb[VXLAN_VNIFILTER_ENTRY_START])
+		vni_start = rta_getattr_u32(ttb[VXLAN_VNIFILTER_ENTRY_START]);
+
+	if (ttb[VXLAN_VNIFILTER_ENTRY_END])
+		vni_end = rta_getattr_u32(ttb[VXLAN_VNIFILTER_ENTRY_END]);
+
+	if (vni_end)
+		print_range("vni", vni_start, vni_end);
+	else
+		print_uint(PRINT_ANY, "vni", " %-14u", vni_start);
+
+	if (ttb[VXLAN_VNIFILTER_ENTRY_GROUP]) {
+		__be32 addr = rta_getattr_u32(ttb[VXLAN_VNIFILTER_ENTRY_GROUP]);
+
+		if (addr) {
+			if (IN_MULTICAST(ntohl(addr)))
+				print_string(PRINT_ANY,
+					     "group",
+					     " %s",
+					     format_host(AF_INET, 4, &addr));
+			else
+				print_string(PRINT_ANY,
+					     "remote",
+					     " %s",
+					     format_host(AF_INET, 4, &addr));
+		}
+	} else if (ttb[VXLAN_VNIFILTER_ENTRY_GROUP6]) {
+		struct in6_addr addr;
+
+		memcpy(&addr, RTA_DATA(ttb[VXLAN_VNIFILTER_ENTRY_GROUP6]), sizeof(struct in6_addr));
+		if (!IN6_IS_ADDR_UNSPECIFIED(&addr)) {
+			if (IN6_IS_ADDR_MULTICAST(&addr))
+				print_string(PRINT_ANY,
+					     "group",
+					     " %s",
+					     format_host(AF_INET6,
+							 sizeof(struct in6_addr),
+							 &addr));
+			else
+				print_string(PRINT_ANY,
+					     "remote",
+					     " %s",
+					     format_host(AF_INET6,
+							 sizeof(struct in6_addr),
+							 &addr));
+		}
+	}
+	close_json_object();
+	print_string(PRINT_FP, NULL, "%s", _SL_);
+}
+
+int print_vnifilter_rtm(struct nlmsghdr *n, void *arg, bool monitor)
+{
+	struct tunnel_msg *tmsg = NLMSG_DATA(n);
+	int len = n->nlmsg_len;
+	bool first = true;
+	struct rtattr *t;
+	int rem;
+
+	if (n->nlmsg_type != RTM_NEWTUNNEL &&
+	    n->nlmsg_type != RTM_DELTUNNEL &&
+	    n->nlmsg_type != RTM_GETTUNNEL) {
+		fprintf(stderr, "Unknown vni tunnel rtm msg: %08x %08x %08x\n",
+			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+		return 0;
+	}
+
+	len -= NLMSG_LENGTH(sizeof(*tmsg));
+	if (len < 0) {
+		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+		return -1;
+	}
+
+	if (tmsg->family != AF_BRIDGE)
+		return 0;
+
+	if (filter_index && filter_index != tmsg->ifindex)
+		return 0;
+
+	if (n->nlmsg_type == RTM_DELTUNNEL)
+		print_bool(PRINT_ANY, "deleted", "Deleted ", true);
+
+	rem = len;
+	for (t = TUNNEL_RTA(tmsg); RTA_OK(t, rem); t = RTA_NEXT(t, rem)) {
+		unsigned short rta_type = t->rta_type & NLA_TYPE_MASK;
+
+		if (rta_type != VXLAN_VNIFILTER_ENTRY)
+			continue;
+		if (first) {
+			open_vni_port(tmsg->ifindex, "%s");
+			open_json_object(NULL);
+			first = false;
+		} else {
+			open_json_object(NULL);
+			print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s  ", "");
+		}
+
+		print_vni(t, tmsg->ifindex);
+	}
+	close_vni_port();
+
+	print_string(PRINT_FP, NULL, "%s", _SL_);
+
+	fflush(stdout);
+	return 0;
+}
+
+static int print_vnifilter_rtm_filter(struct nlmsghdr *n, void *arg)
+{
+	return print_vnifilter_rtm(n, arg, false);
+}
+
+static int vni_show(int argc, char **argv)
+{
+	char *filter_dev = NULL;
+	int ret = 0;
+
+	while (argc > 0) {
+		if (strcmp(*argv, "dev") == 0) {
+			NEXT_ARG();
+			if (filter_dev)
+				duparg("dev", *argv);
+			filter_dev = *argv;
+		}
+		argc--; argv++;
+	}
+
+	if (filter_dev) {
+		filter_index = ll_name_to_index(filter_dev);
+		if (!filter_index)
+			return nodev(filter_dev);
+	}
+
+	new_json_obj(json);
+
+	if (!show_stats) {
+		if (rtnl_tunneldump_req(&rth, PF_BRIDGE, filter_index) < 0) {
+			perror("Cannot send dump request");
+			exit(1);
+		}
+
+		if (!is_json_context()) {
+			printf("%-" __stringify(IFNAMSIZ) "s  %-"
+			       __stringify(VXLAN_ID_LEN) "s  %-"
+			       __stringify(15) "s",
+			       "dev", "vni", "group/remote");
+			printf("\n");
+		}
+
+		ret = rtnl_dump_filter(&rth, print_vnifilter_rtm_filter, NULL);
+		if (ret < 0) {
+			fprintf(stderr, "Dump ternminated\n");
+			exit(1);
+		}
+	}
+
+	delete_json_obj();
+	fflush(stdout);
+	return 0;
+}
+
+int do_vni(int argc, char **argv)
+{
+	ll_init_map(&rth);
+
+	if (argc > 0) {
+		if (matches(*argv, "add") == 0)
+			return vni_modify(RTM_NEWTUNNEL, argc-1, argv+1);
+		if (matches(*argv, "delete") == 0)
+			return vni_modify(RTM_DELTUNNEL, argc-1, argv+1);
+		if (matches(*argv, "show") == 0 ||
+		    matches(*argv, "lst") == 0 ||
+		    matches(*argv, "list") == 0)
+			return vni_show(argc-1, argv+1);
+		if (matches(*argv, "help") == 0)
+			usage();
+	} else {
+		return vni_show(0, NULL);
+	}
+
+	fprintf(stderr, "Command \"%s\" is unknown, try \"bridge vni help\".\n", *argv);
+	exit(-1);
+}
diff --git a/include/libnetlink.h b/include/libnetlink.h
index 372c3706..a1ec91ec 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -112,6 +112,9 @@ int rtnl_nexthop_bucket_dump_req(struct rtnl_handle *rth, int family,
 				 req_filter_fn_t filter_fn)
 	__attribute__((warn_unused_result));
 
+int rtnl_tunneldump_req(struct rtnl_handle *rth, int family, int ifindex)
+	__attribute__((warn_unused_result));
+
 struct rtnl_ctrl_data {
 	int	nsid;
 };
@@ -331,6 +334,11 @@ int rtnl_from_file(FILE *, rtnl_listen_filter_t handler,
 	((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct br_vlan_msg))))
 #endif
 
+#ifndef TUNNEL_RTA
+#define TUNNEL_RTA(r) \
+	((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct tunnel_msg))))
+#endif
+
 /* User defined nlmsg_type which is used mostly for logging netlink
  * messages from dump file */
 #define NLMSG_TSTAMP	15
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index 4d33e4dd..b3c3d0ba 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -1609,3 +1609,21 @@ void nl_print_policy(const struct rtattr *attr, FILE *fp)
 		}
 	}
 }
+
+int rtnl_tunneldump_req(struct rtnl_handle *rth, int family, int ifindex)
+{
+	struct {
+		struct nlmsghdr nlh;
+		struct tunnel_msg tmsg;
+		char buf[256];
+	} req = {
+		.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tunnel_msg)),
+		.nlh.nlmsg_type = RTM_GETTUNNEL,
+		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
+		.nlh.nlmsg_seq = rth->dump = ++rth->seq,
+		.tmsg.family = family,
+		.tmsg.ifindex = ifindex,
+	};
+
+	return send(rth->fd, &req, sizeof(req), 0);
+}
diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
index 2fa4f3d6..d8923d2e 100644
--- a/man/man8/bridge.8
+++ b/man/man8/bridge.8
@@ -13,7 +13,7 @@ bridge \- show / manipulate bridge addresses and devices
 
 .ti -8
 .IR OBJECT " := { "
-.BR link " | " fdb " | " mdb " | " vlan " | " monitor " }"
+.BR link " | " fdb " | " mdb " | " vlan " | " vni " | " monitor " }"
 .sp
 
 .ti -8
@@ -196,6 +196,25 @@ bridge \- show / manipulate bridge addresses and devices
 .B vid
 .IR VID " ]"
 
+.ti -8
+.BR "bridge vlan" " show " [ "
+.B dev
+.IR DEV " ]"
+
+.ti -8
+.BR "bridge vni" " { " add " | " del " } "
+.B dev
+.I DEV
+.B vni
+.IR VNI " [ { "
+.B group | remote "} "
+.IR IPADDR " ] "
+
+.ti -8
+.BR "bridge vni" " show " [ "
+.B dev
+.IR DEV " ]"
+
 .ti -8
 .BR "bridge monitor" " [ " all " | " neigh " | " link " | " mdb " | " vlan " ]"
 
@@ -303,6 +322,10 @@ the output.
 .B vlan
 - VLAN filter list.
 
+.TP
+.B vni
+- VNI filter list.
+
 .SS
 .I COMMAND
 
@@ -1084,6 +1107,58 @@ all bridge interfaces.
 the VLAN ID only whose global options should be listed. Default is to list
 all vlans.
 
+.SH bridge vni - VNI filter list
+
+.B vni
+objects contain known VNI IDs for a dst metadata vxlan link.
+
+.P
+The corresponding commands display vni filter entries, add new entries,
+and delete old ones.
+
+.SS bridge vni add - add a new vni filter entry
+
+This command creates a new vni filter entry.
+
+.TP
+.BI dev " NAME"
+the interface with which this vni is associated.
+
+.TP
+.BI vni " VNI"
+the VNI ID that identifies the vni.
+
+.TP
+.BI remote " IPADDR"
+specifies the unicast destination IP address to use in outgoing packets
+when the destination link layer address is not known in the VXLAN device
+forwarding database. This parameter cannot be specified with the group.
+
+.TP
+.BI group " IPADDR"
+specifies the multicast IP address to join for this VNI
+
+.SS bridge vni del - delete a new vni filter entry
+
+This command removes an existing vni filter entry.
+
+.PP
+The arguments are the same as with
+.BR "bridge vni add".
+
+.SS bridge vni show - list vni filtering configuration.
+
+This command displays the current vni filter table.
+
+.PP
+With the
+.B -statistics
+option, the command displays per-vni traffic statistics.
+
+.TP
+.BI dev " NAME"
+shows vni filtering table associated with the vxlan device
+
 .SH bridge monitor - state monitoring
 
 The
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH iproute2 net-next 2/3] ip: iplink_vxlan: add support to set vnifiltering flag on vxlan device
  2022-05-01  0:12 [PATCH iproute2 net-next 0/3] support for vxlan vni filtering Roopa Prabhu
  2022-05-01  0:12 ` [PATCH iproute2 net-next 1/3] bridge: vxlan device vnifilter support Roopa Prabhu
@ 2022-05-01  0:12 ` Roopa Prabhu
  2022-05-01  0:12 ` [PATCH iproute2 net-next 3/3] bridge: vni: add support for stats dumping Roopa Prabhu
  2022-05-06  3:26 ` [PATCH iproute2 net-next 0/3] support for vxlan vni filtering David Ahern
  3 siblings, 0 replies; 6+ messages in thread
From: Roopa Prabhu @ 2022-05-01  0:12 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, stephen, razor

This patch adds option to set vnifilter flag on a vxlan device. vnifilter is
only supported on a collect metadata device.

example: set vnifilter flag
$ ip link add vxlan0 type vxlan external vnifilter local 172.16.0.1

Signed-off-by: Roopa Prabhu <roopa@nvidia.com>
---
 ip/iplink_vxlan.c     | 23 ++++++++++++++++++++++-
 man/man8/ip-link.8.in |  9 +++++++++
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c
index 9afa3cca..3dde2150 100644
--- a/ip/iplink_vxlan.c
+++ b/ip/iplink_vxlan.c
@@ -48,6 +48,7 @@ static void print_explain(FILE *f)
 		"		[ [no]udp6zerocsumrx ]\n"
 		"		[ [no]remcsumtx ] [ [no]remcsumrx ]\n"
 		"		[ [no]external ] [ gbp ] [ gpe ]\n"
+		"		[ [no]vnifilter ]\n"
 		"\n"
 		"Where:	VNI	:= 0-16777215\n"
 		"	ADDR	:= { IP_ADDRESS | any }\n"
@@ -81,6 +82,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
 	__u8 learning = 1;
 	__u16 dstport = 0;
 	__u8 metadata = 0;
+	__u8 vnifilter = 0;
 	__u64 attrs = 0;
 	bool set_op = (n->nlmsg_type == RTM_NEWLINK &&
 		       !(n->nlmsg_flags & NLM_F_CREATE));
@@ -330,6 +332,15 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
 		} else if (!matches(*argv, "gpe")) {
 			check_duparg(&attrs, IFLA_VXLAN_GPE, *argv, *argv);
 			addattr_l(n, 1024, IFLA_VXLAN_GPE, NULL, 0);
+		} else if (!matches(*argv, "vnifilter")) {
+			check_duparg(&attrs, IFLA_VXLAN_VNIFILTER,
+				     *argv, *argv);
+			addattr8(n, 1024, IFLA_VXLAN_VNIFILTER, 1);
+			vnifilter = 1;
+		} else if (!matches(*argv, "novnifilter")) {
+			check_duparg(&attrs, IFLA_VXLAN_VNIFILTER,
+				     *argv, *argv);
+			addattr8(n, 1024, IFLA_VXLAN_VNIFILTER, 0);
 		} else if (matches(*argv, "help") == 0) {
 			explain();
 			return -1;
@@ -341,12 +352,17 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
 		argc--, argv++;
 	}
 
+	if (!metadata && vnifilter) {
+		fprintf(stderr, "vxlan: vnifilter is valid only when 'external' is set\n");
+		return -1;
+	}
+
 	if (metadata && VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID)) {
 		fprintf(stderr, "vxlan: both 'external' and vni cannot be specified\n");
 		return -1;
 	}
 
-	if (!metadata && !VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID) && !set_op) {
+	if (!metadata && !vnifilter && !VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID) && !set_op) {
 		fprintf(stderr, "vxlan: missing virtual network identifier\n");
 		return -1;
 	}
@@ -420,6 +436,11 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 		print_bool(PRINT_ANY, "external", "external ", true);
 	}
 
+	if (tb[IFLA_VXLAN_VNIFILTER] &&
+	    rta_getattr_u8(tb[IFLA_VXLAN_VNIFILTER])) {
+		print_bool(PRINT_ANY, "vnifilter", "vnifilter", true);
+	}
+
 	if (tb[IFLA_VXLAN_ID] &&
 	    RTA_PAYLOAD(tb[IFLA_VXLAN_ID]) >= sizeof(__u32)) {
 		print_uint(PRINT_ANY, "id", "id %u ", rta_getattr_u32(tb[IFLA_VXLAN_ID]));
diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
index fc214a10..6f332645 100644
--- a/man/man8/ip-link.8.in
+++ b/man/man8/ip-link.8.in
@@ -601,6 +601,8 @@ the following additional arguments are supported:
 .B gbp
 ] [
 .B gpe
+] [
+.RB [ no ] vnifilter
 ]
 
 .in +8
@@ -712,6 +714,13 @@ are entered into the VXLAN device forwarding database.
 .RB "(e.g. " "ip route encap" )
 or the internal FDB should be used.
 
+.sp
+.RB [ no ] vnifilter
+- specifies whether the vxlan device is capable of vni filtering. Only works with a vxlan
+device with external flag set. once enabled, bridge vni command is used to manage the
+vni filtering table on the device. The device can only receive packets with vni's configured
+in the vni filtering table.
+
 .sp
 .B gbp
 - enables the Group Policy extension (VXLAN-GBP).
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH iproute2 net-next 3/3] bridge: vni: add support for stats dumping
  2022-05-01  0:12 [PATCH iproute2 net-next 0/3] support for vxlan vni filtering Roopa Prabhu
  2022-05-01  0:12 ` [PATCH iproute2 net-next 1/3] bridge: vxlan device vnifilter support Roopa Prabhu
  2022-05-01  0:12 ` [PATCH iproute2 net-next 2/3] ip: iplink_vxlan: add support to set vnifiltering flag on vxlan device Roopa Prabhu
@ 2022-05-01  0:12 ` Roopa Prabhu
  2022-05-06  3:26 ` [PATCH iproute2 net-next 0/3] support for vxlan vni filtering David Ahern
  3 siblings, 0 replies; 6+ messages in thread
From: Roopa Prabhu @ 2022-05-01  0:12 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, stephen, razor

From: Nikolay Aleksandrov <nikolay@nvidia.com>

Add support for "-s" option which causes bridge vni to dump per-vni
statistics. Note that it disables vni range compression.

Example:
$ bridge -s vni | more
 dev               vni              group/remote
 vxlan0             1024  239.1.1.1
                     RX: bytes 0 pkts 0 drops 0 errors 0
                     TX: bytes 0 pkts 0 drops 0 errors 0
                    1025  239.1.1.1
                     RX: bytes 0 pkts 0 drops 0 errors 0
                     TX: bytes 0 pkts 0 drops 0 errors 0

Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
Signed-off-by: Roopa Prabhu <roopa@nvidia.com>
---
 bridge/vni.c         | 93 ++++++++++++++++++++++++++++++++++++--------
 include/libnetlink.h |  3 +-
 lib/libnetlink.c     |  4 +-
 3 files changed, 81 insertions(+), 19 deletions(-)

diff --git a/bridge/vni.c b/bridge/vni.c
index 65939b34..28485f8e 100644
--- a/bridge/vni.c
+++ b/bridge/vni.c
@@ -186,6 +186,59 @@ static void print_range(const char *name, __u32 start, __u32 id)
 
 }
 
+static void print_vnifilter_entry_stats(struct rtattr *stats_attr)
+{
+	struct rtattr *stb[VNIFILTER_ENTRY_STATS_MAX+1];
+	__u64 stat;
+
+	open_json_object("stats");
+	parse_rtattr_flags(stb, VNIFILTER_ENTRY_STATS_MAX, RTA_DATA(stats_attr),
+			   RTA_PAYLOAD(stats_attr), NLA_F_NESTED);
+
+	print_nl();
+	print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s   ", "");
+	print_string(PRINT_FP, NULL, "RX: ", "");
+
+	if (stb[VNIFILTER_ENTRY_STATS_RX_BYTES]) {
+		stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_RX_BYTES]);
+		print_lluint(PRINT_ANY, "rx_bytes", "bytes %llu ", stat);
+	}
+	if (stb[VNIFILTER_ENTRY_STATS_RX_PKTS]) {
+		stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_RX_PKTS]);
+		print_lluint(PRINT_ANY, "rx_pkts", "pkts %llu ", stat);
+	}
+	if (stb[VNIFILTER_ENTRY_STATS_RX_DROPS]) {
+		stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_RX_DROPS]);
+		print_lluint(PRINT_ANY, "rx_drops", "drops %llu ", stat);
+	}
+	if (stb[VNIFILTER_ENTRY_STATS_RX_ERRORS]) {
+		stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_RX_ERRORS]);
+		print_lluint(PRINT_ANY, "rx_errors", "errors %llu ", stat);
+	}
+
+	print_nl();
+	print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s   ", "");
+	print_string(PRINT_FP, NULL, "TX: ", "");
+
+	if (stb[VNIFILTER_ENTRY_STATS_TX_BYTES]) {
+		stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_TX_BYTES]);
+		print_lluint(PRINT_ANY, "tx_bytes", "bytes %llu ", stat);
+	}
+	if (stb[VNIFILTER_ENTRY_STATS_TX_PKTS]) {
+		stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_TX_PKTS]);
+		print_lluint(PRINT_ANY, "tx_pkts", "pkts %llu ", stat);
+	}
+	if (stb[VNIFILTER_ENTRY_STATS_TX_DROPS]) {
+		stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_TX_DROPS]);
+		print_lluint(PRINT_ANY, "tx_drops", "drops %llu ", stat);
+	}
+	if (stb[VNIFILTER_ENTRY_STATS_TX_ERRORS]) {
+		stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_TX_ERRORS]);
+		print_lluint(PRINT_ANY, "tx_errors", "errors %llu ", stat);
+	}
+	close_json_object();
+}
+
 static void print_vni(struct rtattr *t, int ifindex)
 {
 	struct rtattr *ttb[VXLAN_VNIFILTER_ENTRY_MAX+1];
@@ -242,6 +295,10 @@ static void print_vni(struct rtattr *t, int ifindex)
 							 &addr));
 		}
 	}
+
+	if (ttb[VXLAN_VNIFILTER_ENTRY_STATS])
+		print_vnifilter_entry_stats(ttb[VXLAN_VNIFILTER_ENTRY_STATS]);
+
 	close_json_object();
 	print_string(PRINT_FP, NULL, "%s", _SL_);
 }
@@ -310,6 +367,7 @@ static int print_vnifilter_rtm_filter(struct nlmsghdr *n, void *arg)
 static int vni_show(int argc, char **argv)
 {
 	char *filter_dev = NULL;
+	__u8 flags = 0;
 	int ret = 0;
 
 	while (argc > 0) {
@@ -330,25 +388,26 @@ static int vni_show(int argc, char **argv)
 
 	new_json_obj(json);
 
-	if (!show_stats) {
-		if (rtnl_tunneldump_req(&rth, PF_BRIDGE, filter_index) < 0) {
-			perror("Cannot send dump request");
-			exit(1);
-		}
+	if (show_stats)
+		flags = TUNNEL_MSG_FLAG_STATS;
 
-		if (!is_json_context()) {
-			printf("%-" __stringify(IFNAMSIZ) "s  %-"
-			       __stringify(VXLAN_ID_LEN) "s  %-"
-			       __stringify(15) "s",
-			       "dev", "vni", "group/remote");
-			printf("\n");
-		}
+	if (rtnl_tunneldump_req(&rth, PF_BRIDGE, filter_index, flags) < 0) {
+		perror("Cannot send dump request");
+		exit(1);
+	}
 
-		ret = rtnl_dump_filter(&rth, print_vnifilter_rtm_filter, NULL);
-		if (ret < 0) {
-			fprintf(stderr, "Dump ternminated\n");
-			exit(1);
-		}
+	if (!is_json_context()) {
+		printf("%-" __stringify(IFNAMSIZ) "s  %-"
+		       __stringify(VXLAN_ID_LEN) "s  %-"
+		       __stringify(15) "s",
+		       "dev", "vni", "group/remote");
+		printf("\n");
+	}
+
+	ret = rtnl_dump_filter(&rth, print_vnifilter_rtm_filter, NULL);
+	if (ret < 0) {
+		fprintf(stderr, "Dump ternminated\n");
+		exit(1);
 	}
 
 	delete_json_obj();
diff --git a/include/libnetlink.h b/include/libnetlink.h
index a1ec91ec..a7b0f352 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -112,7 +112,8 @@ int rtnl_nexthop_bucket_dump_req(struct rtnl_handle *rth, int family,
 				 req_filter_fn_t filter_fn)
 	__attribute__((warn_unused_result));
 
-int rtnl_tunneldump_req(struct rtnl_handle *rth, int family, int ifindex)
+int rtnl_tunneldump_req(struct rtnl_handle *rth, int family, int ifindex,
+			__u8 flags)
 	__attribute__((warn_unused_result));
 
 struct rtnl_ctrl_data {
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index b3c3d0ba..c27627fe 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -1610,7 +1610,8 @@ void nl_print_policy(const struct rtattr *attr, FILE *fp)
 	}
 }
 
-int rtnl_tunneldump_req(struct rtnl_handle *rth, int family, int ifindex)
+int rtnl_tunneldump_req(struct rtnl_handle *rth, int family, int ifindex,
+			__u8 flags)
 {
 	struct {
 		struct nlmsghdr nlh;
@@ -1622,6 +1623,7 @@ int rtnl_tunneldump_req(struct rtnl_handle *rth, int family, int ifindex)
 		.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
 		.nlh.nlmsg_seq = rth->dump = ++rth->seq,
 		.tmsg.family = family,
+		.tmsg.flags = flags,
 		.tmsg.ifindex = ifindex,
 	};
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH iproute2 net-next 0/3] support for vxlan vni filtering
  2022-05-01  0:12 [PATCH iproute2 net-next 0/3] support for vxlan vni filtering Roopa Prabhu
                   ` (2 preceding siblings ...)
  2022-05-01  0:12 ` [PATCH iproute2 net-next 3/3] bridge: vni: add support for stats dumping Roopa Prabhu
@ 2022-05-06  3:26 ` David Ahern
  2022-05-08  3:45   ` Roopa Prabhu
  3 siblings, 1 reply; 6+ messages in thread
From: David Ahern @ 2022-05-06  3:26 UTC (permalink / raw)
  To: Roopa Prabhu; +Cc: netdev, stephen, razor

On 4/30/22 5:12 PM, Roopa Prabhu wrote:
> This series adds bridge command to manage
> recently added vnifilter on a collect metadata
> vxlan (external) device. Also includes per vni stats
> support.
> 
> examples:
> $bridge vni add dev vxlan0 vni 400
> 
> $bridge vni add dev vxlan0 vni 200 group 239.1.1.101
> 
> $bridge vni del dev vxlan0 vni 400
> 
> $bridge vni show
> 
> $bridge -s vni show
> 
> 

hey Roopa: sorry for the delay; traveling. The patches have a number of
new uses of matches(). We are not taking any more of those; please
convert to strcmp. The rest looks fine to me.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH iproute2 net-next 0/3] support for vxlan vni filtering
  2022-05-06  3:26 ` [PATCH iproute2 net-next 0/3] support for vxlan vni filtering David Ahern
@ 2022-05-08  3:45   ` Roopa Prabhu
  0 siblings, 0 replies; 6+ messages in thread
From: Roopa Prabhu @ 2022-05-08  3:45 UTC (permalink / raw)
  To: David Ahern; +Cc: netdev, stephen, razor


On 5/5/22 20:26, David Ahern wrote:
> On 4/30/22 5:12 PM, Roopa Prabhu wrote:
>> This series adds bridge command to manage
>> recently added vnifilter on a collect metadata
>> vxlan (external) device. Also includes per vni stats
>> support.
>>
>> examples:
>> $bridge vni add dev vxlan0 vni 400
>>
>> $bridge vni add dev vxlan0 vni 200 group 239.1.1.101
>>
>> $bridge vni del dev vxlan0 vni 400
>>
>> $bridge vni show
>>
>> $bridge -s vni show
>>
>>
> hey Roopa: sorry for the delay; traveling. The patches have a number of
> new uses of matches(). We are not taking any more of those; please
> convert to strcmp. The rest looks fine to me.
>
will do, thanks David

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-05-08  4:02 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-01  0:12 [PATCH iproute2 net-next 0/3] support for vxlan vni filtering Roopa Prabhu
2022-05-01  0:12 ` [PATCH iproute2 net-next 1/3] bridge: vxlan device vnifilter support Roopa Prabhu
2022-05-01  0:12 ` [PATCH iproute2 net-next 2/3] ip: iplink_vxlan: add support to set vnifiltering flag on vxlan device Roopa Prabhu
2022-05-01  0:12 ` [PATCH iproute2 net-next 3/3] bridge: vni: add support for stats dumping Roopa Prabhu
2022-05-06  3:26 ` [PATCH iproute2 net-next 0/3] support for vxlan vni filtering David Ahern
2022-05-08  3:45   ` Roopa Prabhu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.