platform: address management
Extend nm-platform to support IPv4 and IPv6 address management. Address features: * Retrieve the list of IPv4 and IPv6 addresses * Add/delete/lookup IPv4 and IPv6 addresses * Flush all non-linklocal addresses
This commit is contained in:
@@ -30,6 +30,8 @@
|
||||
|
||||
typedef struct {
|
||||
GArray *links;
|
||||
GArray *ip4_addresses;
|
||||
GArray *ip6_addresses;
|
||||
} NMFakePlatformPrivate;
|
||||
|
||||
#define NM_FAKE_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_FAKE_PLATFORM, NMFakePlatformPrivate))
|
||||
@@ -266,12 +268,185 @@ link_uses_arp (NMPlatform *platform, int ifindex)
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static GArray *
|
||||
ip4_address_get_all (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
GArray *addresses;
|
||||
NMPlatformIP4Address *address;
|
||||
int count = 0, i;
|
||||
|
||||
/* Count addresses */
|
||||
for (i = 0; i < priv->ip4_addresses->len; i++) {
|
||||
address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
|
||||
if (address && address->ifindex == ifindex)
|
||||
count++;
|
||||
}
|
||||
|
||||
addresses = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP4Address), count);
|
||||
|
||||
/* Fill addresses */
|
||||
for (i = 0; i < priv->ip4_addresses->len; i++) {
|
||||
address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
|
||||
if (address && address->ifindex == ifindex)
|
||||
g_array_append_val (addresses, *address);
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
static GArray *
|
||||
ip6_address_get_all (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
GArray *addresses;
|
||||
NMPlatformIP6Address *address;
|
||||
int count = 0, i;
|
||||
|
||||
/* Count addresses */
|
||||
for (i = 0; i < priv->ip6_addresses->len; i++) {
|
||||
address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
|
||||
if (address && address->ifindex == ifindex)
|
||||
count++;
|
||||
}
|
||||
|
||||
addresses = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP6Address), count);
|
||||
|
||||
/* Fill addresses */
|
||||
count = 0;
|
||||
for (i = 0; i < priv->ip6_addresses->len; i++) {
|
||||
address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
|
||||
if (address && address->ifindex == ifindex)
|
||||
g_array_append_val (addresses, *address);
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_address_add (NMPlatform *platform, int ifindex, in_addr_t addr, int plen)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
NMPlatformIP4Address address;
|
||||
|
||||
memset (&address, 0, sizeof (address));
|
||||
address.ifindex = ifindex;
|
||||
address.address = addr;
|
||||
address.plen = plen;
|
||||
|
||||
g_array_append_val (priv->ip4_addresses, address);
|
||||
|
||||
g_signal_emit_by_name (platform, NM_PLATFORM_IP4_ADDRESS_ADDED, &address);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_address_add (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
NMPlatformIP6Address address;
|
||||
|
||||
memset (&address, 0, sizeof (address));
|
||||
address.ifindex = ifindex;
|
||||
address.address = addr;
|
||||
address.plen = plen;
|
||||
|
||||
g_array_append_val (priv->ip6_addresses, address);
|
||||
|
||||
g_signal_emit_by_name (platform, NM_PLATFORM_IP6_ADDRESS_ADDED, &address);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->ip4_addresses->len; i++) {
|
||||
NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
|
||||
|
||||
if (address->ifindex == ifindex && address->plen == plen && address->address == addr) {
|
||||
NMPlatformIP4Address deleted_address;
|
||||
|
||||
memcpy (&deleted_address, address, sizeof (deleted_address));
|
||||
memset (address, 0, sizeof (*address));
|
||||
g_signal_emit_by_name (platform, NM_PLATFORM_IP4_ADDRESS_REMOVED, &deleted_address);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->ip6_addresses->len; i++) {
|
||||
NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
|
||||
|
||||
if (address->ifindex == ifindex && address->plen == plen
|
||||
&& IN6_ARE_ADDR_EQUAL (&address->address, &addr)) {
|
||||
NMPlatformIP6Address deleted_address;
|
||||
|
||||
memcpy (&deleted_address, address, sizeof (deleted_address));
|
||||
memset (address, 0, sizeof (*address));
|
||||
g_signal_emit_by_name (platform, NM_PLATFORM_IP6_ADDRESS_REMOVED, &deleted_address);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_address_exists (NMPlatform *platform, int ifindex, in_addr_t addr, int plen)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->ip4_addresses->len; i++) {
|
||||
NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
|
||||
|
||||
if (address->ifindex == ifindex && address->plen == plen && address->address == addr)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_address_exists (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->ip6_addresses->len; i++) {
|
||||
NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
|
||||
|
||||
if (address->ifindex == ifindex && address->plen == plen &&
|
||||
IN6_ARE_ADDR_EQUAL (&address->address, &addr))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static void
|
||||
nm_fake_platform_init (NMFakePlatform *fake_platform)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (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));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -297,6 +472,8 @@ nm_fake_platform_finalize (GObject *object)
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (object);
|
||||
|
||||
g_array_unref (priv->links);
|
||||
g_array_unref (priv->ip4_addresses);
|
||||
g_array_unref (priv->ip6_addresses);
|
||||
|
||||
G_OBJECT_CLASS (nm_fake_platform_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -328,4 +505,13 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
|
||||
platform_class->link_is_up = link_is_up;
|
||||
platform_class->link_is_connected = link_is_connected;
|
||||
platform_class->link_uses_arp = link_uses_arp;
|
||||
|
||||
platform_class->ip4_address_get_all = ip4_address_get_all;
|
||||
platform_class->ip6_address_get_all = ip6_address_get_all;
|
||||
platform_class->ip4_address_add = ip4_address_add;
|
||||
platform_class->ip6_address_add = ip6_address_add;
|
||||
platform_class->ip4_address_delete = ip4_address_delete;
|
||||
platform_class->ip6_address_delete = ip6_address_delete;
|
||||
platform_class->ip4_address_exists = ip4_address_exists;
|
||||
platform_class->ip6_address_exists = ip6_address_exists;
|
||||
}
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include <netlink/cache.h>
|
||||
#include <netlink/route/link.h>
|
||||
#include <netlink/route/link/vlan.h>
|
||||
#include <netlink/route/addr.h>
|
||||
|
||||
#include "nm-linux-platform.h"
|
||||
#include "nm-logging.h"
|
||||
@@ -45,6 +46,7 @@ typedef struct {
|
||||
struct nl_sock *nlh;
|
||||
struct nl_sock *nlh_event;
|
||||
struct nl_cache *link_cache;
|
||||
struct nl_cache *address_cache;
|
||||
GIOChannel *event_channel;
|
||||
guint event_id;
|
||||
} NMLinuxPlatformPrivate;
|
||||
@@ -76,11 +78,39 @@ put_nl_object (void *ptr)
|
||||
}
|
||||
}
|
||||
|
||||
#define auto_nl_addr __attribute__((cleanup(put_nl_addr)))
|
||||
static void
|
||||
put_nl_addr (void *ptr)
|
||||
{
|
||||
struct nl_addr **object = ptr;
|
||||
|
||||
if (object && *object) {
|
||||
nl_addr_put (*object);
|
||||
*object = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* libnl doesn't use const where due */
|
||||
#define nl_addr_build(family, addr, addrlen) nl_addr_build (family, (gpointer) addr, addrlen)
|
||||
|
||||
/* rtnl_addr_set_prefixlen fails to update the nl_addr prefixlen */
|
||||
static void
|
||||
nm_rtnl_addr_set_prefixlen (struct rtnl_addr *rtnladdr, int plen)
|
||||
{
|
||||
struct nl_addr *nladdr;
|
||||
|
||||
rtnl_addr_set_prefixlen (rtnladdr, plen);
|
||||
|
||||
nladdr = rtnl_addr_get_local (rtnladdr);
|
||||
if (nladdr)
|
||||
nl_addr_set_prefixlen (nladdr, plen);
|
||||
}
|
||||
#define rtnl_addr_set_prefixlen nm_rtnl_addr_set_prefixlen
|
||||
|
||||
typedef enum {
|
||||
LINK,
|
||||
IP4_ADDRESS,
|
||||
IP6_ADDRESS,
|
||||
N_TYPES
|
||||
} ObjectType;
|
||||
|
||||
@@ -98,7 +128,16 @@ object_type_from_nl_object (const struct nl_object *object)
|
||||
|
||||
if (!strcmp (nl_object_get_type (object), "route/link"))
|
||||
return LINK;
|
||||
else
|
||||
else if (!strcmp (nl_object_get_type (object), "route/addr")) {
|
||||
switch (rtnl_addr_get_family ((struct rtnl_addr *) object)) {
|
||||
case AF_INET:
|
||||
return IP4_ADDRESS;
|
||||
case AF_INET6:
|
||||
return IP6_ADDRESS;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
} else
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
@@ -172,6 +211,9 @@ add_kernel_object (struct nl_sock *sock, struct nl_object *object)
|
||||
switch (object_type_from_nl_object (object)) {
|
||||
case LINK:
|
||||
return rtnl_link_add (sock, (struct rtnl_link *) object, NLM_F_CREATE);
|
||||
case IP4_ADDRESS:
|
||||
case IP6_ADDRESS:
|
||||
return rtnl_addr_add (sock, (struct rtnl_addr *) object, NLM_F_CREATE);
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
@@ -184,6 +226,9 @@ delete_kernel_object (struct nl_sock *sock, struct nl_object *object)
|
||||
switch (object_type_from_nl_object (object)) {
|
||||
case LINK:
|
||||
return rtnl_link_delete (sock, (struct rtnl_link *) object);
|
||||
case IP4_ADDRESS:
|
||||
case IP6_ADDRESS:
|
||||
return rtnl_addr_delete (sock, (struct rtnl_addr *) object, 0);
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
@@ -245,12 +290,42 @@ link_init (NMPlatformLink *info, struct rtnl_link *rtnllink)
|
||||
info->arp = !(rtnl_link_get_flags (rtnllink) & IFF_NOARP);
|
||||
}
|
||||
|
||||
static void
|
||||
init_ip4_address (NMPlatformIP4Address *address, struct rtnl_addr *rtnladdr)
|
||||
{
|
||||
struct nl_addr *nladdr = rtnl_addr_get_local (rtnladdr);
|
||||
|
||||
g_assert (nladdr);
|
||||
|
||||
memset (address, 0, sizeof (*address));
|
||||
|
||||
address->ifindex = rtnl_addr_get_ifindex (rtnladdr);
|
||||
address->plen = rtnl_addr_get_prefixlen (rtnladdr);
|
||||
g_assert (nl_addr_get_len (nladdr) == sizeof (address->address));
|
||||
memcpy (&address->address, nl_addr_get_binary_addr (nladdr), sizeof (address->address));
|
||||
}
|
||||
|
||||
static void
|
||||
init_ip6_address (NMPlatformIP6Address *address, struct rtnl_addr *rtnladdr)
|
||||
{
|
||||
struct nl_addr *nladdr = rtnl_addr_get_local (rtnladdr);
|
||||
|
||||
memset (address, 0, sizeof (*address));
|
||||
|
||||
address->ifindex = rtnl_addr_get_ifindex (rtnladdr);
|
||||
address->plen = rtnl_addr_get_prefixlen (rtnladdr);
|
||||
g_assert (nl_addr_get_len (nladdr) == sizeof (address->address));
|
||||
memcpy (&address->address, nl_addr_get_binary_addr (nladdr), sizeof (address->address));
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
/* Object and cache manipulation */
|
||||
|
||||
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 },
|
||||
};
|
||||
|
||||
static struct nl_cache *
|
||||
@@ -261,6 +336,9 @@ choose_cache (NMPlatform *platform, struct nl_object *object)
|
||||
switch (object_type_from_nl_object (object)) {
|
||||
case LINK:
|
||||
return priv->link_cache;
|
||||
case IP4_ADDRESS:
|
||||
case IP6_ADDRESS:
|
||||
return priv->address_cache;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
@@ -281,6 +359,22 @@ announce_object (NMPlatform *platform, const struct nl_object *object, ObjectSta
|
||||
g_signal_emit_by_name (platform, sig, &device);
|
||||
}
|
||||
return;
|
||||
case IP4_ADDRESS:
|
||||
{
|
||||
NMPlatformIP4Address address;
|
||||
|
||||
init_ip4_address (&address, (struct rtnl_addr *) object);
|
||||
g_signal_emit_by_name (platform, sig, &address);
|
||||
}
|
||||
return;
|
||||
case IP6_ADDRESS:
|
||||
{
|
||||
NMPlatformIP6Address address;
|
||||
|
||||
init_ip6_address (&address, (struct rtnl_addr *) object);
|
||||
g_signal_emit_by_name (platform, sig, &address);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
error ("Announcing object: object type unknown: %d", object_type);
|
||||
}
|
||||
@@ -404,6 +498,7 @@ event_notification (struct nl_msg *msg, gpointer user_data)
|
||||
/* Removed object */
|
||||
switch (event) {
|
||||
case RTM_DELLINK:
|
||||
case RTM_DELADDR:
|
||||
/* Ignore inconsistent deletion
|
||||
*
|
||||
* Quick external deletion and addition can be occasionally
|
||||
@@ -420,6 +515,7 @@ event_notification (struct nl_msg *msg, gpointer user_data)
|
||||
|
||||
return NL_OK;
|
||||
case RTM_NEWLINK:
|
||||
case RTM_NEWADDR:
|
||||
/* Ignore inconsistent addition or change (kernel will send a good one)
|
||||
*
|
||||
* Quick sequence of RTM_NEWLINK notifications can be occasionally
|
||||
@@ -642,6 +738,137 @@ link_set_noarp (NMPlatform *platform, int ifindex)
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static int
|
||||
ip_address_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->address_cache); object; object = nl_cache_get_next (object)) {
|
||||
nl_object_unmark (object);
|
||||
if (rtnl_addr_get_family ((struct rtnl_addr *) object) != family)
|
||||
continue;
|
||||
if (rtnl_addr_get_ifindex ((struct rtnl_addr *) object) != ifindex)
|
||||
continue;
|
||||
nl_object_mark (object);
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static GArray *
|
||||
ip4_address_get_all (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
GArray *addresses;
|
||||
NMPlatformIP4Address address;
|
||||
struct nl_object *object;
|
||||
int count;
|
||||
|
||||
count = ip_address_mark_all (platform, AF_INET, ifindex);
|
||||
addresses = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP4Address), count);
|
||||
|
||||
for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) {
|
||||
if (nl_object_is_marked (object)) {
|
||||
init_ip4_address (&address, (struct rtnl_addr *) object);
|
||||
g_array_append_val (addresses, address);
|
||||
nl_object_unmark (object);
|
||||
}
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
static GArray *
|
||||
ip6_address_get_all (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
GArray *addresses;
|
||||
NMPlatformIP6Address address;
|
||||
struct nl_object *object;
|
||||
int count;
|
||||
|
||||
count = ip_address_mark_all (platform, AF_INET6, ifindex);
|
||||
addresses = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP6Address), count);
|
||||
|
||||
for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) {
|
||||
if (nl_object_is_marked (object)) {
|
||||
init_ip6_address (&address, (struct rtnl_addr *) object);
|
||||
g_array_append_val (addresses, address);
|
||||
nl_object_unmark (object);
|
||||
}
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
static struct nl_object *
|
||||
build_rtnl_addr (int family, int ifindex, gconstpointer addr, int plen)
|
||||
{
|
||||
struct rtnl_addr *rtnladdr = rtnl_addr_alloc ();
|
||||
int addrlen = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr);
|
||||
auto_nl_addr struct nl_addr *nladdr = nl_addr_build (family, addr, addrlen);
|
||||
int nle;
|
||||
|
||||
g_assert (rtnladdr && nladdr);
|
||||
|
||||
rtnl_addr_set_ifindex (rtnladdr, ifindex);
|
||||
nle = rtnl_addr_set_local (rtnladdr, nladdr);
|
||||
g_assert (!nle);
|
||||
rtnl_addr_set_prefixlen (rtnladdr, plen);
|
||||
|
||||
return (struct nl_object *) rtnladdr;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_address_add (NMPlatform *platform, int ifindex, in_addr_t addr, int plen)
|
||||
{
|
||||
return add_object (platform, build_rtnl_addr (AF_INET, ifindex, &addr, plen));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_address_add (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
|
||||
{
|
||||
return add_object (platform, build_rtnl_addr (AF_INET6, ifindex, &addr, plen));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen)
|
||||
{
|
||||
return delete_object (platform, build_rtnl_addr (AF_INET, ifindex, &addr, plen));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
|
||||
{
|
||||
return delete_object (platform, build_rtnl_addr (AF_INET6, ifindex, &addr, plen));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip_address_exists (NMPlatform *platform, int family, int ifindex, gconstpointer addr, int plen)
|
||||
{
|
||||
auto_nl_object struct nl_object *object = build_rtnl_addr (family, ifindex, addr, plen);
|
||||
auto_nl_object struct nl_object *cached_object = nl_cache_search (choose_cache (platform, object), object);
|
||||
|
||||
return !!cached_object;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip4_address_exists (NMPlatform *platform, int ifindex, in_addr_t addr, int plen)
|
||||
{
|
||||
return ip_address_exists (platform, AF_INET, ifindex, &addr, plen);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip6_address_exists (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
|
||||
{
|
||||
return ip_address_exists (platform, AF_INET6, ifindex, &addr, plen);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
#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))
|
||||
@@ -735,6 +962,7 @@ setup (NMPlatform *platform)
|
||||
g_assert (!nle);
|
||||
nle = nl_socket_add_memberships (priv->nlh_event,
|
||||
RTNLGRP_LINK,
|
||||
RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR,
|
||||
NULL);
|
||||
g_assert (!nle);
|
||||
debug ("Netlink socket for events established: %d", nl_socket_get_local_port (priv->nlh_event));
|
||||
@@ -753,7 +981,8 @@ setup (NMPlatform *platform)
|
||||
|
||||
/* Allocate netlink caches */
|
||||
rtnl_link_alloc_cache (priv->nlh, AF_UNSPEC, &priv->link_cache);
|
||||
g_assert (priv->link_cache);
|
||||
rtnl_addr_alloc_cache (priv->nlh, &priv->address_cache);
|
||||
g_assert (priv->link_cache && priv->address_cache);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -769,6 +998,7 @@ nm_linux_platform_finalize (GObject *object)
|
||||
nl_socket_free (priv->nlh);
|
||||
nl_socket_free (priv->nlh_event);
|
||||
nl_cache_free (priv->link_cache);
|
||||
nl_cache_free (priv->address_cache);
|
||||
|
||||
G_OBJECT_CLASS (nm_linux_platform_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -802,4 +1032,13 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
|
||||
platform_class->link_is_up = link_is_up;
|
||||
platform_class->link_is_connected = link_is_connected;
|
||||
platform_class->link_uses_arp = link_uses_arp;
|
||||
|
||||
platform_class->ip4_address_get_all = ip4_address_get_all;
|
||||
platform_class->ip6_address_get_all = ip6_address_get_all;
|
||||
platform_class->ip4_address_add = ip4_address_add;
|
||||
platform_class->ip6_address_add = ip6_address_add;
|
||||
platform_class->ip4_address_delete = ip4_address_delete;
|
||||
platform_class->ip6_address_delete = ip6_address_delete;
|
||||
platform_class->ip4_address_exists = ip4_address_exists;
|
||||
platform_class->ip6_address_exists = ip6_address_exists;
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "nm-platform.h"
|
||||
#include "nm-logging.h"
|
||||
@@ -37,6 +38,12 @@ enum {
|
||||
LINK_ADDED,
|
||||
LINK_CHANGED,
|
||||
LINK_REMOVED,
|
||||
IP4_ADDRESS_ADDED,
|
||||
IP4_ADDRESS_CHANGED,
|
||||
IP4_ADDRESS_REMOVED,
|
||||
IP6_ADDRESS_ADDED,
|
||||
IP6_ADDRESS_CHANGED,
|
||||
IP6_ADDRESS_REMOVED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
@@ -473,6 +480,128 @@ nm_platform_link_set_noarp (int ifindex)
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
GArray *
|
||||
nm_platform_ip4_address_get_all (int ifindex)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (ifindex > 0, NULL);
|
||||
g_return_val_if_fail (klass->ip4_address_get_all, NULL);
|
||||
|
||||
return klass->ip4_address_get_all (platform, ifindex);
|
||||
}
|
||||
|
||||
GArray *
|
||||
nm_platform_ip6_address_get_all (int ifindex)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (ifindex > 0, NULL);
|
||||
g_return_val_if_fail (klass->ip6_address_get_all, NULL);
|
||||
|
||||
return klass->ip6_address_get_all (platform, ifindex);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_ip4_address_add (int ifindex, in_addr_t address, int plen)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (ifindex > 0, FALSE);
|
||||
g_return_val_if_fail (plen > 0, FALSE);
|
||||
g_return_val_if_fail (klass->ip4_address_add, FALSE);
|
||||
|
||||
if (nm_platform_ip4_address_exists (ifindex, address, plen)) {
|
||||
debug ("address already exists");
|
||||
platform->error = NM_PLATFORM_ERROR_EXISTS;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
debug ("address: adding IPv4 address");
|
||||
return klass->ip4_address_add (platform, ifindex, address, plen);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_ip6_address_add (int ifindex, struct in6_addr address, int plen)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (ifindex > 0, FALSE);
|
||||
g_return_val_if_fail (plen > 0, FALSE);
|
||||
g_return_val_if_fail (klass->ip6_address_add, FALSE);
|
||||
|
||||
if (nm_platform_ip6_address_exists (ifindex, address, plen)) {
|
||||
debug ("address already exists");
|
||||
platform->error = NM_PLATFORM_ERROR_EXISTS;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
debug ("address: adding IPv6 address");
|
||||
return klass->ip6_address_add (platform, ifindex, address, plen);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_ip4_address_delete (int ifindex, in_addr_t address, int plen)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (ifindex > 0, FALSE);
|
||||
g_return_val_if_fail (plen > 0, FALSE);
|
||||
g_return_val_if_fail (klass->ip4_address_delete, FALSE);
|
||||
|
||||
if (!nm_platform_ip4_address_exists (ifindex, address, plen)) {
|
||||
debug ("address doesn't exists");
|
||||
platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
debug ("address: deleting IPv4 address");
|
||||
return klass->ip4_address_delete (platform, ifindex, address, plen);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_ip6_address_delete (int ifindex, struct in6_addr address, int plen)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (ifindex > 0, FALSE);
|
||||
g_return_val_if_fail (plen > 0, FALSE);
|
||||
g_return_val_if_fail (klass->ip6_address_delete, FALSE);
|
||||
|
||||
if (!nm_platform_ip6_address_exists (ifindex, address, plen)) {
|
||||
debug ("address doesn't exists");
|
||||
platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
debug ("address: deleting IPv6 address");
|
||||
return klass->ip6_address_delete (platform, ifindex, address, plen);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_ip4_address_exists (int ifindex, in_addr_t address, int plen)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (plen > 0, FALSE);
|
||||
g_return_val_if_fail (klass->ip4_address_exists, FALSE);
|
||||
|
||||
return klass->ip4_address_exists (platform, ifindex, address, plen);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_ip6_address_exists (int ifindex, struct in6_addr address, int plen)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (plen > 0, FALSE);
|
||||
g_return_val_if_fail (klass->ip6_address_exists, FALSE);
|
||||
|
||||
return klass->ip6_address_exists (platform, ifindex, address, plen);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static void
|
||||
log_link_added (NMPlatform *p, NMPlatformLink *info, gpointer user_data)
|
||||
{
|
||||
@@ -491,6 +620,66 @@ log_link_removed (NMPlatform *p, NMPlatformLink *info, gpointer user_data)
|
||||
debug ("signal: link removed: '%s' (%d)", info->name, info->ifindex);
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip4_address (NMPlatformIP4Address *address, const char *change_type)
|
||||
{
|
||||
char addr[INET_ADDRSTRLEN];
|
||||
int plen = address->plen;
|
||||
const char *name = nm_platform_link_get_name (address->ifindex);
|
||||
|
||||
inet_ntop (AF_INET, &address->address, addr, sizeof (addr));
|
||||
|
||||
debug ("signal: address %s: %s/%d dev %s", change_type, addr, plen, name);
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip4_address_added (NMPlatform *p, NMPlatformIP4Address *address, gpointer user_data)
|
||||
{
|
||||
log_ip4_address (address, "added");
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip4_address_changed (NMPlatform *p, NMPlatformIP4Address *address, gpointer user_data)
|
||||
{
|
||||
log_ip4_address (address, "changed");
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip4_address_removed (NMPlatform *p, NMPlatformIP4Address *address, gpointer user_data)
|
||||
{
|
||||
log_ip4_address (address, "removed");
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip6_address (NMPlatformIP6Address *address, const char *change_type)
|
||||
{
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
int plen = address->plen;
|
||||
const char *name = nm_platform_link_get_name (address->ifindex);
|
||||
|
||||
inet_ntop (AF_INET6, &address->address, addr, sizeof (addr));
|
||||
|
||||
debug ("signal: address %s: %s/%d dev %s", change_type, addr, plen, name);
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip6_address_added (NMPlatform *p, NMPlatformIP6Address *address, gpointer user_data)
|
||||
{
|
||||
log_ip6_address (address, "added");
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip6_address_changed (NMPlatform *p, NMPlatformIP6Address *address, gpointer user_data)
|
||||
{
|
||||
log_ip6_address (address, "changed");
|
||||
}
|
||||
|
||||
static void
|
||||
log_ip6_address_removed (NMPlatform *p, NMPlatformIP6Address *address, gpointer user_data)
|
||||
{
|
||||
log_ip6_address (address, "removed");
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static void
|
||||
@@ -516,4 +705,10 @@ nm_platform_class_init (NMPlatformClass *platform_class)
|
||||
SIGNAL (LINK_ADDED, log_link_added)
|
||||
SIGNAL (LINK_CHANGED, log_link_changed)
|
||||
SIGNAL (LINK_REMOVED, log_link_removed)
|
||||
SIGNAL (IP4_ADDRESS_ADDED, log_ip4_address_added)
|
||||
SIGNAL (IP4_ADDRESS_CHANGED, log_ip4_address_changed)
|
||||
SIGNAL (IP4_ADDRESS_REMOVED, log_ip4_address_removed)
|
||||
SIGNAL (IP6_ADDRESS_ADDED, log_ip6_address_added)
|
||||
SIGNAL (IP6_ADDRESS_CHANGED, log_ip6_address_changed)
|
||||
SIGNAL (IP6_ADDRESS_REMOVED, log_ip6_address_removed)
|
||||
}
|
||||
|
@@ -52,6 +52,18 @@ typedef struct {
|
||||
gboolean arp;
|
||||
} NMPlatformLink;
|
||||
|
||||
typedef struct {
|
||||
int ifindex;
|
||||
in_addr_t address;
|
||||
int plen;
|
||||
} NMPlatformIP4Address;
|
||||
|
||||
typedef struct {
|
||||
int ifindex;
|
||||
struct in6_addr address;
|
||||
int plen;
|
||||
} NMPlatformIP6Address;
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
/* NMPlatform abstract class and its implementations provide a layer between
|
||||
@@ -107,6 +119,15 @@ typedef struct {
|
||||
gboolean (*link_is_up) (NMPlatform *, int ifindex);
|
||||
gboolean (*link_is_connected) (NMPlatform *, int ifindex);
|
||||
gboolean (*link_uses_arp) (NMPlatform *, int ifindex);
|
||||
|
||||
GArray * (*ip4_address_get_all) (NMPlatform *, int ifindex);
|
||||
GArray * (*ip6_address_get_all) (NMPlatform *, int ifindex);
|
||||
gboolean (*ip4_address_add) (NMPlatform *, int ifindex, in_addr_t address, int plen);
|
||||
gboolean (*ip6_address_add) (NMPlatform *, int ifindex, struct in6_addr address, int plen);
|
||||
gboolean (*ip4_address_delete) (NMPlatform *, int ifindex, in_addr_t address, int plen);
|
||||
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);
|
||||
} NMPlatformClass;
|
||||
|
||||
/* NMPlatform signals
|
||||
@@ -123,6 +144,12 @@ typedef struct {
|
||||
#define NM_PLATFORM_LINK_ADDED "link-added"
|
||||
#define NM_PLATFORM_LINK_CHANGED "link-changed"
|
||||
#define NM_PLATFORM_LINK_REMOVED "link-removed"
|
||||
#define NM_PLATFORM_IP4_ADDRESS_ADDED "ip4-address-added"
|
||||
#define NM_PLATFORM_IP4_ADDRESS_CHANGED "ip4-address-changed"
|
||||
#define NM_PLATFORM_IP4_ADDRESS_REMOVED "ip4-address-removed"
|
||||
#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"
|
||||
|
||||
/* NMPlatform error codes */
|
||||
enum {
|
||||
@@ -164,4 +191,13 @@ gboolean nm_platform_link_is_up (int ifindex);
|
||||
gboolean nm_platform_link_is_connected (int ifindex);
|
||||
gboolean nm_platform_link_uses_arp (int ifindex);
|
||||
|
||||
GArray *nm_platform_ip4_address_get_all (int ifindex);
|
||||
GArray *nm_platform_ip6_address_get_all (int ifindex);
|
||||
gboolean nm_platform_ip4_address_add (int ifindex, in_addr_t address, int plen);
|
||||
gboolean nm_platform_ip6_address_add (int ifindex, struct in6_addr address, int plen);
|
||||
gboolean nm_platform_ip4_address_delete (int ifindex, in_addr_t address, int plen);
|
||||
gboolean nm_platform_ip6_address_delete (int ifindex, struct in6_addr address, int plen);
|
||||
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);
|
||||
|
||||
#endif /* NM_PLATFORM_H */
|
||||
|
2
src/platform/tests/.gitignore
vendored
2
src/platform/tests/.gitignore
vendored
@@ -2,3 +2,5 @@
|
||||
/monitor
|
||||
/test-link-fake
|
||||
/test-link-linux
|
||||
/test-address-fake
|
||||
/test-address-linux
|
||||
|
@@ -20,7 +20,9 @@ noinst_PROGRAMS = \
|
||||
dump \
|
||||
monitor \
|
||||
test-link-fake \
|
||||
test-link-linux
|
||||
test-link-linux \
|
||||
test-address-fake \
|
||||
test-address-linux
|
||||
|
||||
EXTRA_DIST = test-common.h
|
||||
|
||||
@@ -54,6 +56,28 @@ test_link_linux_CPPFLAGS = \
|
||||
-DKERNEL_HACKS=1
|
||||
test_link_linux_LDADD = $(COMMON_LDADD)
|
||||
|
||||
test_address_fake_SOURCES = \
|
||||
test-address.c \
|
||||
test-common.c \
|
||||
${srcdir}/../nm-platform.c \
|
||||
${srcdir}/../nm-fake-platform.c
|
||||
test_address_fake_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
-DSETUP=nm_fake_platform_setup \
|
||||
-DKERNEL_HACKS=0
|
||||
test_address_fake_LDADD = $(COMMON_LDADD)
|
||||
|
||||
test_address_linux_SOURCES = \
|
||||
test-address.c \
|
||||
test-common.c \
|
||||
${srcdir}/../nm-platform.c \
|
||||
${srcdir}/../nm-linux-platform.c
|
||||
test_address_linux_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
-DSETUP=nm_linux_platform_setup \
|
||||
-DKERNEL_HACKS=1
|
||||
test_address_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.
|
||||
@@ -61,8 +85,8 @@ test_link_linux_LDADD = $(COMMON_LDADD)
|
||||
# However, we can check whether the fake platform fakes platform behavior
|
||||
# correctly.
|
||||
@VALGRIND_RULES@
|
||||
TESTS = ./test-link-fake
|
||||
ROOTTESTS = ./test-link-linux
|
||||
TESTS = ./test-link-fake ./test-address-fake
|
||||
ROOTTESTS = ./test-link-linux ./test-address-linux
|
||||
|
||||
# If explicitly enabled, we can run the root tests
|
||||
if RUN_ROOT_TESTS
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "nm-platform.h"
|
||||
#include "nm-linux-platform.h"
|
||||
@@ -23,6 +24,13 @@ type_to_string (NMLinkType type)
|
||||
static void
|
||||
dump_interface (NMPlatformLink *link)
|
||||
{
|
||||
GArray *ip6_addresses;
|
||||
GArray *ip4_addresses;
|
||||
const NMPlatformIP6Address *ip6_address;
|
||||
const NMPlatformIP4Address *ip4_address;
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
int i;
|
||||
|
||||
g_assert (link->up || !link->connected);
|
||||
|
||||
printf ("%d: %s: %s", link->ifindex, link->name, type_to_string (link->type));
|
||||
@@ -33,6 +41,27 @@ dump_interface (NMPlatformLink *link)
|
||||
if (!link->arp)
|
||||
printf (" noarp");
|
||||
printf ("\n");
|
||||
|
||||
ip4_addresses = nm_platform_ip4_address_get_all (link->ifindex);
|
||||
ip6_addresses = nm_platform_ip6_address_get_all (link->ifindex);
|
||||
|
||||
g_assert (ip4_addresses);
|
||||
g_assert (ip6_addresses);
|
||||
|
||||
for (i = 0; i < ip4_addresses->len; i++) {
|
||||
ip4_address = &g_array_index (ip4_addresses, NMPlatformIP4Address, i);
|
||||
inet_ntop (AF_INET, &ip4_address->address, addrstr, sizeof (addrstr));
|
||||
printf (" ip4-address %s/%d\n", addrstr, ip4_address->plen);
|
||||
}
|
||||
|
||||
for (i = 0; i < ip6_addresses->len; i++) {
|
||||
ip6_address = &g_array_index (ip6_addresses, NMPlatformIP6Address, i);
|
||||
inet_ntop (AF_INET6, &ip6_address->address, addrstr, sizeof (addrstr));
|
||||
printf (" ip6-address %s/%d\n", addrstr, ip6_address->plen);
|
||||
}
|
||||
|
||||
g_array_unref (ip4_addresses);
|
||||
g_array_unref (ip6_addresses);
|
||||
}
|
||||
|
||||
static void
|
||||
|
252
src/platform/tests/test-address.c
Normal file
252
src/platform/tests/test-address.c
Normal file
@@ -0,0 +1,252 @@
|
||||
#include "test-common.h"
|
||||
|
||||
#define DEVICE_NAME "nm-test-device"
|
||||
#define IP4_ADDRESS "192.0.2.1"
|
||||
#define IP4_PLEN 24
|
||||
#define IP6_ADDRESS "2001:db8:a:b:1:2:3:4"
|
||||
#define IP6_PLEN 64
|
||||
|
||||
static void
|
||||
ip4_address_callback (NMPlatform *platform, NMPlatformIP4Address *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_address_callback (NMPlatform *platform, NMPlatformIP6Address *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_address (void)
|
||||
{
|
||||
SignalData *address_added = add_signal (NM_PLATFORM_IP4_ADDRESS_ADDED, ip4_address_callback);
|
||||
SignalData *address_removed = add_signal (NM_PLATFORM_IP4_ADDRESS_REMOVED, ip4_address_callback);
|
||||
int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
|
||||
GArray *addresses;
|
||||
NMPlatformIP4Address addrs[2];
|
||||
in_addr_t addr;
|
||||
|
||||
inet_pton (AF_INET, IP4_ADDRESS, &addr);
|
||||
|
||||
/* Add address */
|
||||
g_assert (!nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
|
||||
no_error ();
|
||||
g_assert (nm_platform_ip4_address_add (ifindex, addr, IP4_PLEN));
|
||||
no_error ();
|
||||
g_assert (nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
|
||||
no_error ();
|
||||
accept_signal (address_added);
|
||||
|
||||
/* Add address again */
|
||||
g_assert (!nm_platform_ip4_address_add (ifindex, addr, IP4_PLEN));
|
||||
error (NM_PLATFORM_ERROR_EXISTS);
|
||||
|
||||
/* Test address listing */
|
||||
addresses = nm_platform_ip4_address_get_all (ifindex);
|
||||
g_assert (addresses);
|
||||
no_error ();
|
||||
memset (addrs, 0, sizeof (addrs));
|
||||
addrs[0].ifindex = ifindex;
|
||||
addrs[0].address = addr;
|
||||
addrs[0].plen = IP4_PLEN;
|
||||
g_assert (addresses->len == 1);
|
||||
g_assert (!memcmp (addresses->data, addrs, sizeof (addrs)));
|
||||
g_array_unref (addresses);
|
||||
|
||||
/* Remove address */
|
||||
g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN));
|
||||
no_error ();
|
||||
g_assert (!nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
|
||||
accept_signal (address_removed);
|
||||
|
||||
/* Remove address again */
|
||||
g_assert (!nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN));
|
||||
error (NM_PLATFORM_ERROR_NOT_FOUND);
|
||||
|
||||
free_signal (address_added);
|
||||
free_signal (address_removed);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip6_address (void)
|
||||
{
|
||||
SignalData *address_added = add_signal (NM_PLATFORM_IP6_ADDRESS_ADDED, ip6_address_callback);
|
||||
SignalData *address_removed = add_signal (NM_PLATFORM_IP6_ADDRESS_REMOVED, ip6_address_callback);
|
||||
int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
|
||||
GArray *addresses;
|
||||
NMPlatformIP6Address addrs[2];
|
||||
struct in6_addr addr;
|
||||
|
||||
inet_pton (AF_INET6, IP6_ADDRESS, &addr);
|
||||
|
||||
/* Add address */
|
||||
g_assert (!nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN));
|
||||
no_error ();
|
||||
g_assert (nm_platform_ip6_address_add (ifindex, addr, IP6_PLEN));
|
||||
no_error ();
|
||||
g_assert (nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN));
|
||||
no_error ();
|
||||
accept_signal (address_added);
|
||||
|
||||
/* Add address again */
|
||||
g_assert (!nm_platform_ip6_address_add (ifindex, addr, IP6_PLEN));
|
||||
error (NM_PLATFORM_ERROR_EXISTS);
|
||||
|
||||
/* Test address listing */
|
||||
addresses = nm_platform_ip6_address_get_all (ifindex);
|
||||
g_assert (addresses);
|
||||
no_error ();
|
||||
memset (addrs, 0, sizeof (addrs));
|
||||
addrs[0].ifindex = ifindex;
|
||||
addrs[0].address = addr;
|
||||
addrs[0].plen = IP6_PLEN;
|
||||
g_assert (addresses->len == 1);
|
||||
g_assert (!memcmp (addresses->data, addrs, sizeof (addrs)));
|
||||
g_array_unref (addresses);
|
||||
|
||||
/* Remove address */
|
||||
g_assert (nm_platform_ip6_address_delete (ifindex, addr, IP6_PLEN));
|
||||
no_error ();
|
||||
g_assert (!nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN));
|
||||
accept_signal (address_removed);
|
||||
|
||||
/* Remove address again */
|
||||
g_assert (!nm_platform_ip6_address_delete (ifindex, addr, IP6_PLEN));
|
||||
error (NM_PLATFORM_ERROR_NOT_FOUND);
|
||||
|
||||
free_signal (address_added);
|
||||
free_signal (address_removed);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip4_address_external (void)
|
||||
{
|
||||
SignalData *address_added = add_signal (NM_PLATFORM_IP4_ADDRESS_ADDED, ip4_address_callback);
|
||||
SignalData *address_removed = add_signal (NM_PLATFORM_IP4_ADDRESS_REMOVED, ip4_address_callback);
|
||||
int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
|
||||
in_addr_t addr;
|
||||
|
||||
inet_pton (AF_INET, IP4_ADDRESS, &addr);
|
||||
g_assert (ifindex > 0);
|
||||
|
||||
/* Looks like addresses are not announced by kerenl when the interface
|
||||
* is down. Link-local IPv6 address is automatically added.
|
||||
*/
|
||||
g_assert (nm_platform_link_set_up (nm_platform_link_get_ifindex (DEVICE_NAME)));
|
||||
|
||||
/* Add/delete notification */
|
||||
run_command ("ip address add %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME);
|
||||
wait_signal (address_added);
|
||||
g_assert (nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
|
||||
run_command ("ip address delete %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME);
|
||||
wait_signal (address_removed);
|
||||
g_assert (!nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
|
||||
|
||||
/* Add/delete conflict */
|
||||
run_command ("ip address add %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME);
|
||||
g_assert (nm_platform_ip4_address_add (ifindex, addr, IP4_PLEN));
|
||||
no_error ();
|
||||
g_assert (nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
|
||||
accept_signal (address_added);
|
||||
/*run_command ("ip address delete %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME);
|
||||
g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN));
|
||||
no_error ();
|
||||
g_assert (!nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
|
||||
accept_signal (address_removed);*/
|
||||
|
||||
free_signal (address_added);
|
||||
free_signal (address_removed);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip6_address_external (void)
|
||||
{
|
||||
SignalData *address_added = add_signal (NM_PLATFORM_IP6_ADDRESS_ADDED, ip6_address_callback);
|
||||
SignalData *address_removed = add_signal (NM_PLATFORM_IP6_ADDRESS_REMOVED, ip6_address_callback);
|
||||
int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
|
||||
struct in6_addr addr;
|
||||
|
||||
inet_pton (AF_INET6, IP6_ADDRESS, &addr);
|
||||
|
||||
/* Add/delete notification */
|
||||
run_command ("ip address add %s/%d dev %s", IP6_ADDRESS, IP6_PLEN, DEVICE_NAME);
|
||||
wait_signal (address_added);
|
||||
g_assert (nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN));
|
||||
run_command ("ip address delete %s/%d dev %s", IP6_ADDRESS, IP6_PLEN, DEVICE_NAME);
|
||||
wait_signal (address_removed);
|
||||
g_assert (!nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN));
|
||||
|
||||
/* Add/delete conflict */
|
||||
run_command ("ip address add %s/%d dev %s", IP6_ADDRESS, IP6_PLEN, DEVICE_NAME);
|
||||
g_assert (nm_platform_ip6_address_add (ifindex, addr, IP6_PLEN));
|
||||
no_error ();
|
||||
g_assert (nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN));
|
||||
accept_signal (address_added);
|
||||
/*run_command ("ip address delete %s/%d dev %s", IP6_ADDRESS, IP6_PLEN, DEVICE_NAME);
|
||||
g_assert (nm_platform_ip6_address_delete (ifindex, addr, IP6_PLEN));
|
||||
no_error ();
|
||||
g_assert (!nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN));
|
||||
wait_signal (address_removed);*/
|
||||
|
||||
free_signal (address_added);
|
||||
free_signal (address_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));
|
||||
nm_platform_dummy_add (DEVICE_NAME);
|
||||
|
||||
g_test_add_func ("/address/internal/ip4", test_ip4_address);
|
||||
g_test_add_func ("/address/internal/ip6", test_ip6_address);
|
||||
|
||||
if (strcmp (g_type_name (G_TYPE_FROM_INSTANCE (nm_platform_get ())), "NMFakePlatform")) {
|
||||
g_test_add_func ("/address/external/ip4", test_ip4_address_external);
|
||||
g_test_add_func ("/address/external/ip6", test_ip6_address_external);
|
||||
}
|
||||
|
||||
result = g_test_run ();
|
||||
|
||||
nm_platform_link_delete_by_name (DEVICE_NAME);
|
||||
nm_platform_free ();
|
||||
return result;
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "nm-logging.h"
|
||||
#include "nm-platform.h"
|
||||
|
Reference in New Issue
Block a user