mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-18 21:30:35 +01:00
core: move route iteration to nm-netlink-utils.c
This commit is contained in:
parent
7461e33ce1
commit
abb89a7d2a
3 changed files with 167 additions and 118 deletions
|
|
@ -139,14 +139,8 @@ nm_netlink_route_delete (struct rtnl_route *route)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* nm_netlink_dump_route:
|
||||
* @route: the route to dump
|
||||
*
|
||||
* Logs the details of a route.
|
||||
**/
|
||||
void
|
||||
nm_netlink_dump_route (struct rtnl_route *route)
|
||||
static void
|
||||
dump_route (struct rtnl_route *route)
|
||||
{
|
||||
char buf6[INET6_ADDRSTRLEN];
|
||||
char buf4[INET_ADDRSTRLEN];
|
||||
|
|
@ -189,3 +183,106 @@ nm_netlink_dump_route (struct rtnl_route *route)
|
|||
prefixlen);
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
int ifindex;
|
||||
int family;
|
||||
int scope;
|
||||
gboolean ignore_inet6_ll_mc;
|
||||
const char *iface;
|
||||
NlRouteForeachFunc callback;
|
||||
gpointer user_data;
|
||||
struct rtnl_route *out_route;
|
||||
} ForeachRouteInfo;
|
||||
|
||||
static void
|
||||
foreach_route_cb (struct nl_object *object, void *user_data)
|
||||
{
|
||||
ForeachRouteInfo *info = user_data;
|
||||
struct rtnl_route *route = (struct rtnl_route *) object;
|
||||
struct nl_addr *dst;
|
||||
|
||||
if (info->out_route)
|
||||
return;
|
||||
|
||||
if (nm_logging_level_enabled (LOGL_DEBUG))
|
||||
dump_route (route);
|
||||
|
||||
if ( info->ifindex >= 0
|
||||
&& rtnl_route_get_oif (route) != info->ifindex)
|
||||
return;
|
||||
|
||||
if ( info->scope != RT_SCOPE_UNIVERSE
|
||||
&& rtnl_route_get_scope (route) != info->scope)
|
||||
return;
|
||||
|
||||
if ( info->family != AF_UNSPEC
|
||||
&& rtnl_route_get_family (route) != info->family)
|
||||
return;
|
||||
|
||||
dst = rtnl_route_get_dst (route);
|
||||
|
||||
/* Check for IPv6 LL and MC routes that might need to be ignored */
|
||||
if ( (info->family == AF_INET6 || info->family == AF_UNSPEC)
|
||||
&& (rtnl_route_get_family (route) == AF_INET6)) {
|
||||
struct in6_addr *addr = NULL;
|
||||
|
||||
if (dst)
|
||||
addr = nl_addr_get_binary_addr (dst);
|
||||
if (addr) {
|
||||
if ( IN6_IS_ADDR_LINKLOCAL (addr)
|
||||
|| IN6_IS_ADDR_MC_LINKLOCAL (addr)
|
||||
|| (IN6_IS_ADDR_MULTICAST (addr) && (nl_addr_get_prefixlen (dst) == 8)))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
info->out_route = info->callback (route, dst, info->iface, info->user_data);
|
||||
if (info->out_route) {
|
||||
/* Ref the route so it sticks around after the cache is cleared */
|
||||
rtnl_route_get (info->out_route);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_netlink_foreach_route:
|
||||
* @ifindex: the interface index to filter routes for
|
||||
* @family: the address family to filter routes for
|
||||
* @scope: route scope, eg RT_SCOPE_LINK
|
||||
* @ignore_inet6_ll_mc: if %TRUE ignore IPv6 link-local and multi-cast routes
|
||||
* @callback: function called when a route matches the filter
|
||||
* @user_data: data passed to @callback
|
||||
*
|
||||
* Filters each route in the routing table against the given @ifindex and
|
||||
* @family (if given) and calls @callback for each matching route.
|
||||
*
|
||||
* Returns: a route if @callback returned one; the caller must dispose of the
|
||||
* route using rtnl_route_put() when it is no longer required.
|
||||
**/
|
||||
struct rtnl_route *
|
||||
nm_netlink_foreach_route (int ifindex,
|
||||
int family,
|
||||
int scope,
|
||||
gboolean ignore_inet6_ll_mc,
|
||||
NlRouteForeachFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct nl_cache *cache;
|
||||
ForeachRouteInfo info;
|
||||
|
||||
memset (&info, 0, sizeof (info));
|
||||
info.ifindex = ifindex;
|
||||
info.family = family;
|
||||
info.scope = scope;
|
||||
info.ignore_inet6_ll_mc = ignore_inet6_ll_mc;
|
||||
info.callback = callback;
|
||||
info.user_data = user_data;
|
||||
info.iface = nm_netlink_index_to_iface (ifindex);
|
||||
|
||||
cache = rtnl_route_alloc_cache (nm_netlink_get_default_handle ());
|
||||
g_return_val_if_fail (cache != NULL, NULL);
|
||||
nl_cache_foreach (cache, foreach_route_cb, &info);
|
||||
nl_cache_free (cache);
|
||||
return info.out_route;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,29 @@ gboolean nm_netlink_find_address (int ifindex,
|
|||
|
||||
gboolean nm_netlink_route_delete (struct rtnl_route *route);
|
||||
|
||||
void nm_netlink_dump_route (struct rtnl_route *route);
|
||||
/**
|
||||
* NlRouteForeachFunc:
|
||||
* @route: the route being processed
|
||||
* @dst: the route's destination address
|
||||
* @iface: the interface name of the index passed to nm_netlink_foreach_route()
|
||||
* @in_family: the address family passed to nm_netlink_foreach_route()
|
||||
* @user_data: the user data pointer passed to nm_netlink_foreach_route()
|
||||
*
|
||||
* Returns: a route to return to the caller of nm_netlink_foreach_route() which
|
||||
* terminates routing table iteration, or NULL to continue iterating the
|
||||
* routing table.
|
||||
**/
|
||||
typedef struct rtnl_route * (*NlRouteForeachFunc) (struct rtnl_route *route,
|
||||
struct nl_addr *dst,
|
||||
const char *iface,
|
||||
gpointer user_data);
|
||||
|
||||
struct rtnl_route * nm_netlink_foreach_route (int ifindex,
|
||||
int family,
|
||||
int scope,
|
||||
gboolean ignore_inet6_ll_mc,
|
||||
NlRouteForeachFunc callback,
|
||||
gpointer user_data);
|
||||
|
||||
#endif /* NM_NETLINK_MONITOR_H */
|
||||
|
||||
|
|
|
|||
147
src/nm-system.c
147
src/nm-system.c
|
|
@ -1231,71 +1231,19 @@ nm_system_iface_flush_addresses (int ifindex, int family)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
foreach_route (void (*callback)(struct nl_object *, gpointer),
|
||||
gpointer user_data)
|
||||
static struct rtnl_route *
|
||||
delete_one_route (struct rtnl_route *route,
|
||||
struct nl_addr *dst,
|
||||
const char *iface,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct nl_handle *nlh;
|
||||
struct nl_cache *route_cache;
|
||||
guint32 log_level = GPOINTER_TO_UINT (user_data);
|
||||
|
||||
nlh = nm_netlink_get_default_handle ();
|
||||
route_cache = rtnl_route_alloc_cache (nlh);
|
||||
g_assert (route_cache);
|
||||
nl_cache_foreach (route_cache, callback, user_data);
|
||||
nl_cache_free (route_cache);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *iface;
|
||||
int iface_idx;
|
||||
int family;
|
||||
} RouteCheckData;
|
||||
|
||||
static void
|
||||
check_one_route (struct nl_object *object, void *user_data)
|
||||
{
|
||||
RouteCheckData *data = (RouteCheckData *) user_data;
|
||||
struct rtnl_route *route = (struct rtnl_route *) object;
|
||||
guint32 log_level = LOGD_IP4 | LOGD_IP6;
|
||||
|
||||
if (nm_logging_level_enabled (LOGL_DEBUG))
|
||||
nm_netlink_dump_route (route);
|
||||
|
||||
/* Delete all routes from this interface */
|
||||
if (rtnl_route_get_oif (route) != data->iface_idx)
|
||||
return;
|
||||
if (data->family && rtnl_route_get_family (route) != data->family)
|
||||
return;
|
||||
|
||||
/* We don't want to flush IPv6 link-local routes that may exist on the
|
||||
* the interface since the LL address and routes should normally stay
|
||||
* assigned all the time.
|
||||
*/
|
||||
if ( (data->family == AF_INET6 || data->family == AF_UNSPEC)
|
||||
&& (rtnl_route_get_family (route) == AF_INET6)) {
|
||||
struct nl_addr *nl;
|
||||
struct in6_addr *addr = NULL;
|
||||
|
||||
nl = rtnl_route_get_dst (route);
|
||||
if (nl)
|
||||
addr = nl_addr_get_binary_addr (nl);
|
||||
|
||||
if (addr) {
|
||||
if ( IN6_IS_ADDR_LINKLOCAL (addr)
|
||||
|| IN6_IS_ADDR_MC_LINKLOCAL (addr)
|
||||
|| (IN6_IS_ADDR_MULTICAST (addr) && (nl_addr_get_prefixlen (nl) == 8)))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->family == AF_INET)
|
||||
log_level = LOGD_IP4;
|
||||
else if (data->family == AF_INET6)
|
||||
log_level = LOGD_IP6;
|
||||
nm_log_dbg (log_level, " deleting route");
|
||||
|
||||
if (!nm_netlink_route_delete (route))
|
||||
nm_log_err (LOGD_DEVICE, "(%s): failed to delete route", data->iface);
|
||||
nm_log_err (LOGD_DEVICE, "(%s): failed to delete route", iface);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1310,7 +1258,6 @@ check_one_route (struct nl_object *object, void *user_data)
|
|||
gboolean
|
||||
nm_system_iface_flush_routes (int ifindex, int family)
|
||||
{
|
||||
RouteCheckData check_data;
|
||||
guint32 log_level = LOGD_IP4 | LOGD_IP6;
|
||||
const char *sf = "UNSPEC";
|
||||
const char *iface;
|
||||
|
|
@ -1330,56 +1277,43 @@ nm_system_iface_flush_routes (int ifindex, int family)
|
|||
nm_log_dbg (log_level, "(%s): flushing routes ifindex %d family %s (%d)",
|
||||
iface, ifindex, sf, family);
|
||||
|
||||
memset (&check_data, 0, sizeof (check_data));
|
||||
check_data.iface = iface;
|
||||
check_data.iface_idx = ifindex;
|
||||
check_data.family = family;
|
||||
foreach_route (check_one_route, &check_data);
|
||||
|
||||
/* We don't want to flush IPv6 link-local routes that may exist on the
|
||||
* the interface since the LL address and routes should normally stay
|
||||
* assigned all the time.
|
||||
*/
|
||||
nm_netlink_foreach_route (ifindex, family, RT_SCOPE_UNIVERSE, TRUE, delete_one_route, GUINT_TO_POINTER (log_level));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
struct rtnl_route *route;
|
||||
NMIP4Config *config;
|
||||
int ifindex;
|
||||
} SetPriorityInfo;
|
||||
|
||||
static void
|
||||
find_route (struct nl_object *object, gpointer user_data)
|
||||
static struct rtnl_route *
|
||||
find_route (struct rtnl_route *route,
|
||||
struct nl_addr *dst,
|
||||
const char *iface,
|
||||
gpointer user_data)
|
||||
{
|
||||
struct rtnl_route *route = (struct rtnl_route *) object;
|
||||
SetPriorityInfo *info = (SetPriorityInfo *) user_data;
|
||||
struct nl_addr *dst;
|
||||
NMIP4Config *config = user_data;
|
||||
struct in_addr *dst_addr;
|
||||
int num;
|
||||
int i;
|
||||
|
||||
if (info->route ||
|
||||
rtnl_route_get_oif (route) != info->ifindex ||
|
||||
rtnl_route_get_scope (route) != RT_SCOPE_LINK)
|
||||
return;
|
||||
|
||||
dst = rtnl_route_get_dst (route);
|
||||
if (nl_addr_get_family (dst) != AF_INET)
|
||||
return;
|
||||
if (dst && (nl_addr_get_family (dst) != AF_INET))
|
||||
return NULL;
|
||||
|
||||
/* Find the first route that handles a subnet of at least one of the
|
||||
* device's IPv4 addresses.
|
||||
*/
|
||||
dst_addr = nl_addr_get_binary_addr (dst);
|
||||
num = nm_ip4_config_get_num_addresses (info->config);
|
||||
num = nm_ip4_config_get_num_addresses (config);
|
||||
for (i = 0; i < num; i++) {
|
||||
NMIP4Address *addr = nm_ip4_config_get_address (info->config, i);
|
||||
NMIP4Address *addr = nm_ip4_config_get_address (config, i);
|
||||
guint32 prefix = nm_ip4_address_get_prefix (addr);
|
||||
guint32 address = nm_ip4_address_get_address (addr);
|
||||
|
||||
if (prefix == nl_addr_get_prefixlen (dst) &&
|
||||
(address & nm_utils_ip4_prefix_to_netmask (prefix)) == dst_addr->s_addr) {
|
||||
|
||||
/* Ref the route so it sticks around after the cache is cleared */
|
||||
rtnl_route_get (route);
|
||||
info->route = route;
|
||||
break;
|
||||
}
|
||||
if ( prefix == nl_addr_get_prefixlen (dst)
|
||||
&& (address & nm_utils_ip4_prefix_to_netmask (prefix)) == dst_addr->s_addr)
|
||||
return route;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1387,20 +1321,15 @@ nm_system_device_set_priority (int ifindex,
|
|||
NMIP4Config *config,
|
||||
int priority)
|
||||
{
|
||||
SetPriorityInfo info;
|
||||
struct nl_handle *nlh;
|
||||
struct rtnl_route *found;
|
||||
|
||||
info.route = NULL;
|
||||
info.config = config;
|
||||
info.ifindex = ifindex;
|
||||
|
||||
foreach_route (find_route, &info);
|
||||
if (info.route) {
|
||||
nm_netlink_route_delete (info.route);
|
||||
|
||||
found = nm_netlink_foreach_route (ifindex, AF_INET, RT_SCOPE_LINK, FALSE, find_route, config);
|
||||
if (found) {
|
||||
nlh = nm_netlink_get_default_handle ();
|
||||
rtnl_route_set_prio (info.route, priority);
|
||||
rtnl_route_add (nlh, info.route, 0);
|
||||
rtnl_route_put (info.route);
|
||||
nm_netlink_route_delete (found);
|
||||
rtnl_route_set_prio (found, priority);
|
||||
rtnl_route_add (nlh, found, 0);
|
||||
rtnl_route_put (found);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue