From 61dca2b8bfcb92062fb71a49f2f5e1ccd026fcf8 Mon Sep 17 00:00:00 2001 From: Konrad Derda Date: Tue, 26 Mar 2024 20:05:20 +0100 Subject: [PATCH] net: ipv6: add multiple interfaces to multicast routing entry In order to save memory, a single multicast routing entry now contains configurable number of network interfaces. Signed-off-by: Konrad Derda --- subsys/net/ip/Kconfig | 9 ++++ subsys/net/ip/route.c | 100 ++++++++++++++++++++++++++++++++---------- subsys/net/ip/route.h | 29 +++++++++++- 3 files changed, 114 insertions(+), 24 deletions(-) diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index bc5bdec35c..4c44d59d4c 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -426,6 +426,15 @@ config NET_MAX_MCAST_ROUTES This determines how many entries can be stored in multicast routing table. +config NET_MCAST_ROUTE_MAX_IFACES + int "Max number of network interfaces per multicast routing entry" + default 1 + range 1 8 + depends on NET_ROUTE_MCAST + help + Determines how many network interfaces can be assigned to a + single multicast route entry. + source "subsys/net/ip/Kconfig.tcp" config NET_TEST_PROTOCOL diff --git a/subsys/net/ip/route.c b/subsys/net/ip/route.c index 29751b419e..184b538b85 100644 --- a/subsys/net/ip/route.c +++ b/subsys/net/ip/route.c @@ -729,6 +729,55 @@ int net_route_foreach(net_route_cb_t cb, void *user_data) static struct net_route_entry_mcast route_mcast_entries[CONFIG_NET_MAX_MCAST_ROUTES]; +static int mcast_route_iface_lookup(struct net_route_entry_mcast *entry, struct net_if *iface) +{ + ARRAY_FOR_EACH(entry->ifaces, i) { + if (entry->ifaces[i] == iface) { + return i; + } + } + + return -1; +} + +bool net_route_mcast_iface_add(struct net_route_entry_mcast *entry, struct net_if *iface) +{ + if (!net_if_flag_is_set(iface, NET_IF_FORWARD_MULTICASTS)) { + return false; + } + + if (mcast_route_iface_lookup(entry, iface) >= 0) { + /* Interface is already added */ + return true; + } + + ARRAY_FOR_EACH(entry->ifaces, i) { + if (entry->ifaces[i] == NULL) { + entry->ifaces[i] = iface; + + return true; + } + } + + /* There are no empty slots */ + return false; +} + +bool net_route_mcast_iface_del(struct net_route_entry_mcast *entry, + struct net_if *iface) +{ + int pos = mcast_route_iface_lookup(entry, iface); + + if (pos < 0) { + return false; + } + + entry->ifaces[pos] = NULL; + + return true; +} + + int net_route_mcast_forward_packet(struct net_pkt *pkt, const struct net_ipv6_hdr *hdr) { @@ -737,34 +786,34 @@ int net_route_mcast_forward_packet(struct net_pkt *pkt, ARRAY_FOR_EACH_PTR(route_mcast_entries, route) { struct net_pkt *pkt_cpy = NULL; - if (!route->is_used) { + if (!route->is_used || + !net_ipv6_is_prefix(hdr->dst, route->group.s6_addr, route->prefix_len)) { continue; } - if (!net_if_flag_is_set(route->iface, - NET_IF_FORWARD_MULTICASTS) || - !net_ipv6_is_prefix(hdr->dst, - route->group.s6_addr, - route->prefix_len) || - (pkt->iface == route->iface)) { - continue; - } + ARRAY_FOR_EACH(route->ifaces, i) { + if (!route->ifaces[i] || pkt->iface == route->ifaces[i] || + !net_if_flag_is_set(route->ifaces[i], NET_IF_FORWARD_MULTICASTS)) { + continue; + } - pkt_cpy = net_pkt_shallow_clone(pkt, K_NO_WAIT); + pkt_cpy = net_pkt_shallow_clone(pkt, K_NO_WAIT); - if (pkt_cpy == NULL) { - err--; - continue; - } + if (pkt_cpy == NULL) { + err--; + continue; + } - net_pkt_set_forwarding(pkt_cpy, true); - net_pkt_set_iface(pkt_cpy, route->iface); + net_pkt_set_forwarding(pkt_cpy, true); + net_pkt_set_orig_iface(pkt_cpy, pkt->iface); + net_pkt_set_iface(pkt_cpy, route->ifaces[i]); - if (net_send_data(pkt_cpy) >= 0) { - ++ret; - } else { - net_pkt_unref(pkt_cpy); - --err; + if (net_send_data(pkt_cpy) >= 0) { + ++ret; + } else { + net_pkt_unref(pkt_cpy); + --err; + } } } @@ -812,8 +861,12 @@ struct net_route_entry_mcast *net_route_mcast_add(struct net_if *iface, if (!route->is_used) { net_ipaddr_copy(&route->group, group); + ARRAY_FOR_EACH(route->ifaces, i) { + route->ifaces[i] = NULL; + } + route->prefix_len = prefix_len; - route->iface = iface; + route->ifaces[0] = iface; route->is_used = true; net_ipv6_nbr_unlock(); @@ -1016,5 +1069,8 @@ void net_route_init(void) NET_DBG("Allocated %d nexthop entries (%zu bytes)", CONFIG_NET_MAX_NEXTHOPS, sizeof(net_route_nexthop_pool)); +#if defined(CONFIG_NET_ROUTE_MCAST) + memset(route_mcast_entries, 0, sizeof(route_mcast_entries)); +#endif k_work_init_delayable(&route_lifetime_timer, route_lifetime_timeout); } diff --git a/subsys/net/ip/route.h b/subsys/net/ip/route.h index 1f2d36ee4a..e6dc4a1aac 100644 --- a/subsys/net/ip/route.h +++ b/subsys/net/ip/route.h @@ -183,12 +183,13 @@ typedef void (*net_route_cb_t)(struct net_route_entry *entry, */ int net_route_foreach(net_route_cb_t cb, void *user_data); +#if defined(CONFIG_NET_ROUTE_MCAST) /** * @brief Multicast route entry. */ struct net_route_entry_mcast { - /** Network interface for the route. */ - struct net_if *iface; + /** Network interfaces for the route. */ + struct net_if *ifaces[CONFIG_NET_MCAST_ROUTE_MAX_IFACES]; /** Extra routing engine specific data */ void *data; @@ -205,6 +206,9 @@ struct net_route_entry_mcast { /** IPv6 multicast group prefix length. */ uint8_t prefix_len; }; +#else +struct net_route_entry_mcast; +#endif typedef void (*net_route_mcast_cb_t)(struct net_route_entry_mcast *entry, void *user_data); @@ -268,6 +272,27 @@ bool net_route_mcast_del(struct net_route_entry_mcast *route); struct net_route_entry_mcast * net_route_mcast_lookup(struct in6_addr *group); +/** + * @brief Add an interface to multicast routing entry. + * + * @param entry Multicast routing entry. + * @param iface Network interface to be added. + * + * @return True if the interface was added or found on the + * list, false otherwise. + */ +bool net_route_mcast_iface_add(struct net_route_entry_mcast *entry, struct net_if *iface); + +/** + * @brief Delete an interface from multicast routing entry. + * + * @param entry Multicast routing entry. + * @param iface Network interface to be deleted. + * + * @return True if entry was deleted, false otherwise. + */ +bool net_route_mcast_iface_del(struct net_route_entry_mcast *entry, struct net_if *iface); + /** * @brief Return a route to destination via some intermediate host. *