summaryrefslogtreecommitdiff
path: root/net/bridge/br_mdb.c
diff options
context:
space:
mode:
authorNikolay Aleksandrov <nikolay@nvidia.com>2020-10-29 01:38:31 +0200
committerJakub Kicinski <kuba@kernel.org>2020-10-30 17:49:19 -0700
commit955062b03fa62b802a1ee34fbb04e39f7a70ae73 (patch)
treec507b7adcc545319addfae44a9d46db5545f06c4 /net/bridge/br_mdb.c
parent8ece853d128b486c06dd937cb1f1ed4d1de14486 (diff)
net: bridge: mcast: add support for raw L2 multicast groups
Extend the bridge multicast control and data path to configure routes for L2 (non-IP) multicast groups. The uapi struct br_mdb_entry union u is extended with another variant, mac_addr, which does not change the structure size, and which is valid when the proto field is zero. To be compatible with the forwarding code that is already in place, which acts as an IGMP/MLD snooping bridge with querier capabilities, we need to declare that for L2 MDB entries (for which there exists no such thing as IGMP/MLD snooping/querying), that there is always a querier. Otherwise, these entries would be flooded to all bridge ports and not just to those that are members of the L2 multicast group. Needless to say, only permanent L2 multicast groups can be installed on a bridge port. Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Link: https://lore.kernel.org/r/20201028233831.610076-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/bridge/br_mdb.c')
-rw-r--r--net/bridge/br_mdb.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index e15bab19a012..3c8863418d0b 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -87,6 +87,8 @@ static void __mdb_entry_to_br_ip(struct br_mdb_entry *entry, struct br_ip *ip,
ip->src.ip6 = nla_get_in6_addr(mdb_attrs[MDBE_ATTR_SOURCE]);
break;
#endif
+ default:
+ ether_addr_copy(ip->dst.mac_addr, entry->addr.u.mac_addr);
}
}
@@ -174,9 +176,11 @@ static int __mdb_fill_info(struct sk_buff *skb,
if (mp->addr.proto == htons(ETH_P_IP))
e.addr.u.ip4 = mp->addr.dst.ip4;
#if IS_ENABLED(CONFIG_IPV6)
- if (mp->addr.proto == htons(ETH_P_IPV6))
+ else if (mp->addr.proto == htons(ETH_P_IPV6))
e.addr.u.ip6 = mp->addr.dst.ip6;
#endif
+ else
+ ether_addr_copy(e.addr.u.mac_addr, mp->addr.dst.mac_addr);
e.addr.proto = mp->addr.proto;
nest_ent = nla_nest_start_noflag(skb,
MDBA_MDB_ENTRY_INFO);
@@ -210,6 +214,8 @@ static int __mdb_fill_info(struct sk_buff *skb,
}
break;
#endif
+ default:
+ ether_addr_copy(e.addr.u.mac_addr, mp->addr.dst.mac_addr);
}
if (p) {
if (nla_put_u8(skb, MDBA_MDB_EATTR_RTPROT, p->rt_protocol))
@@ -562,9 +568,12 @@ void br_mdb_notify(struct net_device *dev,
if (mp->addr.proto == htons(ETH_P_IP))
ip_eth_mc_map(mp->addr.dst.ip4, mdb.addr);
#if IS_ENABLED(CONFIG_IPV6)
- else
+ else if (mp->addr.proto == htons(ETH_P_IPV6))
ipv6_eth_mc_map(&mp->addr.dst.ip6, mdb.addr);
#endif
+ else
+ ether_addr_copy(mdb.addr, mp->addr.dst.mac_addr);
+
mdb.obj.orig_dev = pg->key.port->dev;
switch (type) {
case RTM_NEWMDB:
@@ -693,6 +702,12 @@ static bool is_valid_mdb_entry(struct br_mdb_entry *entry,
return false;
}
#endif
+ } else if (entry->addr.proto == 0) {
+ /* L2 mdb */
+ if (!is_multicast_ether_addr(entry->addr.u.mac_addr)) {
+ NL_SET_ERR_MSG_MOD(extack, "L2 entry group is not multicast");
+ return false;
+ }
} else {
NL_SET_ERR_MSG_MOD(extack, "Unknown entry protocol");
return false;
@@ -849,6 +864,11 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
}
}
+ if (br_group_is_l2(&group) && entry->state != MDB_PERMANENT) {
+ NL_SET_ERR_MSG_MOD(extack, "Only permanent L2 entries allowed");
+ return -EINVAL;
+ }
+
mp = br_mdb_ip_get(br, &group);
if (!mp) {
mp = br_multicast_new_group(br, &group);