net/route: Support longest prefix match for routing

Support longest prefix match routing described as "Longest Match" in
RFC 1812, Section 5.2.4.3, Page 75.

Introduced `prefixlen` to indicate the prefix length of currently
founded route, and only looks up for longer prefix in all later steps.

Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
Zhe Weng 2023-12-29 16:12:11 +08:00 committed by Xiang Xiao
parent 54f3452293
commit 3b74cfecc2
7 changed files with 433 additions and 114 deletions

View file

@ -79,9 +79,10 @@ struct neighbor_addr_s
struct neighbor_entry_s
{
net_ipv6addr_t ne_ipaddr; /* IPv6 address of the Neighbor */
struct neighbor_addr_s ne_addr; /* Link layer address of the Neighbor */
clock_t ne_time; /* For aging, units of tick */
net_ipv6addr_t ne_ipaddr; /* IPv6 address of the Neighbor */
struct neighbor_addr_s ne_addr; /* Link layer address of the Neighbor */
clock_t ne_time; /* For aging, units of tick */
FAR struct net_driver_s *ne_dev; /* The device driver structure */
};
#ifdef __cplusplus

View file

@ -99,6 +99,7 @@ void neighbor_add(FAR struct net_driver_s *dev, FAR net_ipv6addr_t ipaddr,
* "oldest_ndx" variable).
*/
g_neighbors[oldest_ndx].ne_dev = dev;
g_neighbors[oldest_ndx].ne_time = clock_systime_ticks();
net_ipv6addr_copy(g_neighbors[oldest_ndx].ne_ipaddr, ipaddr);

View file

@ -25,6 +25,7 @@
#include <nuttx/config.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <debug.h>
@ -34,12 +35,219 @@
#include <nuttx/net/netdev.h>
#include <nuttx/net/ip.h>
#include "arp/arp.h"
#include "neighbor/neighbor.h"
#include "utils/utils.h"
#include "devif/devif.h"
#include "inet/inet.h"
#include "route/route.h"
#include "netdev/netdev.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: netdev_prefixlen_findby_lipv4addr
*
* Description:
* Find a previously registered network device by matching a local address
* with the subnet served by the device. Only "up" devices are considered
* (since a "down" device has no meaningful address).
*
* Input Parameters:
* lipaddr - Local, IPv4 address assigned to the network device. Or any
* IPv4 address on the sub-net served by the network device.
* prefixlen - The length of matching prefix. Range: -1(no match) ~ 32
*
* Returned Value:
* Pointer to driver on success; null on failure
*
****************************************************************************/
#ifdef CONFIG_NET_IPv4
static FAR struct net_driver_s *
netdev_prefixlen_findby_lipv4addr(in_addr_t lipaddr, FAR int8_t *prefixlen)
{
FAR struct net_driver_s *dev;
FAR struct net_driver_s *bestdev = NULL;
int8_t bestpref = -1;
#ifdef CONFIG_ROUTE_LONGEST_MATCH
int8_t len;
#endif
/* Examine each registered network device */
net_lock();
for (dev = g_netdevices; dev; dev = dev->flink)
{
/* Is the interface in the "up" state? */
if ((dev->d_flags & IFF_UP) != 0 &&
!net_ipv4addr_cmp(dev->d_ipaddr, INADDR_ANY))
{
#ifndef CONFIG_ROUTE_LONGEST_MATCH
/* Yes.. check for an address match (under the netmask) */
if (net_ipv4addr_maskcmp(dev->d_ipaddr, lipaddr,
dev->d_netmask))
{
/* Its a match */
bestdev = dev;
bestpref = 32; /* Regard as best (exact) match */
break;
}
#else
/* Longest prefix flow: First, check for an exact address match */
if (net_ipv4addr_cmp(dev->d_ipaddr, lipaddr))
{
/* It's an exact match */
bestdev = dev;
bestpref = 32;
break;
}
/* Then, check for an address match (under the netmask) */
if (net_ipv4addr_maskcmp(dev->d_ipaddr, lipaddr,
dev->d_netmask))
{
len = (int8_t)net_ipv4_mask2pref(dev->d_netmask);
/* Regard current device as better if:
* 1. It has longer prefix length
* 2. It has the same prefix length but it has target address
* in the ARP cache (We don't have other information
* for the precedence of networks)
*/
if (len > bestpref
#ifdef CONFIG_NET_ARP
|| (len == bestpref && arp_find(lipaddr, NULL, dev) == OK)
#endif
)
{
bestdev = dev;
bestpref = len;
}
}
#endif /* CONFIG_ROUTE_LONGEST_MATCH */
}
}
net_unlock();
*prefixlen = bestpref;
return bestdev;
}
#endif /* CONFIG_NET_IPv4 */
/****************************************************************************
* Name: netdev_prefixlen_findby_lipv6addr
*
* Description:
* Find a previously registered network device by matching a local address
* with the subnet served by the device. Only "up" devices are considered
* (since a "down" device has no meaningful address).
*
* Input Parameters:
* lipaddr - Local, IPv6 address assigned to the network device. Or any
* IPv6 address on the sub-net served by the network device.
* prefixlen - The length of matching prefix. Range: -1(no match) ~ 128
*
* Returned Value:
* Pointer to driver on success; null on failure
*
****************************************************************************/
#ifdef CONFIG_NET_IPv6
static FAR struct net_driver_s *
netdev_prefixlen_findby_lipv6addr(const net_ipv6addr_t lipaddr,
FAR int16_t *prefixlen)
{
FAR struct net_driver_s *dev;
FAR struct net_driver_s *bestdev = NULL;
int16_t bestpref = -1;
#ifdef CONFIG_ROUTE_LONGEST_MATCH
FAR struct netdev_ifaddr6_s *ifaddr6;
FAR struct neighbor_entry_s *ne;
FAR struct net_driver_s *hint;
int16_t len;
#endif
net_lock();
#ifdef CONFIG_ROUTE_LONGEST_MATCH
/* Find a hint from neighbor table in case same prefix length exists on
* multiple devices.
*/
ne = neighbor_findentry(lipaddr);
hint = ne ? ne->ne_dev : NULL;
#endif
/* Examine each registered network device */
for (dev = g_netdevices; dev; dev = dev->flink)
{
/* Is the interface in the "up" state? */
if ((dev->d_flags & IFF_UP) != 0 && NETDEV_HAS_V6ADDR(dev))
{
#ifndef CONFIG_ROUTE_LONGEST_MATCH
/* Yes.. check for an address match (under the netmask) */
if (NETDEV_V6ADDR_ONLINK(dev, lipaddr))
{
/* Its a match */
bestdev = dev;
bestpref = 128; /* Regard as best (exact) match */
break;
}
#else
/* Longest prefix flow: First, check for an exact address match */
if (NETDEV_IS_MY_V6ADDR(dev, lipaddr))
{
/* It's an exact match */
bestdev = dev;
bestpref = 128;
break;
}
/* Then, check for an address match (under the netmask) */
if ((ifaddr6 = netdev_ipv6_lookup(dev, lipaddr, true)) != NULL)
{
len = (int16_t)net_ipv6_mask2pref(ifaddr6->mask);
/* Regard current device as better if:
* 1. It has longer prefix length
* 2. It has the same prefix length but it has target address
* in the neighbor cache (We don't have other information
* for the precedence of networks)
*/
if (len > bestpref || (len == bestpref && hint == dev))
{
bestdev = dev;
bestpref = len;
}
}
#endif /* CONFIG_ROUTE_LONGEST_MATCH */
}
}
net_unlock();
*prefixlen = bestpref;
return bestdev;
}
#endif /* CONFIG_NET_IPv6 */
/****************************************************************************
* Public Functions
****************************************************************************/
@ -64,35 +272,8 @@
#ifdef CONFIG_NET_IPv4
FAR struct net_driver_s *netdev_findby_lipv4addr(in_addr_t lipaddr)
{
FAR struct net_driver_s *dev;
/* Examine each registered network device */
net_lock();
for (dev = g_netdevices; dev; dev = dev->flink)
{
/* Is the interface in the "up" state? */
if ((dev->d_flags & IFF_UP) != 0 &&
!net_ipv4addr_cmp(dev->d_ipaddr, INADDR_ANY))
{
/* Yes.. check for an address match (under the netmask) */
if (net_ipv4addr_maskcmp(dev->d_ipaddr, lipaddr,
dev->d_netmask))
{
/* Its a match */
net_unlock();
return dev;
}
}
}
/* No device with the matching address found */
net_unlock();
return NULL;
int8_t prefixlen;
return netdev_prefixlen_findby_lipv4addr(lipaddr, &prefixlen);
}
#endif /* CONFIG_NET_IPv4 */
@ -117,33 +298,8 @@ FAR struct net_driver_s *netdev_findby_lipv4addr(in_addr_t lipaddr)
FAR struct net_driver_s *netdev_findby_lipv6addr(
const net_ipv6addr_t lipaddr)
{
FAR struct net_driver_s *dev;
/* Examine each registered network device */
net_lock();
for (dev = g_netdevices; dev; dev = dev->flink)
{
/* Is the interface in the "up" state? */
if ((dev->d_flags & IFF_UP) != 0 && NETDEV_HAS_V6ADDR(dev))
{
/* Yes.. check for an address match (under the netmask) */
if (NETDEV_V6ADDR_ONLINK(dev, lipaddr))
{
/* Its a match */
net_unlock();
return dev;
}
}
}
/* No device with the matching address found */
net_unlock();
return NULL;
int16_t prefixlen;
return netdev_prefixlen_findby_lipv6addr(lipaddr, &prefixlen);
}
#endif /* CONFIG_NET_IPv6 */
@ -168,7 +324,8 @@ FAR struct net_driver_s *netdev_findby_lipv6addr(
FAR struct net_driver_s *netdev_findby_ripv4addr(in_addr_t lipaddr,
in_addr_t ripaddr)
{
struct net_driver_s *dev;
FAR struct net_driver_s *dev;
int8_t prefixlen;
#ifdef CONFIG_NET_ROUTE
in_addr_t router;
int ret;
@ -198,22 +355,20 @@ FAR struct net_driver_s *netdev_findby_ripv4addr(in_addr_t lipaddr,
}
}
/* Check if the address maps to a locally available network */
/* Check if the address maps to a locally available network
* Note: If longest prefix match is not enabled, prefixlen will be 32 if
* matched and it will disable further routing lookup.
*/
dev = netdev_findby_lipv4addr(ripaddr);
if (dev)
{
return dev;
}
/* No.. The address lies on an external network */
dev = netdev_prefixlen_findby_lipv4addr(ripaddr, &prefixlen);
#ifdef CONFIG_NET_ROUTE
/* If we have a routing table, then perhaps we can find the local
* address of a router that can forward packets to the external network.
* address of a router that can forward packets to the external network
* with longer prefix.
*/
ret = net_ipv4_router(ripaddr, &router);
ret = net_ipv4_router(ripaddr, &router, prefixlen);
if (ret >= 0)
{
/* Success... try to find the network device associated with the local
@ -221,13 +376,16 @@ FAR struct net_driver_s *netdev_findby_ripv4addr(in_addr_t lipaddr,
*/
dev = netdev_findby_lipv4addr(router);
if (dev)
{
return dev;
}
}
#endif /* CONFIG_NET_ROUTE */
/* Return the device we found. */
if (dev)
{
return dev;
}
/* The above lookup will fail if the packet is being sent out of our
* out subnet to a router and there is no routing information. Let's
* try the default network device.
@ -259,7 +417,8 @@ FAR struct net_driver_s *netdev_findby_ripv6addr(
const net_ipv6addr_t lipaddr,
const net_ipv6addr_t ripaddr)
{
struct net_driver_s *dev;
FAR struct net_driver_s *dev;
int16_t prefixlen;
#ifdef CONFIG_NET_ROUTE
net_ipv6addr_t router;
int ret;
@ -291,22 +450,20 @@ FAR struct net_driver_s *netdev_findby_ripv6addr(
}
}
/* Check if the address maps to a locally available network */
/* Check if the address maps to a locally available network
* Note: If longest prefix match is not enabled, prefixlen will be 128 if
* matched and it will disable further routing lookup.
*/
dev = netdev_findby_lipv6addr(ripaddr);
if (dev)
{
return dev;
}
/* No.. The address lies on an external network */
dev = netdev_prefixlen_findby_lipv6addr(ripaddr, &prefixlen);
#ifdef CONFIG_NET_ROUTE
/* If we have a routing table, then perhaps we can find the local
* address of a router that can forward packets to the external network.
* address of a router that can forward packets to the external network
* with longer prefix.
*/
ret = net_ipv6_router(ripaddr, router);
ret = net_ipv6_router(ripaddr, router, prefixlen);
if (ret >= 0)
{
/* Success... try to find the network device associated with the local
@ -314,13 +471,16 @@ FAR struct net_driver_s *netdev_findby_ripv6addr(
*/
dev = netdev_findby_lipv6addr(router);
if (dev)
{
return dev;
}
}
#endif /* CONFIG_NET_ROUTE */
/* Return the device we found. */
if (dev)
{
return dev;
}
/* The above lookup will fail if the packet is being sent out of our
* out subnet to a router and there is no routing information. Let's
* try the default network device.

View file

@ -137,5 +137,12 @@ config ROUTE_MAX_IPv6_CACHEROUTES
This determines the maximum number of routes that can be cached in
memory.
config ROUTE_LONGEST_MATCH
bool "Enable longest prefix match support"
default y
---help---
Enable support for longest prefix match routing.
("Longest Match" in RFC 1812, Section 5.2.4.3, Page 75)
endif # NET_ROUTE
endmenu # ARP Configuration
endmenu # Routing Table Configuration

View file

@ -35,6 +35,7 @@
#include "devif/devif.h"
#include "route/cacheroute.h"
#include "route/route.h"
#include "utils/utils.h"
#if defined(CONFIG_NET) && defined(CONFIG_NET_ROUTE)
@ -67,6 +68,14 @@ struct route_ipv4_match_s
#else
in_addr_t router; /* IPv4 address of router a local networks */
#endif
#ifdef CONFIG_ROUTE_LONGEST_MATCH
/* Only match prefix longer than prefixlen, equals to entry.netmask if we
* have got a match (then we only find longer prefix later).
* Range: -1 ~ 32
*/
int8_t prefixlen;
#endif
};
#endif
@ -79,6 +88,14 @@ struct route_ipv6_match_s
#else
net_ipv6addr_t router; /* IPv6 address of router a local networks */
#endif
#ifdef CONFIG_ROUTE_LONGEST_MATCH
/* Only match prefix longer than prefixlen, equals to entry.netmask if we
* have got a match (then we only find longer prefix later).
* Range: -1 ~ 128
*/
int16_t prefixlen;
#endif
};
#endif
@ -106,13 +123,20 @@ static int net_ipv4_match(FAR struct net_route_ipv4_s *route, FAR void *arg)
{
FAR struct route_ipv4_match_s *match =
(FAR struct route_ipv4_match_s *)arg;
#ifdef CONFIG_ROUTE_LONGEST_MATCH
int8_t prefixlen = (int8_t)net_ipv4_mask2pref(route->netmask);
#endif
/* To match, the masked target addresses must be the same. In the event
* of multiple matches, only the first is returned. There is not (yet) any
* concept for the precedence of networks.
*/
if (net_ipv4addr_maskcmp(route->target, match->target, route->netmask))
if (net_ipv4addr_maskcmp(route->target, match->target, route->netmask)
#ifdef CONFIG_ROUTE_LONGEST_MATCH
&& prefixlen > match->prefixlen
#endif
)
{
#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE
/* They match.. Copy the entire routing table entry */
@ -123,7 +147,13 @@ static int net_ipv4_match(FAR struct net_route_ipv4_s *route, FAR void *arg)
net_ipv4addr_copy(match->router, route->router);
#endif
#ifdef CONFIG_ROUTE_LONGEST_MATCH
/* Cache the prefix length */
match->prefixlen = prefixlen;
#else
return 1;
#endif
}
return 0;
@ -150,13 +180,20 @@ static int net_ipv6_match(FAR struct net_route_ipv6_s *route, FAR void *arg)
{
FAR struct route_ipv6_match_s *match =
(FAR struct route_ipv6_match_s *)arg;
#ifdef CONFIG_ROUTE_LONGEST_MATCH
int16_t prefixlen = (int16_t)net_ipv6_mask2pref(route->netmask);
#endif
/* To match, the masked target addresses must be the same. In the event
* of multiple matches, only the first is returned. There is not (yet) any
* concept for the precedence of networks.
*/
if (net_ipv6addr_maskcmp(route->target, match->target, route->netmask))
if (net_ipv6addr_maskcmp(route->target, match->target, route->netmask)
#ifdef CONFIG_ROUTE_LONGEST_MATCH
&& prefixlen > match->prefixlen
#endif
)
{
#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE
/* They match.. Copy the entire routing table entry */
@ -167,7 +204,13 @@ static int net_ipv6_match(FAR struct net_route_ipv6_s *route, FAR void *arg)
net_ipv6addr_copy(match->router, route->router);
#endif
#ifdef CONFIG_ROUTE_LONGEST_MATCH
/* Cache the prefix length */
match->prefixlen = prefixlen;
#else
return 1;
#endif
}
return 0;
@ -186,9 +229,12 @@ static int net_ipv6_match(FAR struct net_route_ipv6_s *route, FAR void *arg)
* router on a local network that can forward to the external network.
*
* Input Parameters:
* target - An IPv4 address on a remote network to use in the lookup.
* router - The address of router on a local network that can forward our
* packets to the target.
* target - An IPv4 address on a remote network to use in the lookup.
* router - The address of router on a local network that can forward
* our packets to the target.
* prefixlen - The prefix length of previously matched routes (maybe on
* device), will only match prefix longer than prefixlen.
* Range: -1(match all) ~ 32(match none)
*
* Returned Value:
* OK on success; Negated errno on failure.
@ -196,11 +242,19 @@ static int net_ipv6_match(FAR struct net_route_ipv6_s *route, FAR void *arg)
****************************************************************************/
#ifdef CONFIG_NET_IPv4
int net_ipv4_router(in_addr_t target, FAR in_addr_t *router)
int net_ipv4_router(in_addr_t target, FAR in_addr_t *router,
int8_t prefixlen)
{
struct route_ipv4_match_s match;
int ret;
/* Just early return for long prefix, maybe already got exact match. */
if (prefixlen >= 32)
{
return -ENOENT;
}
/* Do not route the special broadcast IP address */
if (net_ipv4addr_cmp(target, INADDR_BROADCAST))
@ -212,6 +266,9 @@ int net_ipv4_router(in_addr_t target, FAR in_addr_t *router)
memset(&match, 0, sizeof(struct route_ipv4_match_s));
net_ipv4addr_copy(match.target, target);
#ifdef CONFIG_ROUTE_LONGEST_MATCH
match.prefixlen = prefixlen;
#endif
#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE
/* First see if we can find a router entry in the cache */
@ -229,7 +286,12 @@ int net_ipv4_router(in_addr_t target, FAR in_addr_t *router)
/* Did we find a route? */
#ifdef CONFIG_ROUTE_LONGEST_MATCH
UNUSED(ret);
if (match.prefixlen <= prefixlen)
#else
if (ret <= 0)
#endif
{
/* No.. there is no route for this address */
@ -261,9 +323,12 @@ int net_ipv4_router(in_addr_t target, FAR in_addr_t *router)
* router on a local network that can forward to the external network.
*
* Input Parameters:
* target - An IPv6 address on a remote network to use in the lookup.
* router - The address of router on a local network that can forward our
* packets to the target.
* target - An IPv6 address on a remote network to use in the lookup.
* router - The address of router on a local network that can forward
* our packets to the target.
* prefixlen - The prefix length of previously matched routes (maybe on
* device), will only match prefix longer than prefixlen.
* Range: -1(match all) ~ 128(match none)
*
* Returned Value:
* OK on success; Negated errno on failure.
@ -271,11 +336,19 @@ int net_ipv4_router(in_addr_t target, FAR in_addr_t *router)
****************************************************************************/
#ifdef CONFIG_NET_IPv6
int net_ipv6_router(const net_ipv6addr_t target, net_ipv6addr_t router)
int net_ipv6_router(const net_ipv6addr_t target, net_ipv6addr_t router,
int16_t prefixlen)
{
struct route_ipv6_match_s match;
int ret;
/* Just early return for long prefix, maybe already got exact match. */
if (prefixlen >= 128)
{
return -ENOENT;
}
/* Do not route to any the special IPv6 multicast addresses */
if (target[0] == HTONS(0xff02))
@ -287,6 +360,9 @@ int net_ipv6_router(const net_ipv6addr_t target, net_ipv6addr_t router)
memset(&match, 0, sizeof(struct route_ipv6_match_s));
net_ipv6addr_copy(match.target, target);
#ifdef CONFIG_ROUTE_LONGEST_MATCH
match.prefixlen = prefixlen;
#endif
#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE
/* First see if we can find a router entry in the cache */
@ -304,7 +380,12 @@ int net_ipv6_router(const net_ipv6addr_t target, net_ipv6addr_t router)
/* Did we find a route? */
#ifdef CONFIG_ROUTE_LONGEST_MATCH
UNUSED(ret);
if (match.prefixlen <= prefixlen)
#else
if (ret <= 0)
#endif
{
/* No.. there is no route for this address */

View file

@ -34,6 +34,7 @@
#include "netdev/netdev.h"
#include "route/cacheroute.h"
#include "route/route.h"
#include "utils/utils.h"
#if defined(CONFIG_NET) && defined(CONFIG_NET_ROUTE)
@ -67,6 +68,14 @@ struct route_ipv4_devmatch_s
#else
in_addr_t router; /* IPv4 address of router a local networks */
#endif
#ifdef CONFIG_ROUTE_LONGEST_MATCH
/* Only match prefix longer than prefixlen, equals to entry.netmask if we
* have got a match (then we only find longer prefix later).
* Range: -1 ~ 32
*/
int8_t prefixlen;
#endif
};
#endif
@ -80,6 +89,14 @@ struct route_ipv6_devmatch_s
#else
net_ipv6addr_t router; /* IPv6 address of router a local networks */
#endif
#ifdef CONFIG_ROUTE_LONGEST_MATCH
/* Only match prefix longer than prefixlen, equals to entry.netmask if we
* have got a match (then we only find longer prefix later).
* Range: -1 ~ 128
*/
int16_t prefixlen;
#endif
};
#endif
@ -109,16 +126,24 @@ static int net_ipv4_devmatch(FAR struct net_route_ipv4_s *route,
FAR struct route_ipv4_devmatch_s *match =
(FAR struct route_ipv4_devmatch_s *)arg;
FAR struct net_driver_s *dev = match->dev;
#ifdef CONFIG_ROUTE_LONGEST_MATCH
int8_t prefixlen = (int8_t)net_ipv4_mask2pref(route->netmask);
#endif
/* To match, (1) the masked target addresses must be the same, and (2) the
* router address must like on the network provided by the device.
*
* In the event of multiple matches, only the first is returned. There
* not (yet) any concept for the precedence of networks.
* In the event of multiple matches, we try to get the longest prefix if
* CONFIG_ROUTE_LONGEST_MATCH is set, otherwise only the first match is
* returned.
*/
if (net_ipv4addr_maskcmp(route->target, match->target, route->netmask) &&
net_ipv4addr_maskcmp(route->router, dev->d_ipaddr, dev->d_netmask))
net_ipv4addr_maskcmp(route->router, dev->d_ipaddr, dev->d_netmask)
#ifdef CONFIG_ROUTE_LONGEST_MATCH
&& prefixlen > match->prefixlen
#endif
)
{
#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE
/* They match.. Copy the entire routing table entry */
@ -129,7 +154,13 @@ static int net_ipv4_devmatch(FAR struct net_route_ipv4_s *route,
net_ipv4addr_copy(match->router, route->router);
#endif
#ifdef CONFIG_ROUTE_LONGEST_MATCH
/* Cache the prefix length */
match->prefixlen = prefixlen;
#else
return 1;
#endif
}
return 0;
@ -158,16 +189,24 @@ static int net_ipv6_devmatch(FAR struct net_route_ipv6_s *route,
FAR struct route_ipv6_devmatch_s *match =
(FAR struct route_ipv6_devmatch_s *)arg;
FAR struct net_driver_s *dev = match->dev;
#ifdef CONFIG_ROUTE_LONGEST_MATCH
int16_t prefixlen = (int16_t)net_ipv6_mask2pref(route->netmask);
#endif
/* To match, (1) the masked target addresses must be the same, and (2) the
* router address must like on the network provided by the device.
*
* In the event of multiple matches, only the first is returned. There
* not (yet) any concept for the precedence of networks.
* In the event of multiple matches, we try to get the longest prefix if
* CONFIG_ROUTE_LONGEST_MATCH is set, otherwise only the first match is
* returned.
*/
if (net_ipv6addr_maskcmp(route->target, match->target, route->netmask) &&
NETDEV_V6ADDR_ONLINK(dev, route->router))
NETDEV_V6ADDR_ONLINK(dev, route->router)
#ifdef CONFIG_ROUTE_LONGEST_MATCH
&& prefixlen > match->prefixlen
#endif
)
{
#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE
/* They match.. Copy the entire routing table entry */
@ -178,7 +217,13 @@ static int net_ipv6_devmatch(FAR struct net_route_ipv6_s *route,
net_ipv6addr_copy(match->router, route->router);
#endif
#ifdef CONFIG_ROUTE_LONGEST_MATCH
/* Cache the prefix length */
match->prefixlen = prefixlen;
#else
return 1;
#endif
}
return 0;
@ -222,6 +267,9 @@ void netdev_ipv4_router(FAR struct net_driver_s *dev, in_addr_t target,
memset(&match, 0, sizeof(struct route_ipv4_devmatch_s));
match.dev = dev;
net_ipv4addr_copy(match.target, target);
#ifdef CONFIG_ROUTE_LONGEST_MATCH
match.prefixlen = -1;
#endif
#ifdef CONFIG_ROUTE_IPv4_CACHEROUTE
/* First see if we can find a router entry in the cache */
@ -239,7 +287,12 @@ void netdev_ipv4_router(FAR struct net_driver_s *dev, in_addr_t target,
/* Did we find a route? */
#ifdef CONFIG_ROUTE_LONGEST_MATCH
UNUSED(ret);
if (match.prefixlen >= 0)
#else
if (ret > 0)
#endif
{
/* We found a route. */
@ -301,6 +354,9 @@ void netdev_ipv6_router(FAR struct net_driver_s *dev,
memset(&match, 0, sizeof(struct route_ipv6_devmatch_s));
match.dev = dev;
net_ipv6addr_copy(match.target, target);
#ifdef CONFIG_ROUTE_LONGEST_MATCH
match.prefixlen = -1;
#endif
#ifdef CONFIG_ROUTE_IPv6_CACHEROUTE
/* First see if we can find a router entry in the cache */
@ -318,7 +374,12 @@ void netdev_ipv6_router(FAR struct net_driver_s *dev,
/* Did we find a route? */
#ifdef CONFIG_ROUTE_LONGEST_MATCH
UNUSED(ret);
if (match.prefixlen >= 0)
#else
if (ret > 0)
#endif
{
/* We found a route. */

View file

@ -159,9 +159,12 @@ int net_delroute_ipv6(net_ipv6addr_t target, net_ipv6addr_t netmask);
* router on a local network that can forward to the external network.
*
* Input Parameters:
* target - An IPv4 address on a remote network to use in the lookup.
* router - The address of router on a local network that can forward our
* packets to the target.
* target - An IPv4 address on a remote network to use in the lookup.
* router - The address of router on a local network that can forward
* our packets to the target.
* prefixlen - The prefix length of previously matched routes (maybe on
* device), will only match prefix longer than prefixlen.
* Range: -1(match all) ~ 32(match none)
*
* Returned Value:
* OK on success; Negated errno on failure.
@ -169,7 +172,8 @@ int net_delroute_ipv6(net_ipv6addr_t target, net_ipv6addr_t netmask);
****************************************************************************/
#ifdef CONFIG_NET_IPv4
int net_ipv4_router(in_addr_t target, FAR in_addr_t *router);
int net_ipv4_router(in_addr_t target, FAR in_addr_t *router,
int8_t prefixlen);
#endif
/****************************************************************************
@ -180,9 +184,12 @@ int net_ipv4_router(in_addr_t target, FAR in_addr_t *router);
* router on a local network that can forward to the external network.
*
* Input Parameters:
* target - An IPv6 address on a remote network to use in the lookup.
* router - The address of router on a local network that can forward our
* packets to the target.
* target - An IPv6 address on a remote network to use in the lookup.
* router - The address of router on a local network that can forward
* our packets to the target.
* prefixlen - The prefix length of previously matched routes (maybe on
* device), will only match prefix longer than prefixlen.
* Range: -1(match all) ~ 128(match none)
*
* Returned Value:
* OK on success; Negated errno on failure.
@ -190,7 +197,8 @@ int net_ipv4_router(in_addr_t target, FAR in_addr_t *router);
****************************************************************************/
#ifdef CONFIG_NET_IPv6
int net_ipv6_router(const net_ipv6addr_t target, net_ipv6addr_t router);
int net_ipv6_router(const net_ipv6addr_t target, net_ipv6addr_t router,
int16_t prefixlen);
#endif
/****************************************************************************