2 This file is part of systemd.
4 Copyright (C) 2016 BISDN GmbH. All rights reserved.
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include <netinet/in.h>
21 #include <linux/if_bridge.h>
24 #include "alloc-util.h"
25 #include "conf-parser.h"
26 #include "netlink-util.h"
27 #include "networkd-brvlan.h"
28 #include "networkd-link.h"
29 #include "networkd-manager.h"
30 #include "networkd-network.h"
31 #include "parse-util.h"
32 #include "vlan-util.h"
34 static bool is_bit_set(unsigned bit
, uint32_t scope
) {
35 assert(bit
< sizeof(scope
)*8);
36 return scope
& (1 << bit
);
39 static inline void set_bit(unsigned nr
, uint32_t *addr
) {
40 if (nr
< BRIDGE_VLAN_BITMAP_MAX
)
41 addr
[nr
/ 32] |= (((uint32_t) 1) << (nr
% 32));
44 static int find_next_bit(int i
, uint32_t x
) {
52 return BUILTIN_FFS_U32(x
);
54 /* mask off prior finds to get next */
55 j
= __builtin_ffs(x
>> i
);
59 static int append_vlan_info_data(Link
*const link
, sd_netlink_message
*req
, uint16_t pvid
, const uint32_t *br_vid_bitmap
, const uint32_t *br_untagged_bitmap
) {
60 struct bridge_vlan_info br_vlan
;
61 int i
, j
, k
, r
, done
, cnt
;
63 bool untagged
= false;
67 assert(br_vid_bitmap
);
68 assert(br_untagged_bitmap
);
72 begin
= end
= UINT16_MAX
;
73 for (k
= 0; k
< BRIDGE_VLAN_BITMAP_LEN
; k
++) {
75 uint32_t vid_map
= br_vid_bitmap
[k
];
76 uint32_t untagged_map
= br_untagged_bitmap
[k
];
82 j
= find_next_bit(i
, vid_map
);
84 /* first hit of any bit */
85 if (begin
== UINT16_MAX
&& end
== UINT16_MAX
) {
86 begin
= end
= j
- 1 + base_bit
;
87 untagged
= is_bit_set(j
- 1, untagged_map
);
91 /* this bit is a continuation of prior bits */
92 if (j
- 2 + base_bit
== end
&& untagged
== is_bit_set(j
- 1, untagged_map
) && (uint16_t)j
- 1 + base_bit
!= pvid
&& (uint16_t)begin
!= pvid
) {
99 if (begin
!= UINT16_MAX
) {
101 if (done
&& k
< BRIDGE_VLAN_BITMAP_LEN
- 1)
106 br_vlan
.flags
|= BRIDGE_VLAN_INFO_UNTAGGED
;
112 br_vlan
.flags
|= BRIDGE_VLAN_INFO_PVID
;
114 r
= sd_netlink_message_append_data(req
, IFLA_BRIDGE_VLAN_INFO
, &br_vlan
, sizeof(br_vlan
));
116 return log_link_error_errno(link
, r
, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
119 br_vlan
.flags
|= BRIDGE_VLAN_INFO_RANGE_BEGIN
;
121 r
= sd_netlink_message_append_data(req
, IFLA_BRIDGE_VLAN_INFO
, &br_vlan
, sizeof(br_vlan
));
123 return log_link_error_errno(link
, r
, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
126 br_vlan
.flags
&= ~BRIDGE_VLAN_INFO_RANGE_BEGIN
;
127 br_vlan
.flags
|= BRIDGE_VLAN_INFO_RANGE_END
;
129 r
= sd_netlink_message_append_data(req
, IFLA_BRIDGE_VLAN_INFO
, &br_vlan
, sizeof(br_vlan
));
131 return log_link_error_errno(link
, r
, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
138 begin
= end
= j
- 1 + base_bit
;
139 untagged
= is_bit_set(j
- 1, untagged_map
);
152 static int set_brvlan_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, void *userdata
) {
153 Link
*link
= userdata
;
158 r
= sd_netlink_message_get_errno(m
);
159 if (r
< 0 && r
!= -EEXIST
)
160 log_link_error_errno(link
, r
, "Could not add VLAN to bridge port: %m");
165 int br_vlan_configure(Link
*link
, uint16_t pvid
, uint32_t *br_vid_bitmap
, uint32_t *br_untagged_bitmap
) {
166 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
172 assert(link
->manager
);
173 assert(br_vid_bitmap
);
174 assert(br_untagged_bitmap
);
175 assert(link
->network
);
177 /* pvid might not be in br_vid_bitmap yet */
179 set_bit(pvid
, br_vid_bitmap
);
181 rtnl
= link
->manager
->rtnl
;
183 /* create new RTM message */
184 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_SETLINK
, link
->ifindex
);
186 return log_link_error_errno(link
, r
, "Could not allocate RTM_SETLINK message: %m");
188 r
= sd_rtnl_message_link_set_family(req
, PF_BRIDGE
);
190 return log_link_error_errno(link
, r
, "Could not set message family: %m");
192 r
= sd_netlink_message_open_container(req
, IFLA_AF_SPEC
);
194 return log_link_error_errno(link
, r
, "Could not open IFLA_AF_SPEC container: %m");
196 /* master needs flag self */
197 if (!link
->network
->bridge
) {
198 flags
= BRIDGE_FLAGS_SELF
;
199 sd_netlink_message_append_data(req
, IFLA_BRIDGE_FLAGS
, &flags
, sizeof(uint16_t));
203 r
= append_vlan_info_data(link
, req
, pvid
, br_vid_bitmap
, br_untagged_bitmap
);
205 return log_link_error_errno(link
, r
, "Could not append VLANs: %m");
207 r
= sd_netlink_message_close_container(req
);
209 return log_link_error_errno(link
, r
, "Could not close IFLA_AF_SPEC container: %m");
211 /* send message to the kernel */
212 r
= sd_netlink_call_async(rtnl
, req
, set_brvlan_handler
, link
, 0, NULL
);
214 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
219 static int parse_vid_range(const char *rvalue
, uint16_t *vid
, uint16_t *vid_end
) {
222 char *_rvalue
= NULL
;
223 uint16_t _vid
= UINT16_MAX
;
224 uint16_t _vid_end
= UINT16_MAX
;
230 _rvalue
= strdupa(rvalue
);
231 p
= strchr(_rvalue
, '-');
235 r
= parse_vlanid(_rvalue
, &_vid
);
242 r
= parse_vlanid(p
, &_vid_end
);
249 r
= parse_vlanid(_rvalue
, &_vid
);
262 int config_parse_brvlan_pvid(const char *unit
, const char *filename
,
263 unsigned line
, const char *section
,
264 unsigned section_line
, const char *lvalue
,
265 int ltype
, const char *rvalue
, void *data
,
267 Network
*network
= userdata
;
270 r
= parse_vlanid(rvalue
, &pvid
);
274 network
->pvid
= pvid
;
275 network
->use_br_vlan
= true;
280 int config_parse_brvlan_vlan(const char *unit
, const char *filename
,
281 unsigned line
, const char *section
,
282 unsigned section_line
, const char *lvalue
,
283 int ltype
, const char *rvalue
, void *data
,
285 Network
*network
= userdata
;
287 uint16_t vid
, vid_end
;
295 r
= parse_vid_range(rvalue
, &vid
, &vid_end
);
297 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse VLAN, ignoring: %s", rvalue
);
301 if (UINT16_MAX
== vid_end
)
302 set_bit(vid
++, network
->br_vid_bitmap
);
304 if (vid
>= vid_end
) {
305 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid VLAN range, ignoring %s", rvalue
);
308 for (; vid
<= vid_end
; vid
++)
309 set_bit(vid
, network
->br_vid_bitmap
);
311 network
->use_br_vlan
= true;
315 int config_parse_brvlan_untagged(const char *unit
, const char *filename
,
316 unsigned line
, const char *section
,
317 unsigned section_line
, const char *lvalue
,
318 int ltype
, const char *rvalue
, void *data
,
320 Network
*network
= userdata
;
322 uint16_t vid
, vid_end
;
330 r
= parse_vid_range(rvalue
, &vid
, &vid_end
);
332 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Could not parse VLAN: %s", rvalue
);
336 if (UINT16_MAX
== vid_end
) {
337 set_bit(vid
, network
->br_vid_bitmap
);
338 set_bit(vid
, network
->br_untagged_bitmap
);
340 if (vid
>= vid_end
) {
341 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid VLAN range, ignoring %s", rvalue
);
344 for (; vid
<= vid_end
; vid
++) {
345 set_bit(vid
, network
->br_vid_bitmap
);
346 set_bit(vid
, network
->br_untagged_bitmap
);
349 network
->use_br_vlan
= true;