Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : : /***
3 : : Copyright © 2016 BISDN GmbH. All rights reserved.
4 : : ***/
5 : :
6 : : #include <netinet/in.h>
7 : : #include <linux/if_bridge.h>
8 : : #include <stdbool.h>
9 : :
10 : : #include "alloc-util.h"
11 : : #include "conf-parser.h"
12 : : #include "netlink-util.h"
13 : : #include "networkd-brvlan.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"
19 : :
20 : 0 : static bool is_bit_set(unsigned bit, uint32_t scope) {
21 [ # # ]: 0 : assert(bit < sizeof(scope)*8);
22 : 0 : return scope & (UINT32_C(1) << bit);
23 : : }
24 : :
25 : 0 : static void set_bit(unsigned nr, uint32_t *addr) {
26 [ # # ]: 0 : if (nr < BRIDGE_VLAN_BITMAP_MAX)
27 : 0 : addr[nr / 32] |= (UINT32_C(1) << (nr % 32));
28 : 0 : }
29 : :
30 : 0 : static int find_next_bit(int i, uint32_t x) {
31 : : int j;
32 : :
33 [ # # ]: 0 : if (i >= 32)
34 : 0 : return -1;
35 : :
36 : : /* find first bit */
37 [ # # ]: 0 : if (i < 0)
38 : 0 : return BUILTIN_FFS_U32(x);
39 : :
40 : : /* mask off prior finds to get next */
41 : 0 : j = __builtin_ffs(x >> i);
42 [ # # ]: 0 : return j ? j + i : 0;
43 : : }
44 : :
45 : 0 : 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) {
46 : : struct bridge_vlan_info br_vlan;
47 : : int i, j, k, r, cnt;
48 : : uint16_t begin, end;
49 : 0 : bool done, untagged = false;
50 : :
51 [ # # ]: 0 : assert(link);
52 [ # # ]: 0 : assert(req);
53 [ # # ]: 0 : assert(br_vid_bitmap);
54 [ # # ]: 0 : assert(br_untagged_bitmap);
55 : :
56 : 0 : cnt = 0;
57 : :
58 : 0 : begin = end = UINT16_MAX;
59 [ # # ]: 0 : for (k = 0; k < BRIDGE_VLAN_BITMAP_LEN; k++) {
60 : : unsigned base_bit;
61 : 0 : uint32_t vid_map = br_vid_bitmap[k];
62 : 0 : uint32_t untagged_map = br_untagged_bitmap[k];
63 : :
64 : 0 : base_bit = k * 32;
65 : 0 : i = -1;
66 : 0 : done = false;
67 : : do {
68 : 0 : j = find_next_bit(i, vid_map);
69 [ # # ]: 0 : if (j > 0) {
70 : : /* first hit of any bit */
71 [ # # # # ]: 0 : if (begin == UINT16_MAX && end == UINT16_MAX) {
72 : 0 : begin = end = j - 1 + base_bit;
73 : 0 : untagged = is_bit_set(j - 1, untagged_map);
74 : 0 : goto next;
75 : : }
76 : :
77 : : /* this bit is a continuation of prior bits */
78 [ # # # # : 0 : 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) {
# # # # ]
79 : 0 : end++;
80 : 0 : goto next;
81 : : }
82 : : } else
83 : 0 : done = true;
84 : :
85 [ # # ]: 0 : if (begin != UINT16_MAX) {
86 : 0 : cnt++;
87 [ # # # # ]: 0 : if (done && k < BRIDGE_VLAN_BITMAP_LEN - 1)
88 : 0 : break;
89 : :
90 : 0 : br_vlan.flags = 0;
91 [ # # ]: 0 : if (untagged)
92 : 0 : br_vlan.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
93 : :
94 [ # # ]: 0 : if (begin == end) {
95 : 0 : br_vlan.vid = begin;
96 : :
97 [ # # ]: 0 : if (begin == pvid)
98 : 0 : br_vlan.flags |= BRIDGE_VLAN_INFO_PVID;
99 : :
100 : 0 : r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
101 [ # # ]: 0 : if (r < 0)
102 [ # # # # ]: 0 : return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
103 : : } else {
104 : 0 : br_vlan.vid = begin;
105 : 0 : br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
106 : :
107 : 0 : r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
108 [ # # ]: 0 : if (r < 0)
109 [ # # # # ]: 0 : return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
110 : :
111 : 0 : br_vlan.vid = end;
112 : 0 : br_vlan.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
113 : 0 : br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_END;
114 : :
115 : 0 : r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
116 [ # # ]: 0 : if (r < 0)
117 [ # # # # ]: 0 : return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
118 : : }
119 : :
120 [ # # ]: 0 : if (done)
121 : 0 : break;
122 : : }
123 [ # # ]: 0 : if (j > 0) {
124 : 0 : begin = end = j - 1 + base_bit;
125 : 0 : untagged = is_bit_set(j - 1, untagged_map);
126 : : }
127 : :
128 : 0 : next:
129 : 0 : i = j;
130 [ # # ]: 0 : } while (!done);
131 : : }
132 : :
133 [ # # ]: 0 : assert(cnt > 0);
134 : 0 : return cnt;
135 : : }
136 : :
137 : 0 : static int set_brvlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
138 : : int r;
139 : :
140 [ # # ]: 0 : assert(link);
141 : :
142 : 0 : r = sd_netlink_message_get_errno(m);
143 [ # # # # ]: 0 : if (r < 0 && r != -EEXIST)
144 [ # # # # ]: 0 : log_link_error_errno(link, r, "Could not add VLAN to bridge port: %m");
145 : :
146 : 0 : return 1;
147 : : }
148 : :
149 : 0 : int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap) {
150 : 0 : _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
151 : : sd_netlink *rtnl;
152 : : uint16_t flags;
153 : : int r;
154 : :
155 [ # # ]: 0 : assert(link);
156 [ # # ]: 0 : assert(link->manager);
157 [ # # ]: 0 : assert(br_vid_bitmap);
158 [ # # ]: 0 : assert(br_untagged_bitmap);
159 [ # # ]: 0 : assert(link->network);
160 : :
161 : : /* pvid might not be in br_vid_bitmap yet */
162 [ # # ]: 0 : if (pvid)
163 : 0 : set_bit(pvid, br_vid_bitmap);
164 : :
165 : 0 : rtnl = link->manager->rtnl;
166 : :
167 : : /* create new RTM message */
168 : 0 : r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, link->ifindex);
169 [ # # ]: 0 : if (r < 0)
170 [ # # # # ]: 0 : return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
171 : :
172 : 0 : r = sd_rtnl_message_link_set_family(req, PF_BRIDGE);
173 [ # # ]: 0 : if (r < 0)
174 [ # # # # ]: 0 : return log_link_error_errno(link, r, "Could not set message family: %m");
175 : :
176 : 0 : r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
177 [ # # ]: 0 : if (r < 0)
178 [ # # # # ]: 0 : return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
179 : :
180 : : /* master needs flag self */
181 [ # # ]: 0 : if (!link->network->bridge) {
182 : 0 : flags = BRIDGE_FLAGS_SELF;
183 : 0 : sd_netlink_message_append_data(req, IFLA_BRIDGE_FLAGS, &flags, sizeof(uint16_t));
184 : : }
185 : :
186 : : /* add vlan info */
187 : 0 : r = append_vlan_info_data(link, req, pvid, br_vid_bitmap, br_untagged_bitmap);
188 [ # # ]: 0 : if (r < 0)
189 [ # # # # ]: 0 : return log_link_error_errno(link, r, "Could not append VLANs: %m");
190 : :
191 : 0 : r = sd_netlink_message_close_container(req);
192 [ # # ]: 0 : if (r < 0)
193 [ # # # # ]: 0 : return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
194 : :
195 : : /* send message to the kernel */
196 : 0 : r = netlink_call_async(rtnl, NULL, req, set_brvlan_handler,
197 : : link_netlink_destroy_callback, link);
198 [ # # ]: 0 : if (r < 0)
199 [ # # # # ]: 0 : return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
200 : :
201 : 0 : link_ref(link);
202 : :
203 : 0 : return 0;
204 : : }
205 : :
206 : 0 : int config_parse_brvlan_pvid(const char *unit, const char *filename,
207 : : unsigned line, const char *section,
208 : : unsigned section_line, const char *lvalue,
209 : : int ltype, const char *rvalue, void *data,
210 : : void *userdata) {
211 : 0 : Network *network = userdata;
212 : : uint16_t pvid;
213 : : int r;
214 : :
215 : 0 : r = parse_vlanid(rvalue, &pvid);
216 [ # # ]: 0 : if (r < 0)
217 : 0 : return r;
218 : :
219 : 0 : network->pvid = pvid;
220 : 0 : network->use_br_vlan = true;
221 : :
222 : 0 : return 0;
223 : : }
224 : :
225 : 0 : int config_parse_brvlan_vlan(const char *unit, const char *filename,
226 : : unsigned line, const char *section,
227 : : unsigned section_line, const char *lvalue,
228 : : int ltype, const char *rvalue, void *data,
229 : : void *userdata) {
230 : 0 : Network *network = userdata;
231 : : uint16_t vid, vid_end;
232 : : int r;
233 : :
234 [ # # ]: 0 : assert(filename);
235 [ # # ]: 0 : assert(section);
236 [ # # ]: 0 : assert(lvalue);
237 [ # # ]: 0 : assert(rvalue);
238 [ # # ]: 0 : assert(data);
239 : :
240 : 0 : r = parse_vid_range(rvalue, &vid, &vid_end);
241 [ # # ]: 0 : if (r < 0) {
242 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VLAN, ignoring: %s", rvalue);
243 : 0 : return 0;
244 : : }
245 : :
246 [ # # ]: 0 : for (; vid <= vid_end; vid++)
247 : 0 : set_bit(vid, network->br_vid_bitmap);
248 : :
249 : 0 : network->use_br_vlan = true;
250 : 0 : return 0;
251 : : }
252 : :
253 : 0 : int config_parse_brvlan_untagged(const char *unit, const char *filename,
254 : : unsigned line, const char *section,
255 : : unsigned section_line, const char *lvalue,
256 : : int ltype, const char *rvalue, void *data,
257 : : void *userdata) {
258 : 0 : Network *network = userdata;
259 : : int r;
260 : : uint16_t vid, vid_end;
261 : :
262 [ # # ]: 0 : assert(filename);
263 [ # # ]: 0 : assert(section);
264 [ # # ]: 0 : assert(lvalue);
265 [ # # ]: 0 : assert(rvalue);
266 [ # # ]: 0 : assert(data);
267 : :
268 : 0 : r = parse_vid_range(rvalue, &vid, &vid_end);
269 [ # # ]: 0 : if (r < 0) {
270 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse VLAN: %s", rvalue);
271 : 0 : return 0;
272 : : }
273 : :
274 [ # # ]: 0 : for (; vid <= vid_end; vid++) {
275 : 0 : set_bit(vid, network->br_vid_bitmap);
276 : 0 : set_bit(vid, network->br_untagged_bitmap);
277 : : }
278 : :
279 : 0 : network->use_br_vlan = true;
280 : 0 : return 0;
281 : : }
|