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_put(&network
->mdb_entries_by_section
, &network_config_hash_ops
, mdb_entry
->section
, mdb_entry
);
77 /* return allocated MDB structure. */
78 *ret
= TAKE_PTR(mdb_entry
);
82 static int set_mdb_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
86 assert(link
->bridge_mdb_messages
> 0);
88 link
->bridge_mdb_messages
--;
90 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
93 r
= sd_netlink_message_get_errno(m
);
94 if (r
== -EINVAL
&& streq_ptr(link
->kind
, "bridge") && (!link
->network
|| !link
->network
->bridge
)) {
95 /* To configure bridge MDB entries on bridge master, 1bc844ee0faa1b92e3ede00bdd948021c78d7088 (v5.4) is required. */
96 if (!link
->manager
->bridge_mdb_on_master_not_supported
) {
97 log_link_warning_errno(link
, r
, "Kernel seems not to support configuring bridge MDB entries on bridge master, ignoring: %m");
98 link
->manager
->bridge_mdb_on_master_not_supported
= true;
100 } else if (r
< 0 && r
!= -EEXIST
) {
101 log_link_message_warning_errno(link
, m
, r
, "Could not add MDB entry");
102 link_enter_failed(link
);
106 if (link
->bridge_mdb_messages
== 0) {
107 link
->bridge_mdb_configured
= true;
108 link_check_ready(link
);
114 static int link_get_bridge_master_ifindex(Link
*link
) {
117 if (link
->network
&& link
->network
->bridge
)
118 return link
->network
->bridge
->ifindex
;
120 if (streq_ptr(link
->kind
, "bridge"))
121 return link
->ifindex
;
126 /* send a request to the kernel to add an MDB entry */
127 static int mdb_entry_configure(Link
*link
, MdbEntry
*mdb_entry
) {
128 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
129 struct br_mdb_entry entry
;
133 assert(link
->network
);
134 assert(link
->manager
);
138 _cleanup_free_
char *a
= NULL
;
140 (void) in_addr_to_string(mdb_entry
->family
, &mdb_entry
->group_addr
, &a
);
141 log_link_debug(link
, "Configuring bridge MDB entry: MulticastGroupAddress=%s, VLANId=%u",
142 strna(a
), mdb_entry
->vlan_id
);
145 master
= link_get_bridge_master_ifindex(link
);
147 return log_link_error_errno(link
, SYNTHETIC_ERRNO(EINVAL
), "Invalid bridge master ifindex %i", master
);
149 entry
= (struct br_mdb_entry
) {
150 /* If MDB entry is added on bridge master, then the state must be MDB_TEMPORARY.
151 * See br_mdb_add_group() in net/bridge/br_mdb.c of kernel. */
152 .state
= master
== link
->ifindex
? MDB_TEMPORARY
: MDB_PERMANENT
,
153 .ifindex
= link
->ifindex
,
154 .vid
= mdb_entry
->vlan_id
,
157 /* create new RTM message */
158 r
= sd_rtnl_message_new_mdb(link
->manager
->rtnl
, &req
, RTM_NEWMDB
, master
);
160 return log_link_error_errno(link
, r
, "Could not create RTM_NEWMDB message: %m");
162 switch (mdb_entry
->family
) {
164 entry
.addr
.u
.ip4
= mdb_entry
->group_addr
.in
.s_addr
;
165 entry
.addr
.proto
= htobe16(ETH_P_IP
);
169 entry
.addr
.u
.ip6
= mdb_entry
->group_addr
.in6
;
170 entry
.addr
.proto
= htobe16(ETH_P_IPV6
);
174 assert_not_reached("Invalid address family");
177 r
= sd_netlink_message_append_data(req
, MDBA_SET_ENTRY
, &entry
, sizeof(entry
));
179 return log_link_error_errno(link
, r
, "Could not append MDBA_SET_ENTRY attribute: %m");
181 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, req
, set_mdb_handler
,
182 link_netlink_destroy_callback
, link
);
184 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
191 int link_set_bridge_mdb(Link
*link
) {
196 assert(link
->manager
);
198 if (link
->bridge_mdb_messages
!= 0) {
199 log_link_debug(link
, "MDB entries are configuring.");
203 link
->bridge_mdb_configured
= false;
208 if (hashmap_isempty(link
->network
->mdb_entries_by_section
))
211 if (!link_has_carrier(link
))
212 return log_link_debug(link
, "Link does not have carrier yet, setting MDB entries later.");
214 if (link
->network
->bridge
) {
217 r
= link_get(link
->manager
, link
->network
->bridge
->ifindex
, &master
);
219 return log_link_error_errno(link
, r
, "Failed to get Link object for Bridge=%s", link
->network
->bridge
->ifname
);
221 if (!link_has_carrier(master
))
222 return log_link_debug(link
, "Bridge interface %s does not have carrier yet, setting MDB entries later.", link
->network
->bridge
->ifname
);
224 } else if (!streq_ptr(link
->kind
, "bridge")) {
225 log_link_warning(link
, "Link is neither a bridge master nor a bridge port, ignoring [BridgeMDB] sections.");
227 } else if (link
->manager
->bridge_mdb_on_master_not_supported
) {
228 log_link_debug(link
, "Kernel seems not to support configuring bridge MDB entries on bridge master, ignoring [BridgeMDB] sections.");
232 HASHMAP_FOREACH(mdb_entry
, link
->network
->mdb_entries_by_section
) {
233 r
= mdb_entry_configure(link
, mdb_entry
);
235 return log_link_error_errno(link
, r
, "Failed to add MDB entry to multicast group database: %m");
237 link
->bridge_mdb_messages
++;
241 if (link
->bridge_mdb_messages
== 0) {
242 link
->bridge_mdb_configured
= true;
243 link_check_ready(link
);
249 static int mdb_entry_verify(MdbEntry
*mdb_entry
) {
250 if (section_is_invalid(mdb_entry
->section
))
253 if (mdb_entry
->family
== AF_UNSPEC
)
254 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
255 "%s: [BridgeMDB] section without MulticastGroupAddress= field configured. "
256 "Ignoring [BridgeMDB] section from line %u.",
257 mdb_entry
->section
->filename
, mdb_entry
->section
->line
);
259 if (!in_addr_is_multicast(mdb_entry
->family
, &mdb_entry
->group_addr
))
260 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
261 "%s: MulticastGroupAddress= is not a multicast address. "
262 "Ignoring [BridgeMDB] section from line %u.",
263 mdb_entry
->section
->filename
, mdb_entry
->section
->line
);
265 if (mdb_entry
->family
== AF_INET
) {
266 if (in4_addr_is_local_multicast(&mdb_entry
->group_addr
.in
))
267 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
268 "%s: MulticastGroupAddress= is a local multicast address. "
269 "Ignoring [BridgeMDB] section from line %u.",
270 mdb_entry
->section
->filename
, mdb_entry
->section
->line
);
272 if (in6_addr_is_link_local_all_nodes(&mdb_entry
->group_addr
.in6
))
273 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
274 "%s: MulticastGroupAddress= is the multicast all nodes address. "
275 "Ignoring [BridgeMDB] section from line %u.",
276 mdb_entry
->section
->filename
, mdb_entry
->section
->line
);
282 void network_drop_invalid_mdb_entries(Network
*network
) {
287 HASHMAP_FOREACH(mdb_entry
, network
->mdb_entries_by_section
)
288 if (mdb_entry_verify(mdb_entry
) < 0)
289 mdb_entry_free(mdb_entry
);
292 /* parse the VLAN Id from config files. */
293 int config_parse_mdb_vlan_id(
295 const char *filename
,
298 unsigned section_line
,
305 _cleanup_(mdb_entry_free_or_set_invalidp
) MdbEntry
*mdb_entry
= NULL
;
306 Network
*network
= userdata
;
315 r
= mdb_entry_new_static(network
, filename
, section_line
, &mdb_entry
);
319 r
= config_parse_vlanid(unit
, filename
, line
, section
,
320 section_line
, lvalue
, ltype
,
321 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");