Skip to content

Commit a2b554c

Browse files
Cristib05jhedberg
authored andcommitted
net: l2: openthread: Improve Border Router packet forwarding logic
There are some cases when OpenThread opens a sockets and doesn't choose as default it's internal interface, this leading to usage of platform UDP module which will then send back the packet to the OpenThread interface. In this case, the packet should not be treated as originated from backbone interface. Backbone router multicast listener callback functionality is improved. A route with a prefix length of 128 is set and a multicast address is added for each listener registration. OpenThread interface joins that multicast address group. Enabled forwarding capabilities for Backbone interface. A border router should be able to perform default packet forwarding for destination addresses with a multicast scope greater than admin-local. In order to achieve this, multicast routes have been added to those addreses. [https://datatracker.ietf.org/doc/rfc7346/] For Border Router application, `ip6_addr_cb` is not installed. otIp6SubscribeMulticastAddress call would re-register an IPV6 multicast address which might have been registered by an OpenThread node using `ipmadd add` command and even if that node performed `ipmaddr del`, the address was still present in multicast listener table. This also led to a missing MLDv2 message with that specific multicast IPV6 address. Signed-off-by: Cristian Bulacu <[email protected]>
1 parent f00aeb4 commit a2b554c

File tree

2 files changed

+80
-8
lines changed

2 files changed

+80
-8
lines changed

subsys/net/l2/openthread/openthread.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,9 +316,12 @@ static int openthread_l2_init(struct net_if *iface)
316316
ot_l2_context->iface = iface;
317317

318318
if (!IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) {
319-
net_mgmt_init_event_callback(&ip6_addr_cb, ipv6_addr_event_handler,
320-
NET_EVENT_IPV6_ADDR_ADD | NET_EVENT_IPV6_MADDR_ADD);
321-
net_mgmt_add_event_callback(&ip6_addr_cb);
319+
if (!IS_ENABLED(CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER)) {
320+
net_mgmt_init_event_callback(&ip6_addr_cb, ipv6_addr_event_handler,
321+
NET_EVENT_IPV6_ADDR_ADD |
322+
NET_EVENT_IPV6_MADDR_ADD);
323+
net_mgmt_add_event_callback(&ip6_addr_cb);
324+
}
322325
net_if_dormant_on(iface);
323326

324327
openthread_set_receive_cb(ot_receive_handler, (void *)ot_l2_context);

subsys/net/l2/openthread/openthread_border_router.c

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <ipv6.h>
2626
#include <zephyr/net/net_mgmt.h>
2727
#include <zephyr/net/openthread.h>
28+
#include <zephyr/sys/util.h>
2829

2930
#include <inttypes.h>
3031
#include <stdarg.h>
@@ -38,6 +39,7 @@ static struct net_mgmt_event_callback ail_net_event_ipv4_addr_add_cb;
3839
#endif /* CONFIG_NET_IPV4 */
3940
static uint32_t ail_iface_index;
4041
static struct net_if *ail_iface_ptr;
42+
static struct net_if *ot_iface_ptr;
4143
static bool is_border_router_started;
4244
char otbr_vendor_name[] = OTBR_VENDOR_NAME;
4345
char otbr_base_service_instance_name[] = OTBR_BASE_SERVICE_INSTANCE_NAME;
@@ -53,6 +55,7 @@ K_MEM_SLAB_DEFINE_STATIC(border_router_messages_slab, sizeof(struct otbr_msg_ctx
5355
CONFIG_OPENTHREAD_ZEPHYR_BORDER_ROUTER_MSG_POOL_NUM, sizeof(void *));
5456

5557
static const char *create_base_name(otInstance *ot_instance, char *base_name);
58+
static void openthread_border_router_add_route_to_multicast_groups(void);
5659

5760
#if defined(CONFIG_NET_IPV4)
5861
static void openthread_border_router_check_for_dhcpv4_addr(struct net_if *iface,
@@ -66,8 +69,12 @@ int openthread_start_border_router_services(struct net_if *ot_iface, struct net_
6669
otInstance *instance = openthread_get_default_instance();
6770
ail_iface_index = (uint32_t)net_if_get_by_iface(ail_iface);
6871
ail_iface_ptr = ail_iface;
72+
ot_iface_ptr = ot_iface;
6973

7074
net_if_flag_set(ot_iface, NET_IF_FORWARD_MULTICASTS);
75+
net_if_flag_set(ail_iface, NET_IF_FORWARD_MULTICASTS);
76+
77+
openthread_border_router_add_route_to_multicast_groups();
7178

7279
openthread_mutex_lock();
7380

@@ -266,19 +273,43 @@ static void ot_bbr_multicast_listener_handler(void *context,
266273
otBackboneRouterMulticastListenerEvent event,
267274
const otIp6Address *address)
268275
{
269-
struct openthread_context *ot_context = context;
270-
struct in6_addr mcast_prefix = {0};
276+
struct openthread_context *ot_context = (struct openthread_context *)context;
277+
struct in6_addr recv_addr = {0};
278+
struct net_if_mcast_addr *mcast_addr = NULL;
279+
struct net_route_entry_mcast *entry = NULL;
271280

272-
memcpy(mcast_prefix.s6_addr, address->mFields.m32, sizeof(otIp6Address));
281+
memcpy(recv_addr.s6_addr, address->mFields.m32, sizeof(otIp6Address));
273282

274283
if (event == OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ADDED) {
275-
net_route_mcast_add((struct net_if *)ot_context->iface, &mcast_prefix, 16);
284+
entry = net_route_mcast_lookup(&recv_addr);
285+
if (entry == NULL) {
286+
entry = net_route_mcast_add(ot_context->iface, &recv_addr,
287+
NUM_BITS(struct in6_addr));
288+
}
289+
if (entry != NULL) {
290+
/*
291+
* No need to perform mcast_lookup explicitly as it's already done in
292+
* net_if_ipv6_maddr_add call. If it's found, NULL will be returned
293+
* and maddr_join will not be performed.
294+
*/
295+
mcast_addr = net_if_ipv6_maddr_add(ot_context->iface,
296+
(const struct in6_addr *)&recv_addr);
297+
if (mcast_addr != NULL) {
298+
net_if_ipv6_maddr_join(ot_context->iface, mcast_addr);
299+
}
300+
}
276301
} else {
277-
struct net_route_entry_mcast *route_to_del = net_route_mcast_lookup(&mcast_prefix);
302+
struct net_route_entry_mcast *route_to_del = net_route_mcast_lookup(&recv_addr);
303+
struct net_if_mcast_addr *addr_to_del;
278304

305+
addr_to_del = net_if_ipv6_maddr_lookup(&recv_addr, &(ot_context->iface));
279306
if (route_to_del != NULL) {
280307
net_route_mcast_del(route_to_del);
281308
}
309+
310+
if (addr_to_del != NULL && net_if_ipv6_maddr_is_joined(addr_to_del)) {
311+
net_if_ipv6_maddr_leave(ot_context->iface, addr_to_del);
312+
}
282313
}
283314
}
284315

@@ -479,6 +510,18 @@ static bool openthread_border_router_check_unicast_packet_forwarding_policy(stru
479510
return false;
480511
}
481512

513+
/*
514+
* This is the case when a packet from OpenThread stack is sent via UDP platform.
515+
* Packet will be eventually returned to OpenThread interface, but it won't have
516+
* orig_iface set, an indication that the packet was not forwarded from another interface.
517+
* In this case, this function should not check and let the packet be handled by
518+
* 15.4 layer.
519+
*/
520+
521+
if (net_pkt_orig_iface(pkt) != ail_iface_ptr && net_pkt_iface(pkt) == ot_iface_ptr) {
522+
return true;
523+
}
524+
482525
/* An IPv6 packet with a link-local source address or a link-local destination address
483526
* is never forwarded.
484527
*/
@@ -536,3 +579,29 @@ bool openthread_border_router_check_packet_forwarding_rules(struct net_pkt *pkt)
536579

537580
return true;
538581
}
582+
583+
static void openthread_border_router_add_route_to_multicast_groups(void)
584+
{
585+
static uint8_t mcast_group_idx[] = {
586+
0x04, /** Admin-Local scope multicast address */
587+
0x05, /** Site-Local scope multicast address */
588+
0x08, /** Organization-Local scope multicast address */
589+
0x0e, /** Global scope multicast address */
590+
};
591+
struct in6_addr addr = {0};
592+
struct net_if_mcast_addr *mcast_addr = NULL;
593+
struct net_route_entry_mcast *entry = NULL;
594+
595+
ARRAY_FOR_EACH(mcast_group_idx, i) {
596+
597+
net_ipv6_addr_create(&addr, (0xff << 8) | mcast_group_idx[i], 0, 0, 0, 0, 0, 0, 1);
598+
entry = net_route_mcast_add(ail_iface_ptr, &addr, NUM_BITS(struct in6_addr));
599+
if (entry != NULL) {
600+
mcast_addr = net_if_ipv6_maddr_add(ail_iface_ptr,
601+
(const struct in6_addr *)&addr);
602+
if (mcast_addr != NULL) {
603+
net_if_ipv6_maddr_join(ail_iface_ptr, mcast_addr);
604+
}
605+
}
606+
}
607+
}

0 commit comments

Comments
 (0)