device: use internal router discovery implementation

This commit is contained in:
Pavel Šimerda 2013-05-30 16:53:23 +02:00
parent c3a4656a68
commit bd1c7fbece
3 changed files with 127 additions and 148 deletions

View file

@ -609,7 +609,7 @@ fi
AM_CONDITIONAL(BUILD_LIBNDP, test "${build_libndp}" = yes)
if test "$build_libndp" = yes; then
LIBNDP_CFLAGS='-I$(top_srcdir)/libndp/include'
LIBNDP_LIBS='$(top_builddir)/libndp/libndp/libndp.la'
LIBNDP_LIBS='$(top_builddir)/libndp/libndp/.libs/libndp.a'
AC_SUBST(LIBNDP_CFLAGS)
AC_SUBST(LIBNDP_LIBS)
libndp_location=bundled

View file

@ -43,7 +43,7 @@ sbin_PROGRAMS = NetworkManager
NetworkManager_SOURCES = \
main.c
NetworkManager_LDADD = libNetworkManager.la $(top_builddir)/libgsystem.la
NetworkManager_LDADD = libNetworkManager.la $(top_builddir)/libgsystem.la $(LIBNDP_LIBS)
noinst_LTLIBRARIES = libNetworkManager.la
@ -143,6 +143,13 @@ nm_sources = \
platform/nm-platform.c \
platform/nm-platform.h \
\
rdisc/nm-fake-rdisc.c \
rdisc/nm-fake-rdisc.h \
rdisc/nm-lndp-rdisc.c \
rdisc/nm-lndp-rdisc.h \
rdisc/nm-rdisc.c \
rdisc/nm-rdisc.h \
\
posix-signals/nm-posix-signals.c \
posix-signals/nm-posix-signals.h \
\
@ -344,6 +351,7 @@ AM_CPPFLAGS = \
$(GLIB_CFLAGS) \
$(GUDEV_CFLAGS) \
$(LIBNL_CFLAGS) \
$(LIBNDP_CFLAGS) \
$(LIBSOUP_CFLAGS) \
$(MM_GLIB_CFLAGS) \
$(POLKIT_CFLAGS) \

View file

@ -43,6 +43,8 @@
#include "nm-device-ethernet.h"
#include "NetworkManagerUtils.h"
#include "nm-platform.h"
#include "nm-rdisc.h"
#include "nm-lndp-rdisc.h"
#include "nm-dhcp-manager.h"
#include "nm-dbus-manager.h"
#include "nm-utils.h"
@ -52,7 +54,6 @@
#include "nm-setting-connection.h"
#include "nm-dnsmasq-manager.h"
#include "nm-dhcp4-config.h"
#include "nm-ip6-manager.h"
#include "nm-rfkill-manager.h"
#include "nm-firewall-manager.h"
#include "nm-properties-changed-signal.h"
@ -253,10 +254,8 @@ typedef struct {
NMIP6Config * ip6_config;
IpState ip6_state;
NMIP6Manager * ip6_manager;
gulong ip6_addrconf_sigid;
gulong ip6_config_changed_sigid;
gboolean ip6_waiting_for_config;
NMRDisc * rdisc;
gulong rdisc_config_changed_sigid;
/* IP6 config from autoconf */
NMIP6Config * ac_ip6_config;
@ -268,7 +267,7 @@ typedef struct {
gint32 ip6_privacy_tempaddr_save;
NMDHCPClient * dhcp6_client;
guint32 dhcp6_mode;
NMRDiscDHCPLevel dhcp6_mode;
gulong dhcp6_state_sigid;
gulong dhcp6_timeout_sigid;
NMDHCP6Config * dhcp6_config;
@ -2658,7 +2657,7 @@ dhcp6_state_changed (NMDHCPClient *client,
* may exit right after getting a response from the server. That's
* normal. In that case we just ignore the exit.
*/
if (priv->dhcp6_mode == IP6_DHCP_OPT_OTHERCONF)
if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_OTHERCONF)
break;
/* Otherwise, fall through */
case DHC_FAIL: /* all attempts to contact server timed out, sleeping */
@ -2681,7 +2680,7 @@ dhcp6_timeout (NMDHCPClient *client, gpointer user_data)
g_return_if_fail (nm_dhcp_client_get_ipv6 (client) == TRUE);
nm_dhcp_client_stop (client, FALSE);
if (priv->dhcp6_mode == IP6_DHCP_OPT_MANAGED)
if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_MANAGED)
dhcp6_fail (device, TRUE);
else {
/* not a hard failure; just live with the RA info */
@ -2739,7 +2738,7 @@ dhcp6_start (NMDevice *self,
nm_connection_get_setting_ip6_config (connection),
priv->dhcp_timeout,
anycast,
(dhcp_opt == IP6_DHCP_OPT_OTHERCONF) ? TRUE : FALSE);
(dhcp_opt == NM_RDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE);
if (tmp)
g_byte_array_free (tmp, TRUE);
@ -2765,117 +2764,111 @@ dhcp6_start (NMDevice *self,
/******************************************/
static void
ip6_addrconf_complete (NMIP6Manager *ip6_manager,
int ifindex,
guint dhcp_opts,
gboolean success,
gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
NMActStageReturn ret;
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
static void dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release);
if (ifindex != nm_device_get_ip_ifindex (self))
return;
g_return_if_fail (priv->act_request != NULL);
connection = nm_device_get_connection (self);
static void
rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
NMConnection *connection;
int i;
NMDeviceStateReason reason;
g_return_if_fail (priv->act_request);
connection = nm_device_get_connection (device);
g_assert (connection);
if (!priv->ip6_waiting_for_config)
return;
if (!priv->ac_ip6_config)
priv->ac_ip6_config = nm_ip6_config_new ();
priv->ip6_waiting_for_config = FALSE;
if (changed & NM_RDISC_CONFIG_GATEWAYS) {
/* Use the first gateway as ordered in router discovery cache. */
if (rdisc->gateways->len) {
NMRDiscGateway *gateway = &g_array_index (rdisc->gateways, NMRDiscGateway, 0);
if (!success) {
nm_device_activate_schedule_ip6_config_timeout (self);
return;
nm_ip6_config_set_gateway (priv->ac_ip6_config, &gateway->address);
} else
nm_ip6_config_set_gateway (priv->ac_ip6_config, NULL);
}
priv->dhcp6_mode = dhcp_opts;
if (changed & NM_RDISC_CONFIG_ADDRESSES) {
/* Rebuild address list from router discovery cache. */
nm_ip6_config_reset_addresses (priv->ac_ip6_config);
/* If addrconf is all that's required, we're done */
if (priv->dhcp6_mode == IP6_DHCP_OPT_NONE) {
priv->ac_ip6_config = nm_ip6_manager_get_ip6_config (ip6_manager, ifindex);
if (priv->ac_ip6_config)
nm_device_activate_schedule_ip6_config_result (self);
else {
/* FIXME: Initial RA/autoconf failed; should we fail IPv6 entirely then? */
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
for (i = 0; i < rdisc->addresses->len; i++) {
NMRDiscAddress *discovered_address = &g_array_index (rdisc->addresses, NMRDiscAddress, i);
NMPlatformIP6Address address;
memset (&address, 0, sizeof (address));
address.address = discovered_address->address;
address.plen = 128;
nm_ip6_config_add_address (priv->ac_ip6_config, &address);
}
return;
}
/* If the router said to use DHCP for managed or otherconf, do it */
if (changed & NM_RDISC_CONFIG_ROUTES) {
/* Rebuild route list from router discovery cache. */
nm_ip6_config_reset_routes (priv->ac_ip6_config);
/* Don't re-start DHCPv6 if it's already in progress */
if (priv->ip6_state != IP_CONF)
return;
for (i = 0; i < rdisc->routes->len; i++) {
NMRDiscRoute *discovered_route = &g_array_index (rdisc->routes, NMRDiscRoute, i);
NMIP6Route *route = nm_ip6_route_new ();
nm_log_info (LOGD_DEVICE | LOGD_DHCP6,
"Activation (%s) Stage 3 of 5 (IP Configure Start) starting DHCPv6"
" as requested by IPv6 router...",
priv->iface);
nm_ip6_route_set_dest (route, &discovered_route->network);
nm_ip6_route_set_prefix (route, discovered_route->plen);
nm_ip6_route_set_next_hop (route, &discovered_route->gateway);
ret = dhcp6_start (self, connection, priv->dhcp6_mode, &reason);
switch (ret) {
case NM_ACT_STAGE_RETURN_SUCCESS:
/* Shouldn't get this, but handle it anyway */
g_warn_if_reached ();
priv->ac_ip6_config = nm_ip6_manager_get_ip6_config (ip6_manager, ifindex);
if (priv->ac_ip6_config)
nm_device_activate_schedule_ip6_config_result (self);
else {
/* FIXME: Initial RA/autoconf failed; should we fail IPv6 entirely then? */
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
nm_ip6_config_take_route (priv->ac_ip6_config, route);
}
break;
case NM_ACT_STAGE_RETURN_POSTPONE:
/* Cache acquired autoconf config and wait for DHCPv6 to complete */
priv->ac_ip6_config = nm_ip6_manager_get_ip6_config (ip6_manager, ifindex);
break;
default:
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
break;
}
}
static void
ip6_config_changed (NMIP6Manager *ip6_manager,
int ifindex,
guint dhcp_opts,
gboolean success,
gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
if (ifindex != nm_device_get_ip_ifindex (self))
return;
g_return_if_fail (priv->act_request != NULL);
/* If autoconf failed and IPv6 previously succeeded, fail */
if (!success && (priv->ip6_state == IP_DONE)) {
nm_device_state_changed (self,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
return;
}
/* FIXME: re-run DHCPv6 here to get any new nameservers or whatever */
if (changed & NM_RDISC_CONFIG_DNS_SERVERS) {
/* Rebuild DNS server list from router discovery cache. */
nm_ip6_config_reset_nameservers (priv->ac_ip6_config);
if (priv->ac_ip6_config)
g_object_unref (priv->ac_ip6_config);
priv->ac_ip6_config = nm_ip6_manager_get_ip6_config (ip6_manager, ifindex);
for (i = 0; i < rdisc->dns_servers->len; i++) {
NMRDiscDNSServer *discovered_server = &g_array_index (rdisc->dns_servers, NMRDiscDNSServer, i);
if (ip6_config_merge_and_apply (self, &reason) == FALSE) {
nm_log_warn (LOGD_DHCP6, "(%s): failed to update IPv6 config in response to Router Advertisement.",
nm_device_get_ip_iface (self));
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
nm_ip6_config_add_nameserver (priv->ac_ip6_config, &discovered_server->address);
}
}
if (changed & NM_RDISC_CONFIG_DNS_DOMAINS) {
for (i = 0; i < rdisc->dns_domains->len; i++) {
NMRDiscDNSDomain *discovered_domain = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i);
nm_ip6_config_add_domain (priv->ac_ip6_config, discovered_domain->domain);
}
}
if (changed & NM_RDISC_CONFIG_DHCP_LEVEL) {
dhcp6_cleanup (device, TRUE, TRUE);
priv->dhcp6_mode = rdisc->dhcp_level;
switch (priv->dhcp6_mode) {
case NM_RDISC_DHCP_LEVEL_NONE:
break;
default:
nm_log_info (LOGD_DEVICE | LOGD_DHCP6,
"Activation (%s) Stage 3 of 5 (IP Configure Start) starting DHCPv6"
" as requested by IPv6 router...",
priv->iface);
switch (dhcp6_start (device, connection, priv->dhcp6_mode, &reason)) {
case NM_ACT_STAGE_RETURN_SUCCESS:
g_warn_if_reached ();
break;
case NM_ACT_STAGE_RETURN_POSTPONE:
return;
default:
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
return;
}
}
}
nm_device_activate_schedule_ip6_config_result (device);
}
static gboolean
@ -2883,7 +2876,6 @@ addrconf6_start (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
gboolean success;
connection = nm_device_get_connection (self);
g_assert (connection);
@ -2894,31 +2886,24 @@ addrconf6_start (NMDevice *self)
priv->ac_ip6_config = NULL;
}
if (!priv->ip6_manager) {
priv->ip6_manager = nm_ip6_manager_get ();
priv->ip6_addrconf_sigid = g_signal_connect (priv->ip6_manager,
"addrconf-complete",
G_CALLBACK (ip6_addrconf_complete),
self);
priv->ip6_config_changed_sigid = g_signal_connect (priv->ip6_manager,
"config-changed",
G_CALLBACK (ip6_config_changed),
self);
priv->rdisc = nm_lndp_rdisc_new (nm_device_get_ip_ifindex (self), nm_device_get_ip_iface (self));
nm_platform_sysctl_set (priv->ip6_accept_ra_path, "0");
if (!priv->rdisc) {
nm_log_err (LOGD_IP6, "Failed to start router discovery.");
return FALSE;
}
g_warn_if_fail (priv->hw_addr_len != 0);
success = nm_ip6_manager_prepare_interface (priv->ip6_manager,
nm_device_get_ip_ifindex (self),
priv->hw_addr,
priv->hw_addr_len,
nm_connection_get_setting_ip6_config (connection),
priv->ip6_accept_ra_path);
if (success) {
priv->ip6_waiting_for_config = TRUE;
nm_ip6_manager_begin_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self));
}
priv->rdisc_config_changed_sigid = g_signal_connect (
priv->rdisc, NM_RDISC_CONFIG_CHANGED, G_CALLBACK (rdisc_config_changed), self);
return success;
/* FIXME: what if interface has no lladdr, like PPP? */
if (priv->hw_addr_len)
nm_rdisc_set_lladdr (priv->rdisc, (const char *) priv->hw_addr, priv->hw_addr_len);
nm_rdisc_start (priv->rdisc);
return TRUE;
}
static void
@ -2926,28 +2911,14 @@ addrconf6_cleanup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->ac_ip6_config) {
g_object_unref (priv->ac_ip6_config);
priv->ac_ip6_config = NULL;
if (priv->rdisc_config_changed_sigid) {
g_signal_handler_disconnect (priv->rdisc,
priv->rdisc_config_changed_sigid);
priv->rdisc_config_changed_sigid = 0;
}
if (!priv->ip6_manager)
return;
if (priv->ip6_addrconf_sigid) {
g_signal_handler_disconnect (priv->ip6_manager,
priv->ip6_addrconf_sigid);
priv->ip6_addrconf_sigid = 0;
}
if (priv->ip6_config_changed_sigid) {
g_signal_handler_disconnect (priv->ip6_manager,
priv->ip6_config_changed_sigid);
priv->ip6_config_changed_sigid = 0;
}
nm_ip6_manager_cancel_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self));
g_object_unref (priv->ip6_manager);
priv->ip6_manager = NULL;
g_clear_object (&priv->ac_ip6_config);
g_clear_object (&priv->rdisc);
}
/******************************************/
@ -3073,7 +3044,7 @@ act_stage3_ip6_config_start (NMDevice *self,
update_accept_ra_save (self);
update_ip6_privacy_save (self);
priv->dhcp6_mode = IP6_DHCP_OPT_NONE;
priv->dhcp6_mode = NM_RDISC_DHCP_LEVEL_NONE;
if ( strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0
|| strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) {
@ -3087,7 +3058,7 @@ act_stage3_ip6_config_start (NMDevice *self,
if (priv->ip6_accept_ra_path)
nm_utils_do_sysctl (priv->ip6_accept_ra_path, "0");
priv->dhcp6_mode = IP6_DHCP_OPT_MANAGED;
priv->dhcp6_mode = NM_RDISC_DHCP_LEVEL_MANAGED;
ret = dhcp6_start (self, connection, priv->dhcp6_mode, reason);
} else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0) {
/* reset the saved RA value when ipv6 is ignored */
@ -3887,7 +3858,7 @@ dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
priv->dhcp6_mode = IP6_DHCP_OPT_NONE;
priv->dhcp6_mode = NM_RDISC_DHCP_LEVEL_NONE;
if (priv->dhcp6_ip6_config) {
g_object_unref (priv->dhcp6_ip6_config);