1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "netlink-util.h"
6 #include "networkd-link.h"
7 #include "networkd-manager.h"
8 #include "networkd-mdb.h"
9 #include "networkd-network.h"
10 #include "string-util.h"
11 #include "vlan-util.h"
13 #define STATIC_MDB_ENTRIES_PER_NETWORK_MAX 1024U
15 /* remove MDB entry. */
16 MdbEntry
*mdb_entry_free(MdbEntry
*mdb_entry
) {
20 if (mdb_entry
->network
) {
21 assert(mdb_entry
->section
);
22 hashmap_remove(mdb_entry
->network
->mdb_entries_by_section
, mdb_entry
->section
);
25 network_config_section_free(mdb_entry
->section
);
27 return mfree(mdb_entry
);
30 DEFINE_NETWORK_SECTION_FUNCTIONS(MdbEntry
, mdb_entry_free
);
32 /* create a new MDB entry or get an existing one. */
33 static int mdb_entry_new_static(
36 unsigned section_line
,
39 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
40 _cleanup_(mdb_entry_freep
) MdbEntry
*mdb_entry
= NULL
;
46 assert(section_line
> 0);
48 r
= network_config_section_new(filename
, section_line
, &n
);
52 /* search entry in hashmap first. */
53 mdb_entry
= hashmap_get(network
->mdb_entries_by_section
, n
);
55 *ret
= TAKE_PTR(mdb_entry
);
59 if (hashmap_size(network
->mdb_entries_by_section
) >= STATIC_MDB_ENTRIES_PER_NETWORK_MAX
)
62 /* allocate space for an MDB entry. */
63 mdb_entry
= new(MdbEntry
, 1);
67 /* init MDB structure. */
68 *mdb_entry
= (MdbEntry
) {
70 .section
= TAKE_PTR(n
),
73 r
= hashmap_ensure_allocated(&network
->mdb_entries_by_section
, &network_config_hash_ops
);
77 r
= hashmap_put(network
->mdb_entries_by_section
, mdb_entry
->section
, mdb_entry
);
81 /* return allocated MDB structure. */
82 *ret
= TAKE_PTR(mdb_entry
);
86 static int set_mdb_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
90 assert(link
->bridge_mdb_messages
> 0);
92 link
->bridge_mdb_messages
--;
94 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
97 r
= sd_netlink_message_get_errno(m
);
98 if (r
== -EINVAL
&& streq_ptr(link
->kind
, "bridge") && (!link
->network
|| !link
->network
->bridge
)) {
99 /* To configure bridge MDB entries on bridge master, 1bc844ee0faa1b92e3ede00bdd948021c78d7088 (v5.4) is required. */
100 if (!link
->manager
->bridge_mdb_on_master_not_supported
) {
101 log_link_warning_errno(link
, r
, "Kernel seems not to support configuring bridge MDB entries on bridge master, ignoring: %m");
102 link
->manager
->bridge_mdb_on_master_not_supported
= true;
104 } else if (r
< 0 && r
!= -EEXIST
) {
105 log_link_message_warning_errno(link
, m
, r
, "Could not add MDB entry");
106 link_enter_failed(link
);
110 if (link
->bridge_mdb_messages
== 0) {
111 link
->bridge_mdb_configured
= true;
112 link_check_ready(link
);
118 static int link_get_bridge_master_ifindex(Link
*link
) {
121 if (link
->network
&& link
->network
->bridge
)
122 return link
->network
->bridge
->ifindex
;
124 if (streq_ptr(link
->kind
, "bridge"))
125 return link
->ifindex
;
130 /* send a request to the kernel to add an MDB entry */
131 static int mdb_entry_configure(Link
*link
, MdbEntry
*mdb_entry
) {
132 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
133 struct br_mdb_entry entry
;
137 assert(link
->network
);
138 assert(link
->manager
);
142 _cleanup_free_
char *a
= NULL
;
144 (void) in_addr_to_string(mdb_entry
->family
, &mdb_entry
->group_addr
, &a
);
145 log_link_debug(link
, "Configuring bridge MDB entry: MulticastGroupAddress=%s, VLANId=%u",
146 strna(a
), mdb_entry
->vlan_id
);
149 master
= link_get_bridge_master_ifindex(link
);
151 return log_link_error_errno(link
, SYNTHETIC_ERRNO(EINVAL
), "Invalid bridge master ifindex %i", master
);
153 entry
= (struct br_mdb_entry
) {
154 /* If MDB entry is added on bridge master, then the state must be MDB_TEMPORARY.
155 * See br_mdb_add_group() in net/bridge/br_mdb.c of kernel. */
156 .state
= master
== link
->ifindex
? MDB_TEMPORARY
: MDB_PERMANENT
,
157 .ifindex
= link
->ifindex
,
158 .vid
= mdb_entry
->vlan_id
,
161 /* create new RTM message */
162 r
= sd_rtnl_message_new_mdb(link
->manager
->rtnl
, &req
, RTM_NEWMDB
, master
);
164 return log_link_error_errno(link
, r
, "Could not create RTM_NEWMDB message: %m");
166 switch (mdb_entry
->family
) {
168 entry
.addr
.u
.ip4
= mdb_entry
->group_addr
.in
.s_addr
;
169 entry
.addr
.proto
= htobe16(ETH_P_IP
);
173 entry
.addr
.u
.ip6
= mdb_entry
->group_addr
.in6
;
174 entry
.addr
.proto
= htobe16(ETH_P_IPV6
);
178 assert_not_reached("Invalid address family");
181 r
= sd_netlink_message_append_data(req
, MDBA_SET_ENTRY
, &entry
, sizeof(entry
));
183 return log_link_error_errno(link
, r
, "Could not append MDBA_SET_ENTRY attribute: %m");
185 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, req
, set_mdb_handler
,
186 link_netlink_destroy_callback
, link
);
188 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
195 int link_set_bridge_mdb(Link
*link
) {
200 assert(link
->manager
);
202 link
->bridge_mdb_configured
= false;
207 if (hashmap_isempty(link
->network
->mdb_entries_by_section
))
210 if (!link_has_carrier(link
))
211 return log_link_debug(link
, "Link does not have carrier yet, setting MDB entries later.");
213 if (link
->network
->bridge
) {
216 r
= link_get(link
->manager
, link
->network
->bridge
->ifindex
, &master
);
218 return log_link_error_errno(link
, r
, "Failed to get Link object for Bridge=%s", link
->network
->bridge
->ifname
);
220 if (!link_has_carrier(master
))
221 return log_link_debug(link
, "Bridge interface %s does not have carrier yet, setting MDB entries later.", link
->network
->bridge
->ifname
);
223 } else if (!streq_ptr(link
->kind
, "bridge")) {
224 log_link_warning(link
, "Link is neither a bridge master nor a bridge port, ignoring [BridgeMDB] sections.");
226 } else if (link
->manager
->bridge_mdb_on_master_not_supported
) {
227 log_link_debug(link
, "Kernel seems not to support configuring bridge MDB entries on bridge master, ignoring [BridgeMDB] sections.");
231 HASHMAP_FOREACH(mdb_entry
, link
->network
->mdb_entries_by_section
) {
232 r
= mdb_entry_configure(link
, mdb_entry
);
234 return log_link_error_errno(link
, r
, "Failed to add MDB entry to multicast group database: %m");
236 link
->bridge_mdb_messages
++;
240 if (link
->bridge_mdb_messages
== 0) {
241 link
->bridge_mdb_configured
= true;
242 link_check_ready(link
);
248 static int mdb_entry_verify(MdbEntry
*mdb_entry
) {
249 if (section_is_invalid(mdb_entry
->section
))
252 if (mdb_entry
->family
== AF_UNSPEC
)
253 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
254 "%s: [BridgeMDB] section without MulticastGroupAddress= field configured. "
255 "Ignoring [BridgeMDB] section from line %u.",
256 mdb_entry
->section
->filename
, mdb_entry
->section
->line
);
258 if (!in_addr_is_multicast(mdb_entry
->family
, &mdb_entry
->group_addr
))
259 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
260 "%s: MulticastGroupAddress= is not a multicast address. "
261 "Ignoring [BridgeMDB] section from line %u.",
262 mdb_entry
->section
->filename
, mdb_entry
->section
->line
);
264 if (mdb_entry
->family
== AF_INET
) {
265 if (in4_addr_is_local_multicast(&mdb_entry
->group_addr
.in
))
266 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
267 "%s: MulticastGroupAddress= is a local multicast address. "
268 "Ignoring [BridgeMDB] section from line %u.",
269 mdb_entry
->section
->filename
, mdb_entry
->section
->line
);
271 if (in6_addr_is_link_local_all_nodes(&mdb_entry
->group_addr
.in6
))
272 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
273 "%s: MulticastGroupAddress= is the multicast all nodes address. "
274 "Ignoring [BridgeMDB] section from line %u.",
275 mdb_entry
->section
->filename
, mdb_entry
->section
->line
);
281 void network_drop_invalid_mdb_entries(Network
*network
) {
286 HASHMAP_FOREACH(mdb_entry
, network
->mdb_entries_by_section
)
287 if (mdb_entry_verify(mdb_entry
) < 0)
288 mdb_entry_free(mdb_entry
);
291 /* parse the VLAN Id from config files. */
292 int config_parse_mdb_vlan_id(
294 const char *filename
,
297 unsigned section_line
,
304 _cleanup_(mdb_entry_free_or_set_invalidp
) MdbEntry
*mdb_entry
= NULL
;
305 Network
*network
= userdata
;
314 r
= mdb_entry_new_static(network
, filename
, section_line
, &mdb_entry
);
318 r
= config_parse_vlanid(unit
, filename
, line
, section
,
319 section_line
, lvalue
, ltype
,
320 rvalue
, &mdb_entry
->vlan_id
, userdata
);
329 /* parse the multicast group from config files. */
330 int config_parse_mdb_group_address(
332 const char *filename
,
335 unsigned section_line
,
342 _cleanup_(mdb_entry_free_or_set_invalidp
) MdbEntry
*mdb_entry
= NULL
;
343 Network
*network
= userdata
;
352 r
= mdb_entry_new_static(network
, filename
, section_line
, &mdb_entry
);
356 r
= in_addr_from_string_auto(rvalue
, &mdb_entry
->family
, &mdb_entry
->group_addr
);
358 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Cannot parse multicast group address: %m");