platform: route management
Extend nm-platform to support IPv4 and IPv6 route management. Route features: * Retrieve the list of IPv4 and IPv6 routes * Add/delete/lookup IPv4 and IPv6 routes * Flush all non-linklocal routes
This commit is contained in:
@@ -32,6 +32,8 @@ typedef struct {
|
||||
GArray *links;
|
||||
GArray *ip4_addresses;
|
||||
GArray *ip6_addresses;
|
||||
GArray *ip4_routes;
|
||||
GArray *ip6_routes;
|
||||
} NMFakePlatformPrivate;
|
||||
|
||||
#define NM_FAKE_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_FAKE_PLATFORM, NMFakePlatformPrivate))
|
||||
@@ -439,6 +441,192 @@ ip6_address_exists (NMPlatform *platform, int ifindex, struct in6_addr addr, int
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static GArray *
|
||||
ip4_route_get_all (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
GArray *routes;
|
||||
NMPlatformIP4Route *route;
|
||||
int count = 0, i;
|
||||
|
||||
/* Count routes */
|
||||
for (i = 0; i < priv->ip4_routes->len; i++) {
|
||||
route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
|
||||
if (route && route->ifindex == ifindex)
|
||||
count++;
|
||||
}
|
||||
|
||||
routes = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP4Route), count);
|
||||
|
||||
/* Fill routes */
|
||||
for (i = 0; i < priv->ip4_routes->len; i++) {
|
||||
route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
|
||||
if (route && route->ifindex == ifindex)
|
||||
g_array_append_val (routes, *route);
|
||||
}
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
static GArray *
|
||||
ip6_route_get_all (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
GArray *routes;
|
||||
NMPlatformIP6Route *route;
|
||||
int count = 0, i;
|
||||
|
||||
/* Count routes */
|
||||
for (i = 0; i < priv->ip6_routes->len; i++) {
|
||||
route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
|
||||
if (route && route->ifindex == ifindex)
|
||||
count++;
|
||||
}
|
||||
|
||||
routes = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP6Route), count);
|
||||
|
||||
/* Fill routes */
|
||||
for (i = 0; i < priv->ip6_routes->len; i++) {
|
||||
route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
|
||||
if (route && route->ifindex == ifindex)
|
||||
g_array_append_val (routes, *route);
|
||||
}
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_route_add (NMPlatform *platform, int ifindex, in_addr_t network, int plen,
|
||||
in_addr_t gateway, int metric, int mss)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
NMPlatformIP4Route route;
|
||||
|
||||
memset (&route, 0, sizeof (route));
|
||||
route.ifindex = ifindex;
|
||||
route.network = network;
|
||||
route.plen = plen;
|
||||
route.gateway = gateway;
|
||||
route.metric = metric;
|
||||
|
||||
g_array_append_val (priv->ip4_routes, route);
|
||||
|
||||
g_signal_emit_by_name (platform, NM_PLATFORM_IP4_ROUTE_ADDED, &route);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_route_add (NMPlatform *platform, int ifindex, struct in6_addr network, int plen,
|
||||
struct in6_addr gateway, int metric, int mss)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
NMPlatformIP6Route route;
|
||||
|
||||
memset (&route, 0, sizeof (route));
|
||||
route.ifindex = ifindex;
|
||||
route.network = network;
|
||||
route.plen = plen;
|
||||
route.gateway = gateway;
|
||||
route.metric = metric;
|
||||
|
||||
g_array_append_val (priv->ip6_routes, route);
|
||||
|
||||
g_signal_emit_by_name (platform, NM_PLATFORM_IP6_ROUTE_ADDED, &route);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static NMPlatformIP4Route *
|
||||
ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, int plen,
|
||||
in_addr_t gateway, int metric)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->ip4_routes->len; i++) {
|
||||
NMPlatformIP4Route *route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
|
||||
|
||||
if (route->ifindex == ifindex
|
||||
&& route->network == network
|
||||
&& route->plen == plen
|
||||
&& route->gateway == gateway
|
||||
&& route->metric == metric)
|
||||
return route;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static NMPlatformIP6Route *
|
||||
ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, int plen,
|
||||
struct in6_addr gateway, int metric)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->ip6_routes->len; i++) {
|
||||
NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
|
||||
|
||||
if (route->ifindex == ifindex
|
||||
&& IN6_ARE_ADDR_EQUAL (&route->network, &network)
|
||||
&& route->plen == plen
|
||||
&& IN6_ARE_ADDR_EQUAL (&route->gateway, &gateway)
|
||||
&& route->metric == metric)
|
||||
return route;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen,
|
||||
in_addr_t gateway, int metric)
|
||||
{
|
||||
NMPlatformIP4Route *route = ip4_route_get (platform, ifindex, network, plen, gateway, metric);
|
||||
NMPlatformIP4Route deleted_route;
|
||||
|
||||
g_assert (route);
|
||||
|
||||
memcpy (&deleted_route, route, sizeof (deleted_route));
|
||||
memset (route, 0, sizeof (*route));
|
||||
g_signal_emit_by_name (platform, NM_PLATFORM_IP4_ROUTE_REMOVED, &deleted_route);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, int plen,
|
||||
struct in6_addr gateway, int metric)
|
||||
{
|
||||
NMPlatformIP6Route *route = ip6_route_get (platform, ifindex, network, plen, gateway, metric);
|
||||
NMPlatformIP6Route deleted_route;
|
||||
|
||||
g_assert (route);
|
||||
|
||||
memcpy (&deleted_route, route, sizeof (deleted_route));
|
||||
memset (route, 0, sizeof (*route));
|
||||
g_signal_emit_by_name (platform, NM_PLATFORM_IP6_ROUTE_REMOVED, &deleted_route);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_route_exists (NMPlatform *platform, int ifindex, in_addr_t network, int plen,
|
||||
in_addr_t gateway, int metric)
|
||||
{
|
||||
return !!ip4_route_get (platform, ifindex, network, plen, gateway, metric);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_route_exists (NMPlatform *platform, int ifindex, struct in6_addr network, int plen,
|
||||
struct in6_addr gateway, int metric)
|
||||
{
|
||||
return !!ip6_route_get (platform, ifindex, network, plen, gateway, metric);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static void
|
||||
nm_fake_platform_init (NMFakePlatform *fake_platform)
|
||||
{
|
||||
@@ -447,6 +635,8 @@ nm_fake_platform_init (NMFakePlatform *fake_platform)
|
||||
priv->links = g_array_new (TRUE, TRUE, sizeof (NMPlatformLink));
|
||||
priv->ip4_addresses = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Address));
|
||||
priv->ip6_addresses = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Address));
|
||||
priv->ip4_routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Route));
|
||||
priv->ip6_routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Route));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -474,6 +664,8 @@ nm_fake_platform_finalize (GObject *object)
|
||||
g_array_unref (priv->links);
|
||||
g_array_unref (priv->ip4_addresses);
|
||||
g_array_unref (priv->ip6_addresses);
|
||||
g_array_unref (priv->ip4_routes);
|
||||
g_array_unref (priv->ip6_routes);
|
||||
|
||||
G_OBJECT_CLASS (nm_fake_platform_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -514,4 +706,13 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
|
||||
platform_class->ip6_address_delete = ip6_address_delete;
|
||||
platform_class->ip4_address_exists = ip4_address_exists;
|
||||
platform_class->ip6_address_exists = ip6_address_exists;
|
||||
|
||||
platform_class->ip4_route_get_all = ip4_route_get_all;
|
||||
platform_class->ip6_route_get_all = ip6_route_get_all;
|
||||
platform_class->ip4_route_add = ip4_route_add;
|
||||
platform_class->ip6_route_add = ip6_route_add;
|
||||
platform_class->ip4_route_delete = ip4_route_delete;
|
||||
platform_class->ip6_route_delete = ip6_route_delete;
|
||||
platform_class->ip4_route_exists = ip4_route_exists;
|
||||
platform_class->ip6_route_exists = ip6_route_exists;
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include <netlink/route/link.h>
|
||||
#include <netlink/route/link/vlan.h>
|
||||
#include <netlink/route/addr.h>
|
||||
#include <netlink/route/route.h>
|
||||
|
||||
#include "nm-linux-platform.h"
|
||||
#include "nm-logging.h"
|
||||
@@ -47,6 +48,7 @@ typedef struct {
|
||||
struct nl_sock *nlh_event;
|
||||
struct nl_cache *link_cache;
|
||||
struct nl_cache *address_cache;
|
||||
struct nl_cache *route_cache;
|
||||
GIOChannel *event_channel;
|
||||
guint event_id;
|
||||
} NMLinuxPlatformPrivate;
|
||||
@@ -111,6 +113,8 @@ typedef enum {
|
||||
LINK,
|
||||
IP4_ADDRESS,
|
||||
IP6_ADDRESS,
|
||||
IP4_ROUTE,
|
||||
IP6_ROUTE,
|
||||
N_TYPES
|
||||
} ObjectType;
|
||||
|
||||
@@ -137,6 +141,15 @@ object_type_from_nl_object (const struct nl_object *object)
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
} else if (!strcmp (nl_object_get_type (object), "route/route")) {
|
||||
switch (rtnl_route_get_family ((struct rtnl_route *) object)) {
|
||||
case AF_INET:
|
||||
return IP4_ROUTE;
|
||||
case AF_INET6:
|
||||
return IP6_ROUTE;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
} else
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
@@ -214,6 +227,9 @@ add_kernel_object (struct nl_sock *sock, struct nl_object *object)
|
||||
case IP4_ADDRESS:
|
||||
case IP6_ADDRESS:
|
||||
return rtnl_addr_add (sock, (struct rtnl_addr *) object, NLM_F_CREATE);
|
||||
case IP4_ROUTE:
|
||||
case IP6_ROUTE:
|
||||
return rtnl_route_add (sock, (struct rtnl_route *) object, NLM_F_CREATE);
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
@@ -229,6 +245,9 @@ delete_kernel_object (struct nl_sock *sock, struct nl_object *object)
|
||||
case IP4_ADDRESS:
|
||||
case IP6_ADDRESS:
|
||||
return rtnl_addr_delete (sock, (struct rtnl_addr *) object, 0);
|
||||
case IP4_ROUTE:
|
||||
case IP6_ROUTE:
|
||||
return rtnl_route_delete (sock, (struct rtnl_route *) object, 0);
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
@@ -318,6 +337,46 @@ init_ip6_address (NMPlatformIP6Address *address, struct rtnl_addr *rtnladdr)
|
||||
memcpy (&address->address, nl_addr_get_binary_addr (nladdr), sizeof (address->address));
|
||||
}
|
||||
|
||||
static void
|
||||
init_ip4_route (NMPlatformIP4Route *route, struct rtnl_route *rtnlroute)
|
||||
{
|
||||
struct nl_addr *dst, *gw;
|
||||
struct rtnl_nexthop *nexthop;
|
||||
|
||||
g_assert (rtnl_route_get_nnexthops (rtnlroute) == 1);
|
||||
nexthop = rtnl_route_nexthop_n (rtnlroute, 0);
|
||||
dst = rtnl_route_get_dst (rtnlroute);
|
||||
gw = rtnl_route_nh_get_gateway (nexthop);
|
||||
|
||||
memset (route, 0, sizeof (*route));
|
||||
route->ifindex = rtnl_route_nh_get_ifindex (nexthop);
|
||||
route->plen = nl_addr_get_prefixlen (dst);
|
||||
memcpy (&route->network, nl_addr_get_binary_addr (dst), sizeof (route->network));
|
||||
if (gw)
|
||||
memcpy (&route->gateway, nl_addr_get_binary_addr (gw), sizeof (route->gateway));
|
||||
route->metric = rtnl_route_get_priority (rtnlroute);
|
||||
}
|
||||
|
||||
static void
|
||||
init_ip6_route (NMPlatformIP6Route *route, struct rtnl_route *rtnlroute)
|
||||
{
|
||||
struct nl_addr *dst, *gw;
|
||||
struct rtnl_nexthop *nexthop;
|
||||
|
||||
g_assert (rtnl_route_get_nnexthops (rtnlroute) == 1);
|
||||
nexthop = rtnl_route_nexthop_n (rtnlroute, 0);
|
||||
dst = rtnl_route_get_dst (rtnlroute);
|
||||
gw = rtnl_route_nh_get_gateway (nexthop);
|
||||
|
||||
memset (route, 0, sizeof (*route));
|
||||
route->ifindex = rtnl_route_nh_get_ifindex (nexthop);
|
||||
route->plen = nl_addr_get_prefixlen (dst);
|
||||
memcpy (&route->network, nl_addr_get_binary_addr (dst), sizeof (route->network));
|
||||
if (gw)
|
||||
memcpy (&route->gateway, nl_addr_get_binary_addr (gw), sizeof (route->gateway));
|
||||
route->metric = rtnl_route_get_priority (rtnlroute);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
/* Object and cache manipulation */
|
||||
@@ -326,6 +385,8 @@ static const char *signal_by_type_and_status[N_TYPES][N_STATUSES] = {
|
||||
{ NM_PLATFORM_LINK_ADDED, NM_PLATFORM_LINK_CHANGED, NM_PLATFORM_LINK_REMOVED },
|
||||
{ NM_PLATFORM_IP4_ADDRESS_ADDED, NM_PLATFORM_IP4_ADDRESS_CHANGED, NM_PLATFORM_IP4_ADDRESS_REMOVED },
|
||||
{ NM_PLATFORM_IP6_ADDRESS_ADDED, NM_PLATFORM_IP6_ADDRESS_CHANGED, NM_PLATFORM_IP6_ADDRESS_REMOVED },
|
||||
{ NM_PLATFORM_IP4_ROUTE_ADDED, NM_PLATFORM_IP4_ROUTE_CHANGED, NM_PLATFORM_IP4_ROUTE_REMOVED },
|
||||
{ NM_PLATFORM_IP6_ROUTE_ADDED, NM_PLATFORM_IP6_ROUTE_CHANGED, NM_PLATFORM_IP6_ROUTE_REMOVED }
|
||||
};
|
||||
|
||||
static struct nl_cache *
|
||||
@@ -339,6 +400,9 @@ choose_cache (NMPlatform *platform, struct nl_object *object)
|
||||
case IP4_ADDRESS:
|
||||
case IP6_ADDRESS:
|
||||
return priv->address_cache;
|
||||
case IP4_ROUTE:
|
||||
case IP6_ROUTE:
|
||||
return priv->route_cache;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
@@ -375,6 +439,22 @@ announce_object (NMPlatform *platform, const struct nl_object *object, ObjectSta
|
||||
g_signal_emit_by_name (platform, sig, &address);
|
||||
}
|
||||
return;
|
||||
case IP4_ROUTE:
|
||||
{
|
||||
NMPlatformIP4Route route;
|
||||
|
||||
init_ip4_route (&route, (struct rtnl_route *) object);
|
||||
g_signal_emit_by_name (platform, sig, &route);
|
||||
}
|
||||
return;
|
||||
case IP6_ROUTE:
|
||||
{
|
||||
NMPlatformIP6Route route;
|
||||
|
||||
init_ip6_route (&route, (struct rtnl_route *) object);
|
||||
g_signal_emit_by_name (platform, sig, &route);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
error ("Announcing object: object type unknown: %d", object_type);
|
||||
}
|
||||
@@ -869,6 +949,165 @@ ip6_address_exists (NMPlatform *platform, int ifindex, struct in6_addr addr, int
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static int
|
||||
ip_route_mark_all (NMPlatform *platform, int family, int ifindex)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
struct nl_object *object;
|
||||
int count = 0;
|
||||
|
||||
for (object = nl_cache_get_first (priv->route_cache); object; object = nl_cache_get_next (object)) {
|
||||
struct rtnl_route *rtnlroute = (struct rtnl_route *) object;
|
||||
struct rtnl_nexthop *nexthop;
|
||||
|
||||
nl_object_unmark (object);
|
||||
if (rtnl_route_get_type (rtnlroute) != RTN_UNICAST)
|
||||
continue;
|
||||
if (rtnl_route_get_table (rtnlroute) != RT_TABLE_MAIN)
|
||||
continue;
|
||||
if (rtnl_route_get_family (rtnlroute) != family)
|
||||
continue;
|
||||
if (rtnl_route_get_nnexthops (rtnlroute) != 1)
|
||||
continue;
|
||||
nexthop = rtnl_route_nexthop_n (rtnlroute, 0);
|
||||
if (rtnl_route_nh_get_ifindex (nexthop) != ifindex)
|
||||
continue;
|
||||
nl_object_mark (object);
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static GArray *
|
||||
ip4_route_get_all (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
GArray *routes;
|
||||
NMPlatformIP4Route route;
|
||||
struct nl_object *object;
|
||||
int count = 0;
|
||||
|
||||
count = ip_route_mark_all (platform, AF_INET, ifindex);
|
||||
routes = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP4Route), count);
|
||||
|
||||
for (object = nl_cache_get_first (priv->route_cache); object; object = nl_cache_get_next (object)) {
|
||||
if (nl_object_is_marked (object)) {
|
||||
init_ip4_route (&route, (struct rtnl_route *) object);
|
||||
g_array_append_val (routes, route);
|
||||
nl_object_unmark (object);
|
||||
}
|
||||
}
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
static GArray *
|
||||
ip6_route_get_all (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
GArray *routes;
|
||||
NMPlatformIP6Route route;
|
||||
struct nl_object *object;
|
||||
int count;
|
||||
|
||||
count = ip_route_mark_all (platform, AF_INET6, ifindex);
|
||||
routes = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP6Route), count);
|
||||
|
||||
for (object = nl_cache_get_first (priv->route_cache); object; object = nl_cache_get_next (object)) {
|
||||
if (nl_object_is_marked (object)) {
|
||||
init_ip6_route (&route, (struct rtnl_route *) object);
|
||||
g_array_append_val (routes, route);
|
||||
nl_object_unmark (object);
|
||||
}
|
||||
}
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
static struct nl_object *
|
||||
build_rtnl_route (int family, int ifindex, gconstpointer network, int plen, gconstpointer gateway, int metric, int mss)
|
||||
{
|
||||
struct rtnl_route *rtnlroute = rtnl_route_alloc ();
|
||||
struct rtnl_nexthop *nexthop = rtnl_route_nh_alloc ();
|
||||
int addrlen = (family == AF_INET) ? sizeof (in_addr_t) : sizeof (struct in6_addr);
|
||||
auto_nl_addr struct nl_addr *dst = nl_addr_build (family, network, addrlen);
|
||||
auto_nl_addr struct nl_addr *gw = nl_addr_build (family, gateway, addrlen);
|
||||
|
||||
g_assert (rtnlroute && dst && gw && nexthop);
|
||||
|
||||
nl_addr_set_prefixlen (dst, plen);
|
||||
|
||||
rtnl_route_set_table (rtnlroute, RT_TABLE_MAIN);
|
||||
rtnl_route_set_tos (rtnlroute, 0);
|
||||
rtnl_route_set_dst (rtnlroute, dst);
|
||||
rtnl_route_set_priority (rtnlroute, metric);
|
||||
|
||||
rtnl_route_nh_set_ifindex (nexthop, ifindex);
|
||||
if (!nl_addr_iszero (gw))
|
||||
rtnl_route_nh_set_gateway (nexthop, gw);
|
||||
rtnl_route_add_nexthop (rtnlroute, nexthop);
|
||||
|
||||
if (mss > 0)
|
||||
rtnl_route_set_metric (rtnlroute, RTAX_ADVMSS, mss);
|
||||
|
||||
return (struct nl_object *) rtnlroute;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_route_add (NMPlatform *platform, int ifindex, in_addr_t network, int plen, in_addr_t gateway, int metric, int mss)
|
||||
{
|
||||
return add_object (platform, build_rtnl_route (AF_INET, ifindex, &network, plen, &gateway, metric, mss));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_route_add (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, struct in6_addr gateway, int metric, int mss)
|
||||
{
|
||||
return add_object (platform, build_rtnl_route (AF_INET6, ifindex, &network, plen, &gateway, metric, mss));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen,
|
||||
in_addr_t gateway, int metric)
|
||||
{
|
||||
return delete_object (platform, build_rtnl_route (AF_INET, ifindex, &network, plen, &gateway, metric, 0));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, int plen,
|
||||
struct in6_addr gateway, int metric)
|
||||
{
|
||||
return delete_object (platform, build_rtnl_route (AF_INET6, ifindex, &network, plen, &gateway, metric, 0));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip_route_exists (NMPlatform *platform, int family, int ifindex, gpointer network, int plen,
|
||||
gpointer gateway, int metric)
|
||||
{
|
||||
auto_nl_object struct nl_object *object = build_rtnl_route (
|
||||
family, ifindex, network, plen, gateway, metric, 0);
|
||||
auto_nl_object struct nl_object *cached_object = nl_cache_search (
|
||||
choose_cache (platform, object), object);
|
||||
|
||||
return !!cached_object;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_route_exists (NMPlatform *platform, int ifindex, in_addr_t network, int plen,
|
||||
in_addr_t gateway, int metric)
|
||||
{
|
||||
return ip_route_exists (platform, AF_INET, ifindex, &network, plen, &gateway, metric);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_route_exists (NMPlatform *platform, int ifindex, struct in6_addr network, int plen,
|
||||
struct in6_addr gateway, int metric)
|
||||
{
|
||||
return ip_route_exists (platform, AF_INET6, ifindex, &network, plen, &gateway, metric);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
#define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI))
|
||||
#define ERROR_CONDITIONS ((GIOCondition) (G_IO_ERR | G_IO_NVAL))
|
||||
#define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP))
|
||||
@@ -982,7 +1221,8 @@ setup (NMPlatform *platform)
|
||||
/* Allocate netlink caches */
|
||||
rtnl_link_alloc_cache (priv->nlh, AF_UNSPEC, &priv->link_cache);
|
||||
rtnl_addr_alloc_cache (priv->nlh, &priv->address_cache);
|
||||
g_assert (priv->link_cache && priv->address_cache);
|
||||
rtnl_route_alloc_cache (priv->nlh, AF_UNSPEC, 0, &priv->route_cache);
|
||||
g_assert (priv->link_cache && priv->address_cache && priv->route_cache);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -999,6 +1239,7 @@ nm_linux_platform_finalize (GObject *object)
|
||||
nl_socket_free (priv->nlh_event);
|
||||
nl_cache_free (priv->link_cache);
|
||||
nl_cache_free (priv->address_cache);
|
||||
nl_cache_free (priv->route_cache);
|
||||
|
||||
G_OBJECT_CLASS (nm_linux_platform_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -1041,4 +1282,13 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
|
||||
platform_class->ip6_address_delete = ip6_address_delete;
|
||||
platform_class->ip4_address_exists = ip4_address_exists;
|
||||
platform_class->ip6_address_exists = ip6_address_exists;
|
||||
|
||||
platform_class->ip4_route_get_all = ip4_route_get_all;
|
||||
platform_class->ip6_route_get_all = ip6_route_get_all;
|
||||
platform_class->ip4_route_add = ip4_route_add;
|
||||
platform_class->ip6_route_add = ip6_route_add;
|
||||
platform_class->ip4_route_delete = ip4_route_delete;
|
||||
platform_class->ip6_route_delete = ip6_route_delete;
|
||||
platform_class->ip4_route_exists = ip4_route_exists;
|
||||
platform_class->ip6_route_exists = ip6_route_exists;
|
||||
}
|
||||
|
@@ -44,6 +44,12 @@ enum {
|
||||
IP6_ADDRESS_ADDED,
|
||||
IP6_ADDRESS_CHANGED,
|
||||
IP6_ADDRESS_REMOVED,
|
||||
IP4_ROUTE_ADDED,
|
||||
IP4_ROUTE_CHANGED,
|
||||
IP4_ROUTE_REMOVED,
|
||||
IP6_ROUTE_ADDED,
|
||||
IP6_ROUTE_CHANGED,
|
||||
IP6_ROUTE_REMOVED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
@@ -600,6 +606,129 @@ nm_platform_ip6_address_exists (int ifindex, struct in6_addr address, int plen)
|
||||
return klass->ip6_address_exists (platform, ifindex, address, plen);
|
||||
}
|
||||
|
||||
GArray *
|
||||
nm_platform_ip4_route_get_all (int ifindex)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (ifindex > 0, NULL);
|
||||
g_return_val_if_fail (klass->ip4_route_get_all, NULL);
|
||||
|
||||
return klass->ip4_route_get_all (platform, ifindex);
|
||||
}
|
||||
|
||||
GArray *
|
||||
nm_platform_ip6_route_get_all (int ifindex)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (ifindex > 0, NULL);
|
||||
g_return_val_if_fail (klass->ip6_route_get_all, NULL);
|
||||
|
||||
return klass->ip6_route_get_all (platform, ifindex);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_ip4_route_add (int ifindex,
|
||||
in_addr_t network, int plen,
|
||||
in_addr_t gateway, int metric, int mss)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (platform, FALSE);
|
||||
g_return_val_if_fail (0 <= plen && plen <= 32, FALSE);
|
||||
g_return_val_if_fail (metric >= 0, FALSE);
|
||||
g_return_val_if_fail (mss >= 0, FALSE);
|
||||
g_return_val_if_fail (klass->ip4_route_add, FALSE);
|
||||
|
||||
if (nm_platform_ip4_route_exists (ifindex, network, plen, gateway, metric)) {
|
||||
debug ("route already exists");
|
||||
platform->error = NM_PLATFORM_ERROR_EXISTS;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return klass->ip4_route_add (platform, ifindex, network, plen, gateway, metric, mss);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_ip6_route_add (int ifindex,
|
||||
struct in6_addr network, int plen, struct in6_addr gateway, int metric, int mss)
|
||||
{
|
||||
g_return_val_if_fail (platform, FALSE);
|
||||
g_return_val_if_fail (0 <= plen && plen <= 128, FALSE);
|
||||
g_return_val_if_fail (metric >= 0, FALSE);
|
||||
g_return_val_if_fail (mss >= 0, FALSE);
|
||||
g_return_val_if_fail (klass->ip6_route_add, FALSE);
|
||||
|
||||
if (nm_platform_ip6_route_exists (ifindex, network, plen, gateway, metric)) {
|
||||
debug ("route already exists");
|
||||
platform->error = NM_PLATFORM_ERROR_EXISTS;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return klass->ip6_route_add (platform, ifindex, network, plen, gateway, metric, mss);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_ip4_route_delete (int ifindex,
|
||||
in_addr_t network, int plen, in_addr_t gateway, int metric)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (platform, FALSE);
|
||||
g_return_val_if_fail (klass->ip4_route_delete, FALSE);
|
||||
|
||||
if (!nm_platform_ip4_route_exists (ifindex, network, plen, gateway, metric)) {
|
||||
debug ("route not found");
|
||||
platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return klass->ip4_route_delete (platform,ifindex, network, plen, gateway, metric);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_ip6_route_delete (int ifindex,
|
||||
struct in6_addr network, int plen, struct in6_addr gateway, int metric)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (platform, FALSE);
|
||||
g_return_val_if_fail (klass->ip6_route_delete, FALSE);
|
||||
|
||||
if (!nm_platform_ip6_route_exists (ifindex, network, plen, gateway, metric)) {
|
||||
debug ("route not found");
|
||||
platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return klass->ip6_route_delete (platform, ifindex, network, plen, gateway, metric);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_ip4_route_exists (int ifindex,
|
||||
in_addr_t network, int plen, in_addr_t gateway, int metric)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (platform, FALSE);
|
||||
g_return_val_if_fail (klass->ip4_route_exists, FALSE);
|
||||
|
||||
return klass->ip4_route_exists (platform,ifindex, network, plen, gateway, metric);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_ip6_route_exists (int ifindex,
|
||||
struct in6_addr network, int plen, struct in6_addr gateway, int metric)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (platform, FALSE);
|
||||
g_return_val_if_fail (klass->ip6_route_exists, FALSE);
|
||||
|
||||
return klass->ip6_route_exists (platform, ifindex, network, plen, gateway, metric);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static void
|
||||
@@ -680,6 +809,70 @@ log_ip6_address_removed (NMPlatform *p, NMPlatformIP6Address *address, gpointer
|
||||
log_ip6_address (address, "removed");
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip4_route (NMPlatformIP4Route *route, const char *change_type)
|
||||
{
|
||||
char network[INET_ADDRSTRLEN];
|
||||
char gateway[INET_ADDRSTRLEN];
|
||||
int plen = route->plen;
|
||||
const char *name = nm_platform_link_get_name (route->ifindex);
|
||||
|
||||
inet_ntop (AF_INET, &route->network, network, sizeof (network));
|
||||
inet_ntop (AF_INET, &route->gateway, gateway, sizeof (gateway));
|
||||
|
||||
debug ("signal: route %s: %s/%d via %s dev %s", change_type, network, plen, gateway, name);
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip4_route_added (NMPlatform *p, NMPlatformIP4Route *route, gpointer user_data)
|
||||
{
|
||||
log_ip4_route (route, "added");
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip4_route_changed (NMPlatform *p, NMPlatformIP4Route *route, gpointer user_data)
|
||||
{
|
||||
log_ip4_route (route, "changed");
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip4_route_removed (NMPlatform *p, NMPlatformIP4Route *route, gpointer user_data)
|
||||
{
|
||||
log_ip4_route (route, "removed");
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip6_route (NMPlatformIP6Route *route, const char *change_type)
|
||||
{
|
||||
char network[INET6_ADDRSTRLEN];
|
||||
char gateway[INET6_ADDRSTRLEN];
|
||||
int plen = route->plen;
|
||||
const char *name = nm_platform_link_get_name (route->ifindex);
|
||||
|
||||
inet_ntop (AF_INET6, &route->network, network, sizeof (network));
|
||||
inet_ntop (AF_INET6, &route->gateway, gateway, sizeof (gateway));
|
||||
|
||||
debug ("signal: route %s: %s/%d via %s dev %s", change_type, network, plen, gateway, name);
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip6_route_added (NMPlatform *p, NMPlatformIP6Route *route, gpointer user_data)
|
||||
{
|
||||
log_ip6_route (route, "added");
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip6_route_changed (NMPlatform *p, NMPlatformIP6Route *route, gpointer user_data)
|
||||
{
|
||||
log_ip6_route (route, "changed");
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip6_route_removed (NMPlatform *p, NMPlatformIP6Route *route, gpointer user_data)
|
||||
{
|
||||
log_ip6_route (route, "removed");
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static void
|
||||
@@ -711,4 +904,10 @@ nm_platform_class_init (NMPlatformClass *platform_class)
|
||||
SIGNAL (IP6_ADDRESS_ADDED, log_ip6_address_added)
|
||||
SIGNAL (IP6_ADDRESS_CHANGED, log_ip6_address_changed)
|
||||
SIGNAL (IP6_ADDRESS_REMOVED, log_ip6_address_removed)
|
||||
SIGNAL (IP4_ROUTE_ADDED, log_ip4_route_added)
|
||||
SIGNAL (IP4_ROUTE_CHANGED, log_ip4_route_changed)
|
||||
SIGNAL (IP4_ROUTE_REMOVED, log_ip4_route_removed)
|
||||
SIGNAL (IP6_ROUTE_ADDED, log_ip6_route_added)
|
||||
SIGNAL (IP6_ROUTE_CHANGED, log_ip6_route_changed)
|
||||
SIGNAL (IP6_ROUTE_REMOVED, log_ip6_route_removed)
|
||||
}
|
||||
|
@@ -64,6 +64,22 @@ typedef struct {
|
||||
int plen;
|
||||
} NMPlatformIP6Address;
|
||||
|
||||
typedef struct {
|
||||
int ifindex;
|
||||
in_addr_t network;
|
||||
int plen;
|
||||
in_addr_t gateway;
|
||||
int metric;
|
||||
} NMPlatformIP4Route;
|
||||
|
||||
typedef struct {
|
||||
int ifindex;
|
||||
struct in6_addr network;
|
||||
int plen;
|
||||
struct in6_addr gateway;
|
||||
int metric;
|
||||
} NMPlatformIP6Route;
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
/* NMPlatform abstract class and its implementations provide a layer between
|
||||
@@ -128,6 +144,21 @@ typedef struct {
|
||||
gboolean (*ip6_address_delete) (NMPlatform *, int ifindex, struct in6_addr address, int plen);
|
||||
gboolean (*ip4_address_exists) (NMPlatform *, int ifindex, in_addr_t address, int plen);
|
||||
gboolean (*ip6_address_exists) (NMPlatform *, int ifindex, struct in6_addr address, int plen);
|
||||
|
||||
GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex);
|
||||
GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex);
|
||||
gboolean (*ip4_route_add) (NMPlatform *, int ifindex,
|
||||
in_addr_t network, int plen, in_addr_t gateway, int prio, int mss);
|
||||
gboolean (*ip6_route_add) (NMPlatform *, int ifindex,
|
||||
struct in6_addr network, int plen, struct in6_addr gateway, int prio, int mss);
|
||||
gboolean (*ip4_route_delete) (NMPlatform *, int ifindex,
|
||||
in_addr_t network, int plen, in_addr_t gateway, int metric);
|
||||
gboolean (*ip6_route_delete) (NMPlatform *, int ifindex,
|
||||
struct in6_addr network, int plen, struct in6_addr gateway, int metric);
|
||||
gboolean (*ip4_route_exists) (NMPlatform *, int ifindex,
|
||||
in_addr_t network, int plen, in_addr_t gateway, int metric);
|
||||
gboolean (*ip6_route_exists) (NMPlatform *, int ifindex,
|
||||
struct in6_addr network, int plen, struct in6_addr gateway, int metric);
|
||||
} NMPlatformClass;
|
||||
|
||||
/* NMPlatform signals
|
||||
@@ -150,6 +181,12 @@ typedef struct {
|
||||
#define NM_PLATFORM_IP6_ADDRESS_ADDED "ip6-address-added"
|
||||
#define NM_PLATFORM_IP6_ADDRESS_CHANGED "ip6-address-changed"
|
||||
#define NM_PLATFORM_IP6_ADDRESS_REMOVED "ip6-address-removed"
|
||||
#define NM_PLATFORM_IP4_ROUTE_ADDED "ip4-route-added"
|
||||
#define NM_PLATFORM_IP4_ROUTE_CHANGED "ip4-route-changed"
|
||||
#define NM_PLATFORM_IP4_ROUTE_REMOVED "ip4-route-removed"
|
||||
#define NM_PLATFORM_IP6_ROUTE_ADDED "ip6-route-added"
|
||||
#define NM_PLATFORM_IP6_ROUTE_CHANGED "ip6-route-changed"
|
||||
#define NM_PLATFORM_IP6_ROUTE_REMOVED "ip6-route-removed"
|
||||
|
||||
/* NMPlatform error codes */
|
||||
enum {
|
||||
@@ -200,4 +237,20 @@ gboolean nm_platform_ip6_address_delete (int ifindex, struct in6_addr address, i
|
||||
gboolean nm_platform_ip4_address_exists (int ifindex, in_addr_t address, int plen);
|
||||
gboolean nm_platform_ip6_address_exists (int ifindex, struct in6_addr address, int plen);
|
||||
|
||||
GArray *nm_platform_ip4_route_get_all (int ifindex);
|
||||
GArray *nm_platform_ip6_route_get_all (int ifindex);
|
||||
gboolean nm_platform_route_set_metric (int ifindex, int metric);
|
||||
gboolean nm_platform_ip4_route_add (int ifindex,
|
||||
in_addr_t network, int plen, in_addr_t gateway, int metric, int mss);
|
||||
gboolean nm_platform_ip6_route_add (int ifindex,
|
||||
struct in6_addr network, int plen, struct in6_addr gateway, int metric, int mss);
|
||||
gboolean nm_platform_ip4_route_delete (int ifindex,
|
||||
in_addr_t network, int plen, in_addr_t gateway, int metric);
|
||||
gboolean nm_platform_ip6_route_delete (int ifindex,
|
||||
struct in6_addr network, int plen, struct in6_addr gateway, int metric);
|
||||
gboolean nm_platform_ip4_route_exists (int ifindex,
|
||||
in_addr_t network, int plen, in_addr_t gateway, int metric);
|
||||
gboolean nm_platform_ip6_route_exists (int ifindex,
|
||||
struct in6_addr network, int plen, struct in6_addr gateway, int metric);
|
||||
|
||||
#endif /* NM_PLATFORM_H */
|
||||
|
@@ -22,7 +22,9 @@ noinst_PROGRAMS = \
|
||||
test-link-fake \
|
||||
test-link-linux \
|
||||
test-address-fake \
|
||||
test-address-linux
|
||||
test-address-linux \
|
||||
test-route-fake \
|
||||
test-route-linux
|
||||
|
||||
EXTRA_DIST = test-common.h
|
||||
|
||||
@@ -78,6 +80,28 @@ test_address_linux_CPPFLAGS = \
|
||||
-DKERNEL_HACKS=1
|
||||
test_address_linux_LDADD = $(COMMON_LDADD)
|
||||
|
||||
test_route_fake_SOURCES = \
|
||||
test-route.c \
|
||||
test-common.c \
|
||||
${srcdir}/../nm-platform.c \
|
||||
${srcdir}/../nm-fake-platform.c
|
||||
test_route_fake_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
-DSETUP=nm_fake_platform_setup \
|
||||
-DKERNEL_HACKS=0
|
||||
test_route_fake_LDADD = $(COMMON_LDADD)
|
||||
|
||||
test_route_linux_SOURCES = \
|
||||
test-route.c \
|
||||
test-common.c \
|
||||
${srcdir}/../nm-platform.c \
|
||||
${srcdir}/../nm-linux-platform.c
|
||||
test_route_linux_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
-DSETUP=nm_linux_platform_setup \
|
||||
-DKERNEL_HACKS=1
|
||||
test_route_linux_LDADD = $(COMMON_LDADD)
|
||||
|
||||
# Unfortunately, we cannot run nm-linux-platform-test as an automatic test
|
||||
# program by default, as it requires root access and modifies kernel
|
||||
# configuration.
|
||||
@@ -85,8 +109,8 @@ test_address_linux_LDADD = $(COMMON_LDADD)
|
||||
# However, we can check whether the fake platform fakes platform behavior
|
||||
# correctly.
|
||||
@VALGRIND_RULES@
|
||||
TESTS = ./test-link-fake ./test-address-fake
|
||||
ROOTTESTS = ./test-link-linux ./test-address-linux
|
||||
TESTS = ./test-link-fake ./test-address-fake ./test-route-fake
|
||||
ROOTTESTS = ./test-link-linux ./test-address-linux ./test-route-linux
|
||||
|
||||
# If explicitly enabled, we can run the root tests
|
||||
if RUN_ROOT_TESTS
|
||||
|
@@ -29,6 +29,12 @@ dump_interface (NMPlatformLink *link)
|
||||
const NMPlatformIP6Address *ip6_address;
|
||||
const NMPlatformIP4Address *ip4_address;
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
GArray *ip6_routes;
|
||||
GArray *ip4_routes;
|
||||
const NMPlatformIP6Route *ip6_route;
|
||||
const NMPlatformIP4Route *ip4_route;
|
||||
char networkstr[INET6_ADDRSTRLEN];
|
||||
char gatewaystr[INET6_ADDRSTRLEN];
|
||||
int i;
|
||||
|
||||
g_assert (link->up || !link->connected);
|
||||
@@ -62,6 +68,29 @@ dump_interface (NMPlatformLink *link)
|
||||
|
||||
g_array_unref (ip4_addresses);
|
||||
g_array_unref (ip6_addresses);
|
||||
|
||||
ip4_routes = nm_platform_ip4_route_get_all (link->ifindex);
|
||||
ip6_routes = nm_platform_ip6_route_get_all (link->ifindex);
|
||||
|
||||
g_assert (ip4_routes);
|
||||
g_assert (ip6_routes);
|
||||
|
||||
for (i = 0; i < ip4_routes->len; i++) {
|
||||
ip4_route = &g_array_index (ip4_routes, NMPlatformIP4Route, i);
|
||||
inet_ntop (AF_INET, &ip4_route->network, networkstr, sizeof (networkstr));
|
||||
inet_ntop (AF_INET, &ip4_route->gateway, gatewaystr, sizeof (gatewaystr));
|
||||
printf (" ip4-route %s/%d via %s\n", networkstr, ip4_route->plen, gatewaystr);
|
||||
}
|
||||
|
||||
for (i = 0; i < ip6_routes->len; i++) {
|
||||
ip6_route = &g_array_index (ip6_routes, NMPlatformIP6Route, i);
|
||||
inet_ntop (AF_INET6, &ip6_route->network, networkstr, sizeof (networkstr));
|
||||
inet_ntop (AF_INET6, &ip6_route->gateway, gatewaystr, sizeof (gatewaystr));
|
||||
printf (" ip6-route %s/%d via %s\n", networkstr, ip6_route->plen, gatewaystr);
|
||||
}
|
||||
|
||||
g_array_unref (ip4_routes);
|
||||
g_array_unref (ip6_routes);
|
||||
}
|
||||
|
||||
static void
|
||||
|
190
src/platform/tests/test-route.c
Normal file
190
src/platform/tests/test-route.c
Normal file
@@ -0,0 +1,190 @@
|
||||
#include "test-common.h"
|
||||
|
||||
#define DEVICE_NAME "nm-test-device"
|
||||
|
||||
static void
|
||||
ip4_route_callback (NMPlatform *platform, NMPlatformIP4Route *received, SignalData *data)
|
||||
{
|
||||
g_assert (received);
|
||||
|
||||
if (data->ifindex && data->ifindex != received->ifindex)
|
||||
return;
|
||||
|
||||
if (data->loop)
|
||||
g_main_loop_quit (data->loop);
|
||||
|
||||
if (data->received)
|
||||
g_error ("Received signal '%s' a second time.", data->name);
|
||||
|
||||
data->received = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ip6_route_callback (NMPlatform *platform, NMPlatformIP6Route *received, SignalData *data)
|
||||
{
|
||||
g_assert (received);
|
||||
|
||||
if (data->ifindex && data->ifindex != received->ifindex)
|
||||
return;
|
||||
|
||||
if (data->loop)
|
||||
g_main_loop_quit (data->loop);
|
||||
|
||||
if (data->received)
|
||||
g_error ("Received signal '%s' a second time.", data->name);
|
||||
|
||||
data->received = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip4_route ()
|
||||
{
|
||||
SignalData *route_added = add_signal (NM_PLATFORM_IP4_ROUTE_ADDED, ip4_route_callback);
|
||||
SignalData *route_removed = add_signal (NM_PLATFORM_IP4_ROUTE_REMOVED, ip4_route_callback);
|
||||
int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
|
||||
GArray *routes;
|
||||
NMPlatformIP4Route rts[3];
|
||||
in_addr_t network;
|
||||
int plen = 24;
|
||||
in_addr_t gateway;
|
||||
int metric = 20;
|
||||
int mss = 1000;
|
||||
|
||||
inet_pton (AF_INET, "192.0.2.0", &network);
|
||||
inet_pton (AF_INET, "198.51.100.0", &gateway);
|
||||
|
||||
/* Add route to gateway */
|
||||
g_assert (nm_platform_ip4_route_add (ifindex, gateway, 32, INADDR_ANY, metric, 0)); no_error ();
|
||||
accept_signal (route_added);
|
||||
|
||||
/* Add route */
|
||||
g_assert (!nm_platform_ip4_route_exists (ifindex, network, plen, gateway, metric)); no_error ();
|
||||
g_assert (nm_platform_ip4_route_add (ifindex, network, plen, gateway, metric, mss)); no_error ();
|
||||
g_assert (nm_platform_ip4_route_exists (ifindex, network, plen, gateway, metric)); no_error ();
|
||||
accept_signal (route_added);
|
||||
|
||||
/* Add route again */
|
||||
g_assert (!nm_platform_ip4_route_add (ifindex, network, plen, gateway, metric, mss));
|
||||
error (NM_PLATFORM_ERROR_EXISTS);
|
||||
|
||||
/* Test route listing */
|
||||
routes = nm_platform_ip4_route_get_all (ifindex);
|
||||
memset (rts, 0, sizeof (rts));
|
||||
rts[0].network = gateway;
|
||||
rts[0].plen = 32;
|
||||
rts[0].ifindex = ifindex;
|
||||
rts[0].gateway = INADDR_ANY;
|
||||
rts[0].metric = metric;
|
||||
rts[1].network = network;
|
||||
rts[1].plen = plen;
|
||||
rts[1].ifindex = ifindex;
|
||||
rts[1].gateway = gateway;
|
||||
rts[1].metric = metric;
|
||||
g_assert (routes->len == 2);
|
||||
g_assert (!memcmp (routes->data, rts, sizeof (rts)));
|
||||
g_array_unref (routes);
|
||||
|
||||
/* Remove route */
|
||||
g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, gateway, metric)); no_error ();
|
||||
g_assert (!nm_platform_ip4_route_exists (ifindex, network, plen, gateway, metric));
|
||||
accept_signal (route_removed);
|
||||
|
||||
/* Remove route again */
|
||||
g_assert (!nm_platform_ip4_route_delete (ifindex, network, plen, gateway, metric));
|
||||
error (NM_PLATFORM_ERROR_NOT_FOUND);
|
||||
|
||||
free_signal (route_added);
|
||||
free_signal (route_removed);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip6_route ()
|
||||
{
|
||||
SignalData *route_added = add_signal (NM_PLATFORM_IP6_ROUTE_ADDED, ip6_route_callback);
|
||||
SignalData *route_removed = add_signal (NM_PLATFORM_IP6_ROUTE_REMOVED, ip6_route_callback);
|
||||
int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
|
||||
GArray *routes;
|
||||
NMPlatformIP6Route rts[3];
|
||||
struct in6_addr network;
|
||||
int plen = 64;
|
||||
struct in6_addr gateway;
|
||||
int metric = 20;
|
||||
int mss = 1000;
|
||||
|
||||
inet_pton (AF_INET6, "2001:db8:a:b:0:0:0:0", &network);
|
||||
inet_pton (AF_INET6, "2001:db8:c:d:1:2:3:4", &gateway);
|
||||
|
||||
/* Add gateway address */
|
||||
g_assert (nm_platform_ip6_route_add (ifindex, gateway, 128, in6addr_any, metric, 0)); no_error ();
|
||||
accept_signal (route_added);
|
||||
|
||||
/* Add route */
|
||||
g_assert (!nm_platform_ip6_route_exists (ifindex, network, plen, gateway, metric)); no_error ();
|
||||
g_assert (nm_platform_ip6_route_add (ifindex, network, plen, gateway, metric, mss)); no_error ();
|
||||
g_assert (nm_platform_ip6_route_exists (ifindex, network, plen, gateway, metric)); no_error ();
|
||||
accept_signal (route_added);
|
||||
|
||||
/* Add route again */
|
||||
g_assert (!nm_platform_ip6_route_add (ifindex, network, plen, gateway, metric, mss));
|
||||
error (NM_PLATFORM_ERROR_EXISTS);
|
||||
|
||||
/* Test route listing */
|
||||
routes = nm_platform_ip6_route_get_all (ifindex);
|
||||
memset (rts, 0, sizeof (rts));
|
||||
rts[0].network = gateway;
|
||||
rts[0].plen = 128;
|
||||
rts[0].ifindex = ifindex;
|
||||
rts[0].gateway = in6addr_any;
|
||||
rts[0].metric = metric;
|
||||
rts[1].network = network;
|
||||
rts[1].plen = plen;
|
||||
rts[1].ifindex = ifindex;
|
||||
rts[1].gateway = gateway;
|
||||
rts[1].metric = metric;
|
||||
g_assert (routes->len == 2);
|
||||
g_assert (!memcmp (routes->data, rts, sizeof (rts)));
|
||||
g_array_unref (routes);
|
||||
|
||||
/* Remove route */
|
||||
g_assert (nm_platform_ip6_route_delete (ifindex, network, plen, gateway, metric)); no_error ();
|
||||
g_assert (!nm_platform_ip6_route_exists (ifindex, network, plen, gateway, metric));
|
||||
accept_signal (route_removed);
|
||||
|
||||
/* Remove route again */
|
||||
g_assert (!nm_platform_ip6_route_delete (ifindex, network, plen, gateway, metric));
|
||||
error (NM_PLATFORM_ERROR_NOT_FOUND);
|
||||
|
||||
free_signal (route_added);
|
||||
free_signal (route_removed);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int result;
|
||||
|
||||
openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR, LOG_DAEMON);
|
||||
g_type_init ();
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
/* Enable debug messages if called with --debug */
|
||||
for (; *argv; argv++)
|
||||
if (!g_strcmp0 (*argv, "--debug"))
|
||||
nm_logging_setup ("debug", NULL, NULL);
|
||||
|
||||
SETUP ();
|
||||
|
||||
/* Clean up */
|
||||
nm_platform_link_delete_by_name (DEVICE_NAME);
|
||||
g_assert (!nm_platform_link_exists (DEVICE_NAME));
|
||||
g_assert (nm_platform_dummy_add (DEVICE_NAME));
|
||||
g_assert (nm_platform_link_set_up (nm_platform_link_get_ifindex (DEVICE_NAME)));
|
||||
|
||||
g_test_add_func ("/route/ip4", test_ip4_route);
|
||||
g_test_add_func ("/route/ip6", test_ip6_route);
|
||||
|
||||
result = g_test_run ();
|
||||
|
||||
nm_platform_link_delete_by_name (DEVICE_NAME);
|
||||
nm_platform_free ();
|
||||
return result;
|
||||
}
|
Reference in New Issue
Block a user