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 <konrad.derda@nordicsemi.no>
This commit is contained in:
Konrad Derda 2024-03-26 20:05:20 +01:00 committed by Alberto Escolar
parent 97fc5ea597
commit 61dca2b8bf
3 changed files with 114 additions and 24 deletions

View file

@ -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

View file

@ -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);
}

View file

@ -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.
*