1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2016 BISDN GmbH. All rights reserved.
6 #include <netinet/in.h>
7 #include <linux/if_bridge.h>
10 #include "alloc-util.h"
11 #include "conf-parser.h"
12 #include "netlink-util.h"
13 #include "networkd-bridge-vlan.h"
14 #include "networkd-link.h"
15 #include "networkd-manager.h"
16 #include "networkd-network.h"
17 #include "parse-util.h"
18 #include "vlan-util.h"
20 static bool is_bit_set(unsigned nr
, const uint32_t *addr
) {
21 assert(nr
< BRIDGE_VLAN_BITMAP_MAX
);
22 return addr
[nr
/ 32] & (UINT32_C(1) << (nr
% 32));
25 static void set_bit(unsigned nr
, uint32_t *addr
) {
26 assert(nr
< BRIDGE_VLAN_BITMAP_MAX
);
27 addr
[nr
/ 32] |= (UINT32_C(1) << (nr
% 32));
30 static int add_single(sd_netlink_message
*m
, uint16_t id
, bool untagged
, bool is_pvid
, char **str
) {
32 assert(id
< BRIDGE_VLAN_BITMAP_MAX
);
35 (void) strextendf_with_separator(str
, ",", "%u%s%s%s%s%s", id
,
36 (untagged
|| is_pvid
) ? "(" : "",
37 untagged
? "untagged" : "",
38 (untagged
&& is_pvid
) ? "," : "",
39 is_pvid
? "pvid" : "",
40 (untagged
|| is_pvid
) ? ")" : "");
42 return sd_netlink_message_append_data(m
, IFLA_BRIDGE_VLAN_INFO
,
43 &(struct bridge_vlan_info
) {
45 .flags
= (untagged
? BRIDGE_VLAN_INFO_UNTAGGED
: 0) |
46 (is_pvid
? BRIDGE_VLAN_INFO_PVID
: 0),
48 sizeof(struct bridge_vlan_info
));
51 static int add_range(sd_netlink_message
*m
, uint16_t begin
, uint16_t end
, bool untagged
, char **str
) {
56 assert(end
< BRIDGE_VLAN_BITMAP_MAX
);
59 return add_single(m
, begin
, untagged
, /* is_pvid = */ false, str
);
62 (void) strextendf_with_separator(str
, ",", "%u-%u%s", begin
, end
, untagged
? "(untagged)" : "");
64 r
= sd_netlink_message_append_data(m
, IFLA_BRIDGE_VLAN_INFO
,
65 &(struct bridge_vlan_info
) {
67 .flags
= (untagged
? BRIDGE_VLAN_INFO_UNTAGGED
: 0) |
68 BRIDGE_VLAN_INFO_RANGE_BEGIN
,
70 sizeof(struct bridge_vlan_info
));
74 r
= sd_netlink_message_append_data(m
, IFLA_BRIDGE_VLAN_INFO
,
75 &(struct bridge_vlan_info
) {
77 .flags
= (untagged
? BRIDGE_VLAN_INFO_UNTAGGED
: 0) |
78 BRIDGE_VLAN_INFO_RANGE_END
,
80 sizeof(struct bridge_vlan_info
));
87 static uint16_t link_get_pvid(Link
*link
, bool *ret_untagged
) {
89 assert(link
->network
);
91 if (vlanid_is_valid(link
->network
->bridge_vlan_pvid
)) {
93 *ret_untagged
= is_bit_set(link
->network
->bridge_vlan_pvid
,
94 link
->network
->bridge_vlan_untagged_bitmap
);
95 return link
->network
->bridge_vlan_pvid
;
98 if (link
->network
->bridge_vlan_pvid
== BRIDGE_VLAN_KEEP_PVID
) {
100 *ret_untagged
= link
->bridge_vlan_pvid_is_untagged
;
101 return link
->bridge_vlan_pvid
;
105 *ret_untagged
= false;
109 static int bridge_vlan_append_set_info(Link
*link
, sd_netlink_message
*m
) {
110 _cleanup_free_
char *str
= NULL
;
111 uint16_t pvid
, begin
= UINT16_MAX
;
112 bool untagged
, pvid_is_untagged
;
116 assert(link
->network
);
119 pvid
= link_get_pvid(link
, &pvid_is_untagged
);
121 for (uint16_t k
= 0; k
< BRIDGE_VLAN_BITMAP_MAX
; k
++) {
124 /* PVID needs to be sent alone. Finish previous bits. */
125 if (begin
!= UINT16_MAX
) {
128 r
= add_range(m
, begin
, k
- 1, untagged
, &str
);
135 r
= add_single(m
, pvid
, pvid_is_untagged
, /* is_pvid = */ true, &str
);
142 if (!is_bit_set(k
, link
->network
->bridge_vlan_bitmap
)) {
143 /* This bit is not set. Finish previous bits. */
144 if (begin
!= UINT16_MAX
) {
147 r
= add_range(m
, begin
, k
- 1, untagged
, &str
);
157 if (begin
!= UINT16_MAX
) {
162 u
= is_bit_set(k
, link
->network
->bridge_vlan_untagged_bitmap
);
166 /* Tagging flag is changed from the previous bits. Finish them. */
167 r
= add_range(m
, begin
, k
- 1, untagged
, &str
);
176 /* This is the starting point of a new bit sequence. Save the position and the tagging flag. */
178 untagged
= is_bit_set(k
, link
->network
->bridge_vlan_untagged_bitmap
);
181 /* No pending bit sequence.
182 * Why? There is a trick. The conf parsers below only accepts vlan ID in the range 0…4094, but in
183 * the above loop, we run 0…4095. */
184 assert_cc(BRIDGE_VLAN_BITMAP_MAX
> VLANID_MAX
);
185 assert(begin
== UINT16_MAX
);
187 log_link_debug(link
, "Setting Bridge VLAN IDs: %s", strna(str
));
191 static int bridge_vlan_append_del_info(Link
*link
, sd_netlink_message
*m
) {
192 _cleanup_free_
char *str
= NULL
;
193 uint16_t pvid
, begin
= UINT16_MAX
;
197 assert(link
->network
);
200 pvid
= link_get_pvid(link
, NULL
);
202 for (uint16_t k
= 0; k
< BRIDGE_VLAN_BITMAP_MAX
; k
++) {
205 !is_bit_set(k
, link
->bridge_vlan_bitmap
) ||
206 is_bit_set(k
, link
->network
->bridge_vlan_bitmap
)) {
207 /* This bit is not necessary to be removed. Finish previous bits. */
208 if (begin
!= UINT16_MAX
) {
211 r
= add_range(m
, begin
, k
- 1, /* untagged = */ false, &str
);
221 if (begin
!= UINT16_MAX
)
224 /* This is the starting point of a new bit sequence. Save the position. */
228 /* No pending bit sequence. */
229 assert(begin
== UINT16_MAX
);
231 log_link_debug(link
, "Removing Bridge VLAN IDs: %s", strna(str
));
235 int bridge_vlan_set_message(Link
*link
, sd_netlink_message
*m
, bool is_set
) {
241 r
= sd_rtnl_message_link_set_family(m
, AF_BRIDGE
);
245 r
= sd_netlink_message_open_container(m
, IFLA_AF_SPEC
);
249 if (link
->master_ifindex
<= 0) {
250 /* master needs BRIDGE_FLAGS_SELF flag */
251 r
= sd_netlink_message_append_u16(m
, IFLA_BRIDGE_FLAGS
, BRIDGE_FLAGS_SELF
);
257 r
= bridge_vlan_append_set_info(link
, m
);
259 r
= bridge_vlan_append_del_info(link
, m
);
263 r
= sd_netlink_message_close_container(m
);
270 #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
272 int link_update_bridge_vlan(Link
*link
, sd_netlink_message
*m
) {
273 _cleanup_free_
void *data
= NULL
;
275 uint16_t begin
= UINT16_MAX
;
281 r
= sd_rtnl_message_get_family(m
, &family
);
285 if (family
!= AF_BRIDGE
)
288 r
= sd_netlink_message_read_data(m
, IFLA_AF_SPEC
, &len
, &data
);
294 memzero(link
->bridge_vlan_bitmap
, sizeof(link
->bridge_vlan_bitmap
));
296 for (struct rtattr
*rta
= data
; RTA_OK(rta
, len
); rta
= RTA_NEXT(rta
, len
)) {
297 struct bridge_vlan_info
*p
;
299 if (RTA_TYPE(rta
) != IFLA_BRIDGE_VLAN_INFO
)
301 if (RTA_PAYLOAD(rta
) != sizeof(struct bridge_vlan_info
))
306 if (FLAGS_SET(p
->flags
, BRIDGE_VLAN_INFO_RANGE_BEGIN
)) {
311 if (FLAGS_SET(p
->flags
, BRIDGE_VLAN_INFO_RANGE_END
)) {
312 for (uint16_t k
= begin
; k
<= p
->vid
; k
++)
313 set_bit(k
, link
->bridge_vlan_bitmap
);
319 if (FLAGS_SET(p
->flags
, BRIDGE_VLAN_INFO_PVID
)) {
320 link
->bridge_vlan_pvid
= p
->vid
;
321 link
->bridge_vlan_pvid_is_untagged
= FLAGS_SET(p
->flags
, BRIDGE_VLAN_INFO_UNTAGGED
);
324 set_bit(p
->vid
, link
->bridge_vlan_bitmap
);
331 void network_adjust_bridge_vlan(Network
*network
) {
334 for (uint16_t k
= 0; k
< BRIDGE_VLAN_BITMAP_MAX
; k
++)
335 if (is_bit_set(k
, network
->bridge_vlan_untagged_bitmap
))
336 set_bit(k
, network
->bridge_vlan_bitmap
);
338 if (vlanid_is_valid(network
->bridge_vlan_pvid
))
339 set_bit(network
->bridge_vlan_pvid
, network
->bridge_vlan_bitmap
);
342 int config_parse_bridge_vlan_id(
344 const char *filename
,
347 unsigned section_line
,
354 uint16_t v
, *id
= ASSERT_PTR(data
);
362 if (isempty(rvalue
)) {
363 *id
= BRIDGE_VLAN_KEEP_PVID
;
367 if (parse_boolean(rvalue
) == 0) {
368 *id
= BRIDGE_VLAN_REMOVE_PVID
;
372 r
= parse_vlanid(rvalue
, &v
);
374 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
375 "Failed to parse %s=, ignoring: %s",
384 int config_parse_bridge_vlan_id_range(
386 const char *filename
,
389 unsigned section_line
,
396 uint32_t *bitmap
= ASSERT_PTR(data
);
397 uint16_t vid
, vid_end
;
405 if (isempty(rvalue
)) {
406 memzero(bitmap
, BRIDGE_VLAN_BITMAP_LEN
* sizeof(uint32_t));
410 r
= parse_vid_range(rvalue
, &vid
, &vid_end
);
412 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
413 "Failed to parse %s=, ignoring: %s",
418 for (; vid
<= vid_end
; vid
++)
419 set_bit(vid
, bitmap
);