core: move route iteration to nm-netlink-utils.c

This commit is contained in:
Dan Williams 2011-07-22 17:08:53 -05:00
parent 7461e33ce1
commit abb89a7d2a
3 changed files with 167 additions and 118 deletions

View file

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

View file

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

View file

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