mirror of
https://github.com/systemd/systemd.git
synced 2025-03-31 14:50:15 +03:00
Added support for L2 BridgeMDB entries (#32894)
* Added support for L2 BridgeMDB entries
This commit is contained in:
parent
4d1fbe53c1
commit
82f2a2f032
@ -4570,7 +4570,7 @@ ServerAddress=192.168.0.1/24</programlisting>
|
||||
<varlistentry>
|
||||
<term><varname>MulticastGroupAddress=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the IPv4 or IPv6 multicast group address to add. This setting is mandatory.</para>
|
||||
<para>Specifies the IPv4, IPv6, or L2 MAC multicast group address to add. This setting is mandatory.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v247"/>
|
||||
</listitem>
|
||||
|
@ -71,6 +71,7 @@ static int bridge_mdb_new_static(
|
||||
*mdb = (BridgeMDB) {
|
||||
.network = network,
|
||||
.section = TAKE_PTR(n),
|
||||
.type = _BRIDGE_MDB_ENTRY_TYPE_INVALID,
|
||||
};
|
||||
|
||||
r = hashmap_ensure_put(&network->bridge_mdb_entries_by_section, &config_section_hash_ops, mdb->section, mdb);
|
||||
@ -125,24 +126,35 @@ static int bridge_mdb_configure(BridgeMDB *mdb, Link *link, Request *req) {
|
||||
IN_ADDR_TO_STRING(mdb->family, &mdb->group_addr), mdb->vlan_id);
|
||||
|
||||
entry = (struct br_mdb_entry) {
|
||||
/* If MDB entry is added on bridge master, then the state must be MDB_TEMPORARY.
|
||||
/* If MDB entry is added on bridge master, then the state must be MDB_TEMPORARY,
|
||||
* except on L2 routes, where they must always be permanent.
|
||||
* See br_mdb_add_group() in net/bridge/br_mdb.c of kernel. */
|
||||
.state = link->master_ifindex <= 0 ? MDB_TEMPORARY : MDB_PERMANENT,
|
||||
.state = link->master_ifindex <= 0 && mdb->type == BRIDGE_MDB_ENTRY_TYPE_L3 ? MDB_TEMPORARY : MDB_PERMANENT,
|
||||
.ifindex = link->ifindex,
|
||||
.vid = mdb->vlan_id,
|
||||
};
|
||||
|
||||
switch (mdb->family) {
|
||||
case AF_INET:
|
||||
entry.addr.u.ip4 = mdb->group_addr.in.s_addr;
|
||||
entry.addr.proto = htobe16(ETH_P_IP);
|
||||
switch (mdb->type) {
|
||||
case BRIDGE_MDB_ENTRY_TYPE_L2:
|
||||
memcpy(entry.addr.u.mac_addr, &mdb->l2_addr.ether_addr_octet, ETH_ALEN);
|
||||
entry.addr.proto = 0;
|
||||
break;
|
||||
case BRIDGE_MDB_ENTRY_TYPE_L3:
|
||||
switch (mdb->family) {
|
||||
case AF_INET:
|
||||
entry.addr.u.ip4 = mdb->group_addr.in.s_addr;
|
||||
entry.addr.proto = htobe16(ETH_P_IP);
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
entry.addr.u.ip6 = mdb->group_addr.in6;
|
||||
entry.addr.proto = htobe16(ETH_P_IPV6);
|
||||
case AF_INET6:
|
||||
entry.addr.u.ip6 = mdb->group_addr.in6;
|
||||
entry.addr.proto = htobe16(ETH_P_IPV6);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
@ -252,30 +264,49 @@ static int bridge_mdb_verify(BridgeMDB *mdb) {
|
||||
if (section_is_invalid(mdb->section))
|
||||
return -EINVAL;
|
||||
|
||||
if (mdb->family == AF_UNSPEC)
|
||||
switch (mdb->type) {
|
||||
case BRIDGE_MDB_ENTRY_TYPE_L2:
|
||||
if (!ether_addr_is_multicast(&mdb->l2_addr))
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: MulticastGroupAddress= is not an L2 multicast address. "
|
||||
"Ignoring [BridgeMDB] section from line %u.",
|
||||
mdb->section->filename, mdb->section->line);
|
||||
break;
|
||||
case BRIDGE_MDB_ENTRY_TYPE_L3:
|
||||
if (mdb->family == AF_UNSPEC)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: [BridgeMDB] section without MulticastGroupAddress= field configured. "
|
||||
"Ignoring [BridgeMDB] section from line %u.",
|
||||
mdb->section->filename, mdb->section->line);
|
||||
|
||||
if (!in_addr_is_multicast(mdb->family, &mdb->group_addr))
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: MulticastGroupAddress= is not a multicast address. "
|
||||
"Ignoring [BridgeMDB] section from line %u.",
|
||||
mdb->section->filename, mdb->section->line);
|
||||
|
||||
switch (mdb->family) {
|
||||
case AF_INET:
|
||||
if (in4_addr_is_local_multicast(&mdb->group_addr.in))
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: MulticastGroupAddress= is a local multicast address. "
|
||||
"Ignoring [BridgeMDB] section from line %u.",
|
||||
mdb->section->filename, mdb->section->line);
|
||||
break;
|
||||
default:
|
||||
if (in6_addr_is_link_local_all_nodes(&mdb->group_addr.in6))
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: MulticastGroupAddress= is the multicast all nodes address. "
|
||||
"Ignoring [BridgeMDB] section from line %u.",
|
||||
mdb->section->filename, mdb->section->line);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: [BridgeMDB] section without MulticastGroupAddress= field configured. "
|
||||
"Ignoring [BridgeMDB] section from line %u.",
|
||||
mdb->section->filename, mdb->section->line);
|
||||
|
||||
if (!in_addr_is_multicast(mdb->family, &mdb->group_addr))
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: MulticastGroupAddress= is not a multicast address. "
|
||||
"Ignoring [BridgeMDB] section from line %u.",
|
||||
mdb->section->filename, mdb->section->line);
|
||||
|
||||
if (mdb->family == AF_INET) {
|
||||
if (in4_addr_is_local_multicast(&mdb->group_addr.in))
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: MulticastGroupAddress= is a local multicast address. "
|
||||
"Ignoring [BridgeMDB] section from line %u.",
|
||||
mdb->section->filename, mdb->section->line);
|
||||
} else {
|
||||
if (in6_addr_is_link_local_all_nodes(&mdb->group_addr.in6))
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: MulticastGroupAddress= is the multicast all nodes address. "
|
||||
"Ignoring [BridgeMDB] section from line %u.",
|
||||
mdb->section->filename, mdb->section->line);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -355,10 +386,17 @@ int config_parse_mdb_group_address(
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = in_addr_from_string_auto(rvalue, &mdb->family, &mdb->group_addr);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Cannot parse multicast group address: %m");
|
||||
return 0;
|
||||
r = parse_ether_addr(rvalue, &mdb->l2_addr);
|
||||
if (r >= 0)
|
||||
mdb->type = BRIDGE_MDB_ENTRY_TYPE_L2;
|
||||
else {
|
||||
r = in_addr_from_string_auto(rvalue, &mdb->family, &mdb->group_addr);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Cannot parse multicast group address as either L2 MAC, IPv4 or IPv6, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
mdb->type = BRIDGE_MDB_ENTRY_TYPE_L3;
|
||||
}
|
||||
|
||||
TAKE_PTR(mdb);
|
||||
|
@ -10,10 +10,21 @@
|
||||
typedef struct Link Link;
|
||||
typedef struct Network Network;
|
||||
|
||||
typedef enum BridgeMDBEntryType {
|
||||
BRIDGE_MDB_ENTRY_TYPE_L2,
|
||||
BRIDGE_MDB_ENTRY_TYPE_L3,
|
||||
_BRIDGE_MDB_ENTRY_TYPE_MAX,
|
||||
_BRIDGE_MDB_ENTRY_TYPE_INVALID = -EINVAL,
|
||||
} BridgeMDBEntryType;
|
||||
|
||||
typedef struct BridgeMDB {
|
||||
Network *network;
|
||||
ConfigSection *section;
|
||||
|
||||
BridgeMDBEntryType type;
|
||||
|
||||
struct ether_addr l2_addr;
|
||||
|
||||
int family;
|
||||
union in_addr_union group_addr;
|
||||
uint16_t vlan_id;
|
||||
|
@ -12,3 +12,7 @@ MulticastGroupAddress=ff02:aaaa:fee5:0000:0000:0000:0001:0004
|
||||
[BridgeMDB]
|
||||
VLANId=4067
|
||||
MulticastGroupAddress=224.0.1.2
|
||||
|
||||
[BridgeMDB]
|
||||
VLANId=4069
|
||||
MulticastGroupAddress=01:80:c2:00:00:0e
|
||||
|
@ -5077,6 +5077,10 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
|
||||
self.assertRegex(output, 'dev bridge99 port bridge99 grp ff02:aaaa:fee5::1:4 temp *vid 4066')
|
||||
self.assertRegex(output, 'dev bridge99 port bridge99 grp 224.0.1.2 temp *vid 4067')
|
||||
|
||||
# Old kernel may not support L2 bridge MDB entries
|
||||
if call_quiet('bridge mdb add dev bridge99 port bridge99 grp 01:80:c2:00:00:0f permanent vid 4070') == 0:
|
||||
self.assertRegex(output, 'dev bridge99 port bridge99 grp 01:80:c2:00:00:0e permanent *vid 4069')
|
||||
|
||||
def test_bridge_keep_master(self):
|
||||
check_output('ip link add bridge99 type bridge')
|
||||
check_output('ip link set bridge99 up')
|
||||
|
Loading…
x
Reference in New Issue
Block a user