rdisc: abstract class and fake implementation

Abstract class, fake implementation and a manual testing tool for
NetworkManager's internal IPv6 router discovery module. When a real
implementation is ready, it will replace nm-ip6-manager and will be used
by nm-device.
This commit is contained in:
Pavel Šimerda 2013-05-30 16:50:05 +02:00
parent 74d8d374b3
commit 21a8a71d48
9 changed files with 543 additions and 0 deletions

View file

@ -689,6 +689,8 @@ src/settings/plugins/example/Makefile
src/settings/tests/Makefile
src/platform/Makefile
src/platform/tests/Makefile
src/rdisc/Makefile
src/rdisc/tests/Makefile
src/devices/wimax/Makefile
libnm-util/libnm-util.pc
libnm-util/Makefile

1
src/rdisc/Makefile.am Normal file
View file

@ -0,0 +1 @@
SUBDIRS = tests

133
src/rdisc/nm-fake-rdisc.c Normal file
View file

@ -0,0 +1,133 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* nm-fake-rdisc.c - Fake implementation of router discovery
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2013 Red Hat, Inc.
*/
#include <string.h>
#include <arpa/inet.h>
#include "nm-fake-rdisc.h"
#include "nm-logging.h"
#define debug(...) nm_log_dbg (LOGD_IP6, __VA_ARGS__)
#define warning(...) nm_log_warn (LOGD_IP6, __VA_ARGS__)
#define error(...) nm_log_err (LOGD_IP6, __VA_ARGS__)
#define NM_FAKE_RDISC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_FAKE_RDISC, NMFakeRDiscPrivate))
G_DEFINE_TYPE (NMFakeRDisc, nm_fake_rdisc, NM_TYPE_RDISC)
/******************************************************************/
NMRDisc *
nm_fake_rdisc_new (int ifindex, const char *ifname)
{
NMRDisc *rdisc = g_object_new (NM_TYPE_FAKE_RDISC, NULL);
g_assert (rdisc);
rdisc->ifindex = ifindex;
rdisc->ifname = g_strdup (ifname);
return rdisc;
}
static void
delayed_start (NMRDisc *rdisc)
{
int changed =
NM_RDISC_CONFIG_GATEWAYS | NM_RDISC_CONFIG_ADDRESSES | NM_RDISC_CONFIG_ROUTES |
NM_RDISC_CONFIG_DNS_SERVERS | NM_RDISC_CONFIG_DNS_DOMAINS;
debug ("%d", rdisc->dhcp_level);
g_signal_emit_by_name (
rdisc, NM_RDISC_CONFIG_CHANGED, changed);
}
static void
start (NMRDisc *rdisc)
{
g_idle_add ((GSourceFunc) (delayed_start), rdisc);
}
/******************************************************************/
static void
nm_fake_rdisc_init (NMFakeRDisc *fake_rdisc)
{
NMRDisc *rdisc = NM_RDISC (fake_rdisc);
NMRDiscGateway gateway;
NMRDiscAddress address;
NMRDiscRoute route;
NMRDiscDNSServer dns_server;
NMRDiscDNSDomain dns_domain;
rdisc->dhcp_level = NM_RDISC_DHCP_LEVEL_NONE;
memset (&gateway, 0, sizeof (gateway));
inet_pton (AF_INET6, "fe80::1", &gateway.address);
g_array_append_val (rdisc->gateways, gateway);
inet_pton (AF_INET6, "fe80::2", &gateway.address);
g_array_append_val (rdisc->gateways, gateway);
inet_pton (AF_INET6, "fe80::3", &gateway.address);
g_array_append_val (rdisc->gateways, gateway);
memset (&address, 0, sizeof (address));
inet_pton (AF_INET6, "2001:db8:a:a::1", &address.address);
g_array_append_val (rdisc->addresses, address);
inet_pton (AF_INET6, "2001:db8:a:a::2", &address.address);
g_array_append_val (rdisc->addresses, address);
inet_pton (AF_INET6, "2001:db8:f:f::1", &address.address);
g_array_append_val (rdisc->addresses, address);
memset (&route, 0, sizeof (route));
route.plen = 64;
inet_pton (AF_INET6, "2001:db8:a:a::", &route.network);
g_array_append_val (rdisc->routes, route);
inet_pton (AF_INET6, "2001:db8:b:b::", &route.network);
g_array_append_val (rdisc->routes, route);
memset (&dns_server, 0, sizeof (dns_server));
inet_pton (AF_INET6, "2001:db8:c:c::1", &dns_server.address);
g_array_append_val (rdisc->dns_servers, dns_server);
inet_pton (AF_INET6, "2001:db8:c:c::2", &dns_server.address);
g_array_append_val (rdisc->dns_servers, dns_server);
inet_pton (AF_INET6, "2001:db8:c:c::3", &dns_server.address);
g_array_append_val (rdisc->dns_servers, dns_server);
inet_pton (AF_INET6, "2001:db8:c:c::4", &dns_server.address);
g_array_append_val (rdisc->dns_servers, dns_server);
inet_pton (AF_INET6, "2001:db8:c:c::5", &dns_server.address);
g_array_append_val (rdisc->dns_servers, dns_server);
memset (&dns_domain, 0, sizeof (dns_domain));
dns_domain.domain = g_strdup ("example.net");
g_array_append_val (rdisc->dns_domains, dns_domain);
dns_domain.domain = g_strdup ("example.com");
g_array_append_val (rdisc->dns_domains, dns_domain);
dns_domain.domain = g_strdup ("example.org");
g_array_append_val (rdisc->dns_domains, dns_domain);
}
static void
nm_fake_rdisc_class_init (NMFakeRDiscClass *klass)
{
NMRDiscClass *rdisc_class = NM_RDISC_CLASS (klass);
rdisc_class->start = start;
}

49
src/rdisc/nm-fake-rdisc.h Normal file
View file

@ -0,0 +1,49 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* nm-fake-rdisc.h - Fake implementation of router discovery
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2013 Red Hat, Inc.
*/
#ifndef NM_FAKE_RDISC_H
#define NM_FAKE_RDISC_H
#include "nm-rdisc.h"
#define NM_TYPE_FAKE_RDISC (nm_fake_rdisc_get_type ())
#define NM_FAKE_RDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_FAKE_RDISC, NMFakeRDisc))
#define NM_FAKE_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_FAKE_RDISC, NMFakeRDiscClass))
#define NM_IS_FAKE_RDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_FAKE_RDISC))
#define NM_IS_FAKE_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_FAKE_RDISC))
#define NM_FAKE_RDISC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_FAKE_RDISC, NMFakeRDiscClass))
/******************************************************************/
typedef struct {
NMRDisc parent;
} NMFakeRDisc;
typedef struct {
NMRDiscClass parent;
} NMFakeRDiscClass;
/******************************************************************/
GType nm_fake_rdisc_get_type (void);
NMRDisc *nm_fake_rdisc_new (int ifindex, const char *ifname);
#endif /* NM_FAKE_RDISC_H */

179
src/rdisc/nm-rdisc.c Normal file
View file

@ -0,0 +1,179 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* nm-rdisc.c - Perform IPv6 router discovery
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2013 Red Hat, Inc.
*/
#include <stdlib.h>
#include <arpa/inet.h>
#include "nm-rdisc.h"
#include "nm-logging.h"
#define debug(...) nm_log_dbg (LOGD_IP6, __VA_ARGS__)
G_DEFINE_TYPE (NMRDisc, nm_rdisc, G_TYPE_OBJECT)
enum {
CONFIG_CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
/******************************************************************/
void
nm_rdisc_set_lladdr (NMRDisc *rdisc, const char *addr, size_t addrlen)
{
rdisc->lladdr = g_bytes_new (addr, addrlen);
}
void
nm_rdisc_start (NMRDisc *rdisc)
{
NMRDiscClass *klass = NM_RDISC_GET_CLASS (rdisc);
g_assert (klass->start);
debug ("(%s): starting router discovery: %d", rdisc->ifname, rdisc->ifindex);
if (klass->start)
klass->start (rdisc);
}
#define CONFIG_MAP_MAX_STR 7
static void
config_map_to_string (NMRDiscConfigMap map, char *p)
{
if (map & NM_RDISC_CONFIG_DHCP_LEVEL)
*p++ = 'd';
if (map & NM_RDISC_CONFIG_GATEWAYS)
*p++ = 'G';
if (map & NM_RDISC_CONFIG_ADDRESSES)
*p++ = 'A';
if (map & NM_RDISC_CONFIG_ROUTES)
*p++ = 'R';
if (map & NM_RDISC_CONFIG_DNS_SERVERS)
*p++ = 'S';
if (map & NM_RDISC_CONFIG_DNS_DOMAINS)
*p++ = 'D';
*p = '\0';
}
static const char *
dhcp_level_to_string (NMRDiscDHCPLevel dhcp_level)
{
switch (dhcp_level) {
case NM_RDISC_DHCP_LEVEL_NONE:
return "none";
case NM_RDISC_DHCP_LEVEL_OTHERCONF:
return "otherconf";
case NM_RDISC_DHCP_LEVEL_MANAGED:
return "managed";
default:
return "INVALID";
}
}
#define expiry(item) (item->timestamp + item->lifetime)
static void
config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed)
{
int i;
char changedstr[CONFIG_MAP_MAX_STR];
char addrstr[INET6_ADDRSTRLEN];
config_map_to_string (changed, changedstr);
debug ("(%s): router discovery configuration changed [%s]:", rdisc->ifname, changedstr);
debug (" dhcp-level %s", dhcp_level_to_string (rdisc->dhcp_level));
for (i = 0; i < rdisc->gateways->len; i++) {
NMRDiscGateway *gateway = &g_array_index (rdisc->gateways, NMRDiscGateway, i);
inet_ntop (AF_INET6, &gateway->address, addrstr, sizeof (addrstr));
debug (" gateway %s pref %d exp %u", addrstr, gateway->preference, expiry (gateway));
}
for (i = 0; i < rdisc->addresses->len; i++) {
NMRDiscGateway *address = &g_array_index (rdisc->addresses, NMRDiscGateway, i);
inet_ntop (AF_INET6, &address->address, addrstr, sizeof (addrstr));
debug (" address %s exp %u", addrstr, expiry (address));
}
for (i = 0; i < rdisc->routes->len; i++) {
NMRDiscRoute *route = &g_array_index (rdisc->routes, NMRDiscRoute, i);
inet_ntop (AF_INET6, &route->network, addrstr, sizeof (addrstr));
debug (" route %s pref %d exp %u", addrstr, route->preference, expiry (route));
}
for (i = 0; i < rdisc->dns_servers->len; i++) {
NMRDiscDNSServer *dns_server = &g_array_index (rdisc->dns_servers, NMRDiscDNSServer, i);
inet_ntop (AF_INET6, &dns_server->address, addrstr, sizeof (addrstr));
debug (" dns_server %s exp %u", addrstr, expiry (dns_server));
}
for (i = 0; i < rdisc->dns_domains->len; i++) {
NMRDiscDNSDomain *dns_domain = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i);
debug (" dns_domain %s exp %u", dns_domain->domain, expiry (dns_domain));
}
}
/******************************************************************/
static void
nm_rdisc_init (NMRDisc *rdisc)
{
rdisc->gateways = g_array_new (FALSE, FALSE, sizeof (NMRDiscGateway));
rdisc->addresses = g_array_new (FALSE, FALSE, sizeof (NMRDiscAddress));
rdisc->routes = g_array_new (FALSE, FALSE, sizeof (NMRDiscRoute));
rdisc->dns_servers = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSServer));
rdisc->dns_domains = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSDomain));
}
static void
nm_rdisc_finalize (GObject *object)
{
NMRDisc *rdisc = NM_RDISC (object);
g_free (rdisc->ifname);
g_array_unref (rdisc->gateways);
g_array_unref (rdisc->addresses);
g_array_unref (rdisc->routes);
g_array_unref (rdisc->dns_servers);
g_array_unref (rdisc->dns_domains);
}
static void
nm_rdisc_class_init (NMRDiscClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = nm_rdisc_finalize;
klass->config_changed = config_changed;
signals[CONFIG_CHANGED] = g_signal_new (
NM_RDISC_CONFIG_CHANGED,
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMRDiscClass, config_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_INT);
}

130
src/rdisc/nm-rdisc.h Normal file
View file

@ -0,0 +1,130 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* nm-rdisc.h - Perform IPv6 router discovery
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2013 Red Hat, Inc.
*/
#ifndef NM_RDISC_H
#define NM_RDISC_H
#include <glib-object.h>
#include <stdlib.h>
#include <netinet/in.h>
#define NM_TYPE_RDISC (nm_rdisc_get_type ())
#define NM_RDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_RDISC, NMRDisc))
#define NM_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_RDISC, NMRDiscClass))
#define NM_IS_RDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_RDISC))
#define NM_IS_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_RDISC))
#define NM_RDISC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_RDISC, NMRDiscClass))
#define NM_RDISC_CONFIG_CHANGED "config-changed"
typedef enum {
NM_RDISC_DHCP_LEVEL_UNKNOWN,
NM_RDISC_DHCP_LEVEL_NONE,
NM_RDISC_DHCP_LEVEL_OTHERCONF,
NM_RDISC_DHCP_LEVEL_MANAGED
} NMRDiscDHCPLevel;
typedef enum {
NM_RDISC_PREFERENCE_INVALID,
NM_RDISC_PREFERENCE_LOW,
NM_RDISC_PREFERENCE_MEDIUM,
NM_RDISC_PREFERENCE_HIGH
} NMRDiscPreference;
typedef struct {
struct in6_addr address;
guint32 timestamp;
guint32 lifetime;
NMRDiscPreference preference;
} NMRDiscGateway;
typedef struct {
struct in6_addr address;
guint32 timestamp;
guint32 lifetime;
guint32 preferred_lft;
} NMRDiscAddress;
typedef struct {
struct in6_addr network;
int plen;
struct in6_addr gateway;
guint32 timestamp;
guint32 lifetime;
NMRDiscPreference preference;
} NMRDiscRoute;
typedef struct {
struct in6_addr address;
guint32 timestamp;
guint32 lifetime;
} NMRDiscDNSServer;
typedef struct {
char *domain;
guint32 timestamp;
guint32 lifetime;
} NMRDiscDNSDomain;
typedef enum {
NM_RDISC_CONFIG_DHCP_LEVEL = 1 << 0,
NM_RDISC_CONFIG_GATEWAYS = 1 << 1,
NM_RDISC_CONFIG_ADDRESSES = 1 << 2,
NM_RDISC_CONFIG_ROUTES = 1 << 3,
NM_RDISC_CONFIG_DNS_SERVERS = 1 << 4,
NM_RDISC_CONFIG_DNS_DOMAINS = 1 << 5
} NMRDiscConfigMap;
/**
* NMRDisc:
* @ifindex: Interface index
*
* Interface-specific structure that handles incoming router advertisements,
* caches advertised items and removes them when they are obsolete.
*/
typedef struct {
GObject parent;
int ifindex;
char *ifname;
GBytes *lladdr;
NMRDiscDHCPLevel dhcp_level;
GArray *gateways;
GArray *addresses;
GArray *routes;
GArray *dns_servers;
GArray *dns_domains;
} NMRDisc;
typedef struct {
GObjectClass parent;
void (*start) (NMRDisc *rdisc);
void (*config_changed) (NMRDisc *rdisc, NMRDiscConfigMap changed);
} NMRDiscClass;
GType nm_rdisc_get_type (void);
void nm_rdisc_set_lladdr (NMRDisc *rdisc, const char *addr, size_t addrlen);
void nm_rdisc_start (NMRDisc *rdisc);
#endif /* NM_RDISC_H */

1
src/rdisc/tests/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/rdisc

View file

@ -0,0 +1,22 @@
AM_CPPFLAGS = \
-I${top_srcdir} \
-I${top_srcdir}/src \
-I${top_srcdir}/src/logging \
-I${top_srcdir}/libnm-util \
-I${srcdir}/.. \
$(GLIB_CFLAGS) \
$(LIBNL_CFLAGS)
AM_CFLAGS = $(CODE_COVERAGE_CFLAGS)
AM_LDFLAGS = $(GLIB_LIBS) $(CODE_COVERAGE_LDFLAGS)
@GNOME_CODE_COVERAGE_RULES@
noinst_PROGRAMS = \
rdisc
rdisc_SOURCES = \
rdisc.c \
../nm-rdisc.c \
../nm-fake-rdisc.c \
../../logging/nm-logging.c

26
src/rdisc/tests/rdisc.c Normal file
View file

@ -0,0 +1,26 @@
#include <syslog.h>
#include "nm-rdisc.h"
#include "nm-fake-rdisc.h"
#include "nm-logging.h"
int
main (int argc, char **argv)
{
GMainLoop *loop;
NMRDisc *rdisc;
g_type_init ();
loop = g_main_loop_new (NULL, FALSE);
nm_logging_setup ("debug", NULL, NULL);
openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR, LOG_DAEMON);
rdisc = nm_fake_rdisc_new (1);
nm_rdisc_start (rdisc);
g_main_loop_run (loop);
g_clear_object (&rdisc);
return EXIT_SUCCESS;
}