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@c0d3.blue>
[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_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 = {
};
const struct uci_blob_param_list device_attr_list = {
n->dadtransmits = s->flags & DEV_OPT_DADTRANSMITS ?
s->dadtransmits : os->dadtransmits;
n->multicast_to_unicast = s->multicast_to_unicast;
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;
}
n->flags = s->flags | os->flags;
}
s->flags |= DEV_OPT_MULTICAST_TO_UNICAST;
}
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 <= 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);
}
device_set_disabled(dev, disabled);
}
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);
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");
}
s = blobmsg_open_table(b, "statistics");
DEV_ATTR_XPS,
DEV_ATTR_DADTRANSMITS,
DEV_ATTR_MULTICAST_TO_UNICAST,
DEV_ATTR_XPS,
DEV_ATTR_DADTRANSMITS,
DEV_ATTR_MULTICAST_TO_UNICAST,
+ DEV_ATTR_MULTICAST_ROUTER,
DEV_OPT_MTU6 = (1 << 12),
DEV_OPT_DADTRANSMITS = (1 << 13),
DEV_OPT_MULTICAST_TO_UNICAST = (1 << 14),
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 */
};
/* events broadcasted to all users of a device */
bool xps;
unsigned int dadtransmits;
bool multicast_to_unicast;
bool xps;
unsigned int dadtransmits;
bool multicast_to_unicast;
+ unsigned int multicast_router;
system_set_dev_sysctl("/sys/class/net/%s/brport/hairpin_mode", dev->ifname, 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;
static int system_get_sysctl(const char *path, char *buf, const size_t buf_sz)
{
int fd = -1, ret = -1;
int system_bridge_addif(struct device *bridge, struct device *dev)
{
int system_bridge_addif(struct device *bridge, struct device *dev)
{
char *oldbr;
int ret = 0;
char *oldbr;
int ret = 0;
if (dev->wireless)
system_bridge_set_wireless(bridge, 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);
+ }
+
system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/hash_max",
bridge->ifname, buf);
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);
args[0] = BRCTL_SET_BRIDGE_PRIORITY;
args[1] = cfg->priority;
system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);