diff options
Diffstat (limited to 'src/devices/nm-acd-manager.c')
| -rw-r--r-- | src/devices/nm-acd-manager.c | 489 |
1 files changed, 0 insertions, 489 deletions
diff --git a/src/devices/nm-acd-manager.c b/src/devices/nm-acd-manager.c deleted file mode 100644 index 1bade4ff..00000000 --- a/src/devices/nm-acd-manager.c +++ /dev/null @@ -1,489 +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-acd-manager.h" - -#include <netinet/in.h> -#include <sys/types.h> -#include <sys/wait.h> - -#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; - 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); -} |