From beebbbb24902cc3967afd5a8ef6514ad22827d5f Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 5 Apr 2018 15:19:27 +0200 Subject: core: rename 'arping' to 'acd' Now that the ACD functionality is no longer using arping, rename nm-arping-manager to nm-acd-manager and other occurences of arping as well. --- .gitignore | 3 +- Makefile.am | 14 +- src/devices/nm-acd-manager.c | 490 ++++++++++++++++++++++++++++++++++++++++ src/devices/nm-acd-manager.h | 43 ++++ src/devices/nm-arping-manager.c | 490 ---------------------------------------- src/devices/nm-arping-manager.h | 43 ---- src/devices/nm-device.c | 72 +++--- src/devices/tests/meson.build | 2 +- src/devices/tests/test-acd.c | 185 +++++++++++++++ src/devices/tests/test-arping.c | 185 --------------- src/meson.build | 2 +- src/nm-types.h | 4 +- 12 files changed, 767 insertions(+), 766 deletions(-) create mode 100644 src/devices/nm-acd-manager.c create mode 100644 src/devices/nm-acd-manager.h delete mode 100644 src/devices/nm-arping-manager.c delete mode 100644 src/devices/nm-arping-manager.h create mode 100644 src/devices/tests/test-acd.c delete mode 100644 src/devices/tests/test-arping.c diff --git a/.gitignore b/.gitignore index 15284f5267..febc17298a 100644 --- a/.gitignore +++ b/.gitignore @@ -243,7 +243,7 @@ test-*.trs /src/NetworkManager /src/NetworkManager.ver -/src/devices/tests/test-arping +/src/devices/tests/test-acd /src/devices/tests/test-lldp /src/devices/wifi/tests/test-general /src/dhcp/nm-dhcp-helper @@ -314,3 +314,4 @@ test-*.trs /libnm-core/tests/test-setting-dcb /src/settings/plugins/ifnet /src/tests/test-resolvconf-capture +/src/devices/tests/test-arping diff --git a/Makefile.am b/Makefile.am index bbfd1d56b1..b488c37e80 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1497,8 +1497,8 @@ src_libNetworkManager_la_SOURCES = \ src/devices/nm-device.h \ src/devices/nm-lldp-listener.c \ src/devices/nm-lldp-listener.h \ - src/devices/nm-arping-manager.c \ - src/devices/nm-arping-manager.h \ + src/devices/nm-acd-manager.c \ + src/devices/nm-acd-manager.h \ src/devices/nm-device-ethernet-utils.c \ src/devices/nm-device-ethernet-utils.h \ src/devices/nm-device-factory.c \ @@ -2999,20 +2999,20 @@ src_devices_tests_ldflags = \ check_programs += \ src/devices/tests/test-lldp \ - src/devices/tests/test-arping + src/devices/tests/test-acd src_devices_tests_test_lldp_CPPFLAGS = $(src_tests_cppflags) src_devices_tests_test_lldp_LDFLAGS = $(src_devices_tests_ldflags) src_devices_tests_test_lldp_LDADD = \ src/libNetworkManagerTest.la -src_devices_tests_test_arping_CPPFLAGS = $(src_tests_cppflags) -src_devices_tests_test_arping_LDFLAGS = $(src_devices_tests_ldflags) -src_devices_tests_test_arping_LDADD = \ +src_devices_tests_test_acd_CPPFLAGS = $(src_tests_cppflags) +src_devices_tests_test_acd_LDFLAGS = $(src_devices_tests_ldflags) +src_devices_tests_test_acd_LDADD = \ src/libNetworkManagerTest.la $(src_devices_tests_test_lldp_OBJECTS): $(libnm_core_lib_h_pub_mkenums) -$(src_devices_tests_test_arping_OBJECTS): $(libnm_core_lib_h_pub_mkenums) +$(src_devices_tests_test_acd_OBJECTS): $(libnm_core_lib_h_pub_mkenums) EXTRA_DIST += \ src/devices/tests/meson.build diff --git a/src/devices/nm-acd-manager.c b/src/devices/nm-acd-manager.c new file mode 100644 index 0000000000..3feb9de7b1 --- /dev/null +++ b/src/devices/nm-acd-manager.c @@ -0,0 +1,490 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * 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 of the License, 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. + * + * Copyright (C) 2015-2018 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-acd-manager.h" + +#include +#include +#include + +#include "platform/nm-platform.h" +#include "nm-utils.h" +#include "NetworkManagerUtils.h" +#include "n-acd/src/n-acd.h" + +/*****************************************************************************/ + +typedef enum { + STATE_INIT, + STATE_PROBING, + STATE_PROBE_DONE, + STATE_ANNOUNCING, +} State; + +typedef struct { + in_addr_t address; + gboolean duplicate; + NMAcdManager *manager; + NAcd *acd; + GIOChannel *channel; + guint event_id; +} AddressInfo; + +enum { + PROBE_TERMINATED, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +typedef struct { + int ifindex; + guint8 hwaddr[ETH_ALEN]; + State state; + GHashTable *addresses; + guint completed; +} NMAcdManagerPrivate; + +struct _NMAcdManager { + GObject parent; + NMAcdManagerPrivate _priv; +}; + +struct _NMAcdManagerClass { + GObjectClass parent; +}; + +G_DEFINE_TYPE (NMAcdManager, nm_acd_manager, G_TYPE_OBJECT) + +#define NM_ACD_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMAcdManager, NM_IS_ACD_MANAGER) + +/*****************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_IP4 +#define _NMLOG_PREFIX_NAME "acd" +#define _NMLOG(level, ...) \ + G_STMT_START { \ + char _sbuf[64]; \ + int _ifindex = (self) ? NM_ACD_MANAGER_GET_PRIVATE (self)->ifindex : 0; \ + \ + nm_log ((level), _NMLOG_DOMAIN, \ + nm_platform_link_get_name (NM_PLATFORM_GET, _ifindex), \ + NULL, \ + "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + self ? nm_sprintf_buf (_sbuf, "[%p,%d]", self, _ifindex) : "" \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } G_STMT_END + +/*****************************************************************************/ + +static const char * +_acd_event_to_string (unsigned int event) +{ + switch (event) { + case N_ACD_EVENT_READY: + return "ready"; + case N_ACD_EVENT_USED: + return "used"; + case N_ACD_EVENT_DEFENDED: + return "defended"; + case N_ACD_EVENT_CONFLICT: + return "conflict"; + case N_ACD_EVENT_DOWN: + return "down"; + } + return NULL; +} + +#define acd_event_to_string(event) NM_UTILS_LOOKUP_STR (_acd_event_to_string, event) + +static const char * +_acd_error_to_string (int error) +{ + if (error < 0) + return strerror(-error); + + switch (error) { + case _N_ACD_E_SUCCESS: + return "success"; + case N_ACD_E_DONE: + return "no more events (engine running)"; + case N_ACD_E_STOPPED: + return "no more events (engine stopped)"; + case N_ACD_E_PREEMPTED: + return "preempted"; + case N_ACD_E_INVALID_ARGUMENT: + return "invalid argument"; + case N_ACD_E_BUSY: + return "busy"; + } + return NULL; +} + +#define acd_error_to_string(error) NM_UTILS_LOOKUP_STR (_acd_error_to_string, error) + +/*****************************************************************************/ + +/** + * nm_acd_manager_add_address: + * @self: a #NMAcdManager + * @address: an IP address + * + * Add @address to the list of IP addresses to probe. + + * Returns: %TRUE on success, %FALSE if the address was already in the list + */ +gboolean +nm_acd_manager_add_address (NMAcdManager *self, in_addr_t address) +{ + NMAcdManagerPrivate *priv; + AddressInfo *info; + + g_return_val_if_fail (NM_IS_ACD_MANAGER (self), FALSE); + priv = NM_ACD_MANAGER_GET_PRIVATE (self); + g_return_val_if_fail (priv->state == STATE_INIT, FALSE); + + if (g_hash_table_lookup (priv->addresses, GUINT_TO_POINTER (address))) + return FALSE; + + info = g_slice_new0 (AddressInfo); + info->address = address; + info->manager = self; + + g_hash_table_insert (priv->addresses, GUINT_TO_POINTER (address), info); + + return TRUE; +} + +static gboolean +acd_event (GIOChannel *source, GIOCondition condition, gpointer data) +{ + AddressInfo *info = data; + NMAcdManager *self = info->manager; + NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); + NAcdEvent *event; + char address_str[INET_ADDRSTRLEN]; + gs_free char *hwaddr_str = NULL; + int r; + + if ( n_acd_dispatch (info->acd) + || n_acd_pop_event (info->acd, &event)) + return G_SOURCE_CONTINUE; + + switch (event->event) { + case N_ACD_EVENT_READY: + info->duplicate = FALSE; + if (priv->state == STATE_ANNOUNCING) { + r = n_acd_announce (info->acd, N_ACD_DEFEND_ONCE); + if (r) { + _LOGW ("couldn't announce address %s on interface '%s': %s", + nm_utils_inet4_ntop (info->address, address_str), + nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), + acd_error_to_string (r)); + } else { + _LOGD ("announcing address %s", + nm_utils_inet4_ntop (info->address, address_str)); + } + } + break; + case N_ACD_EVENT_USED: + info->duplicate = TRUE; + break; + case N_ACD_EVENT_DEFENDED: + _LOGD ("defended address %s from host %s", + nm_utils_inet4_ntop (info->address, address_str), + (hwaddr_str = nm_utils_hwaddr_ntoa (event->defended.sender, + event->defended.n_sender))); + break; + case N_ACD_EVENT_CONFLICT: + _LOGW ("conflict for address %s detected with host %s on interface '%s'", + nm_utils_inet4_ntop (info->address, address_str), + (hwaddr_str = nm_utils_hwaddr_ntoa (event->defended.sender, + event->defended.n_sender)), + nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex)); + break; + default: + _LOGD ("event '%s' for address %s", + acd_event_to_string (event->event), + nm_utils_inet4_ntop (info->address, address_str)); + return G_SOURCE_CONTINUE; + } + + if ( priv->state == STATE_PROBING + && ++priv->completed == g_hash_table_size (priv->addresses)) { + priv->state = STATE_PROBE_DONE; + g_signal_emit (self, signals[PROBE_TERMINATED], 0); + } + + return G_SOURCE_CONTINUE; +} + +static gboolean +acd_probe_start (NMAcdManager *self, + AddressInfo *info, + guint64 timeout) +{ + NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); + NAcdConfig *config; + int r, fd; + + r = n_acd_new (&info->acd); + if (r) { + _LOGW ("could not create ACD for %s on interface '%s': %s", + nm_utils_inet4_ntop (info->address, NULL), + nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), + acd_error_to_string (r)); + return FALSE; + } + + n_acd_get_fd (info->acd, &fd); + info->channel = g_io_channel_unix_new (fd); + info->event_id = g_io_add_watch (info->channel, G_IO_IN, acd_event, info); + + config = &(NAcdConfig) { + .ifindex = priv->ifindex, + .mac = priv->hwaddr, + .n_mac = ETH_ALEN, + .ip = info->address, + .timeout_msec = timeout, + .transport = N_ACD_TRANSPORT_ETHERNET, + }; + + r = n_acd_start (info->acd, config); + if (r) { + _LOGW ("could not start probe for %s on interface '%s': %s", + nm_utils_inet4_ntop (info->address, NULL), + nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), + acd_error_to_string (r)); + return FALSE; + } + + _LOGD ("start probe for %s", nm_utils_inet4_ntop (info->address, NULL)); + + return TRUE; +} + +/** + * nm_acd_manager_start_probe: + * @self: a #NMAcdManager + * @timeout: maximum probe duration in milliseconds + * @error: location to store error, or %NULL + * + * Start probing IP addresses for duplicates; when the probe terminates a + * PROBE_TERMINATED signal is emitted. + * + * Returns: %TRUE if at least one probe could be started, %FALSE otherwise + */ +gboolean +nm_acd_manager_start_probe (NMAcdManager *self, guint timeout) +{ + NMAcdManagerPrivate *priv; + GHashTableIter iter; + AddressInfo *info; + gs_free char *timeout_str = NULL; + gboolean success = FALSE; + + g_return_val_if_fail (NM_IS_ACD_MANAGER (self), FALSE); + priv = NM_ACD_MANAGER_GET_PRIVATE (self); + g_return_val_if_fail (priv->state == STATE_INIT, FALSE); + + priv->completed = 0; + + g_hash_table_iter_init (&iter, priv->addresses); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) + success |= acd_probe_start (self, info, timeout); + + if (success) + priv->state = STATE_PROBING; + + return success; +} + +/** + * nm_acd_manager_reset: + * @self: a #NMAcdManager + * + * Stop any operation in progress and reset @self to the initial state. + */ +void +nm_acd_manager_reset (NMAcdManager *self) +{ + NMAcdManagerPrivate *priv; + + g_return_if_fail (NM_IS_ACD_MANAGER (self)); + priv = NM_ACD_MANAGER_GET_PRIVATE (self); + + g_hash_table_remove_all (priv->addresses); + + priv->state = STATE_INIT; +} + +/** + * nm_acd_manager_destroy: + * @self: the #NMAcdManager + * + * Calls nm_acd_manager_reset() and unrefs @self. + */ +void +nm_acd_manager_destroy (NMAcdManager *self) +{ + g_return_if_fail (NM_IS_ACD_MANAGER (self)); + + nm_acd_manager_reset (self); + g_object_unref (self); +} + +/** + * nm_acd_manager_check_address: + * @self: a #NMAcdManager + * @address: an IP address + * + * Check if an IP address is duplicate. @address must have been added with + * nm_acd_manager_add_address(). + * + * Returns: %TRUE if the address is not duplicate, %FALSE otherwise + */ +gboolean +nm_acd_manager_check_address (NMAcdManager *self, in_addr_t address) +{ + NMAcdManagerPrivate *priv; + AddressInfo *info; + + g_return_val_if_fail (NM_IS_ACD_MANAGER (self), FALSE); + priv = NM_ACD_MANAGER_GET_PRIVATE (self); + g_return_val_if_fail ( priv->state == STATE_INIT + || priv->state == STATE_PROBE_DONE, FALSE); + + info = g_hash_table_lookup (priv->addresses, GUINT_TO_POINTER (address)); + g_return_val_if_fail (info, FALSE); + + return !info->duplicate; +} + +/** + * nm_acd_manager_announce_addresses: + * @self: a #NMAcdManager + * + * Start announcing addresses. + */ +void +nm_acd_manager_announce_addresses (NMAcdManager *self) +{ + NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); + GHashTableIter iter; + AddressInfo *info; + int r; + + if (priv->state == STATE_INIT) { + /* n-acd can't announce without probing, therefore let's + * start a fake probe with zero timeout and then perform + * the announce. */ + priv->state = STATE_ANNOUNCING; + g_hash_table_iter_init (&iter, priv->addresses); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) { + if (!acd_probe_start (self, info, 0)) { + _LOGW ("couldn't announce address %s on interface '%s'", + nm_utils_inet4_ntop (info->address, NULL), + nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex)); + } + } + } else if (priv->state == STATE_PROBE_DONE) { + priv->state = STATE_ANNOUNCING; + g_hash_table_iter_init (&iter, priv->addresses); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) { + if (info->duplicate) + continue; + r = n_acd_announce (info->acd, N_ACD_DEFEND_ONCE); + if (r) { + _LOGW ("couldn't announce address %s on interface '%s': %s", + nm_utils_inet4_ntop (info->address, NULL), + nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), + acd_error_to_string (r)); + } else + _LOGD ("announcing address %s", nm_utils_inet4_ntop (info->address, NULL)); + } + } else + nm_assert_not_reached (); +} + +static void +destroy_address_info (gpointer data) +{ + AddressInfo *info = (AddressInfo *) data; + + g_clear_pointer (&info->channel, g_io_channel_unref); + g_clear_pointer (&info->acd, n_acd_free); + nm_clear_g_source (&info->event_id); + + g_slice_free (AddressInfo, info); +} + +/*****************************************************************************/ + +static void +nm_acd_manager_init (NMAcdManager *self) +{ + NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); + + priv->addresses = g_hash_table_new_full (nm_direct_hash, NULL, + NULL, destroy_address_info); + priv->state = STATE_INIT; +} + +NMAcdManager * +nm_acd_manager_new (int ifindex, const guint8 *hwaddr, size_t hwaddr_len) +{ + NMAcdManager *self; + NMAcdManagerPrivate *priv; + + g_return_val_if_fail (hwaddr, NULL); + g_return_val_if_fail (hwaddr_len == ETH_ALEN, NULL); + + self = g_object_new (NM_TYPE_ACD_MANAGER, NULL); + priv = NM_ACD_MANAGER_GET_PRIVATE (self); + priv->ifindex = ifindex; + memcpy (priv->hwaddr, hwaddr, ETH_ALEN); + + return self; +} + +static void +dispose (GObject *object) +{ + NMAcdManager *self = NM_ACD_MANAGER (object); + NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); + + g_clear_pointer (&priv->addresses, g_hash_table_destroy); + + G_OBJECT_CLASS (nm_acd_manager_parent_class)->dispose (object); +} + +static void +nm_acd_manager_class_init (NMAcdManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = dispose; + + signals[PROBE_TERMINATED] = + g_signal_new (NM_ACD_MANAGER_PROBE_TERMINATED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); +} diff --git a/src/devices/nm-acd-manager.h b/src/devices/nm-acd-manager.h new file mode 100644 index 0000000000..eeede5da7f --- /dev/null +++ b/src/devices/nm-acd-manager.h @@ -0,0 +1,43 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * 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 of the License, 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. + * + * Copyright (C) 2015-2018 Red Hat, Inc. + */ + +#ifndef __NM_ACD_MANAGER__ +#define __NM_ACD_MANAGER__ + +#include + +#define NM_TYPE_ACD_MANAGER (nm_acd_manager_get_type ()) +#define NM_ACD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ACD_MANAGER, NMAcdManager)) +#define NM_ACD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ACD_MANAGER, NMAcdManagerClass)) +#define NM_IS_ACD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_ACD_MANAGER)) +#define NM_IS_ACD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_ACD_MANAGER)) +#define NM_ACD_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ACD_MANAGER, NMAcdManagerClass)) + +#define NM_ACD_MANAGER_PROBE_TERMINATED "probe-terminated" + +typedef struct _NMAcdManagerClass NMAcdManagerClass; + +GType nm_acd_manager_get_type (void); + +NMAcdManager *nm_acd_manager_new (int ifindex, const guint8 *hwaddr, size_t hwaddr_len); +void nm_acd_manager_destroy (NMAcdManager *self); +gboolean nm_acd_manager_add_address (NMAcdManager *self, in_addr_t address); +gboolean nm_acd_manager_start_probe (NMAcdManager *self, guint timeout); +gboolean nm_acd_manager_check_address (NMAcdManager *self, in_addr_t address); +void nm_acd_manager_announce_addresses (NMAcdManager *self); +void nm_acd_manager_reset (NMAcdManager *self); + +#endif /* __NM_ACD_MANAGER__ */ diff --git a/src/devices/nm-arping-manager.c b/src/devices/nm-arping-manager.c deleted file mode 100644 index 2133aa117a..0000000000 --- a/src/devices/nm-arping-manager.c +++ /dev/null @@ -1,490 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * 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 of the License, 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. - * - * Copyright (C) 2015-2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-arping-manager.h" - -#include -#include -#include - -#include "platform/nm-platform.h" -#include "nm-utils.h" -#include "NetworkManagerUtils.h" -#include "n-acd/src/n-acd.h" - -/*****************************************************************************/ - -typedef enum { - STATE_INIT, - STATE_PROBING, - STATE_PROBE_DONE, - STATE_ANNOUNCING, -} State; - -typedef struct { - in_addr_t address; - gboolean duplicate; - NMArpingManager *manager; - NAcd *acd; - GIOChannel *channel; - guint event_id; -} AddressInfo; - -enum { - PROBE_TERMINATED, - LAST_SIGNAL, -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -typedef struct { - int ifindex; - guint8 hwaddr[ETH_ALEN]; - State state; - GHashTable *addresses; - guint completed; -} NMArpingManagerPrivate; - -struct _NMArpingManager { - GObject parent; - NMArpingManagerPrivate _priv; -}; - -struct _NMArpingManagerClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE (NMArpingManager, nm_arping_manager, G_TYPE_OBJECT) - -#define NM_ARPING_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMArpingManager, NM_IS_ARPING_MANAGER) - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_IP4 -#define _NMLOG_PREFIX_NAME "arping" -#define _NMLOG(level, ...) \ - G_STMT_START { \ - char _sbuf[64]; \ - int _ifindex = (self) ? NM_ARPING_MANAGER_GET_PRIVATE (self)->ifindex : 0; \ - \ - nm_log ((level), _NMLOG_DOMAIN, \ - nm_platform_link_get_name (NM_PLATFORM_GET, _ifindex), \ - NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - self ? nm_sprintf_buf (_sbuf, "[%p,%d]", self, _ifindex) : "" \ - _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ - } G_STMT_END - -/*****************************************************************************/ - -static const char * -_acd_event_to_string (unsigned int event) -{ - switch (event) { - case N_ACD_EVENT_READY: - return "ready"; - case N_ACD_EVENT_USED: - return "used"; - case N_ACD_EVENT_DEFENDED: - return "defended"; - case N_ACD_EVENT_CONFLICT: - return "conflict"; - case N_ACD_EVENT_DOWN: - return "down"; - } - return NULL; -} - -#define acd_event_to_string(event) NM_UTILS_LOOKUP_STR (_acd_event_to_string, event) - -static const char * -_acd_error_to_string (int error) -{ - if (error < 0) - return strerror(-error); - - switch (error) { - case _N_ACD_E_SUCCESS: - return "success"; - case N_ACD_E_DONE: - return "no more events (engine running)"; - case N_ACD_E_STOPPED: - return "no more events (engine stopped)"; - case N_ACD_E_PREEMPTED: - return "preempted"; - case N_ACD_E_INVALID_ARGUMENT: - return "invalid argument"; - case N_ACD_E_BUSY: - return "busy"; - } - return NULL; -} - -#define acd_error_to_string(error) NM_UTILS_LOOKUP_STR (_acd_error_to_string, error) - -/*****************************************************************************/ - -/** - * nm_arping_manager_add_address: - * @self: a #NMArpingManager - * @address: an IP address - * - * Add @address to the list of IP addresses to probe. - - * Returns: %TRUE on success, %FALSE if the address was already in the list - */ -gboolean -nm_arping_manager_add_address (NMArpingManager *self, in_addr_t address) -{ - NMArpingManagerPrivate *priv; - AddressInfo *info; - - g_return_val_if_fail (NM_IS_ARPING_MANAGER (self), FALSE); - priv = NM_ARPING_MANAGER_GET_PRIVATE (self); - g_return_val_if_fail (priv->state == STATE_INIT, FALSE); - - if (g_hash_table_lookup (priv->addresses, GUINT_TO_POINTER (address))) - return FALSE; - - info = g_slice_new0 (AddressInfo); - info->address = address; - info->manager = self; - - g_hash_table_insert (priv->addresses, GUINT_TO_POINTER (address), info); - - return TRUE; -} - -static gboolean -acd_event (GIOChannel *source, GIOCondition condition, gpointer data) -{ - AddressInfo *info = data; - NMArpingManager *self = info->manager; - NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self); - NAcdEvent *event; - char address_str[INET_ADDRSTRLEN]; - gs_free char *hwaddr_str = NULL; - int r; - - if ( n_acd_dispatch (info->acd) - || n_acd_pop_event (info->acd, &event)) - return G_SOURCE_CONTINUE; - - switch (event->event) { - case N_ACD_EVENT_READY: - info->duplicate = FALSE; - if (priv->state == STATE_ANNOUNCING) { - r = n_acd_announce (info->acd, N_ACD_DEFEND_ONCE); - if (r) { - _LOGW ("couldn't announce address %s on interface '%s': %s", - nm_utils_inet4_ntop (info->address, address_str), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), - acd_error_to_string (r)); - } else { - _LOGD ("announcing address %s", - nm_utils_inet4_ntop (info->address, address_str)); - } - } - break; - case N_ACD_EVENT_USED: - info->duplicate = TRUE; - break; - case N_ACD_EVENT_DEFENDED: - _LOGD ("defended address %s from host %s", - nm_utils_inet4_ntop (info->address, address_str), - (hwaddr_str = nm_utils_hwaddr_ntoa (event->defended.sender, - event->defended.n_sender))); - break; - case N_ACD_EVENT_CONFLICT: - _LOGW ("conflict for address %s detected with host %s on interface '%s'", - nm_utils_inet4_ntop (info->address, address_str), - (hwaddr_str = nm_utils_hwaddr_ntoa (event->defended.sender, - event->defended.n_sender)), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex)); - break; - default: - _LOGD ("event '%s' for address %s", - acd_event_to_string (event->event), - nm_utils_inet4_ntop (info->address, address_str)); - return G_SOURCE_CONTINUE; - } - - if ( priv->state == STATE_PROBING - && ++priv->completed == g_hash_table_size (priv->addresses)) { - priv->state = STATE_PROBE_DONE; - g_signal_emit (self, signals[PROBE_TERMINATED], 0); - } - - return G_SOURCE_CONTINUE; -} - -static gboolean -acd_probe_start (NMArpingManager *self, - AddressInfo *info, - guint64 timeout) -{ - NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self); - NAcdConfig *config; - int r, fd; - - r = n_acd_new (&info->acd); - if (r) { - _LOGW ("could not create ACD for %s on interface '%s': %s", - nm_utils_inet4_ntop (info->address, NULL), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), - acd_error_to_string (r)); - return FALSE; - } - - n_acd_get_fd (info->acd, &fd); - info->channel = g_io_channel_unix_new (fd); - info->event_id = g_io_add_watch (info->channel, G_IO_IN, acd_event, info); - - config = &(NAcdConfig) { - .ifindex = priv->ifindex, - .mac = priv->hwaddr, - .n_mac = ETH_ALEN, - .ip = info->address, - .timeout_msec = timeout, - .transport = N_ACD_TRANSPORT_ETHERNET, - }; - - r = n_acd_start (info->acd, config); - if (r) { - _LOGW ("could not start probe for %s on interface '%s': %s", - nm_utils_inet4_ntop (info->address, NULL), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), - acd_error_to_string (r)); - return FALSE; - } - - _LOGD ("start probe for %s", nm_utils_inet4_ntop (info->address, NULL)); - - return TRUE; -} - -/** - * nm_arping_manager_start_probe: - * @self: a #NMArpingManager - * @timeout: maximum probe duration in milliseconds - * @error: location to store error, or %NULL - * - * Start probing IP addresses for duplicates; when the probe terminates a - * PROBE_TERMINATED signal is emitted. - * - * Returns: %TRUE if at least one probe could be started, %FALSE otherwise - */ -gboolean -nm_arping_manager_start_probe (NMArpingManager *self, guint timeout) -{ - NMArpingManagerPrivate *priv; - GHashTableIter iter; - AddressInfo *info; - gs_free char *timeout_str = NULL; - gboolean success = FALSE; - - g_return_val_if_fail (NM_IS_ARPING_MANAGER (self), FALSE); - priv = NM_ARPING_MANAGER_GET_PRIVATE (self); - g_return_val_if_fail (priv->state == STATE_INIT, FALSE); - - priv->completed = 0; - - g_hash_table_iter_init (&iter, priv->addresses); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) - success |= acd_probe_start (self, info, timeout); - - if (success) - priv->state = STATE_PROBING; - - return success; -} - -/** - * nm_arping_manager_reset: - * @self: a #NMArpingManager - * - * Stop any operation in progress and reset @self to the initial state. - */ -void -nm_arping_manager_reset (NMArpingManager *self) -{ - NMArpingManagerPrivate *priv; - - g_return_if_fail (NM_IS_ARPING_MANAGER (self)); - priv = NM_ARPING_MANAGER_GET_PRIVATE (self); - - g_hash_table_remove_all (priv->addresses); - - priv->state = STATE_INIT; -} - -/** - * nm_arping_manager_destroy: - * @self: the #NMArpingManager - * - * Calls nm_arping_manager_reset() and unrefs @self. - */ -void -nm_arping_manager_destroy (NMArpingManager *self) -{ - g_return_if_fail (NM_IS_ARPING_MANAGER (self)); - - nm_arping_manager_reset (self); - g_object_unref (self); -} - -/** - * nm_arping_manager_check_address: - * @self: a #NMArpingManager - * @address: an IP address - * - * Check if an IP address is duplicate. @address must have been added with - * nm_arping_manager_add_address(). - * - * Returns: %TRUE if the address is not duplicate, %FALSE otherwise - */ -gboolean -nm_arping_manager_check_address (NMArpingManager *self, in_addr_t address) -{ - NMArpingManagerPrivate *priv; - AddressInfo *info; - - g_return_val_if_fail (NM_IS_ARPING_MANAGER (self), FALSE); - priv = NM_ARPING_MANAGER_GET_PRIVATE (self); - g_return_val_if_fail ( priv->state == STATE_INIT - || priv->state == STATE_PROBE_DONE, FALSE); - - info = g_hash_table_lookup (priv->addresses, GUINT_TO_POINTER (address)); - g_return_val_if_fail (info, FALSE); - - return !info->duplicate; -} - -/** - * nm_arping_manager_announce_addresses: - * @self: a #NMArpingManager - * - * Start announcing addresses. - */ -void -nm_arping_manager_announce_addresses (NMArpingManager *self) -{ - NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self); - GHashTableIter iter; - AddressInfo *info; - int r; - - if (priv->state == STATE_INIT) { - /* n-acd can't announce without probing, therefore let's - * start a fake probe with zero timeout and then perform - * the announce. */ - priv->state = STATE_ANNOUNCING; - g_hash_table_iter_init (&iter, priv->addresses); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) { - if (!acd_probe_start (self, info, 0)) { - _LOGW ("couldn't announce address %s on interface '%s'", - nm_utils_inet4_ntop (info->address, NULL), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex)); - } - } - } else if (priv->state == STATE_PROBE_DONE) { - priv->state = STATE_ANNOUNCING; - g_hash_table_iter_init (&iter, priv->addresses); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) { - if (info->duplicate) - continue; - r = n_acd_announce (info->acd, N_ACD_DEFEND_ONCE); - if (r) { - _LOGW ("couldn't announce address %s on interface '%s': %s", - nm_utils_inet4_ntop (info->address, NULL), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), - acd_error_to_string (r)); - } else - _LOGD ("announcing address %s", nm_utils_inet4_ntop (info->address, NULL)); - } - } else - nm_assert_not_reached (); -} - -static void -destroy_address_info (gpointer data) -{ - AddressInfo *info = (AddressInfo *) data; - - g_clear_pointer (&info->channel, g_io_channel_unref); - g_clear_pointer (&info->acd, n_acd_free); - nm_clear_g_source (&info->event_id); - - g_slice_free (AddressInfo, info); -} - -/*****************************************************************************/ - -static void -nm_arping_manager_init (NMArpingManager *self) -{ - NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self); - - priv->addresses = g_hash_table_new_full (nm_direct_hash, NULL, - NULL, destroy_address_info); - priv->state = STATE_INIT; -} - -NMArpingManager * -nm_arping_manager_new (int ifindex, const guint8 *hwaddr, size_t hwaddr_len) -{ - NMArpingManager *self; - NMArpingManagerPrivate *priv; - - g_return_val_if_fail (hwaddr, NULL); - g_return_val_if_fail (hwaddr_len == ETH_ALEN, NULL); - - self = g_object_new (NM_TYPE_ARPING_MANAGER, NULL); - priv = NM_ARPING_MANAGER_GET_PRIVATE (self); - priv->ifindex = ifindex; - memcpy (priv->hwaddr, hwaddr, ETH_ALEN); - - return self; -} - -static void -dispose (GObject *object) -{ - NMArpingManager *self = NM_ARPING_MANAGER (object); - NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self); - - g_clear_pointer (&priv->addresses, g_hash_table_destroy); - - G_OBJECT_CLASS (nm_arping_manager_parent_class)->dispose (object); -} - -static void -nm_arping_manager_class_init (NMArpingManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = dispose; - - signals[PROBE_TERMINATED] = - g_signal_new (NM_ARPING_MANAGER_PROBE_TERMINATED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); -} diff --git a/src/devices/nm-arping-manager.h b/src/devices/nm-arping-manager.h deleted file mode 100644 index a6585d36ac..0000000000 --- a/src/devices/nm-arping-manager.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * 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 of the License, 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. - * - * Copyright (C) 2015 Red Hat, Inc. - */ - -#ifndef __NM_ARPING_MANAGER__ -#define __NM_ARPING_MANAGER__ - -#include - -#define NM_TYPE_ARPING_MANAGER (nm_arping_manager_get_type ()) -#define NM_ARPING_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ARPING_MANAGER, NMArpingManager)) -#define NM_ARPING_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ARPING_MANAGER, NMArpingManagerClass)) -#define NM_IS_ARPING_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_ARPING_MANAGER)) -#define NM_IS_ARPING_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_ARPING_MANAGER)) -#define NM_ARPING_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ARPING_MANAGER, NMArpingManagerClass)) - -#define NM_ARPING_MANAGER_PROBE_TERMINATED "probe-terminated" - -typedef struct _NMArpingManagerClass NMArpingManagerClass; - -GType nm_arping_manager_get_type (void); - -NMArpingManager *nm_arping_manager_new (int ifindex, const guint8 *hwaddr, size_t hwaddr_len); -void nm_arping_manager_destroy (NMArpingManager *self); -gboolean nm_arping_manager_add_address (NMArpingManager *self, in_addr_t address); -gboolean nm_arping_manager_start_probe (NMArpingManager *self, guint timeout); -gboolean nm_arping_manager_check_address (NMArpingManager *self, in_addr_t address); -void nm_arping_manager_announce_addresses (NMArpingManager *self); -void nm_arping_manager_reset (NMArpingManager *self); - -#endif /* __NM_ARPING_MANAGER__ */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 64a9cc1bcf..6815ffaac9 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -68,11 +68,11 @@ #include "nm-config.h" #include "c-list/src/c-list.h" #include "dns/nm-dns-manager.h" +#include "nm-acd-manager.h" #include "nm-core-internal.h" #include "systemd/nm-sd.h" #include "nm-lldp-listener.h" #include "nm-audit-manager.h" -#include "nm-arping-manager.h" #include "nm-connectivity.h" #include "nm-dbus-interface.h" #include "nm-device-vlan.h" @@ -129,13 +129,13 @@ typedef struct { int ifindex; } DeleteOnDeactivateData; -typedef void (*ArpingCallback) (NMDevice *, NMIP4Config **, gboolean); +typedef void (*AcdCallback) (NMDevice *, NMIP4Config **, gboolean); typedef struct { - ArpingCallback callback; + AcdCallback callback; NMDevice *device; NMIP4Config **configs; -} ArpingData; +} AcdData; typedef enum { HW_ADDR_TYPE_UNSET = 0, @@ -485,8 +485,8 @@ typedef struct _NMDevicePrivate { /* IPv4 DAD stuff */ struct { GSList * dad_list; - NMArpingManager * announcing; - } arping; + NMAcdManager * announcing; + } acd; union { const IpState ip6_state; @@ -6043,16 +6043,16 @@ get_ipv4_dad_timeout (NMDevice *self) } static void -arping_data_destroy (gpointer ptr, GClosure *closure) +acd_data_destroy (gpointer ptr, GClosure *closure) { - ArpingData *data = ptr; + AcdData *data = ptr; int i; if (data) { for (i = 0; data->configs && data->configs[i]; i++) g_object_unref (data->configs[i]); g_free (data->configs); - g_slice_free (ArpingData, data); + g_slice_free (AcdData, data); } } @@ -6072,7 +6072,7 @@ ipv4_manual_method_apply (NMDevice *self, NMIP4Config **configs, gboolean succes } static void -arping_manager_probe_terminated (NMArpingManager *arping_manager, ArpingData *data) +acd_manager_probe_terminated (NMAcdManager *acd_manager, AcdData *data) { NMDevice *self; NMDevicePrivate *priv; @@ -6087,7 +6087,7 @@ arping_manager_probe_terminated (NMArpingManager *arping_manager, ArpingData *da for (i = 0; data->configs && data->configs[i]; i++) { nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, data->configs[i], &address) { - result = nm_arping_manager_check_address (arping_manager, address->address); + result = nm_acd_manager_check_address (acd_manager, address->address); success &= result; _NMLOG (result ? LOGL_DEBUG : LOGL_WARN, @@ -6100,8 +6100,8 @@ arping_manager_probe_terminated (NMArpingManager *arping_manager, ArpingData *da data->callback (self, data->configs, success); - priv->arping.dad_list = g_slist_remove (priv->arping.dad_list, arping_manager); - nm_arping_manager_destroy (arping_manager); + priv->acd.dad_list = g_slist_remove (priv->acd.dad_list, acd_manager); + nm_acd_manager_destroy (acd_manager); } /** @@ -6115,13 +6115,13 @@ arping_manager_probe_terminated (NMArpingManager *arping_manager, ArpingData *da * be started. @configs will be unreferenced after @cb has been called. */ static void -ipv4_dad_start (NMDevice *self, NMIP4Config **configs, ArpingCallback cb) +ipv4_dad_start (NMDevice *self, NMIP4Config **configs, AcdCallback cb) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMArpingManager *arping_manager; + NMAcdManager *acd_manager; const NMPlatformIP4Address *address; NMDedupMultiIter ipconf_iter; - ArpingData *data; + AcdData *data; guint timeout; gboolean ret, addr_found; const guint8 *hwaddr_arr; @@ -6160,36 +6160,36 @@ ipv4_dad_start (NMDevice *self, NMIP4Config **configs, ArpingCallback cb) return; } - /* don't take additional references of @arping_manager that outlive @self. + /* don't take additional references of @acd_manager that outlive @self. * Otherwise, the callback can be invoked on a dangling pointer as we don't * disconnect the handler. */ - arping_manager = nm_arping_manager_new (nm_device_get_ip_ifindex (self), hwaddr_arr, length); - priv->arping.dad_list = g_slist_append (priv->arping.dad_list, arping_manager); + acd_manager = nm_acd_manager_new (nm_device_get_ip_ifindex (self), hwaddr_arr, length); + priv->acd.dad_list = g_slist_append (priv->acd.dad_list, acd_manager); - data = g_slice_new0 (ArpingData); + data = g_slice_new0 (AcdData); data->configs = configs; data->callback = cb; data->device = self; for (i = 0; configs[i]; i++) { nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, configs[i], &address) - nm_arping_manager_add_address (arping_manager, address->address); + nm_acd_manager_add_address (acd_manager, address->address); } - g_signal_connect_data (arping_manager, NM_ARPING_MANAGER_PROBE_TERMINATED, - G_CALLBACK (arping_manager_probe_terminated), data, - arping_data_destroy, 0); + g_signal_connect_data (acd_manager, NM_ACD_MANAGER_PROBE_TERMINATED, + G_CALLBACK (acd_manager_probe_terminated), data, + acd_data_destroy, 0); - ret = nm_arping_manager_start_probe (arping_manager, timeout); + ret = nm_acd_manager_start_probe (acd_manager, timeout); if (!ret) { - _LOGW (LOGD_DEVICE, "arping probe failed"); + _LOGW (LOGD_DEVICE, "acd probe failed"); /* DAD could not be started, signal success */ cb (self, configs, TRUE); - priv->arping.dad_list = g_slist_remove (priv->arping.dad_list, arping_manager); - nm_arping_manager_destroy (arping_manager); + priv->acd.dad_list = g_slist_remove (priv->acd.dad_list, acd_manager); + nm_acd_manager_destroy (acd_manager); } } @@ -9232,9 +9232,9 @@ arp_cleanup (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->arping.announcing) { - nm_arping_manager_destroy (priv->arping.announcing); - priv->arping.announcing = NULL; + if (priv->acd.announcing) { + nm_acd_manager_destroy (priv->acd.announcing); + priv->acd.announcing = NULL; } } @@ -9270,19 +9270,19 @@ arp_announce (NMDevice *self) if (num == 0) return; - priv->arping.announcing = nm_arping_manager_new (nm_device_get_ip_ifindex (self), hw_addr, hw_addr_len); + priv->acd.announcing = nm_acd_manager_new (nm_device_get_ip_ifindex (self), hw_addr, hw_addr_len); for (i = 0; i < num; i++) { NMIPAddress *ip = nm_setting_ip_config_get_address (s_ip4, i); in_addr_t addr; if (inet_pton (AF_INET, nm_ip_address_get_address (ip), &addr) == 1) - nm_arping_manager_add_address (priv->arping.announcing, addr); + nm_acd_manager_add_address (priv->acd.announcing, addr); else g_warn_if_reached (); } - nm_arping_manager_announce_addresses (priv->arping.announcing); + nm_acd_manager_announce_addresses (priv->acd.announcing); } static void @@ -14907,8 +14907,8 @@ dispose (GObject *object) g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ipx_changed), self); g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (link_changed_cb), self); - g_slist_free_full (priv->arping.dad_list, (GDestroyNotify) nm_arping_manager_destroy); - priv->arping.dad_list = NULL; + g_slist_free_full (priv->acd.dad_list, (GDestroyNotify) nm_acd_manager_destroy); + priv->acd.dad_list = NULL; arp_cleanup (self); diff --git a/src/devices/tests/meson.build b/src/devices/tests/meson.build index 64afc278d6..02c61ced1d 100644 --- a/src/devices/tests/meson.build +++ b/src/devices/tests/meson.build @@ -1,5 +1,5 @@ test_units = [ - 'test-arping', + 'test-acd', 'test-lldp' ] diff --git a/src/devices/tests/test-acd.c b/src/devices/tests/test-acd.c new file mode 100644 index 0000000000..8a2852a2d7 --- /dev/null +++ b/src/devices/tests/test-acd.c @@ -0,0 +1,185 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-platform.c - Handle runtime kernel networking configuration + * + * 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) 2015 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "devices/nm-acd-manager.h" +#include "platform/tests/test-common.h" + +#define IFACE_VETH0 "nm-test-veth0" +#define IFACE_VETH1 "nm-test-veth1" + +#define ADDR1 0x01010101 +#define ADDR2 0x02020202 +#define ADDR3 0x03030303 +#define ADDR4 0x04040404 + +typedef struct { + int ifindex0; + int ifindex1; + const guint8 *hwaddr0; + const guint8 *hwaddr1; + size_t hwaddr0_len; + size_t hwaddr1_len; +} test_fixture; + +static void +fixture_setup (test_fixture *fixture, gconstpointer user_data) +{ + /* create veth pair. */ + fixture->ifindex0 = nmtstp_link_veth_add (NM_PLATFORM_GET, -1, IFACE_VETH0, IFACE_VETH1)->ifindex; + fixture->ifindex1 = nmtstp_link_get_typed (NM_PLATFORM_GET, -1, IFACE_VETH1, NM_LINK_TYPE_VETH)->ifindex; + + g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex0, NULL)); + g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex1, NULL)); + + fixture->hwaddr0 = nm_platform_link_get_address (NM_PLATFORM_GET, fixture->ifindex0, &fixture->hwaddr0_len); + fixture->hwaddr1 = nm_platform_link_get_address (NM_PLATFORM_GET, fixture->ifindex1, &fixture->hwaddr1_len); +} + +typedef struct { + in_addr_t addresses[8]; + in_addr_t peer_addresses[8]; + gboolean expected_result[8]; +} TestInfo; + +static void +acd_manager_probe_terminated (NMAcdManager *acd_manager, GMainLoop *loop) +{ + g_main_loop_quit (loop); +} + +static void +test_acd_common (test_fixture *fixture, TestInfo *info) +{ + gs_unref_object NMAcdManager *manager = NULL; + GMainLoop *loop; + int i; + const guint WAIT_TIME_OPTIMISTIC = 50; + guint wait_time; + gulong signal_id; + + /* first, try with a short waittime. We hope that this is long enough + * to successfully complete the test. Only if that's not the case, we + * assume the computer is currently busy (high load) and we retry with + * a longer timeout. */ + wait_time = WAIT_TIME_OPTIMISTIC; +again: + + manager = nm_acd_manager_new (fixture->ifindex0, fixture->hwaddr0, fixture->hwaddr0_len); + g_assert (manager != NULL); + + for (i = 0; info->addresses[i]; i++) + g_assert (nm_acd_manager_add_address (manager, info->addresses[i])); + + for (i = 0; info->peer_addresses[i]; i++) { + nmtstp_ip4_address_add (NULL, FALSE, fixture->ifindex1, info->peer_addresses[i], + 24, 0, 3600, 1800, 0, NULL); + } + + loop = g_main_loop_new (NULL, FALSE); + signal_id = g_signal_connect (manager, NM_ACD_MANAGER_PROBE_TERMINATED, + G_CALLBACK (acd_manager_probe_terminated), loop); + g_assert (nm_acd_manager_start_probe (manager, wait_time)); + g_assert (nmtst_main_loop_run (loop, 2000)); + g_signal_handler_disconnect (manager, signal_id); + g_main_loop_unref (loop); + + for (i = 0; info->addresses[i]; i++) { + gboolean val; + + val = nm_acd_manager_check_address (manager, info->addresses[i]); + if (val == info->expected_result[i]) + continue; + + if (wait_time == WAIT_TIME_OPTIMISTIC) { + /* probably we just had a glitch and the system took longer than + * expected. Re-verify with a large timeout this time. */ + wait_time = 1000; + g_clear_object (&manager); + goto again; + } + + g_error ("expected check for address #%d (%s) to %s, but it didn't", + i, nm_utils_inet4_ntop (info->addresses[i], NULL), + info->expected_result[i] ? "detect no duplicated" : "detect a duplicate"); + } +} + +static void +test_acd_probe_1 (test_fixture *fixture, gconstpointer user_data) +{ + TestInfo info = { .addresses = { ADDR1, ADDR2, ADDR3 }, + .peer_addresses = { ADDR4 }, + .expected_result = { TRUE, TRUE, TRUE } }; + + test_acd_common (fixture, &info); +} + +static void +test_acd_probe_2 (test_fixture *fixture, gconstpointer user_data) +{ + TestInfo info = { .addresses = { ADDR1, ADDR2, ADDR3, ADDR4 }, + .peer_addresses = { ADDR3, ADDR2 }, + .expected_result = { TRUE, FALSE, FALSE, TRUE } }; + + test_acd_common (fixture, &info); +} + +static void +test_acd_announce (test_fixture *fixture, gconstpointer user_data) +{ + gs_unref_object NMAcdManager *manager = NULL; + GMainLoop *loop; + + manager = nm_acd_manager_new (fixture->ifindex0, fixture->hwaddr0, fixture->hwaddr0_len); + g_assert (manager != NULL); + + g_assert (nm_acd_manager_add_address (manager, ADDR1)); + g_assert (nm_acd_manager_add_address (manager, ADDR2)); + + loop = g_main_loop_new (NULL, FALSE); + nm_acd_manager_announce_addresses (manager); + g_assert (!nmtst_main_loop_run (loop, 200)); + g_main_loop_unref (loop); +} + +static void +fixture_teardown (test_fixture *fixture, gconstpointer user_data) +{ + nm_platform_link_delete (NM_PLATFORM_GET, fixture->ifindex0); + nm_platform_link_delete (NM_PLATFORM_GET, fixture->ifindex1); +} + +NMTstpSetupFunc const _nmtstp_setup_platform_func = nm_linux_platform_setup; + +void +_nmtstp_init_tests (int *argc, char ***argv) +{ + nmtst_init_with_logging (argc, argv, NULL, "ALL"); +} + +void +_nmtstp_setup_tests (void) +{ + g_test_add ("/acd/probe/1", test_fixture, NULL, fixture_setup, test_acd_probe_1, fixture_teardown); + g_test_add ("/acd/probe/2", test_fixture, NULL, fixture_setup, test_acd_probe_2, fixture_teardown); + g_test_add ("/acd/announce", test_fixture, NULL, fixture_setup, test_acd_announce, fixture_teardown); +} diff --git a/src/devices/tests/test-arping.c b/src/devices/tests/test-arping.c deleted file mode 100644 index 0fe6c0dee9..0000000000 --- a/src/devices/tests/test-arping.c +++ /dev/null @@ -1,185 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* nm-platform.c - Handle runtime kernel networking configuration - * - * 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) 2015 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "devices/nm-arping-manager.h" -#include "platform/tests/test-common.h" - -#define IFACE_VETH0 "nm-test-veth0" -#define IFACE_VETH1 "nm-test-veth1" - -#define ADDR1 0x01010101 -#define ADDR2 0x02020202 -#define ADDR3 0x03030303 -#define ADDR4 0x04040404 - -typedef struct { - int ifindex0; - int ifindex1; - const guint8 *hwaddr0; - const guint8 *hwaddr1; - size_t hwaddr0_len; - size_t hwaddr1_len; -} test_fixture; - -static void -fixture_setup (test_fixture *fixture, gconstpointer user_data) -{ - /* create veth pair. */ - fixture->ifindex0 = nmtstp_link_veth_add (NM_PLATFORM_GET, -1, IFACE_VETH0, IFACE_VETH1)->ifindex; - fixture->ifindex1 = nmtstp_link_get_typed (NM_PLATFORM_GET, -1, IFACE_VETH1, NM_LINK_TYPE_VETH)->ifindex; - - g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex0, NULL)); - g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex1, NULL)); - - fixture->hwaddr0 = nm_platform_link_get_address (NM_PLATFORM_GET, fixture->ifindex0, &fixture->hwaddr0_len); - fixture->hwaddr1 = nm_platform_link_get_address (NM_PLATFORM_GET, fixture->ifindex1, &fixture->hwaddr1_len); -} - -typedef struct { - in_addr_t addresses[8]; - in_addr_t peer_addresses[8]; - gboolean expected_result[8]; -} TestInfo; - -static void -arping_manager_probe_terminated (NMArpingManager *arping_manager, GMainLoop *loop) -{ - g_main_loop_quit (loop); -} - -static void -test_arping_common (test_fixture *fixture, TestInfo *info) -{ - gs_unref_object NMArpingManager *manager = NULL; - GMainLoop *loop; - int i; - const guint WAIT_TIME_OPTIMISTIC = 50; - guint wait_time; - gulong signal_id; - - /* first, try with a short waittime. We hope that this is long enough - * to successfully complete the test. Only if that's not the case, we - * assume the computer is currently busy (high load) and we retry with - * a longer timeout. */ - wait_time = WAIT_TIME_OPTIMISTIC; -again: - - manager = nm_arping_manager_new (fixture->ifindex0, fixture->hwaddr0, fixture->hwaddr0_len); - g_assert (manager != NULL); - - for (i = 0; info->addresses[i]; i++) - g_assert (nm_arping_manager_add_address (manager, info->addresses[i])); - - for (i = 0; info->peer_addresses[i]; i++) { - nmtstp_ip4_address_add (NULL, FALSE, fixture->ifindex1, info->peer_addresses[i], - 24, 0, 3600, 1800, 0, NULL); - } - - loop = g_main_loop_new (NULL, FALSE); - signal_id = g_signal_connect (manager, NM_ARPING_MANAGER_PROBE_TERMINATED, - G_CALLBACK (arping_manager_probe_terminated), loop); - g_assert (nm_arping_manager_start_probe (manager, wait_time)); - g_assert (nmtst_main_loop_run (loop, 2000)); - g_signal_handler_disconnect (manager, signal_id); - g_main_loop_unref (loop); - - for (i = 0; info->addresses[i]; i++) { - gboolean val; - - val = nm_arping_manager_check_address (manager, info->addresses[i]); - if (val == info->expected_result[i]) - continue; - - if (wait_time == WAIT_TIME_OPTIMISTIC) { - /* probably we just had a glitch and the system took longer than - * expected. Re-verify with a large timeout this time. */ - wait_time = 1000; - g_clear_object (&manager); - goto again; - } - - g_error ("expected check for address #%d (%s) to %s, but it didn't", - i, nm_utils_inet4_ntop (info->addresses[i], NULL), - info->expected_result[i] ? "detect no duplicated" : "detect a duplicate"); - } -} - -static void -test_arping_probe_1 (test_fixture *fixture, gconstpointer user_data) -{ - TestInfo info = { .addresses = { ADDR1, ADDR2, ADDR3 }, - .peer_addresses = { ADDR4 }, - .expected_result = { TRUE, TRUE, TRUE } }; - - test_arping_common (fixture, &info); -} - -static void -test_arping_probe_2 (test_fixture *fixture, gconstpointer user_data) -{ - TestInfo info = { .addresses = { ADDR1, ADDR2, ADDR3, ADDR4 }, - .peer_addresses = { ADDR3, ADDR2 }, - .expected_result = { TRUE, FALSE, FALSE, TRUE } }; - - test_arping_common (fixture, &info); -} - -static void -test_arping_announce (test_fixture *fixture, gconstpointer user_data) -{ - gs_unref_object NMArpingManager *manager = NULL; - GMainLoop *loop; - - manager = nm_arping_manager_new (fixture->ifindex0, fixture->hwaddr0, fixture->hwaddr0_len); - g_assert (manager != NULL); - - g_assert (nm_arping_manager_add_address (manager, ADDR1)); - g_assert (nm_arping_manager_add_address (manager, ADDR2)); - - loop = g_main_loop_new (NULL, FALSE); - nm_arping_manager_announce_addresses (manager); - g_assert (!nmtst_main_loop_run (loop, 200)); - g_main_loop_unref (loop); -} - -static void -fixture_teardown (test_fixture *fixture, gconstpointer user_data) -{ - nm_platform_link_delete (NM_PLATFORM_GET, fixture->ifindex0); - nm_platform_link_delete (NM_PLATFORM_GET, fixture->ifindex1); -} - -NMTstpSetupFunc const _nmtstp_setup_platform_func = nm_linux_platform_setup; - -void -_nmtstp_init_tests (int *argc, char ***argv) -{ - nmtst_init_with_logging (argc, argv, NULL, "ALL"); -} - -void -_nmtstp_setup_tests (void) -{ - g_test_add ("/arping/probe/1", test_fixture, NULL, fixture_setup, test_arping_probe_1, fixture_teardown); - g_test_add ("/arping/probe/2", test_fixture, NULL, fixture_setup, test_arping_probe_2, fixture_teardown); - g_test_add ("/arping/announce", test_fixture, NULL, fixture_setup, test_arping_announce, fixture_teardown); -} diff --git a/src/meson.build b/src/meson.build index 845a098b8e..591c9c79c1 100644 --- a/src/meson.build +++ b/src/meson.build @@ -91,7 +91,7 @@ libnetwork_manager_base = static_library( ) sources = files( - 'devices/nm-arping-manager.c', + 'devices/nm-acd-manager.c', 'devices/nm-device-bond.c', 'devices/nm-device-bridge.c', 'devices/nm-device.c', diff --git a/src/nm-types.h b/src/nm-types.h index e48a6e2a18..e1991c2809 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -34,10 +34,10 @@ typedef struct _NMAuditManager NMAuditManager; typedef struct _NMVpnConnection NMVpnConnection; typedef struct _NMActRequest NMActRequest; typedef struct _NMAuthSubject NMAuthSubject; -typedef struct _NMDBusManager NMDBusManager; +typedef struct _NMDBusManager NMDBusManager; typedef struct _NMConfig NMConfig; typedef struct _NMConfigData NMConfigData; -typedef struct _NMArpingManager NMArpingManager; +typedef struct _NMAcdManager NMAcdManager; typedef struct _NMConnectivity NMConnectivity; typedef struct _NMDevice NMDevice; typedef struct _NMDhcp4Config NMDhcp4Config; -- cgit v1.2.1