[OpenWrt-Devel] [PATCHv3 netifd 3/3] bridge: Allow setting multicast_router option

Linus Lüssing linus.luessing at c0d3.blue
Sun Aug 23 11:19:28 EDT 2015


The multicast_router option of a bridge allows to control the forwarding
behaviour of multicast packets independant of the listener state:

* 0: Only forward if specific listener is present
* 1 (default): Forward if specific listener or a multicast router
  was detected (currently only learned via query messages, no MRD
  support yet)
* 2: Always forward any multicast traffic on this port

Since MRD is not mandated you might end up with silent multicast routers
(e.g. if your link has more than one multicast router; only one can
become the selected, "noisy" querier). Here you might need a manual
configuration option like the "multicast_router" option.

Other scenarios where this can be useful are for instance:
* Segmentation of IGMP/MLD domains together with ebtables
* Dedicated bridge port for monitoring/debugging purposes

Signed-off-by: Linus Lüssing <linus.luessing at c0d3.blue>
---
 device.c       |   12 ++++++++++++
 device.h       |    3 +++
 system-linux.c |   18 ++++++++++++++++++
 3 files changed, 33 insertions(+)

diff --git a/device.c b/device.c
index b44ccb8..d6e288c 100644
--- a/device.c
+++ b/device.c
@@ -49,6 +49,7 @@ static const struct blobmsg_policy dev_attrs[__DEV_ATTR_MAX] = {
 	[DEV_ATTR_XPS] = { .name = "xps", .type = BLOBMSG_TYPE_BOOL },
 	[DEV_ATTR_DADTRANSMITS] = { .name = "dadtransmits", .type = BLOBMSG_TYPE_INT32 },
 	[DEV_ATTR_MULTICAST_TO_UNICAST] = { .name = "multicast_to_unicast", .type = BLOBMSG_TYPE_BOOL },
+	[DEV_ATTR_MULTICAST_ROUTER] = { .name = "multicast_router", .type = BLOBMSG_TYPE_INT32 },
 };
 
 const struct uci_blob_param_list device_attr_list = {
@@ -176,6 +177,7 @@ device_merge_settings(struct device *dev, struct device_settings *n)
 	n->dadtransmits = s->flags & DEV_OPT_DADTRANSMITS ?
 		s->dadtransmits : os->dadtransmits;
 	n->multicast_to_unicast = s->multicast_to_unicast;
+	n->multicast_router = s->multicast_router;
 	n->flags = s->flags | os->flags;
 }
 
@@ -281,6 +283,14 @@ device_init_settings(struct device *dev, struct blob_attr **tb)
 		s->flags |= DEV_OPT_MULTICAST_TO_UNICAST;
 	}
 
+	if ((cur = tb[DEV_ATTR_MULTICAST_ROUTER])) {
+		s->multicast_router = blobmsg_get_u32(cur);
+		if (s->multicast_router >= 0 && s->multicast_router <= 2)
+			s->flags |= DEV_OPT_MULTICAST_ROUTER;
+		else
+			DPRINTF("Invalid value: %d - (Use 0: never, 1: learn, 2: always)\n", blobmsg_get_u32(cur));
+	}
+
 	device_set_disabled(dev, disabled);
 }
 
@@ -893,6 +903,8 @@ device_dump_status(struct blob_buf *b, struct device *dev)
 			blobmsg_add_u32(b, "dadtransmits", st.dadtransmits);
 		if (st.flags & DEV_OPT_MULTICAST_TO_UNICAST)
 			blobmsg_add_u8(b, "multicast_to_unicast", st.multicast_to_unicast);
+		if (st.flags & DEV_OPT_MULTICAST_ROUTER)
+			blobmsg_add_u32(b, "multicast_router", st.multicast_router);
 	}
 
 	s = blobmsg_open_table(b, "statistics");
diff --git a/device.h b/device.h
index 4344d8a..86a1628 100644
--- a/device.h
+++ b/device.h
@@ -43,6 +43,7 @@ enum {
 	DEV_ATTR_XPS,
 	DEV_ATTR_DADTRANSMITS,
 	DEV_ATTR_MULTICAST_TO_UNICAST,
+	DEV_ATTR_MULTICAST_ROUTER,
 	__DEV_ATTR_MAX,
 };
 
@@ -86,6 +87,7 @@ enum {
 	DEV_OPT_MTU6			= (1 << 12),
 	DEV_OPT_DADTRANSMITS		= (1 << 13),
 	DEV_OPT_MULTICAST_TO_UNICAST	= (1 << 14),
+	DEV_OPT_MULTICAST_ROUTER	= (1 << 15),
 };
 
 /* events broadcasted to all users of a device */
@@ -144,6 +146,7 @@ struct device_settings {
 	bool xps;
 	unsigned int dadtransmits;
 	bool multicast_to_unicast;
+	unsigned int multicast_router;
 };
 
 /*
diff --git a/system-linux.c b/system-linux.c
index 944245c..01500a5 100644
--- a/system-linux.c
+++ b/system-linux.c
@@ -325,6 +325,13 @@ static void system_bridge_set_hairpin_mode(struct device *dev, const char *val)
 	system_set_dev_sysctl("/sys/class/net/%s/brport/hairpin_mode", dev->ifname, val);
 }
 
+static void system_bridge_set_multicast_router(struct device *dev, const char *val, bool bridge)
+{
+	system_set_dev_sysctl(bridge ? "/sys/class/net/%s/bridge/multicast_router" :
+				       "/sys/class/net/%s/brport/multicast_router",
+			      dev->ifname, val);
+}
+
 static int system_get_sysctl(const char *path, char *buf, const size_t buf_sz)
 {
 	int fd = -1, ret = -1;
@@ -585,6 +592,7 @@ system_bridge_set_wireless(struct device *bridge, struct device *dev)
 
 int system_bridge_addif(struct device *bridge, struct device *dev)
 {
+	char buf[64];
 	char *oldbr;
 	int ret = 0;
 
@@ -595,6 +603,11 @@ int system_bridge_addif(struct device *bridge, struct device *dev)
 	if (dev->wireless)
 		system_bridge_set_wireless(bridge, dev);
 
+	if (dev->settings.flags & DEV_OPT_MULTICAST_ROUTER) {
+		snprintf(buf, sizeof(buf), "%i", dev->settings.multicast_router);
+		system_bridge_set_multicast_router(dev, buf, false);
+	}
+
 	return ret;
 }
 
@@ -845,6 +858,11 @@ int system_bridge_addbr(struct device *bridge, struct bridge_config *cfg)
 	system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/hash_max",
 		bridge->ifname, buf);
 
+	if (bridge->settings.flags & DEV_OPT_MULTICAST_ROUTER) {
+		snprintf(buf, sizeof(buf), "%i", bridge->settings.multicast_router);
+		system_bridge_set_multicast_router(bridge, buf, true);
+	}
+
 	args[0] = BRCTL_SET_BRIDGE_PRIORITY;
 	args[1] = cfg->priority;
 	system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
-- 
1.7.10.4
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel


More information about the openwrt-devel mailing list