mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-30 14:20:17 +01:00
1086 lines
28 KiB
C
1086 lines
28 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||
/* nm-platform-fake.c - Fake platform interaction code for testing NetworkManager
|
||
*
|
||
* 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) 2012–2013 Red Hat, Inc.
|
||
*/
|
||
|
||
#include <errno.h>
|
||
#include <unistd.h>
|
||
#include <netinet/icmp6.h>
|
||
#include <netinet/in.h>
|
||
|
||
#include "nm-fake-platform.h"
|
||
#include "nm-logging.h"
|
||
|
||
#define debug(format, ...) nm_log_dbg (LOGD_PLATFORM, format, __VA_ARGS__)
|
||
|
||
typedef struct {
|
||
GHashTable *options;
|
||
GArray *links;
|
||
GArray *ip4_addresses;
|
||
GArray *ip6_addresses;
|
||
GArray *ip4_routes;
|
||
GArray *ip6_routes;
|
||
} NMFakePlatformPrivate;
|
||
|
||
typedef struct {
|
||
NMPlatformLink link;
|
||
|
||
char *udi;
|
||
GBytes *address;
|
||
int vlan_id;
|
||
} NMFakePlatformLink;
|
||
|
||
#define NM_FAKE_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_FAKE_PLATFORM, NMFakePlatformPrivate))
|
||
|
||
G_DEFINE_TYPE (NMFakePlatform, nm_fake_platform, NM_TYPE_PLATFORM)
|
||
|
||
/******************************************************************/
|
||
|
||
void
|
||
nm_fake_platform_setup (void)
|
||
{
|
||
nm_platform_setup (NM_TYPE_FAKE_PLATFORM);
|
||
}
|
||
|
||
/******************************************************************/
|
||
|
||
static gboolean
|
||
sysctl_set (NMPlatform *platform, const char *path, const char *value)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
|
||
g_hash_table_insert (priv->options, g_strdup (path), g_strdup (value));
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static char *
|
||
sysctl_get (NMPlatform *platform, const char *path)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
|
||
return g_strdup (g_hash_table_lookup (priv->options, path));
|
||
}
|
||
|
||
static const char *
|
||
type_to_type_name (NMLinkType type)
|
||
{
|
||
switch (type) {
|
||
case NM_LINK_TYPE_UNKNOWN:
|
||
return "unknown";
|
||
case NM_LINK_TYPE_LOOPBACK:
|
||
return "loopback";
|
||
case NM_LINK_TYPE_ETHERNET:
|
||
return "ethernet";
|
||
case NM_LINK_TYPE_DUMMY:
|
||
return "dummy";
|
||
case NM_LINK_TYPE_BRIDGE:
|
||
return "bridge";
|
||
case NM_LINK_TYPE_BOND:
|
||
return "bond";
|
||
case NM_LINK_TYPE_TEAM:
|
||
return "team";
|
||
case NM_LINK_TYPE_VLAN:
|
||
return "vlan";
|
||
case NM_LINK_TYPE_NONE:
|
||
default:
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
static void
|
||
link_init (NMFakePlatformLink *device, int ifindex, int type, const char *name)
|
||
{
|
||
g_assert (!name || strlen (name) < sizeof(device->link.name));
|
||
|
||
memset (device, 0, sizeof (*device));
|
||
|
||
device->link.ifindex = name ? ifindex : 0;
|
||
device->link.type = type;
|
||
device->link.type_name = type_to_type_name (type);
|
||
device->link.driver = type_to_type_name (type);
|
||
device->link.udi = device->udi = g_strdup_printf ("fake:%d", ifindex);
|
||
if (name)
|
||
strcpy (device->link.name, name);
|
||
switch (device->link.type) {
|
||
case NM_LINK_TYPE_DUMMY:
|
||
device->link.arp = FALSE;
|
||
break;
|
||
default:
|
||
device->link.arp = TRUE;
|
||
}
|
||
device->address = NULL;
|
||
}
|
||
|
||
static NMFakePlatformLink *
|
||
link_get (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
NMFakePlatformLink *device;
|
||
|
||
if (ifindex >= priv->links->len)
|
||
goto not_found;
|
||
device = &g_array_index (priv->links, NMFakePlatformLink, ifindex);
|
||
if (!device->link.ifindex)
|
||
goto not_found;
|
||
|
||
return device;
|
||
not_found:
|
||
debug ("link not found: %d", ifindex);
|
||
platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
|
||
return NULL;
|
||
}
|
||
|
||
static GArray *
|
||
link_get_all (NMPlatform *platform)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
GArray *links = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformLink), priv->links->len);
|
||
int i;
|
||
|
||
for (i = 0; i < priv->links->len; i++)
|
||
if (g_array_index (priv->links, NMFakePlatformLink, i).link.ifindex)
|
||
g_array_append_val (links, g_array_index (priv->links, NMFakePlatformLink, i).link);
|
||
|
||
return links;
|
||
}
|
||
|
||
static gboolean
|
||
link_add (NMPlatform *platform, const char *name, NMLinkType type)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
NMFakePlatformLink device;
|
||
|
||
link_init (&device, priv->links->len, type, name);
|
||
|
||
g_array_append_val (priv->links, device);
|
||
|
||
if (device.link.ifindex)
|
||
g_signal_emit_by_name (platform, NM_PLATFORM_LINK_ADDED, device.link.ifindex, &device.link);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
link_delete (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
NMPlatformLink deleted_device;
|
||
|
||
if (!device || !device->link.ifindex)
|
||
return FALSE;
|
||
|
||
memcpy (&deleted_device, &device->link, sizeof (deleted_device));
|
||
memset (&device->link, 0, sizeof (device->link));
|
||
|
||
g_signal_emit_by_name (platform, NM_PLATFORM_LINK_REMOVED, ifindex, &deleted_device);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static int
|
||
link_get_ifindex (NMPlatform *platform, const char *name)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
int i;
|
||
|
||
for (i = 0; i < priv->links->len; i++) {
|
||
NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i);
|
||
|
||
if (device && !g_strcmp0 (device->link.name, name))
|
||
return device->link.ifindex;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static const char *
|
||
link_get_name (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
return device ? device->link.name : NULL;
|
||
}
|
||
|
||
static NMLinkType
|
||
link_get_type (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
return device ? device->link.type : NM_LINK_TYPE_NONE;
|
||
}
|
||
|
||
static const char *
|
||
link_get_type_name (NMPlatform *platform, int ifindex)
|
||
{
|
||
return type_to_type_name (link_get_type (platform, ifindex));
|
||
}
|
||
|
||
static void
|
||
link_changed (NMPlatform *platform, NMFakePlatformLink *device)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
int i;
|
||
|
||
g_signal_emit_by_name (platform, "link-changed", device->link.ifindex, &device->link);
|
||
|
||
if (device->link.master) {
|
||
NMFakePlatformLink *master = link_get (platform, device->link.master);
|
||
|
||
g_return_if_fail (master != device);
|
||
|
||
master->link.connected = FALSE;
|
||
for (i = 0; i < priv->links->len; i++) {
|
||
NMFakePlatformLink *slave = &g_array_index (priv->links, NMFakePlatformLink, i);
|
||
|
||
if (slave && slave->link.master == master->link.ifindex && slave->link.connected)
|
||
master->link.connected = TRUE;
|
||
}
|
||
|
||
link_changed (platform, master);
|
||
}
|
||
}
|
||
|
||
static gboolean
|
||
link_set_up (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
if (!device)
|
||
return FALSE;
|
||
|
||
device->link.up = TRUE;
|
||
switch (device->link.type) {
|
||
case NM_LINK_TYPE_DUMMY:
|
||
case NM_LINK_TYPE_VLAN:
|
||
device->link.connected = TRUE;
|
||
break;
|
||
case NM_LINK_TYPE_BRIDGE:
|
||
case NM_LINK_TYPE_BOND:
|
||
case NM_LINK_TYPE_TEAM:
|
||
device->link.connected = FALSE;
|
||
break;
|
||
default:
|
||
device->link.connected = FALSE;
|
||
g_error ("Unexpected device type: %d", device->link.type);
|
||
}
|
||
|
||
link_changed (platform, device);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
link_set_down (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
if (!device)
|
||
return FALSE;
|
||
|
||
device->link.up = FALSE;
|
||
device->link.connected = FALSE;
|
||
|
||
link_changed (platform, device);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
link_set_arp (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
if (!device)
|
||
return FALSE;
|
||
|
||
device->link.arp = TRUE;
|
||
|
||
link_changed (platform, device);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
link_set_noarp (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
if (!device)
|
||
return FALSE;
|
||
|
||
device->link.arp = FALSE;
|
||
|
||
link_changed (platform, device);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
link_is_up (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
return device ? device->link.up : FALSE;
|
||
}
|
||
|
||
static gboolean
|
||
link_is_connected (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
return device ? device->link.connected : FALSE;
|
||
}
|
||
|
||
static gboolean
|
||
link_uses_arp (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
return device ? device->link.arp : FALSE;
|
||
}
|
||
|
||
static gboolean
|
||
link_set_address (NMPlatform *platform, int ifindex, gconstpointer addr, size_t len)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
if (device->address)
|
||
g_bytes_unref (device->address);
|
||
|
||
device->address = g_bytes_new (addr, len);
|
||
|
||
link_changed (platform, link_get (platform, ifindex));
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gconstpointer
|
||
link_get_address (NMPlatform *platform, int ifindex, size_t *length)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
if (!device || !device->address) {
|
||
if (length)
|
||
*length = 0;
|
||
return NULL;
|
||
}
|
||
|
||
return g_bytes_get_data (device->address, length);
|
||
}
|
||
|
||
static gboolean
|
||
link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
if (device) {
|
||
device->link.mtu = mtu;
|
||
link_changed (platform, device);
|
||
}
|
||
|
||
return !!device;
|
||
}
|
||
|
||
static guint32
|
||
link_get_mtu (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
return device ? device->link.mtu : 0;
|
||
}
|
||
|
||
static gboolean
|
||
link_supports_carrier_detect (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
if (!device)
|
||
return FALSE;
|
||
|
||
switch (device->link.type) {
|
||
case NM_LINK_TYPE_DUMMY:
|
||
return FALSE;
|
||
default:
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
static gboolean
|
||
link_supports_vlans (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
if (!device)
|
||
return FALSE;
|
||
|
||
switch (device->link.type) {
|
||
case NM_LINK_TYPE_LOOPBACK:
|
||
return FALSE;
|
||
default:
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
static gboolean
|
||
link_enslave (NMPlatform *platform, int master, int slave)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, slave);
|
||
|
||
g_return_val_if_fail (device, FALSE);
|
||
|
||
device->link.master = master;
|
||
|
||
link_changed (platform, device);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
link_release (NMPlatform *platform, int master_idx, int slave_idx)
|
||
{
|
||
NMFakePlatformLink *master = link_get (platform, master_idx);
|
||
NMFakePlatformLink *slave = link_get (platform, slave_idx);
|
||
|
||
g_return_val_if_fail (master, FALSE);
|
||
g_return_val_if_fail (slave, FALSE);
|
||
|
||
if (slave->link.master != master->link.ifindex) {
|
||
platform->error = NM_PLATFORM_ERROR_NOT_SLAVE;
|
||
return FALSE;
|
||
}
|
||
|
||
slave->link.master = 0;
|
||
|
||
link_changed (platform, slave);
|
||
link_changed (platform, master);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static int
|
||
link_get_master (NMPlatform *platform, int slave)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, slave);
|
||
|
||
g_return_val_if_fail (device, FALSE);
|
||
|
||
return device->link.master;
|
||
}
|
||
|
||
static gboolean
|
||
master_set_option (NMPlatform *platform, int master, const char *option, const char *value)
|
||
{
|
||
auto_g_free char *path = g_strdup_printf ("master:%d:%s", master, option);
|
||
|
||
return sysctl_set (platform, path, value);
|
||
}
|
||
|
||
static char *
|
||
master_get_option (NMPlatform *platform, int master, const char *option)
|
||
{
|
||
auto_g_free char *path = g_strdup_printf ("master:%d:%s", master, option);
|
||
|
||
return sysctl_get (platform, path);
|
||
}
|
||
|
||
static gboolean
|
||
slave_set_option (NMPlatform *platform, int slave, const char *option, const char *value)
|
||
{
|
||
auto_g_free char *path = g_strdup_printf ("slave:%d:%s", slave, option);
|
||
|
||
return sysctl_set (platform, path, value);
|
||
}
|
||
|
||
static char *
|
||
slave_get_option (NMPlatform *platform, int slave, const char *option)
|
||
{
|
||
auto_g_free char *path = g_strdup_printf ("slave:%d:%s", slave, option);
|
||
|
||
return sysctl_get (platform, path);
|
||
}
|
||
|
||
static gboolean
|
||
vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags)
|
||
{
|
||
NMFakePlatformLink *device;
|
||
|
||
if (!link_add (platform, name, NM_LINK_TYPE_VLAN))
|
||
return FALSE;
|
||
|
||
device = link_get (platform, link_get_ifindex (platform, name));
|
||
|
||
g_return_val_if_fail (device, FALSE);
|
||
|
||
device->vlan_id = vlan_id;
|
||
device->link.parent = parent;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
vlan_get_info (NMPlatform *platform, int ifindex, int *parent, int *vlan_id)
|
||
{
|
||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||
|
||
g_return_val_if_fail (device, FALSE);
|
||
|
||
if (parent)
|
||
*parent = device->link.parent;
|
||
if (vlan_id)
|
||
*vlan_id = device->vlan_id;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
vlan_set_ingress_map (NMPlatform *platform, int ifindex, int from, int to)
|
||
{
|
||
return !!link_get (platform, ifindex);
|
||
}
|
||
|
||
static gboolean
|
||
vlan_set_egress_map (NMPlatform *platform, int ifindex, int from, int to)
|
||
{
|
||
return !!link_get (platform, ifindex);
|
||
}
|
||
|
||
static gboolean
|
||
infiniband_partition_add (NMPlatform *platform, int parent, int p_key)
|
||
{
|
||
NMFakePlatformLink *parent_device;
|
||
char *name;
|
||
gboolean success;
|
||
|
||
parent_device = link_get (platform, parent);
|
||
g_return_val_if_fail (parent_device != NULL, FALSE);
|
||
|
||
name = g_strdup_printf ("%s.%04x", parent_device->link.name, p_key);
|
||
success = link_add (platform, name, NM_LINK_TYPE_INFINIBAND);
|
||
g_free (name);
|
||
|
||
return success;
|
||
}
|
||
|
||
static gboolean
|
||
veth_get_properties (NMPlatform *platform, int ifindex, NMPlatformVethProperties *props)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
static gboolean
|
||
tun_get_properties (NMPlatform *platform, int ifindex, NMPlatformTunProperties *props)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
static gboolean
|
||
macvlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformMacvlanProperties *props)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
static gboolean
|
||
gre_get_properties (NMPlatform *platform, int ifindex, NMPlatformGreProperties *props)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
/******************************************************************/
|
||
|
||
static GArray *
|
||
ip4_address_get_all (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
GArray *addresses;
|
||
NMPlatformIP4Address *address;
|
||
int count = 0, i;
|
||
|
||
/* Count addresses */
|
||
for (i = 0; i < priv->ip4_addresses->len; i++) {
|
||
address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
|
||
if (address && address->ifindex == ifindex)
|
||
count++;
|
||
}
|
||
|
||
addresses = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP4Address), count);
|
||
|
||
/* Fill addresses */
|
||
for (i = 0; i < priv->ip4_addresses->len; i++) {
|
||
address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
|
||
if (address && address->ifindex == ifindex)
|
||
g_array_append_val (addresses, *address);
|
||
}
|
||
|
||
return addresses;
|
||
}
|
||
|
||
static GArray *
|
||
ip6_address_get_all (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
GArray *addresses;
|
||
NMPlatformIP6Address *address;
|
||
int count = 0, i;
|
||
|
||
/* Count addresses */
|
||
for (i = 0; i < priv->ip6_addresses->len; i++) {
|
||
address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
|
||
if (address && address->ifindex == ifindex)
|
||
count++;
|
||
}
|
||
|
||
addresses = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP6Address), count);
|
||
|
||
/* Fill addresses */
|
||
count = 0;
|
||
for (i = 0; i < priv->ip6_addresses->len; i++) {
|
||
address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
|
||
if (address && address->ifindex == ifindex)
|
||
g_array_append_val (addresses, *address);
|
||
}
|
||
|
||
return addresses;
|
||
}
|
||
|
||
static gboolean
|
||
ip4_address_add (NMPlatform *platform, int ifindex, in_addr_t addr, int plen)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
NMPlatformIP4Address address;
|
||
|
||
memset (&address, 0, sizeof (address));
|
||
address.ifindex = ifindex;
|
||
address.address = addr;
|
||
address.plen = plen;
|
||
|
||
g_array_append_val (priv->ip4_addresses, address);
|
||
|
||
g_signal_emit_by_name (platform, NM_PLATFORM_IP4_ADDRESS_ADDED, ifindex, &address);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
ip6_address_add (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
NMPlatformIP6Address address;
|
||
|
||
memset (&address, 0, sizeof (address));
|
||
address.ifindex = ifindex;
|
||
address.address = addr;
|
||
address.plen = plen;
|
||
|
||
g_array_append_val (priv->ip6_addresses, address);
|
||
|
||
g_signal_emit_by_name (platform, NM_PLATFORM_IP6_ADDRESS_ADDED, ifindex, &address);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
int i;
|
||
|
||
for (i = 0; i < priv->ip4_addresses->len; i++) {
|
||
NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
|
||
|
||
if (address->ifindex == ifindex && address->plen == plen && address->address == addr) {
|
||
NMPlatformIP4Address deleted_address;
|
||
|
||
memcpy (&deleted_address, address, sizeof (deleted_address));
|
||
memset (address, 0, sizeof (*address));
|
||
g_signal_emit_by_name (platform, NM_PLATFORM_IP4_ADDRESS_REMOVED, ifindex, &deleted_address);
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
g_assert_not_reached ();
|
||
}
|
||
|
||
static gboolean
|
||
ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
int i;
|
||
|
||
for (i = 0; i < priv->ip6_addresses->len; i++) {
|
||
NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
|
||
|
||
if (address->ifindex == ifindex && address->plen == plen
|
||
&& IN6_ARE_ADDR_EQUAL (&address->address, &addr)) {
|
||
NMPlatformIP6Address deleted_address;
|
||
|
||
memcpy (&deleted_address, address, sizeof (deleted_address));
|
||
memset (address, 0, sizeof (*address));
|
||
g_signal_emit_by_name (platform, NM_PLATFORM_IP6_ADDRESS_REMOVED, ifindex, &deleted_address);
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
g_assert_not_reached ();
|
||
}
|
||
|
||
static gboolean
|
||
ip4_address_exists (NMPlatform *platform, int ifindex, in_addr_t addr, int plen)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
int i;
|
||
|
||
for (i = 0; i < priv->ip4_addresses->len; i++) {
|
||
NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
|
||
|
||
if (address->ifindex == ifindex && address->plen == plen && address->address == addr)
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
static gboolean
|
||
ip6_address_exists (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
int i;
|
||
|
||
for (i = 0; i < priv->ip6_addresses->len; i++) {
|
||
NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
|
||
|
||
if (address->ifindex == ifindex && address->plen == plen &&
|
||
IN6_ARE_ADDR_EQUAL (&address->address, &addr))
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
/******************************************************************/
|
||
|
||
static GArray *
|
||
ip4_route_get_all (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
GArray *routes;
|
||
NMPlatformIP4Route *route;
|
||
int count = 0, i;
|
||
|
||
/* Count routes */
|
||
for (i = 0; i < priv->ip4_routes->len; i++) {
|
||
route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
|
||
if (route && route->ifindex == ifindex)
|
||
count++;
|
||
}
|
||
|
||
routes = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP4Route), count);
|
||
|
||
/* Fill routes */
|
||
for (i = 0; i < priv->ip4_routes->len; i++) {
|
||
route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
|
||
if (route && route->ifindex == ifindex)
|
||
g_array_append_val (routes, *route);
|
||
}
|
||
|
||
return routes;
|
||
}
|
||
|
||
static GArray *
|
||
ip6_route_get_all (NMPlatform *platform, int ifindex)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
GArray *routes;
|
||
NMPlatformIP6Route *route;
|
||
int count = 0, i;
|
||
|
||
/* Count routes */
|
||
for (i = 0; i < priv->ip6_routes->len; i++) {
|
||
route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
|
||
if (route && route->ifindex == ifindex)
|
||
count++;
|
||
}
|
||
|
||
routes = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP6Route), count);
|
||
|
||
/* Fill routes */
|
||
for (i = 0; i < priv->ip6_routes->len; i++) {
|
||
route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
|
||
if (route && route->ifindex == ifindex)
|
||
g_array_append_val (routes, *route);
|
||
}
|
||
|
||
return routes;
|
||
}
|
||
|
||
static gboolean
|
||
ip4_route_add (NMPlatform *platform, int ifindex, in_addr_t network, int plen,
|
||
in_addr_t gateway, int metric, int mss)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
NMPlatformIP4Route route;
|
||
|
||
memset (&route, 0, sizeof (route));
|
||
route.ifindex = ifindex;
|
||
route.network = network;
|
||
route.plen = plen;
|
||
route.gateway = gateway;
|
||
route.metric = metric;
|
||
route.mss = mss;
|
||
|
||
g_array_append_val (priv->ip4_routes, route);
|
||
|
||
g_signal_emit_by_name (platform, NM_PLATFORM_IP4_ROUTE_ADDED, ifindex, &route);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
ip6_route_add (NMPlatform *platform, int ifindex, struct in6_addr network, int plen,
|
||
struct in6_addr gateway, int metric, int mss)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
NMPlatformIP6Route route;
|
||
|
||
memset (&route, 0, sizeof (route));
|
||
route.ifindex = ifindex;
|
||
route.network = network;
|
||
route.plen = plen;
|
||
route.gateway = gateway;
|
||
route.metric = metric;
|
||
route.mss = mss;
|
||
|
||
g_array_append_val (priv->ip6_routes, route);
|
||
|
||
g_signal_emit_by_name (platform, NM_PLATFORM_IP6_ROUTE_ADDED, ifindex, &route);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static NMPlatformIP4Route *
|
||
ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, int plen, int metric)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
int i;
|
||
|
||
for (i = 0; i < priv->ip4_routes->len; i++) {
|
||
NMPlatformIP4Route *route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
|
||
|
||
if (route->ifindex == ifindex
|
||
&& route->network == network
|
||
&& route->plen == plen
|
||
&& route->metric == metric)
|
||
return route;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
static NMPlatformIP6Route *
|
||
ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, int metric)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||
int i;
|
||
|
||
for (i = 0; i < priv->ip6_routes->len; i++) {
|
||
NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
|
||
|
||
if (route->ifindex == ifindex
|
||
&& IN6_ARE_ADDR_EQUAL (&route->network, &network)
|
||
&& route->plen == plen
|
||
&& route->metric == metric)
|
||
return route;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
static gboolean
|
||
ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen, int metric)
|
||
{
|
||
NMPlatformIP4Route *route = ip4_route_get (platform, ifindex, network, plen, metric);
|
||
NMPlatformIP4Route deleted_route;
|
||
|
||
g_assert (route);
|
||
|
||
memcpy (&deleted_route, route, sizeof (deleted_route));
|
||
memset (route, 0, sizeof (*route));
|
||
g_signal_emit_by_name (platform, NM_PLATFORM_IP4_ROUTE_REMOVED, ifindex, &deleted_route);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, int metric)
|
||
{
|
||
NMPlatformIP6Route *route = ip6_route_get (platform, ifindex, network, plen, metric);
|
||
NMPlatformIP6Route deleted_route;
|
||
|
||
g_assert (route);
|
||
|
||
memcpy (&deleted_route, route, sizeof (deleted_route));
|
||
memset (route, 0, sizeof (*route));
|
||
g_signal_emit_by_name (platform, NM_PLATFORM_IP6_ROUTE_REMOVED, ifindex, &deleted_route);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static gboolean
|
||
ip4_route_exists (NMPlatform *platform, int ifindex, in_addr_t network, int plen, int metric)
|
||
{
|
||
return !!ip4_route_get (platform, ifindex, network, plen, metric);
|
||
}
|
||
|
||
static gboolean
|
||
ip6_route_exists (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, int metric)
|
||
{
|
||
return !!ip6_route_get (platform, ifindex, network, plen, metric);
|
||
}
|
||
|
||
/******************************************************************/
|
||
|
||
static void
|
||
nm_fake_platform_init (NMFakePlatform *fake_platform)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (fake_platform);
|
||
|
||
priv->options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||
priv->links = g_array_new (TRUE, TRUE, sizeof (NMFakePlatformLink));
|
||
priv->ip4_addresses = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Address));
|
||
priv->ip6_addresses = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Address));
|
||
priv->ip4_routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Route));
|
||
priv->ip6_routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Route));
|
||
}
|
||
|
||
static gboolean
|
||
setup (NMPlatform *platform)
|
||
{
|
||
/* skip zero element */
|
||
link_add (platform, NULL, NM_LINK_TYPE_NONE);
|
||
|
||
/* add loopback interface */
|
||
link_add (platform, "lo", NM_LINK_TYPE_LOOPBACK);
|
||
|
||
/* add some ethernets */
|
||
link_add (platform, "eth0", NM_LINK_TYPE_ETHERNET);
|
||
link_add (platform, "eth1", NM_LINK_TYPE_ETHERNET);
|
||
link_add (platform, "eth2", NM_LINK_TYPE_ETHERNET);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static void
|
||
nm_fake_platform_finalize (GObject *object)
|
||
{
|
||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (object);
|
||
int i;
|
||
|
||
g_hash_table_unref (priv->options);
|
||
for (i = 0; i < priv->links->len; i++) {
|
||
NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i);
|
||
|
||
g_bytes_unref (device->address);
|
||
g_free (device->udi);
|
||
}
|
||
g_array_unref (priv->links);
|
||
g_array_unref (priv->ip4_addresses);
|
||
g_array_unref (priv->ip6_addresses);
|
||
g_array_unref (priv->ip4_routes);
|
||
g_array_unref (priv->ip6_routes);
|
||
|
||
G_OBJECT_CLASS (nm_fake_platform_parent_class)->finalize (object);
|
||
}
|
||
|
||
static void
|
||
nm_fake_platform_class_init (NMFakePlatformClass *klass)
|
||
{
|
||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
NMPlatformClass *platform_class = NM_PLATFORM_CLASS (klass);
|
||
|
||
g_type_class_add_private (klass, sizeof (NMFakePlatformPrivate));
|
||
|
||
/* virtual methods */
|
||
object_class->finalize = nm_fake_platform_finalize;
|
||
|
||
platform_class->setup = setup;
|
||
|
||
platform_class->sysctl_set = sysctl_set;
|
||
platform_class->sysctl_get = sysctl_get;
|
||
|
||
platform_class->link_get_all = link_get_all;
|
||
platform_class->link_add = link_add;
|
||
platform_class->link_delete = link_delete;
|
||
platform_class->link_get_ifindex = link_get_ifindex;
|
||
platform_class->link_get_name = link_get_name;
|
||
platform_class->link_get_type = link_get_type;
|
||
platform_class->link_get_type_name = link_get_type_name;
|
||
|
||
platform_class->link_set_up = link_set_up;
|
||
platform_class->link_set_down = link_set_down;
|
||
platform_class->link_set_arp = link_set_arp;
|
||
platform_class->link_set_noarp = link_set_noarp;
|
||
platform_class->link_is_up = link_is_up;
|
||
platform_class->link_is_connected = link_is_connected;
|
||
platform_class->link_uses_arp = link_uses_arp;
|
||
|
||
platform_class->link_set_address = link_set_address;
|
||
platform_class->link_get_address = link_get_address;
|
||
platform_class->link_get_mtu = link_get_mtu;
|
||
platform_class->link_set_mtu = link_set_mtu;
|
||
|
||
platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
|
||
platform_class->link_supports_vlans = link_supports_vlans;
|
||
|
||
platform_class->link_enslave = link_enslave;
|
||
platform_class->link_release = link_release;
|
||
platform_class->link_get_master = link_get_master;
|
||
platform_class->master_set_option = master_set_option;
|
||
platform_class->master_get_option = master_get_option;
|
||
platform_class->slave_set_option = slave_set_option;
|
||
platform_class->slave_get_option = slave_get_option;
|
||
|
||
platform_class->vlan_add = vlan_add;
|
||
platform_class->vlan_get_info = vlan_get_info;
|
||
platform_class->vlan_set_ingress_map = vlan_set_ingress_map;
|
||
platform_class->vlan_set_egress_map = vlan_set_egress_map;
|
||
|
||
platform_class->infiniband_partition_add = infiniband_partition_add;
|
||
|
||
platform_class->veth_get_properties = veth_get_properties;
|
||
platform_class->tun_get_properties = tun_get_properties;
|
||
platform_class->macvlan_get_properties = macvlan_get_properties;
|
||
platform_class->gre_get_properties = gre_get_properties;
|
||
|
||
platform_class->ip4_address_get_all = ip4_address_get_all;
|
||
platform_class->ip6_address_get_all = ip6_address_get_all;
|
||
platform_class->ip4_address_add = ip4_address_add;
|
||
platform_class->ip6_address_add = ip6_address_add;
|
||
platform_class->ip4_address_delete = ip4_address_delete;
|
||
platform_class->ip6_address_delete = ip6_address_delete;
|
||
platform_class->ip4_address_exists = ip4_address_exists;
|
||
platform_class->ip6_address_exists = ip6_address_exists;
|
||
|
||
platform_class->ip4_route_get_all = ip4_route_get_all;
|
||
platform_class->ip6_route_get_all = ip6_route_get_all;
|
||
platform_class->ip4_route_add = ip4_route_add;
|
||
platform_class->ip6_route_add = ip6_route_add;
|
||
platform_class->ip4_route_delete = ip4_route_delete;
|
||
platform_class->ip6_route_delete = ip6_route_delete;
|
||
platform_class->ip4_route_exists = ip4_route_exists;
|
||
platform_class->ip6_route_exists = ip6_route_exists;
|
||
}
|