1 /*
2 * Copyright (c) 2021 BayLibre SAS
3 * Copyright (c) 2024 Nordic Semiconductor
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_REGISTER(net_eth_bridge, CONFIG_NET_ETHERNET_BRIDGE_LOG_LEVEL);
10
11 #include <zephyr/net/net_core.h>
12 #include <zephyr/net/net_l2.h>
13 #include <zephyr/net/net_if.h>
14 #include <zephyr/net/virtual.h>
15 #include <zephyr/net/ethernet.h>
16 #include <zephyr/net/ethernet_bridge.h>
17 #include <zephyr/sys/slist.h>
18 #include <zephyr/random/random.h>
19
20 #include "net_private.h"
21 #include "bridge.h"
22
23 #if defined(CONFIG_NET_ETHERNET_BRIDGE_TXRX_DEBUG)
24 #define DEBUG_TX 1
25 #define DEBUG_RX 1
26 #else
27 #define DEBUG_TX 0
28 #define DEBUG_RX 0
29 #endif
30
31 #define MAX_BRIDGE_NAME_LEN MIN(sizeof("bridge##"), CONFIG_NET_INTERFACE_NAME_LEN)
32 #define MAX_VIRT_NAME_LEN MIN(sizeof("<no config>"), CONFIG_NET_L2_VIRTUAL_MAX_NAME_LEN)
33
lock_bridge(struct eth_bridge_iface_context * ctx)34 static void lock_bridge(struct eth_bridge_iface_context *ctx)
35 {
36 k_mutex_lock(&ctx->lock, K_FOREVER);
37 }
38
unlock_bridge(struct eth_bridge_iface_context * ctx)39 static void unlock_bridge(struct eth_bridge_iface_context *ctx)
40 {
41 k_mutex_unlock(&ctx->lock);
42 }
43
44 struct ud {
45 eth_bridge_cb_t cb;
46 void *user_data;
47 };
48
iface_cb(struct net_if * iface,void * user_data)49 static void iface_cb(struct net_if *iface, void *user_data)
50 {
51 struct ud *br_user_data = user_data;
52 struct eth_bridge_iface_context *ctx;
53 enum virtual_interface_caps caps;
54
55 if (net_if_l2(iface) != &NET_L2_GET_NAME(VIRTUAL)) {
56 return;
57 }
58
59 caps = net_virtual_get_iface_capabilities(iface);
60 if (!(caps & VIRTUAL_INTERFACE_BRIDGE)) {
61 return;
62 }
63
64 ctx = net_if_get_device(iface)->data;
65
66 br_user_data->cb(ctx, br_user_data->user_data);
67 }
68
net_eth_bridge_foreach(eth_bridge_cb_t cb,void * user_data)69 void net_eth_bridge_foreach(eth_bridge_cb_t cb, void *user_data)
70 {
71 struct ud br_user_data = {
72 .cb = cb,
73 .user_data = user_data,
74 };
75
76 net_if_foreach(iface_cb, &br_user_data);
77 }
78
eth_bridge_get_index(struct net_if * br)79 int eth_bridge_get_index(struct net_if *br)
80 {
81 return net_if_get_by_iface(br);
82 }
83
eth_bridge_get_by_index(int index)84 struct net_if *eth_bridge_get_by_index(int index)
85 {
86 return net_if_get_by_index(index);
87 }
88
eth_bridge_iface_add(struct net_if * br,struct net_if * iface)89 int eth_bridge_iface_add(struct net_if *br, struct net_if *iface)
90 {
91 struct eth_bridge_iface_context *ctx = net_if_get_device(br)->data;
92 struct ethernet_context *eth_ctx = net_if_l2_data(iface);
93 bool found = false;
94 int count = 0;
95 int ret;
96
97 if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET) ||
98 !(net_eth_get_hw_capabilities(iface) & ETHERNET_PROMISC_MODE)) {
99 return -EINVAL;
100 }
101
102 if (net_if_l2(br) != &NET_L2_GET_NAME(VIRTUAL) ||
103 !(net_virtual_get_iface_capabilities(br) & VIRTUAL_INTERFACE_BRIDGE)) {
104 return -EINVAL;
105 }
106
107 lock_bridge(ctx);
108
109 if (eth_ctx->bridge == br) {
110 /* This Ethernet interface was already added to the bridge */
111 found = true;
112 }
113
114 ARRAY_FOR_EACH(ctx->eth_iface, i) {
115 if (!found && ctx->eth_iface[i] == NULL) {
116 ctx->eth_iface[i] = iface;
117 eth_ctx->bridge = br;
118 found = true;
119 }
120
121 /* Calculate how many interfaces are added to this bridge */
122 if (ctx->eth_iface[i] != NULL) {
123 struct ethernet_context *tmp = net_if_l2_data(ctx->eth_iface[i]);
124
125 if (tmp->bridge == br) {
126 count++;
127 }
128 }
129 }
130
131 unlock_bridge(ctx);
132
133 if (!found) {
134 return -ENOMEM;
135 }
136
137 ret = net_eth_promisc_mode(iface, true);
138 if (ret != 0 && ret != -EALREADY) {
139 /* Ignore any errors when using native-sim driver,
140 * we do not need host promiscuous working when testing
141 * bridging using native-sim.
142 */
143 if (!IS_ENABLED(CONFIG_ETH_NATIVE_POSIX)) {
144 NET_DBG("iface %d promiscuous mode failed: %d",
145 net_if_get_by_iface(iface), ret);
146 eth_bridge_iface_remove(br, iface);
147 return ret;
148 }
149 }
150
151 NET_DBG("iface %d added to bridge %d", net_if_get_by_iface(iface),
152 net_if_get_by_iface(br));
153
154 if (count > 1) {
155 ctx->is_setup = true;
156
157 NET_INFO("Bridge %d is %ssetup", net_if_get_by_iface(eth_ctx->bridge), "");
158
159 net_virtual_set_name(ctx->iface, "<config ok>");
160 }
161
162 ctx->count = count;
163
164 return 0;
165 }
166
eth_bridge_iface_remove(struct net_if * br,struct net_if * iface)167 int eth_bridge_iface_remove(struct net_if *br, struct net_if *iface)
168 {
169 struct eth_bridge_iface_context *ctx = net_if_get_device(br)->data;
170 struct ethernet_context *eth_ctx = net_if_l2_data(iface);
171 bool found = false;
172 int count = 0;
173
174 if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
175 return -EINVAL;
176 }
177
178 if (net_if_l2(br) != &NET_L2_GET_NAME(VIRTUAL) ||
179 !(net_virtual_get_iface_capabilities(br) & VIRTUAL_INTERFACE_BRIDGE)) {
180 return -EINVAL;
181 }
182
183 lock_bridge(ctx);
184
185 ARRAY_FOR_EACH(ctx->eth_iface, i) {
186 if (!found && ctx->eth_iface[i] == iface) {
187 ctx->eth_iface[i] = NULL;
188 eth_ctx->bridge = NULL;
189 found = true;
190 }
191
192 /* Calculate how many interfaces are added to this bridge */
193 if (ctx->eth_iface[i] != NULL) {
194 struct ethernet_context *tmp = net_if_l2_data(ctx->eth_iface[i]);
195
196 if (tmp->bridge == br) {
197 count++;
198 }
199 }
200 }
201
202 unlock_bridge(ctx);
203
204 NET_DBG("iface %d removed from bridge %d", net_if_get_by_iface(iface),
205 net_if_get_by_iface(br));
206
207 if (count < 2) {
208 ctx->is_setup = false;
209
210 NET_INFO("Bridge %d is %ssetup", net_if_get_by_iface(br), "not ");
211
212 net_virtual_set_name(ctx->iface, "<no config>");
213 }
214
215 ctx->count = count;
216
217 return 0;
218 }
219
is_link_local_addr(struct net_eth_addr * addr)220 static inline bool is_link_local_addr(struct net_eth_addr *addr)
221 {
222 if (addr->addr[0] == 0x01 &&
223 addr->addr[1] == 0x80 &&
224 addr->addr[2] == 0xc2 &&
225 addr->addr[3] == 0x00 &&
226 addr->addr[4] == 0x00 &&
227 (addr->addr[5] & 0x0f) == 0x00) {
228 return true;
229 }
230
231 return false;
232 }
233
random_linkaddr(uint8_t * linkaddr,size_t len)234 static void random_linkaddr(uint8_t *linkaddr, size_t len)
235 {
236 sys_rand_get(linkaddr, len);
237 }
238
bridge_iface_init(struct net_if * iface)239 static void bridge_iface_init(struct net_if *iface)
240 {
241 struct eth_bridge_iface_context *ctx = net_if_get_device(iface)->data;
242 struct virtual_interface_context *vctx = net_if_l2_data(iface);
243 char name[MAX_BRIDGE_NAME_LEN];
244
245 if (ctx->is_init) {
246 return;
247 }
248
249 k_mutex_init(&ctx->lock);
250
251 ctx->iface = iface;
252
253 net_if_flag_set(iface, NET_IF_NO_AUTO_START);
254 net_if_flag_clear(iface, NET_IF_IPV4);
255 net_if_flag_clear(iface, NET_IF_IPV6);
256 net_if_flag_clear(iface, NET_IF_FORWARD_MULTICASTS);
257
258 net_virtual_set_flags(iface, NET_L2_PROMISC_MODE);
259
260 snprintk(name, sizeof(name), "bridge%d", ctx->id);
261 net_if_set_name(iface, name);
262
263 net_virtual_set_name(iface, "<no config>");
264
265 /* We need to set the link address here as normally it would be set in
266 * virtual interface API attach function but we do not use that in
267 * bridging.
268 */
269 random_linkaddr(vctx->lladdr.addr, sizeof(vctx->lladdr.addr));
270
271 vctx->lladdr.len = sizeof(vctx->lladdr.addr);
272 vctx->lladdr.type = NET_LINK_UNKNOWN;
273
274 net_if_set_link_addr(iface, vctx->lladdr.addr,
275 vctx->lladdr.len, vctx->lladdr.type);
276
277 ctx->is_init = true;
278 ctx->is_setup = false;
279 }
280
bridge_get_capabilities(struct net_if * iface)281 static enum virtual_interface_caps bridge_get_capabilities(struct net_if *iface)
282 {
283 ARG_UNUSED(iface);
284
285 return VIRTUAL_INTERFACE_BRIDGE;
286 }
287
bridge_iface_start(const struct device * dev)288 static int bridge_iface_start(const struct device *dev)
289 {
290 struct eth_bridge_iface_context *ctx = dev->data;
291
292 if (!ctx->is_setup) {
293 NET_DBG("Bridge interface %d not configured yet.",
294 net_if_get_by_iface(ctx->iface));
295 return -ENOENT;
296 }
297
298 if (ctx->status) {
299 return -EALREADY;
300 }
301
302 ctx->status = true;
303
304 NET_DBG("Starting iface %d", net_if_get_by_iface(ctx->iface));
305
306 NET_INFO("Bridge %d is %sactive", net_if_get_by_iface(ctx->iface), "");
307
308 net_virtual_set_name(ctx->iface, "<enabled>");
309
310 return 0;
311 }
312
bridge_iface_stop(const struct device * dev)313 static int bridge_iface_stop(const struct device *dev)
314 {
315 struct eth_bridge_iface_context *ctx = dev->data;
316
317 if (!ctx->status) {
318 return -EALREADY;
319 }
320
321 ctx->status = false;
322
323 NET_DBG("Stopping iface %d", net_if_get_by_iface(ctx->iface));
324
325 NET_INFO("Bridge %d is %sactive", net_if_get_by_iface(ctx->iface), "not ");
326
327 if (ctx->is_setup) {
328 net_virtual_set_name(ctx->iface, "<disabled>");
329 } else {
330 net_virtual_set_name(ctx->iface, "<no config>");
331 }
332
333 return 0;
334 }
335
bridge_iface_process(struct net_if * iface,struct net_pkt * pkt,bool is_send)336 static enum net_verdict bridge_iface_process(struct net_if *iface,
337 struct net_pkt *pkt,
338 bool is_send)
339 {
340 struct eth_bridge_iface_context *ctx = net_if_get_device(iface)->data;
341 struct net_if *orig_iface;
342 struct net_pkt *send_pkt;
343 size_t count;
344
345 /* Drop all link-local packets for now. */
346 if (is_link_local_addr((struct net_eth_addr *)net_pkt_lladdr_dst(pkt))) {
347 NET_DBG("DROP: lladdr");
348 goto out;
349 }
350
351 lock_bridge(ctx);
352
353 /* Keep the original packet interface so that we can send to each
354 * bridged interface.
355 */
356 orig_iface = net_pkt_orig_iface(pkt);
357
358 count = ctx->count;
359
360 /* Pass the data to all the Ethernet interface except the originator
361 * Ethernet interface.
362 */
363 ARRAY_FOR_EACH(ctx->eth_iface, i) {
364 if (ctx->eth_iface[i] != NULL && ctx->eth_iface[i] != orig_iface) {
365 /* Skip it if not up */
366 if (!net_if_flag_is_set(ctx->eth_iface[i], NET_IF_UP)) {
367 continue;
368 }
369
370 /* Clone the packet if we have more than two interfaces in the bridge
371 * because the first send might mess the data part of the message.
372 */
373 if (count > 2) {
374 send_pkt = net_pkt_clone(pkt, K_NO_WAIT);
375 if (send_pkt == NULL) {
376 NET_DBG("DROP: clone failed");
377 break;
378 }
379
380 net_pkt_ref(send_pkt);
381 } else {
382 send_pkt = net_pkt_ref(pkt);
383 }
384
385 net_pkt_set_family(send_pkt, AF_UNSPEC);
386 net_pkt_set_iface(send_pkt, ctx->eth_iface[i]);
387 net_if_queue_tx(ctx->eth_iface[i], send_pkt);
388
389 NET_DBG("%s iface %d pkt %p (ref %d)",
390 is_send ? "Send" : "Recv",
391 net_if_get_by_iface(ctx->eth_iface[i]),
392 send_pkt, (int)atomic_get(&send_pkt->atomic_ref));
393
394 net_pkt_unref(send_pkt);
395 }
396 }
397
398 unlock_bridge(ctx);
399
400 out:
401 /* The packet was cloned by the caller so remove it here. */
402 net_pkt_unref(pkt);
403
404 return NET_OK;
405 }
406
bridge_iface_send(struct net_if * iface,struct net_pkt * pkt)407 int bridge_iface_send(struct net_if *iface, struct net_pkt *pkt)
408 {
409 if (DEBUG_TX) {
410 char str[sizeof("TX iface xx")];
411
412 snprintk(str, sizeof(str), "TX iface %d",
413 net_if_get_by_iface(net_pkt_iface(pkt)));
414
415 net_pkt_hexdump(pkt, str);
416 }
417
418 (void)bridge_iface_process(iface, pkt, true);
419
420 return 0;
421 }
422
bridge_iface_recv(struct net_if * iface,struct net_pkt * pkt)423 static enum net_verdict bridge_iface_recv(struct net_if *iface,
424 struct net_pkt *pkt)
425 {
426 if (DEBUG_RX) {
427 char str[sizeof("RX iface xx")];
428
429 snprintk(str, sizeof(str), "RX iface %d",
430 net_if_get_by_iface(net_pkt_iface(pkt)));
431
432 net_pkt_hexdump(pkt, str);
433 }
434
435 return bridge_iface_process(iface, pkt, false);
436 }
437
438 /* We cannot attach the bridge interface to Ethernet interface because
439 * the attachment can be done to only one Ethernet interface and we
440 * need to "attach" at least two Ethernet interfaces to the bridge interface.
441 * So we return -ENOTSUP here so that the attachment fails if it is tried.
442 */
bridge_iface_attach(struct net_if * br,struct net_if * iface)443 static int bridge_iface_attach(struct net_if *br,
444 struct net_if *iface)
445 {
446 ARG_UNUSED(br);
447 ARG_UNUSED(iface);
448
449 return -ENOTSUP;
450 }
451
452 static const struct virtual_interface_api bridge_iface_api = {
453 .iface_api.init = bridge_iface_init,
454
455 .get_capabilities = bridge_get_capabilities,
456 .start = bridge_iface_start,
457 .stop = bridge_iface_stop,
458 .send = bridge_iface_send,
459 .recv = bridge_iface_recv,
460 .attach = bridge_iface_attach,
461 };
462
463 #define ETH_DEFINE_BRIDGE(x, _) \
464 static struct eth_bridge_iface_context bridge_context_data_##x = { \
465 .id = x, \
466 }; \
467 NET_VIRTUAL_INTERFACE_INIT_INSTANCE(bridge_##x, \
468 "BRIDGE_" #x, \
469 x, \
470 NULL, \
471 NULL, \
472 &bridge_context_data_##x, \
473 NULL, /* config */ \
474 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
475 &bridge_iface_api, \
476 NET_ETH_MTU)
477
478 LISTIFY(CONFIG_NET_ETHERNET_BRIDGE_COUNT, ETH_DEFINE_BRIDGE, (;), _);
479