*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);
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 AF_INET6:
- entry.addr.u.ip6 = mdb->group_addr.in6;
- entry.addr.proto = htobe16(ETH_P_IPV6);
+ 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);
+ break;
+
+ default:
+ assert_not_reached();
+ }
break;
-
default:
assert_not_reached();
}
if (section_is_invalid(mdb->section))
return -EINVAL;
- 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);
-
- if (mdb->family == AF_INET) {
- if (in4_addr_is_local_multicast(&mdb->group_addr.in))
+ 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 a local multicast address. "
+ "%s: MulticastGroupAddress= is not an L2 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))
+ break;
+ case BRIDGE_MDB_ENTRY_TYPE_L3:
+ if (mdb->family == AF_UNSPEC)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
- "%s: MulticastGroupAddress= is the multicast all nodes address. "
+ "%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);
}
return 0;
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);