platform: merge branch 'th/platform_refact_caching-bgo747981'

Refactor caching of NMPlatform and the way how to load objects
via libnl/netlink.

https://bugzilla.gnome.org/show_bug.cgi?id=747981
https://bugzilla.gnome.org/show_bug.cgi?id=747985
https://bugzilla.redhat.com/show_bug.cgi?id=1211133
This commit is contained in:
Thomas Haller 2015-06-17 11:44:37 +02:00
commit 35dcd8ac33
40 changed files with 6891 additions and 2521 deletions

View file

@ -163,4 +163,53 @@ q_n##_quark (void) \
}
#endif
static inline gboolean
nm_g_hash_table_replace (GHashTable *hash, gpointer key, gpointer value)
{
/* glib 2.40 added a return value indicating whether the key already existed
* (910191597a6c2e5d5d460e9ce9efb4f47d9cc63c). */
#if GLIB_CHECK_VERSION(2, 40, 0)
return g_hash_table_replace (hash, key, value);
#else
gboolean contained = g_hash_table_contains (hash, key);
g_hash_table_replace (hash, key, value);
return !contained;
#endif
}
#if !GLIB_CHECK_VERSION(2, 40, 0) || defined (NM_GLIB_COMPAT_H_TEST)
static inline void
_nm_g_ptr_array_insert (GPtrArray *array,
gint index_,
gpointer data)
{
g_return_if_fail (array);
g_return_if_fail (index_ >= -1);
g_return_if_fail (index_ <= (gint) array->len);
g_ptr_array_add (array, data);
if (index_ != -1 && index_ != (gint) (array->len - 1)) {
memmove (&(array->pdata[index_ + 1]),
&(array->pdata[index_]),
(array->len - index_ - 1) * sizeof (gpointer));
array->pdata[index_] = data;
}
}
#endif
#if !GLIB_CHECK_VERSION(2, 40, 0)
#define g_ptr_array_insert(array, index, data) G_STMT_START { _nm_g_ptr_array_insert (array, index, data); } G_STMT_END
#else
#define g_ptr_array_insert(array, index, data) \
G_STMT_START { \
G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
g_ptr_array_insert (array, index, data); \
G_GNUC_END_IGNORE_DEPRECATIONS \
} G_STMT_END
#endif
#endif /* __NM_GLIB_COMPAT_H__ */

View file

@ -181,6 +181,23 @@ nm_clear_g_source (guint *id)
/*****************************************************************************/
/* Determine whether @x is a power of two (@x being an integer type).
* For the special cases @x equals zero or one, it also returns true.
* For negative @x, always returns FALSE. That only applies, is the data
* type of @x is signed. */
#define nm_utils_is_power_of_two(x) ({ \
const typeof(x) __x = (x); \
\
((__x & (__x - 1)) == 0) && \
/* Check if the value is negative. In that case, return FALSE.
* The first expression is a compile time constant, depending on whether
* the type is signed. The second expression is a clumsy way for (__x >= 0),
* which causes a compiler warning for unsigned types. */ \
( ( ((typeof(__x)) -1) > ((typeof(__x)) 0) ) || (__x > 0) || (__x == 0) ); \
})
/*****************************************************************************/
/* check if @flags has exactly one flag (@check) set. You should call this
* only with @check being a compile time constant and a power of two. */
#define NM_FLAGS_HAS(flags, check) \

View file

@ -112,6 +112,8 @@ GPtrArray *_nm_utils_copy_array (const GPtrArray *array,
GDestroyNotify free_func);
GPtrArray *_nm_utils_copy_object_array (const GPtrArray *array);
gssize _nm_utils_ptrarray_find_first (gpointer *list, gssize len, gconstpointer needle);
gboolean _nm_utils_string_in_list (const char *str,
const char **valid_strings);

View file

@ -631,6 +631,32 @@ _nm_utils_copy_object_array (const GPtrArray *array)
return _nm_utils_copy_array (array, g_object_ref, g_object_unref);
}
/* have @list of type 'gpointer *' instead of 'gconstpointer *' to
* reduce the necessity for annoying const-casts. */
gssize
_nm_utils_ptrarray_find_first (gpointer *list, gssize len, gconstpointer needle)
{
gssize i;
if (len == 0)
return -1;
if (len > 0) {
g_return_val_if_fail (list, -1);
for (i = 0; i < len; i++) {
if (list[i] == needle)
return i;
}
} else {
g_return_val_if_fail (needle, -1);
for (i = 0; list && list[i]; i++) {
if (list[i] == needle)
return i;
}
}
return -1;
}
GVariant *
_nm_utils_bytes_to_dbus (const GValue *prop_value)
{

View file

@ -19,6 +19,8 @@
*
*/
#define NM_GLIB_COMPAT_H_TEST
#include "config.h"
#include <glib.h>
@ -59,6 +61,7 @@
#include "nm-setting-wireless-security.h"
#include "nm-simple-connection.h"
#include "nm-keyfile-internal.h"
#include "nm-glib-compat.h"
#include "nm-test-utils.h"
@ -4358,6 +4361,128 @@ test_nm_utils_dns_option_find_idx (void)
/******************************************************************************/
enum TEST_IS_POWER_OF_TWP_ENUM_SIGNED {
_DUMMY_1 = -1,
};
enum TEST_IS_POWER_OF_TWP_ENUM_UNSIGNED {
_DUMMY_2,
};
enum TEST_IS_POWER_OF_TWP_ENUM_SIGNED_64 {
_DUMMY_3 = (1LL << 40),
};
enum TEST_IS_POWER_OF_TWP_ENUM_UNSIGNED_64 {
_DUMMY_4a = -1,
_DUMMY_4b = (1LL << 40),
};
#define test_nm_utils_is_power_of_two_do(type, x, expect) \
G_STMT_START { \
typeof (x) x1 = (x); \
type x2 = (type) x1; \
\
if (((typeof (x1)) x2) == x1 && (x2 > 0 || x2 == 0)) { \
/* x2 equals @x, and is positive. Compare to @expect */ \
g_assert_cmpint (expect, ==, nm_utils_is_power_of_two (x2)); \
} else if (!(x2 > 0) && !(x2 == 0)) { \
/* a (signed) negative value is always FALSE. */ \
g_assert_cmpint (FALSE, ==, nm_utils_is_power_of_two (x2));\
} \
g_assert_cmpint (expect, ==, nm_utils_is_power_of_two (x1)); \
} G_STMT_END
static void
test_nm_utils_is_power_of_two ()
{
guint64 xyes, xno;
gint i, j;
GRand *rand = nmtst_get_rand ();
int numbits;
for (i = -1; i < 64; i++) {
/* find a (positive) x which is a power of two. */
if (i == -1)
xyes = 0;
else {
xyes = (1LL << i);
g_assert (xyes != 0);
}
xno = xyes;
if (xyes != 0) {
again:
/* Find another @xno, that is not a power of two. Do that,
* by randomly setting bits. */
numbits = g_rand_int_range (rand, 1, 65);
while (xno != ~((guint64) 0) && numbits > 0) {
guint64 v = (1LL << g_rand_int_range (rand, 0, 65));
if ((xno | v) != xno) {
xno |= v;
--numbits;
}
}
if (xno == xyes)
goto again;
}
for (j = 0; j < 2; j++) {
gboolean expect = j == 0;
guint64 x = expect ? xyes : xno;
if (!expect && xno == 0)
continue;
/* check if @x is as @expect, when casted to a certain data type. */
test_nm_utils_is_power_of_two_do (gint8, x, expect);
test_nm_utils_is_power_of_two_do (guint8, x, expect);
test_nm_utils_is_power_of_two_do (gint16, x, expect);
test_nm_utils_is_power_of_two_do (guint16, x, expect);
test_nm_utils_is_power_of_two_do (gint32, x, expect);
test_nm_utils_is_power_of_two_do (guint32, x, expect);
test_nm_utils_is_power_of_two_do (gint64, x, expect);
test_nm_utils_is_power_of_two_do (guint64, x, expect);
test_nm_utils_is_power_of_two_do (char, x, expect);
test_nm_utils_is_power_of_two_do (unsigned char, x, expect);
test_nm_utils_is_power_of_two_do (signed char, x, expect);
test_nm_utils_is_power_of_two_do (enum TEST_IS_POWER_OF_TWP_ENUM_SIGNED, x, expect);
test_nm_utils_is_power_of_two_do (enum TEST_IS_POWER_OF_TWP_ENUM_UNSIGNED, x, expect);
test_nm_utils_is_power_of_two_do (enum TEST_IS_POWER_OF_TWP_ENUM_SIGNED_64, x, expect);
test_nm_utils_is_power_of_two_do (enum TEST_IS_POWER_OF_TWP_ENUM_UNSIGNED_64, x, expect);
}
}
}
/******************************************************************************/
static void
test_g_ptr_array_insert (void)
{
/* this test only makes sense on a recent glib, where we compare our compat
* with the original implementation. */
#if GLIB_CHECK_VERSION(2, 40, 0)
gs_unref_ptrarray GPtrArray *arr1 = g_ptr_array_new ();
gs_unref_ptrarray GPtrArray *arr2 = g_ptr_array_new ();
GRand *rand = nmtst_get_rand ();
guint i;
for (i = 0; i < 560; i++) {
gint32 idx = g_rand_int_range (rand, -1, arr1->len + 1);
g_ptr_array_insert (arr1, idx, GINT_TO_POINTER (i));
_nm_g_ptr_array_insert (arr2, idx, GINT_TO_POINTER (i));
g_assert_cmpint (arr1->len, ==, arr2->len);
g_assert (memcmp (arr1->pdata, arr2->pdata, arr1->len * sizeof (gpointer)) == 0);
}
#endif
}
/******************************************************************************/
NMTST_DEFINE ();
int main (int argc, char **argv)
@ -4459,6 +4584,8 @@ int main (int argc, char **argv)
g_test_add_func ("/core/general/_nm_utils_uuid_generate_from_strings", test_nm_utils_uuid_generate_from_strings);
g_test_add_func ("/core/general/_nm_utils_ascii_str_to_int64", test_nm_utils_ascii_str_to_int64);
g_test_add_func ("/core/general/nm_utils_is_power_of_two", test_nm_utils_is_power_of_two);
g_test_add_func ("/core/general/_glib_compat_g_ptr_array_insert", test_g_ptr_array_insert);
g_test_add_func ("/core/general/_nm_utils_dns_option_validate", test_nm_utils_dns_option_validate);
g_test_add_func ("/core/general/_nm_utils_dns_option_find_idx", test_nm_utils_dns_option_find_idx);

View file

@ -227,6 +227,8 @@ nm_sources = \
platform/nm-platform.h \
platform/nm-platform-utils.c \
platform/nm-platform-utils.h \
platform/nmp-object.c \
platform/nmp-object.h \
platform/wifi/wifi-utils-nl80211.c \
platform/wifi/wifi-utils-nl80211.h \
platform/wifi/wifi-utils-private.h \
@ -331,6 +333,8 @@ nm_sources = \
nm-auth-utils.h \
nm-manager.c \
nm-manager.h \
nm-multi-index.c \
nm-multi-index.h \
nm-policy.c \
nm-policy.h \
nm-properties-changed-signal.c \
@ -473,6 +477,8 @@ libnm_iface_helper_la_SOURCES = \
platform/nm-platform.h \
platform/nm-platform-utils.c \
platform/nm-platform-utils.h \
platform/nmp-object.c \
platform/nmp-object.h \
platform/wifi/wifi-utils-nl80211.c \
platform/wifi/wifi-utils-nl80211.h \
platform/wifi/wifi-utils-private.h \
@ -498,6 +504,8 @@ libnm_iface_helper_la_SOURCES = \
nm-enum-types.h \
nm-logging.c \
nm-logging.h \
nm-multi-index.c \
nm-multi-index.h \
NetworkManagerUtils.c \
NetworkManagerUtils.h

View file

@ -352,7 +352,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_reason)
_LOGD (LOGD_ADSL, "ATM setup successful");
/* otherwise we're good for stage3 */
nm_platform_link_set_up (NM_PLATFORM_GET, priv->nas_ifindex);
nm_platform_link_set_up (NM_PLATFORM_GET, priv->nas_ifindex, NULL);
ret = NM_ACT_STAGE_RETURN_SUCCESS;
} else if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOA) == 0) {

View file

@ -571,16 +571,17 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
GError **error)
{
const char *iface = nm_connection_get_interface_name (connection);
NMPlatformError plerr;
g_assert (iface);
if ( !nm_platform_bond_add (NM_PLATFORM_GET, iface, NULL)
&& nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) {
plerr = nm_platform_bond_add (NM_PLATFORM_GET, iface, NULL);
if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
"Failed to create bond interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_get_error_msg (NM_PLATFORM_GET));
nm_platform_error_to_string (plerr));
return NULL;
}

View file

@ -498,6 +498,7 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
NMSettingBridge *s_bridge;
const char *mac_address_str;
guint8 mac_address[NM_UTILS_HWADDR_LEN_MAX];
NMPlatformError plerr;
g_assert (iface);
@ -510,17 +511,17 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
mac_address_str = NULL;
}
if ( !nm_platform_bridge_add (NM_PLATFORM_GET,
plerr = nm_platform_bridge_add (NM_PLATFORM_GET,
iface,
mac_address_str ? mac_address : NULL,
mac_address_str ? ETH_ALEN : 0,
NULL)
&& nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) {
NULL);
if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
"Failed to create bridge interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_get_error_msg (NM_PLATFORM_GET));
nm_platform_error_to_string (plerr));
return NULL;
}

View file

@ -52,6 +52,7 @@
#include "nm-connection-provider.h"
#include "nm-device-factory.h"
#include "nm-core-internal.h"
#include "NetworkManagerUtils.h"
#include "nm-device-ethernet-glue.h"
@ -151,28 +152,21 @@ static void
_update_s390_subchannels (NMDeviceEthernet *self)
{
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
GUdevClient *client;
GUdevDevice *dev;
GUdevDevice *parent = NULL;
const char *parent_path, *item, *driver;
const char *subsystems[] = { "net", NULL };
const char *iface;
int ifindex;
GDir *dir;
GError *error = NULL;
client = g_udev_client_new (subsystems);
if (!client) {
_LOGW (LOGD_DEVICE | LOGD_HW, "failed to initialize GUdev client");
return;
}
iface = nm_device_get_iface (NM_DEVICE (self));
dev = iface ? g_udev_client_query_by_subsystem_and_name (client, "net", iface) : NULL;
ifindex = nm_device_get_ifindex (NM_DEVICE (self));
dev = (GUdevDevice *) nm_platform_link_get_udev_device (NM_PLATFORM_GET, ifindex);
if (!dev) {
_LOGW (LOGD_DEVICE | LOGD_HW, "failed to find device '%s' with udev",
iface ? iface : "(null)");
_LOGW (LOGD_DEVICE | LOGD_HW, "failed to find device %d '%s' with udev",
ifindex, str_if_set (nm_device_get_iface (NM_DEVICE (self)), "(null)"));
goto out;
}
g_object_ref (dev);
/* Try for the "ccwgroup" parent */
parent = g_udev_device_get_parent_with_subsystem (dev, "ccwgroup", NULL);
@ -244,7 +238,6 @@ out:
g_object_unref (parent);
if (dev)
g_object_unref (dev);
g_object_unref (client);
}
static GObject*
@ -1559,7 +1552,7 @@ link_changed (NMDevice *device, NMPlatformLink *info)
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->link_changed (device, info);
if (!priv->subchan1 && info->udi)
if (!priv->subchan1 && info->initialized)
_update_s390_subchannels (self);
}

View file

@ -326,6 +326,7 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
NMSettingInfiniband *s_infiniband;
int p_key, parent_ifindex;
const char *iface;
NMPlatformError plerr;
if (!NM_IS_DEVICE_INFINIBAND (parent)) {
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
@ -342,13 +343,13 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
parent_ifindex = nm_device_get_ifindex (parent);
p_key = nm_setting_infiniband_get_p_key (s_infiniband);
if ( !nm_platform_infiniband_partition_add (NM_PLATFORM_GET, parent_ifindex, p_key, NULL)
&& nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) {
plerr = nm_platform_infiniband_partition_add (NM_PLATFORM_GET, parent_ifindex, p_key, NULL);
if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
"Failed to create InfiniBand P_Key interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_get_error_msg (NM_PLATFORM_GET));
nm_platform_error_to_string (plerr));
return NULL;
}

View file

@ -656,6 +656,7 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
NMDevice *device;
NMSettingVlan *s_vlan;
gs_free char *iface = NULL;
NMPlatformError plerr;
if (!NM_IS_DEVICE (parent)) {
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
@ -672,18 +673,18 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
nm_setting_vlan_get_id (s_vlan));
}
if ( !nm_platform_vlan_add (NM_PLATFORM_GET,
plerr = nm_platform_vlan_add (NM_PLATFORM_GET,
iface,
nm_device_get_ifindex (parent),
nm_setting_vlan_get_id (s_vlan),
nm_setting_vlan_get_flags (s_vlan),
NULL)
&& nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) {
NULL);
if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
"Failed to create VLAN interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_get_error_msg (NM_PLATFORM_GET));
nm_platform_error_to_string (plerr));
return NULL;
}

View file

@ -598,7 +598,7 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface)
nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, priv->ip_ifindex, TRUE);
if (!nm_platform_link_is_up (NM_PLATFORM_GET, priv->ip_ifindex))
nm_platform_link_set_up (NM_PLATFORM_GET, priv->ip_ifindex);
nm_platform_link_set_up (NM_PLATFORM_GET, priv->ip_ifindex, NULL);
} else {
/* Device IP interface must always be a kernel network interface */
_LOGW (LOGD_HW, "failed to look up interface index");
@ -1341,11 +1341,13 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
NMUtilsIPv6IfaceId token_iid;
gboolean ip_ifname_changed = FALSE;
gboolean platform_unmanaged = FALSE;
const char *udi;
if (info->udi && g_strcmp0 (info->udi, priv->udi)) {
udi = nm_platform_link_get_udi (NM_PLATFORM_GET, info->ifindex);
if (udi && g_strcmp0 (udi, priv->udi)) {
/* Update UDI to what udev gives us */
g_free (priv->udi);
priv->udi = g_strdup (info->udi);
priv->udi = g_strdup (udi);
g_object_notify (G_OBJECT (self), NM_DEVICE_UDI);
}
@ -1406,15 +1408,15 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
if (ip_ifname_changed)
update_for_ip_ifname_change (self);
if (priv->up != info->up) {
priv->up = info->up;
if (priv->up != NM_FLAGS_HAS (info->flags, IFF_UP)) {
priv->up = NM_FLAGS_HAS (info->flags, IFF_UP);
/* Manage externally-created software interfaces only when they are IFF_UP */
g_assert (priv->ifindex > 0);
if (NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)) {
gboolean external_down = nm_device_get_unmanaged_flag (self, NM_UNMANAGED_EXTERNAL_DOWN);
if (external_down && info->up) {
if (external_down && NM_FLAGS_HAS (info->flags, IFF_UP)) {
if (nm_device_get_state (self) < NM_DEVICE_STATE_DISCONNECTED) {
/* Ensure the assume check is queued before any queued state changes
* from the transition to UNAVAILABLE.
@ -1437,7 +1439,7 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
*/
priv->unmanaged_flags &= ~NM_UNMANAGED_EXTERNAL_DOWN;
}
} else if (!external_down && !info->up && nm_device_get_state (self) <= NM_DEVICE_STATE_DISCONNECTED) {
} else if (!external_down && !NM_FLAGS_HAS (info->flags, IFF_UP) && nm_device_get_state (self) <= NM_DEVICE_STATE_DISCONNECTED) {
/* If the device is already disconnected and is set !IFF_UP,
* unmanage it.
*/
@ -4721,8 +4723,7 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable)
const char *detail = enable ? "enable" : "disable";
_LOGD (LOGD_IP6, "will %s userland IPv6LL", detail);
if ( !nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, ifindex, enable)
&& nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_NOT_FOUND)
if (!nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, ifindex, enable))
_LOGW (LOGD_IP6, "failed to %s userspace IPv6LL address handling", detail);
if (enable) {
@ -5526,7 +5527,7 @@ nm_device_activate_ip4_config_commit (gpointer user_data)
/* Interface must be IFF_UP before IP config can be applied */
ip_ifindex = nm_device_get_ip_ifindex (self);
if (!nm_platform_link_is_up (NM_PLATFORM_GET, ip_ifindex) && !nm_device_uses_assumed_connection (self)) {
nm_platform_link_set_up (NM_PLATFORM_GET, ip_ifindex);
nm_platform_link_set_up (NM_PLATFORM_GET, ip_ifindex, NULL);
if (!nm_platform_link_is_up (NM_PLATFORM_GET, ip_ifindex))
_LOGW (LOGD_DEVICE, "interface %s not up for IP configuration", nm_device_get_ip_iface (self));
}
@ -5647,7 +5648,7 @@ nm_device_activate_ip6_config_commit (gpointer user_data)
/* Interface must be IFF_UP before IP config can be applied */
ip_ifindex = nm_device_get_ip_ifindex (self);
if (!nm_platform_link_is_up (NM_PLATFORM_GET, ip_ifindex) && !nm_device_uses_assumed_connection (self)) {
nm_platform_link_set_up (NM_PLATFORM_GET, ip_ifindex);
nm_platform_link_set_up (NM_PLATFORM_GET, ip_ifindex, NULL);
if (!nm_platform_link_is_up (NM_PLATFORM_GET, ip_ifindex))
_LOGW (LOGD_DEVICE, "interface %s not up for IP configuration", nm_device_get_ip_iface (self));
}
@ -6791,9 +6792,7 @@ bring_up (NMDevice *self, gboolean *no_firmware)
return TRUE;
}
result = nm_platform_link_set_up (NM_PLATFORM_GET, ifindex);
if (no_firmware)
*no_firmware = nm_platform_get_error (NM_PLATFORM_GET) == NM_PLATFORM_ERROR_NO_FIRMWARE;
result = nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, no_firmware);
/* Store carrier immediately. */
if (result && nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT))
@ -8772,8 +8771,7 @@ constructed (GObject *object)
priv->perm_hw_addr);
} else {
/* Fall back to current address */
_LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address (error %d)",
nm_platform_get_error (NM_PLATFORM_GET));
_LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address");
priv->perm_hw_addr = g_strdup (priv->hw_addr);
}
}
@ -8938,11 +8936,11 @@ set_property (GObject *object, guint prop_id,
platform_device = g_value_get_pointer (value);
if (platform_device) {
g_free (priv->udi);
priv->udi = g_strdup (platform_device->udi);
priv->udi = g_strdup (nm_platform_link_get_udi (NM_PLATFORM_GET, platform_device->ifindex));
g_free (priv->iface);
priv->iface = g_strdup (platform_device->name);
priv->ifindex = platform_device->ifindex;
priv->up = platform_device->up;
priv->up = NM_FLAGS_HAS (platform_device->flags, IFF_UP);
g_free (priv->driver);
priv->driver = g_strdup (platform_device->driver);
priv->platform_link_initialized = platform_device->initialized;

View file

@ -689,16 +689,17 @@ NMDevice *
nm_device_team_new_for_connection (NMConnection *connection, GError **error)
{
const char *iface = nm_connection_get_interface_name (connection);
NMPlatformError plerr;
g_assert (iface);
if ( !nm_platform_team_add (NM_PLATFORM_GET, iface, NULL)
&& nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) {
plerr = nm_platform_team_add (NM_PLATFORM_GET, iface, NULL);
if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
"Failed to create team master interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_get_error_msg (NM_PLATFORM_GET));
nm_platform_error_to_string (plerr));
return NULL;
}

View file

@ -477,7 +477,7 @@ main (int argc, char *argv[])
* physical interfaces.
*/
nm_log_dbg (LOGD_CORE, "setting up local loopback");
nm_platform_link_set_up (NM_PLATFORM_GET, 1);
nm_platform_link_set_up (NM_PLATFORM_GET, 1, NULL);
success = TRUE;

441
src/nm-multi-index.c Normal file
View file

@ -0,0 +1,441 @@
/* -*- 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.
*
* 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 "config.h"
#include "nm-multi-index.h"
#include <string.h>
#include "nm-glib-compat.h"
#include "nm-macros-internal.h"
struct NMMultiIndex {
NMMultiIndexFuncEqual equal_fcn;
NMMultiIndexFuncClone clone_fcn;
GHashTable *hash;
};
typedef struct {
GHashTable *index;
gpointer *values;
} ValuesData;
/******************************************************************************************/
static ValuesData *
_values_data_create ()
{
ValuesData *values_data;
values_data = g_slice_new (ValuesData);
values_data->index = g_hash_table_new (NULL, NULL);
values_data->values = NULL;
return values_data;
}
static void
_values_data_destroy (ValuesData *values_data)
{
if (values_data) {
g_free (values_data->values);
g_hash_table_unref (values_data->index);
g_slice_free (ValuesData, values_data);
}
}
static void
_values_data_populate_array (ValuesData *values_data)
{
guint i, len;
gpointer *values;
GHashTableIter iter;
nm_assert (values_data);
nm_assert (values_data->index && g_hash_table_size (values_data->index) > 0);
if (values_data->values)
return;
len = g_hash_table_size (values_data->index);
values = g_new (gpointer, len + 1);
g_hash_table_iter_init (&iter, values_data->index);
for (i = 0; g_hash_table_iter_next (&iter, &values[i], NULL); i++)
nm_assert (i < len);
nm_assert (i == len);
values[i] = NULL;
values_data->values = values;
}
/******************************************************************************************/
/**
* nm_multi_index_lookup():
* @index:
* @id:
* @out_len: (allow-none): output the number of values
* that are returned.
*
* Returns: (transfer-none): %NULL if there are no values
* or a %NULL terminated array of pointers.
*/
void *const*
nm_multi_index_lookup (const NMMultiIndex *index,
const NMMultiIndexId *id,
guint *out_len)
{
ValuesData *values_data;
g_return_val_if_fail (index, NULL);
g_return_val_if_fail (id, NULL);
values_data = g_hash_table_lookup (index->hash, id);
if (!values_data) {
if (out_len)
*out_len = 0;
return NULL;
}
_values_data_populate_array (values_data);
if (out_len)
*out_len = g_hash_table_size (values_data->index);
return values_data->values;
}
gboolean
nm_multi_index_contains (const NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value)
{
ValuesData *values_data;
g_return_val_if_fail (index, FALSE);
g_return_val_if_fail (id, FALSE);
g_return_val_if_fail (value, FALSE);
values_data = g_hash_table_lookup (index->hash, id);
return values_data
&& g_hash_table_contains (values_data->index, value);
}
const NMMultiIndexId *
nm_multi_index_lookup_first_by_value (const NMMultiIndex *index,
gconstpointer value)
{
GHashTableIter iter;
const NMMultiIndexId *id;
ValuesData *values_data;
g_return_val_if_fail (index, NULL);
g_return_val_if_fail (value, NULL);
/* reverse-lookup needs to iterate over all hash tables. It should
* still be fairly quick, if the number of hash tables is small.
* There is no O(1) reverse lookup implemented, because this access
* pattern is not what NMMultiIndex is here for.
* You are supposed to use NMMultiIndex by always knowing which @id
* a @value has.
*/
g_hash_table_iter_init (&iter, index->hash);
while (g_hash_table_iter_next (&iter, (gpointer *) &id, (gpointer *) &values_data)) {
if (g_hash_table_contains (values_data->index, value))
return id;
}
return NULL;
}
void
nm_multi_index_foreach (const NMMultiIndex *index,
gconstpointer value,
NMMultiIndexFuncForeach foreach_func,
gpointer user_data)
{
GHashTableIter iter;
const NMMultiIndexId *id;
ValuesData *values_data;
g_return_if_fail (index);
g_return_if_fail (foreach_func);
g_hash_table_iter_init (&iter, index->hash);
while (g_hash_table_iter_next (&iter, (gpointer *) &id, (gpointer *) &values_data)) {
if ( value
&& !g_hash_table_contains (values_data->index, value))
continue;
_values_data_populate_array (values_data);
if (!foreach_func (id, values_data->values, g_hash_table_size (values_data->index), user_data))
return;
}
}
void
nm_multi_index_iter_init (NMMultiIndexIter *iter,
const NMMultiIndex *index,
gconstpointer value)
{
g_return_if_fail (index);
g_return_if_fail (iter);
g_hash_table_iter_init (&iter->_iter, index->hash);
iter->_index = index;
iter->_value = value;
}
gboolean
nm_multi_index_iter_next (NMMultiIndexIter *iter,
const NMMultiIndexId **out_id,
void *const**out_values,
guint *out_len)
{
const NMMultiIndexId *id;
ValuesData *values_data;
g_return_val_if_fail (iter, FALSE);
while (g_hash_table_iter_next (&iter->_iter, (gpointer *) &id, (gpointer *) &values_data)) {
if ( !iter->_value
|| g_hash_table_contains (values_data->index, iter->_value)) {
_values_data_populate_array (values_data);
if (out_id)
*out_id = id;
if (out_values)
*out_values = values_data->values;
if (out_len)
*out_len = g_hash_table_size (values_data->index);
return TRUE;
}
}
return FALSE;
}
/******************************************************************************************/
void
nm_multi_index_id_iter_init (NMMultiIndexIdIter *iter,
const NMMultiIndex *index,
const NMMultiIndexId *id)
{
ValuesData *values_data;
g_return_if_fail (index);
g_return_if_fail (iter);
g_return_if_fail (id);
values_data = g_hash_table_lookup (index->hash, id);
if (!values_data)
iter->_state = 1;
else {
iter->_state = 0;
g_hash_table_iter_init (&iter->_iter, values_data->index);
}
}
gboolean
nm_multi_index_id_iter_next (NMMultiIndexIdIter *iter,
void **out_value)
{
g_return_val_if_fail (iter, FALSE);
g_return_val_if_fail (iter->_state <= 1, FALSE);
if (iter->_state == 0)
return g_hash_table_iter_next (&iter->_iter, out_value, NULL);
else {
iter->_state = 2;
return FALSE;
}
}
/******************************************************************************************/
static gboolean
_do_add (NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value)
{
ValuesData *values_data;
values_data = g_hash_table_lookup (index->hash, id);
if (!values_data) {
NMMultiIndexId *id_new;
/* Contrary to GHashTable, we don't take ownership of the @id that was
* provided to nm_multi_index_add(). Instead we clone it via @clone_fcn
* when needed.
*
* The reason is, that we expect in most cases that there exists
* already a @id so that we don't need ownership of it (or clone it).
* By doing this, the caller can pass a stack allocated @id or
* reuse the @id for other insertions.
*/
id_new = index->clone_fcn (id);
if (!id_new)
g_return_val_if_reached (FALSE);
values_data = _values_data_create ();
g_hash_table_replace (values_data->index, (gpointer) value, (gpointer) value);
g_hash_table_insert (index->hash, id_new, values_data);
} else {
if (!nm_g_hash_table_replace (values_data->index, (gpointer) value, (gpointer) value))
return FALSE;
g_clear_pointer (&values_data->values, g_free);
}
return TRUE;
}
static gboolean
_do_remove (NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value)
{
ValuesData *values_data;
values_data = g_hash_table_lookup (index->hash, id);
if (!values_data)
return FALSE;
if (!g_hash_table_remove (values_data->index, value))
return FALSE;
if (g_hash_table_size (values_data->index) == 0)
g_hash_table_remove (index->hash, id);
else
g_clear_pointer (&values_data->values, g_free);
return TRUE;
}
gboolean
nm_multi_index_add (NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value)
{
g_return_val_if_fail (index, FALSE);
g_return_val_if_fail (id, FALSE);
g_return_val_if_fail (value, FALSE);
return _do_add (index, id, value);
}
gboolean
nm_multi_index_remove (NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value)
{
g_return_val_if_fail (index, FALSE);
g_return_val_if_fail (value, FALSE);
if (!id)
g_return_val_if_reached (FALSE);
return _do_remove (index, id, value);
}
/**
* nm_multi_index_move:
* @index:
* @id_old: (allow-none): remove @value at @id_old
* @id_new: (allow-none): add @value under @id_new
* @value: the value to add
*
* Similar to a remove(), followed by an add(). The difference
* is, that we allow %NULL for both @id_old and @id_new.
* And the return value indicates whether @value was successfully
* removed *and* added.
*
* Returns: %TRUE, if the value was removed from @id_old and added
* as %id_new. %FALSE could mean, that @value was not added to @id_old
* before, or that that @value was already part of @id_new. */
gboolean
nm_multi_index_move (NMMultiIndex *index,
const NMMultiIndexId *id_old,
const NMMultiIndexId *id_new,
gconstpointer value)
{
g_return_val_if_fail (index, FALSE);
g_return_val_if_fail (value, FALSE);
if (!id_old && !id_new) {
/* nothing to do, @value was and is not in @index. */
return TRUE;
} if (!id_old) {
/* add @value to @index with @id_new */
return _do_add (index, id_new, value);
} else if (!id_new) {
/* remove @value from @index with @id_old */
return _do_remove (index, id_old, value);
} else if (index->equal_fcn (id_old, id_new)) {
if (_do_add (index, id_new, value)) {
/* we would expect, that @value is already in @index,
* Return %FALSE, if it wasn't. */
return FALSE;
}
return TRUE;
} else {
gboolean did_remove;
did_remove = _do_remove (index, id_old, value);
return _do_add (index, id_new, value) && did_remove;
}
}
/******************************************************************************************/
guint
nm_multi_index_get_num_groups (const NMMultiIndex *index)
{
g_return_val_if_fail (index, 0);
return g_hash_table_size (index->hash);
}
NMMultiIndex *
nm_multi_index_new (NMMultiIndexFuncHash hash_fcn,
NMMultiIndexFuncEqual equal_fcn,
NMMultiIndexFuncClone clone_fcn,
NMMultiIndexFuncDestroy destroy_fcn)
{
NMMultiIndex *index;
g_return_val_if_fail (hash_fcn, NULL);
g_return_val_if_fail (equal_fcn, NULL);
g_return_val_if_fail (clone_fcn, NULL);
g_return_val_if_fail (destroy_fcn, NULL);
index = g_new (NMMultiIndex, 1);
index->equal_fcn = equal_fcn;
index->clone_fcn = clone_fcn;
index->hash = g_hash_table_new_full ((GHashFunc) hash_fcn,
(GEqualFunc) equal_fcn,
(GDestroyNotify) destroy_fcn,
(GDestroyNotify) _values_data_destroy);
return index;
}
void
nm_multi_index_free (NMMultiIndex *index)
{
g_return_if_fail (index);
g_hash_table_unref (index->hash);
g_free (index);
}

109
src/nm-multi-index.h Normal file
View file

@ -0,0 +1,109 @@
/* -*- 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.
*
* 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.
*/
#ifndef __NM_MULTI_INDEX__
#define __NM_MULTI_INDEX__
#include <glib.h>
G_BEGIN_DECLS
typedef struct {
char _dummy;
} NMMultiIndexId;
typedef struct NMMultiIndex NMMultiIndex;
typedef struct {
GHashTableIter _iter;
const NMMultiIndex *_index;
gconstpointer _value;
} NMMultiIndexIter;
typedef struct {
GHashTableIter _iter;
guint _state;
} NMMultiIndexIdIter;
typedef gboolean (*NMMultiIndexFuncEqual) (const NMMultiIndexId *id_a, const NMMultiIndexId *id_b);
typedef guint (*NMMultiIndexFuncHash) (const NMMultiIndexId *id);
typedef NMMultiIndexId *(*NMMultiIndexFuncClone) (const NMMultiIndexId *id);
typedef void (*NMMultiIndexFuncDestroy) (NMMultiIndexId *id);
typedef gboolean (*NMMultiIndexFuncForeach) (const NMMultiIndexId *id, void *const* values, guint len, gpointer user_data);
NMMultiIndex *nm_multi_index_new (NMMultiIndexFuncHash hash_fcn,
NMMultiIndexFuncEqual equal_fcn,
NMMultiIndexFuncClone clone_fcn,
NMMultiIndexFuncDestroy destroy_fcn);
void nm_multi_index_free (NMMultiIndex *index);
gboolean nm_multi_index_add (NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value);
gboolean nm_multi_index_remove (NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value);
gboolean nm_multi_index_move (NMMultiIndex *index,
const NMMultiIndexId *id_old,
const NMMultiIndexId *id_new,
gconstpointer value);
guint nm_multi_index_get_num_groups (const NMMultiIndex *index);
void *const*nm_multi_index_lookup (const NMMultiIndex *index,
const NMMultiIndexId *id,
guint *out_len);
gboolean nm_multi_index_contains (const NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value);
const NMMultiIndexId *nm_multi_index_lookup_first_by_value (const NMMultiIndex *index,
gconstpointer value);
void nm_multi_index_foreach (const NMMultiIndex *index,
gconstpointer value,
NMMultiIndexFuncForeach foreach_func,
gpointer user_data);
void nm_multi_index_iter_init (NMMultiIndexIter *iter,
const NMMultiIndex *index,
gconstpointer value);
gboolean nm_multi_index_iter_next (NMMultiIndexIter *iter,
const NMMultiIndexId **out_id,
void *const**out_values,
guint *out_len);
void nm_multi_index_id_iter_init (NMMultiIndexIdIter *iter,
const NMMultiIndex *index,
const NMMultiIndexId *id);
gboolean nm_multi_index_id_iter_next (NMMultiIndexIdIter *iter,
void **out_value);
G_END_DECLS
#endif /* __NM_MULTI_INDEX__ */

View file

@ -51,6 +51,13 @@ typedef struct _NMSleepMonitor NMSleepMonitor;
typedef enum {
/* In priority order; higher number == higher priority */
NM_IP_CONFIG_SOURCE_UNKNOWN,
/* platform internal flag used to mark routes with RTM_F_CLONED. */
_NM_IP_CONFIG_SOURCE_RTM_F_CLONED,
/* platform internal flag used to mark routes with protocol RTPROT_KERNEL. */
_NM_IP_CONFIG_SOURCE_RTPROT_KERNEL,
NM_IP_CONFIG_SOURCE_KERNEL,
NM_IP_CONFIG_SOURCE_SHARED,
NM_IP_CONFIG_SOURCE_IP4LL,

View file

@ -24,12 +24,16 @@
#include <unistd.h>
#include <netinet/icmp6.h>
#include <netinet/in.h>
#include <linux/rtnetlink.h>
#include "gsystem-local-alloc.h"
#include "nm-utils.h"
#include "NetworkManagerUtils.h"
#include "nm-fake-platform.h"
#include "nm-logging.h"
#include "nm-test-utils.h"
#define debug(format, ...) nm_log_dbg (LOGD_PLATFORM, format, __VA_ARGS__)
typedef struct {
@ -48,6 +52,7 @@ typedef struct {
GBytes *address;
int vlan_id;
int ib_p_key;
struct in6_addr ip6_lladdr;
} NMFakePlatformLink;
#define NM_FAKE_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_FAKE_PLATFORM, NMFakePlatformPrivate))
@ -56,6 +61,15 @@ G_DEFINE_TYPE (NMFakePlatform, nm_fake_platform, NM_TYPE_PLATFORM)
/******************************************************************/
static void link_changed (NMPlatform *platform, NMFakePlatformLink *device, gboolean raise_signal);
static gboolean ip6_address_add (NMPlatform *platform, int ifindex,
struct in6_addr addr, struct in6_addr peer_addr,
int plen, guint32 lifetime, guint32 preferred, guint flags);
static gboolean ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen);
/******************************************************************/
static gboolean
sysctl_set (NMPlatform *platform, const char *path, const char *value)
{
@ -103,24 +117,30 @@ type_to_type_name (NMLinkType type)
static void
link_init (NMFakePlatformLink *device, int ifindex, int type, const char *name)
{
gs_free char *ip6_lladdr = NULL;
g_assert (!name || strlen (name) < sizeof(device->link.name));
memset (device, 0, sizeof (*device));
ip6_lladdr = ifindex > 0 ? g_strdup_printf ("fe80::fa1e:%0x:%0x", ifindex / 256, ifindex % 256) : NULL;
device->link.ifindex = name ? ifindex : 0;
device->link.type = type;
device->link.kind = type_to_type_name (type);
device->link.driver = type_to_type_name (type);
device->link.udi = device->udi = g_strdup_printf ("fake:%d", ifindex);
device->udi = g_strdup_printf ("fake:%d", ifindex);
device->link.initialized = TRUE;
device->ip6_lladdr = *nmtst_inet6_from_string (ip6_lladdr);
if (name)
strcpy (device->link.name, name);
switch (device->link.type) {
case NM_LINK_TYPE_DUMMY:
device->link.arp = FALSE;
device->link.flags = NM_FLAGS_SET (device->link.flags, IFF_NOARP);
break;
default:
device->link.arp = TRUE;
device->link.flags = NM_FLAGS_UNSET (device->link.flags, IFF_NOARP);
break;
}
device->address = NULL;
}
@ -140,7 +160,6 @@ link_get (NMPlatform *platform, int ifindex)
return device;
not_found:
debug ("link not found: %d", ifindex);
platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
return NULL;
}
@ -205,9 +224,12 @@ link_add (NMPlatform *platform,
g_array_append_val (priv->links, device);
if (device.link.ifindex)
if (device.link.ifindex) {
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, device.link.ifindex, &device, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL);
link_changed (platform, &g_array_index (priv->links, NMFakePlatformLink, priv->links->len - 1), FALSE);
}
if (out_link)
*out_link = device.link;
return TRUE;
@ -303,55 +325,76 @@ link_get_unmanaged (NMPlatform *platform, int ifindex, gboolean *managed)
}
static void
link_changed (NMPlatform *platform, NMFakePlatformLink *device)
link_changed (NMPlatform *platform, NMFakePlatformLink *device, gboolean raise_signal)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
int i;
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, device->link.ifindex, &device->link, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL);
if (raise_signal)
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, device->link.ifindex, &device->link, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL);
if (device->link.ifindex && !IN6_IS_ADDR_UNSPECIFIED (&device->ip6_lladdr)) {
if (device->link.connected)
ip6_address_add (platform, device->link.ifindex, device->ip6_lladdr, in6addr_any, 64, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0);
else
ip6_address_delete (platform, device->link.ifindex, device->ip6_lladdr, 64);
}
if (device->link.master) {
gboolean connected = FALSE;
NMFakePlatformLink *master = link_get (platform, device->link.master);
g_return_if_fail (master != device);
g_return_if_fail (master && 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;
connected = TRUE;
}
link_changed (platform, master);
if (master->link.connected != connected) {
master->link.connected = connected;
link_changed (platform, master, TRUE);
}
}
}
static gboolean
link_set_up (NMPlatform *platform, int ifindex)
link_set_up (NMPlatform *platform, int ifindex, gboolean *out_no_firmware)
{
NMFakePlatformLink *device = link_get (platform, ifindex);
gboolean up, connected;
if (out_no_firmware)
*out_no_firmware = FALSE;
if (!device)
return FALSE;
device->link.up = TRUE;
up = TRUE;
connected = 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;
connected = FALSE;
break;
default:
device->link.connected = FALSE;
connected = FALSE;
g_error ("Unexpected device type: %d", device->link.type);
}
link_changed (platform, device);
if ( NM_FLAGS_HAS (device->link.flags, IFF_UP) != !!up
|| device->link.connected != connected) {
device->link.flags = NM_FLAGS_ASSIGN (device->link.flags, IFF_UP, up);
device->link.connected = connected;
link_changed (platform, device, TRUE);
}
return TRUE;
}
@ -364,10 +407,12 @@ link_set_down (NMPlatform *platform, int ifindex)
if (!device)
return FALSE;
device->link.up = FALSE;
device->link.connected = FALSE;
if (NM_FLAGS_HAS (device->link.flags, IFF_UP) || device->link.connected) {
device->link.flags = NM_FLAGS_UNSET (device->link.flags, IFF_UP);
device->link.connected = FALSE;
link_changed (platform, device);
link_changed (platform, device, TRUE);
}
return TRUE;
}
@ -380,9 +425,9 @@ link_set_arp (NMPlatform *platform, int ifindex)
if (!device)
return FALSE;
device->link.arp = TRUE;
device->link.flags = NM_FLAGS_UNSET (device->link.flags, IFF_NOARP);
link_changed (platform, device);
link_changed (platform, device, TRUE);
return TRUE;
}
@ -395,9 +440,9 @@ link_set_noarp (NMPlatform *platform, int ifindex)
if (!device)
return FALSE;
device->link.arp = FALSE;
device->link.flags = NM_FLAGS_SET (device->link.flags, IFF_NOARP);
link_changed (platform, device);
link_changed (platform, device, TRUE);
return TRUE;
}
@ -407,7 +452,7 @@ link_is_up (NMPlatform *platform, int ifindex)
{
NMFakePlatformLink *device = link_get (platform, ifindex);
return device ? device->link.up : FALSE;
return device ? NM_FLAGS_HAS (device->link.flags, IFF_UP) : FALSE;
}
static gboolean
@ -423,7 +468,7 @@ link_uses_arp (NMPlatform *platform, int ifindex)
{
NMFakePlatformLink *device = link_get (platform, ifindex);
return device ? device->link.arp : FALSE;
return device ? !NM_FLAGS_HAS (device->link.flags, IFF_NOARP) : FALSE;
}
static gboolean
@ -436,7 +481,7 @@ link_set_address (NMPlatform *platform, int ifindex, gconstpointer addr, size_t
device->address = g_bytes_new (addr, len);
link_changed (platform, link_get (platform, ifindex));
link_changed (platform, link_get (platform, ifindex), TRUE);
return TRUE;
}
@ -468,7 +513,7 @@ link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
if (device) {
device->link.mtu = mtu;
link_changed (platform, device);
link_changed (platform, device, TRUE);
}
return !!device;
@ -500,6 +545,16 @@ link_get_dev_id (NMPlatform *platform, int ifindex)
return 0;
}
static const char *
link_get_udi (NMPlatform *platform, int ifindex)
{
NMFakePlatformLink *device = link_get (platform, ifindex);
if (!device)
return NULL;
return device->udi;
}
static gboolean
link_get_wake_on_lan (NMPlatform *platform, int ifindex)
{
@ -565,12 +620,21 @@ static gboolean
link_enslave (NMPlatform *platform, int master, int slave)
{
NMFakePlatformLink *device = link_get (platform, slave);
NMFakePlatformLink *master_device = link_get (platform, master);
g_return_val_if_fail (device, FALSE);
g_return_val_if_fail (master_device, FALSE);
device->link.master = master;
if (device->link.master != master) {
device->link.master = master;
link_changed (platform, device);
if (NM_IN_SET (master_device->link.type, NM_LINK_TYPE_BOND, NM_LINK_TYPE_TEAM)) {
device->link.flags = NM_FLAGS_SET (device->link.flags, IFF_UP);
device->link.connected = TRUE;
}
link_changed (platform, device, TRUE);
}
return TRUE;
}
@ -584,15 +648,13 @@ link_release (NMPlatform *platform, int master_idx, int 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;
if (slave->link.master != master->link.ifindex)
return FALSE;
}
slave->link.master = 0;
link_changed (platform, slave);
link_changed (platform, master);
link_changed (platform, slave, TRUE);
link_changed (platform, master, TRUE);
return TRUE;
}
@ -982,8 +1044,10 @@ ip6_address_add (NMPlatform *platform, int ifindex,
if (item->plen != address.plen)
continue;
memcpy (item, &address, sizeof (address));
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL);
if (nm_platform_ip6_address_cmp (item, &address) != 0) {
memcpy (item, &address, sizeof (address));
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL);
}
return TRUE;
}
@ -1196,6 +1260,9 @@ ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
NMPlatformIP4Route route;
guint i;
guint8 scope;
scope = gateway == 0 ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
memset (&route, 0, sizeof (route));
route.source = NM_IP_CONFIG_SOURCE_KERNEL;
@ -1206,6 +1273,7 @@ ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
route.gateway = gateway;
route.metric = metric;
route.mss = mss;
route.scope_inv = nm_platform_route_scope_inv (scope);
if (gateway) {
for (i = 0; i < priv->ip4_routes->len; i++) {
@ -1218,8 +1286,8 @@ ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
break;
}
if (i == priv->ip4_routes->len) {
nm_log_warn (LOGD_PLATFORM, "Fake platform: error adding %s: Network Unreachable",
nm_platform_ip4_route_to_string (&route));
nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip4-route '%d: %s/%d %d': Network Unreachable",
route.ifindex, nm_utils_inet4_ntop (route.network, NULL), route.plen, route.metric);
return FALSE;
}
}
@ -1285,8 +1353,8 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
break;
}
if (i == priv->ip6_routes->len) {
nm_log_warn (LOGD_PLATFORM, "Fake platform: error adding %s: Network Unreachable",
nm_platform_ip6_route_to_string (&route));
nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip6-route '%d: %s/%d %d': Network Unreachable",
route.ifindex, nm_utils_inet6_ntop (&route.network, NULL), route.plen, route.metric);
return FALSE;
}
}
@ -1453,6 +1521,8 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
platform_class->link_get_type_name = link_get_type_name;
platform_class->link_get_unmanaged = link_get_unmanaged;
platform_class->link_get_udi = link_get_udi;
platform_class->link_set_up = link_set_up;
platform_class->link_set_down = link_set_down;
platform_class->link_set_arp = link_set_arp;

File diff suppressed because it is too large Load diff

View file

@ -32,8 +32,12 @@
/******************************************************************/
struct _NMLinuxPlatformPrivate;
typedef struct {
NMPlatform parent;
struct _NMLinuxPlatformPrivate *priv;
} NMLinuxPlatform;
typedef struct {

File diff suppressed because it is too large Load diff

View file

@ -29,6 +29,7 @@
#include <nm-dbus-interface.h>
#include "nm-types.h"
#include "NetworkManagerUtils.h"
#define NM_TYPE_PLATFORM (nm_platform_get_type ())
#define NM_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PLATFORM, NMPlatform))
@ -39,6 +40,10 @@
/******************************************************************/
#define NM_PLATFORM_REGISTER_SINGLETON "register-singleton"
/******************************************************************/
typedef struct _NMPlatform NMPlatform;
/* workaround for older libnl version, that does not define these flags. */
@ -50,18 +55,23 @@ typedef struct _NMPlatform NMPlatform;
#endif
typedef enum {
/* no error specified, sometimes this means the arguments were wrong */
NM_PLATFORM_ERROR_NONE,
/* object was not found */
/* dummy value, to enforce that the enum type is signed and has a size
* to hold an integer. We want to encode errno from <errno.h> as negative
* values. */
_NM_PLATFORM_ERROR_MININT = G_MININT,
NM_PLATFORM_ERROR_SUCCESS = 0,
NM_PLATFORM_ERROR_BUG,
NM_PLATFORM_ERROR_UNSPECIFIED,
NM_PLATFORM_ERROR_NOT_FOUND,
/* object already exists */
NM_PLATFORM_ERROR_EXISTS,
/* object is wrong type */
NM_PLATFORM_ERROR_WRONG_TYPE,
/* object is not a slave */
NM_PLATFORM_ERROR_NOT_SLAVE,
/* firmware is not found */
NM_PLATFORM_ERROR_NO_FIRMWARE
NM_PLATFORM_ERROR_NO_FIRMWARE,
} NMPlatformError;
typedef enum {
@ -90,19 +100,44 @@ struct _NMPlatformLink {
/* NMPlatform initializes this field with a static string. */
const char *kind;
/* Beware: NMPlatform initializes this string with an allocated string.
* Handle it properly (i.e. don't keep a reference to it). */
const char *udi;
/* NMPlatform initializes this field with a static string. */
const char *driver;
gboolean initialized;
int master;
int parent;
gboolean up;
/* rtnl_link_get_arptype(), ifinfomsg.ifi_type. */
guint32 arptype;
/* rtnl_link_get_addr() */
struct {
guint8 data[20]; /* NM_UTILS_HWADDR_LEN_MAX */
guint8 len;
} addr;
/* rtnl_link_inet6_get_token() */
struct {
NMUtilsIPv6IfaceId iid;
guint8 is_valid;
} inet6_token;
/* The bitwise inverse of rtnl_link_inet6_get_addr_gen_mode(). It is inverse
* to have a default of 0 -- meaning: unspecified. That way, a struct
* initialized with memset(0) has and unset value.*/
guint8 inet6_addr_gen_mode_inv;
/* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */
guint16 vlan_id;
/* IFF_* flags as u32. Note that ifi_flags in 'struct ifinfomsg' is declared as 'unsigned',
* but libnl stores the flag internally as u32. */
guint32 flags;
/* @connected is mostly identical to (@flags & IFF_UP). Except for bridge/bond masters,
* where we coerce the link as disconnect if it has no slaves. */
gboolean connected;
gboolean arp;
guint mtu;
};
@ -237,6 +272,10 @@ struct _NMPlatformIP4Route {
__NMPlatformIPRoute_COMMON;
in_addr_t network;
in_addr_t gateway;
/* The bitwise inverse of the route scope. It is inverted so that the
* default value (RT_SCOPE_NOWHERE) is nul. */
guint8 scope_inv;
};
G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OFFSET (NMPlatformIP4Route, network));
@ -275,6 +314,7 @@ typedef struct {
extern const NMPlatformVTableRoute nm_platform_vtable_route_v4;
extern const NMPlatformVTableRoute nm_platform_vtable_route_v6;
extern char _nm_platform_to_string_buffer[256];
typedef struct {
int peer;
@ -361,8 +401,6 @@ typedef struct {
struct _NMPlatform {
GObject parent;
NMPlatformError error;
};
typedef struct {
@ -389,7 +427,7 @@ typedef struct {
gboolean (*link_refresh) (NMPlatform *, int ifindex);
gboolean (*link_set_up) (NMPlatform *, int ifindex);
gboolean (*link_set_up) (NMPlatform *, int ifindex, gboolean *out_no_firmware);
gboolean (*link_set_down) (NMPlatform *, int ifindex);
gboolean (*link_set_arp) (NMPlatform *, int ifindex);
gboolean (*link_set_noarp) (NMPlatform *, int ifindex);
@ -397,6 +435,8 @@ typedef struct {
gboolean (*link_is_connected) (NMPlatform *, int ifindex);
gboolean (*link_uses_arp) (NMPlatform *, int ifindex);
const char *(*link_get_udi) (NMPlatform *self, int ifindex);
GObject *(*link_get_udev_device) (NMPlatform *self, int ifindex);
gboolean (*link_get_ipv6_token) (NMPlatform *, int ifindex, NMUtilsIPv6IfaceId *iid);
gboolean (*link_get_user_ipv6ll_enabled) (NMPlatform *, int ifindex);
@ -529,11 +569,25 @@ NMPlatform *nm_platform_try_get (void);
/******************************************************************/
/**
* nm_platform_route_scope_inv:
* @scope: the route scope, either its original value, or its inverse.
*
* This function is useful, because the constants such as RT_SCOPE_NOWHERE
* are 'int', so ~scope also gives an 'int'. This function gets the type
* casts to guint8 right.
*
* Returns: the bitwise inverse of the route scope.
* */
static inline guint8
nm_platform_route_scope_inv (guint8 scope)
{
return (guint8) ~scope;
}
const char *nm_link_type_to_string (NMLinkType link_type);
void nm_platform_set_error (NMPlatform *self, NMPlatformError error);
NMPlatformError nm_platform_get_error (NMPlatform *self);
const char *nm_platform_get_error_msg (NMPlatform *self);
const char *nm_platform_error_to_string (NMPlatformError error);
gboolean nm_platform_sysctl_set (NMPlatform *self, const char *path, const char *value);
char *nm_platform_sysctl_get (NMPlatform *self, const char *path);
@ -545,10 +599,10 @@ gboolean nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char
gboolean nm_platform_link_get (NMPlatform *self, int ifindex, NMPlatformLink *link);
GArray *nm_platform_link_get_all (NMPlatform *self);
gboolean nm_platform_link_get_by_address (NMPlatform *self, gconstpointer address, size_t length, NMPlatformLink *link);
gboolean nm_platform_dummy_add (NMPlatform *self, const char *name, NMPlatformLink *out_link);
gboolean nm_platform_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len, NMPlatformLink *out_link);
gboolean nm_platform_bond_add (NMPlatform *self, const char *name, NMPlatformLink *out_link);
gboolean nm_platform_team_add (NMPlatform *self, const char *name, NMPlatformLink *out_link);
NMPlatformError nm_platform_dummy_add (NMPlatform *self, const char *name, NMPlatformLink *out_link);
NMPlatformError nm_platform_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len, NMPlatformLink *out_link);
NMPlatformError nm_platform_bond_add (NMPlatform *self, const char *name, NMPlatformLink *out_link);
NMPlatformError nm_platform_team_add (NMPlatform *self, const char *name, NMPlatformLink *out_link);
gboolean nm_platform_link_exists (NMPlatform *self, const char *name);
gboolean nm_platform_link_delete (NMPlatform *self, int ifindex);
int nm_platform_link_get_ifindex (NMPlatform *self, const char *name);
@ -561,7 +615,7 @@ gboolean nm_platform_link_supports_slaves (NMPlatform *self, int ifindex);
gboolean nm_platform_link_refresh (NMPlatform *self, int ifindex);
gboolean nm_platform_link_set_up (NMPlatform *self, int ifindex);
gboolean nm_platform_link_set_up (NMPlatform *self, int ifindex, gboolean *out_no_firmware);
gboolean nm_platform_link_set_down (NMPlatform *self, int ifindex);
gboolean nm_platform_link_set_arp (NMPlatform *self, int ifindex);
gboolean nm_platform_link_set_noarp (NMPlatform *self, int ifindex);
@ -570,6 +624,9 @@ gboolean nm_platform_link_is_connected (NMPlatform *self, int ifindex);
gboolean nm_platform_link_uses_arp (NMPlatform *self, int ifindex);
gboolean nm_platform_link_get_ipv6_token (NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId *iid);
const char *nm_platform_link_get_udi (NMPlatform *self, int ifindex);
GObject *nm_platform_link_get_udev_device (NMPlatform *self, int ifindex);
gboolean nm_platform_link_get_user_ipv6ll_enabled (NMPlatform *self, int ifindex);
gboolean nm_platform_link_set_user_ipv6ll_enabled (NMPlatform *self, int ifindex, gboolean enabled);
@ -600,12 +657,12 @@ char *nm_platform_master_get_option (NMPlatform *self, int ifindex, const char *
gboolean nm_platform_slave_set_option (NMPlatform *self, int ifindex, const char *option, const char *value);
char *nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *option);
gboolean nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags, NMPlatformLink *out_link);
NMPlatformError nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags, NMPlatformLink *out_link);
gboolean nm_platform_vlan_get_info (NMPlatform *self, int ifindex, int *parent, int *vlanid);
gboolean nm_platform_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to);
gboolean nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to);
gboolean nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link);
NMPlatformError nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link);
gboolean nm_platform_infiniband_get_info (NMPlatform *self, int ifindex, int *parent, int *p_key, const char **mode);
gboolean nm_platform_veth_get_properties (NMPlatform *self, int ifindex, NMPlatformVethProperties *properties);

1941
src/platform/nmp-object.c Normal file

File diff suppressed because it is too large Load diff

383
src/platform/nmp-object.h Normal file
View file

@ -0,0 +1,383 @@
/* -*- 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.
*/
#ifndef __NMP_OBJECT_H__
#define __NMP_OBJECT_H__
#include "config.h"
#include "nm-platform.h"
#include "nm-multi-index.h"
#include "nm-macros-internal.h"
#include <netlink/netlink.h>
#include <gudev/gudev.h>
typedef enum { /*< skip >*/
OBJECT_TYPE_UNKNOWN,
OBJECT_TYPE_LINK,
OBJECT_TYPE_IP4_ADDRESS,
OBJECT_TYPE_IP6_ADDRESS,
OBJECT_TYPE_IP4_ROUTE,
OBJECT_TYPE_IP6_ROUTE,
__OBJECT_TYPE_LAST,
OBJECT_TYPE_MAX = __OBJECT_TYPE_LAST - 1,
} ObjectType;
typedef enum { /*< skip >*/
NMP_OBJECT_TO_STRING_ID,
NMP_OBJECT_TO_STRING_PUBLIC,
NMP_OBJECT_TO_STRING_ALL,
} NMPObjectToStringMode;
typedef enum { /*< skip >*/
NMP_CACHE_OPS_UNCHANGED = NM_PLATFORM_SIGNAL_NONE,
NMP_CACHE_OPS_UPDATED = NM_PLATFORM_SIGNAL_CHANGED,
NMP_CACHE_OPS_ADDED = NM_PLATFORM_SIGNAL_ADDED,
NMP_CACHE_OPS_REMOVED = NM_PLATFORM_SIGNAL_REMOVED,
} NMPCacheOpsType;
/* The NMPCacheIdType are the different index types.
*
* An object of a certain object-type, can be candidate to being
* indexed by a certain NMPCacheIdType or not. For example, all
* objects are indexed via an index of type NMP_CACHE_ID_TYPE_OBJECT_TYPE,
* but only route objects are indexed by NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ALL.
*
* Of one index type, there can be different indexes or not.
* For example, there is only one single instance of
* NMP_CACHE_ID_TYPE_LINKS_VISIBLE_ONLY, because this instance is
* applicable for all link objects.
* But there are different instances of NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX
* type index, which differ in v4/v6, the ifindex, and whether the index
* is for routes or address instances.
*
* But one object, can only be indexed by one particular index of one
* type. For example, a certain address instance is only indexed by
* the index NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX with matching v4/v6
* and ifindex.
* */
typedef enum { /*< skip >*/
NMP_CACHE_ID_TYPE_OBJECT_TYPE,
NMP_CACHE_ID_TYPE_LINKS_VISIBLE_ONLY,
NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX,
/* three indeces for the visibile routes. */
NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ALL,
NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT,
NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT,
__NMP_CACHE_ID_TYPE_MAX,
NMP_CACHE_ID_TYPE_MAX = __NMP_CACHE_ID_TYPE_MAX - 1,
} NMPCacheIdType;
typedef struct _NMPObject NMPObject;
typedef struct {
union {
NMMultiIndexId base;
guint8 _id_type; /* NMPCacheIdType as guint8 */
struct {
/* NMP_CACHE_ID_TYPE_OBJECT_TYPE */
guint8 _id_type;
guint8 obj_type; /* ObjectType as guint8 */
} object_type;
struct {
/* NMP_CACHE_ID_TYPE_LINKS_VISIBLE_ONLY */
guint8 _id_type;
/* the @_global_id is only defined by it's type and has no arguments.
* It is used by NMP_CACHE_ID_TYPE_LINKS_VISIBLE_ONLY. There is only
* one single occurence of an index of this type. */
} _global_id;
struct {
/* NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX */
guint8 _id_type;
guint8 obj_type; /* ObjectType as guint8 */
int ifindex;
} addrroute_by_ifindex;
struct {
/* NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ALL */
/* NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT */
/* NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT */
guint8 _id_type;
guint8 is_v4;
int ifindex;
} routes_visible;
};
} NMPCacheId;
extern NMPCacheId _nmp_cache_id_static;
#define NMP_CACHE_ID_STATIC (&_nmp_cache_id_static)
typedef struct {
ObjectType obj_type;
int addr_family;
int rtm_gettype;
int sizeof_data;
int sizeof_public;
const char *obj_type_name;
const char *nl_type;
const char *signal_type;
/* returns %FALSE, if the obj type would never have an entry for index type @id_type. If @obj has an index,
* initialize @id and set @out_id to it. Otherwise, @out_id is NULL. */
gboolean (*cmd_obj_init_cache_id) (const NMPObject *obj, NMPCacheIdType id_type, NMPCacheId *id, const NMPCacheId **out_id);
gboolean (*cmd_obj_equal) (const NMPObject *obj1, const NMPObject *obj2);
void (*cmd_obj_copy) (NMPObject *dst, const NMPObject *src);
void (*cmd_obj_stackinit_id) (NMPObject *obj, const NMPObject *src);
void (*cmd_obj_dispose) (NMPObject *obj);
gboolean (*cmd_obj_is_alive) (const NMPObject *obj);
gboolean (*cmd_obj_is_visible) (const NMPObject *obj);
/* functions that operate on NMPlatformObject */
gboolean (*cmd_plobj_init_from_nl) (NMPlatform *platform, NMPlatformObject *obj, const struct nl_object *nlo, gboolean id_only, gboolean complete_from_cache);
struct nl_object *(*cmd_plobj_to_nl) (NMPlatform *platform, const NMPlatformObject *obj, gboolean id_only);
void (*cmd_plobj_id_copy) (NMPlatformObject *dst, const NMPlatformObject *src);
gboolean (*cmd_plobj_id_equal) (const NMPlatformObject *obj1, const NMPlatformObject *obj2);
guint (*cmd_plobj_id_hash) (const NMPlatformObject *obj);
const char *(*cmd_plobj_to_string_id) (const NMPlatformObject *obj, char *buf, gsize buf_size);
const char *(*cmd_plobj_to_string) (const NMPlatformObject *obj);
int (*cmd_plobj_cmp) (const NMPlatformObject *obj1, const NMPlatformObject *obj2);
} NMPClass;
extern const NMPClass _nmp_classes[OBJECT_TYPE_MAX];
typedef struct {
NMPlatformLink _public;
struct {
guint8 is_in_netlink;
} netlink;
struct {
GUdevDevice *device;
} udev;
} NMPObjectLink;
typedef struct {
NMPlatformIP4Address _public;
} NMPObjectIP4Address;
typedef struct {
NMPlatformIP4Route _public;
} NMPObjectIP4Route;
typedef struct {
NMPlatformIP6Address _public;
} NMPObjectIP6Address;
typedef struct {
NMPlatformIP6Route _public;
} NMPObjectIP6Route;
struct _NMPObject {
const NMPClass *_class;
int _ref_count;
guint8 is_cached;
union {
NMPlatformObject object;
NMPlatformLink link;
NMPObjectLink _link;
NMPlatformIPAddress ip_address;
NMPlatformIPXAddress ipx_address;
NMPlatformIP4Address ip4_address;
NMPlatformIP6Address ip6_address;
NMPObjectIP4Address _ip4_address;
NMPObjectIP6Address _ip6_address;
NMPlatformIPRoute ip_route;
NMPlatformIPXRoute ipx_route;
NMPlatformIP4Route ip4_route;
NMPlatformIP6Route ip6_route;
NMPObjectIP4Route _ip4_route;
NMPObjectIP6Route _ip6_route;
};
};
static inline gboolean
NMP_CLASS_IS_VALID (const NMPClass *klass)
{
return klass >= &_nmp_classes[0]
&& klass <= &_nmp_classes[G_N_ELEMENTS (_nmp_classes)]
&& ((((char *) klass) - ((char *) NULL)) % (&_nmp_classes[1] - &_nmp_classes[0])) == 0;
}
#define NMP_REF_COUNT_STACKINIT (G_MAXINT)
static inline NMPObject *
NMP_OBJECT_UP_CAST(const NMPlatformObject *plobj)
{
NMPObject *obj;
obj = plobj
? (NMPObject *) ( &(((char *) plobj)[-((int) G_STRUCT_OFFSET (NMPObject, object))]) )
: NULL;
nm_assert (!obj || (obj->_ref_count > 0 && NMP_CLASS_IS_VALID (obj->_class)));
return obj;
}
#define NMP_OBJECT_UP_CAST(plobj) (NMP_OBJECT_UP_CAST ((const NMPlatformObject *) (plobj)))
static inline gboolean
NMP_OBJECT_IS_VALID (const NMPObject *obj)
{
nm_assert (!obj || ( obj
&& obj->_ref_count > 0
&& NMP_CLASS_IS_VALID (obj->_class)));
/* There isn't really much to check. Either @obj is NULL, or we must
* assume that it points to valid memory. */
return obj != NULL;
}
static inline gboolean
NMP_OBJECT_IS_STACKINIT (const NMPObject *obj)
{
nm_assert (!obj || NMP_OBJECT_IS_VALID (obj));
return obj && obj->_ref_count == NMP_REF_COUNT_STACKINIT;
}
static inline const NMPClass *
NMP_OBJECT_GET_CLASS (const NMPObject *obj)
{
nm_assert (NMP_OBJECT_IS_VALID (obj));
return obj->_class;
}
static inline ObjectType
NMP_OBJECT_GET_TYPE (const NMPObject *obj)
{
nm_assert (!obj || NMP_OBJECT_IS_VALID (obj));
return obj ? obj->_class->obj_type : OBJECT_TYPE_UNKNOWN;
}
const NMPClass *nmp_class_from_type (ObjectType obj_type);
NMPObject *nmp_object_ref (NMPObject *object);
void nmp_object_unref (NMPObject *object);
NMPObject *nmp_object_new (ObjectType obj_type, const NMPlatformObject *plob);
NMPObject *nmp_object_new_link (int ifindex);
const NMPObject *nmp_object_stackinit (NMPObject *obj, ObjectType obj_type, const NMPlatformObject *plobj);
const NMPObject *nmp_object_stackinit_id (NMPObject *obj, const NMPObject *src);
const NMPObject *nmp_object_stackinit_id_link (NMPObject *obj, int ifindex);
const NMPObject *nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, int plen);
const NMPObject *nmp_object_stackinit_id_ip6_address (NMPObject *obj, int ifindex, const struct in6_addr *address, int plen);
const NMPObject *nmp_object_stackinit_id_ip4_route (NMPObject *obj, int ifindex, guint32 network, int plen, guint32 metric);
const NMPObject *nmp_object_stackinit_id_ip6_route (NMPObject *obj, int ifindex, const struct in6_addr *network, int plen, guint32 metric);
const char *nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size);
int nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2);
gboolean nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2);
void nmp_object_copy (NMPObject *dst, const NMPObject *src, gboolean id_only);
NMPObject *nmp_object_clone (const NMPObject *obj, gboolean id_only);
gboolean nmp_object_id_equal (const NMPObject *obj1, const NMPObject *obj2);
guint nmp_object_id_hash (const NMPObject *obj);
gboolean nmp_object_is_alive (const NMPObject *obj);
gboolean nmp_object_is_visible (const NMPObject *obj);
void _nmp_object_fixup_link_udev_fields (NMPObject *obj, gboolean use_udev);
#define auto_nmp_obj __attribute__((cleanup(_nmp_auto_obj_cleanup)))
static inline void
_nmp_auto_obj_cleanup (NMPObject **pobj)
{
nmp_object_unref (*pobj);
}
typedef struct _NMPCache NMPCache;
typedef void (*NMPCachePreHook) (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data);
typedef gboolean (*NMPObjectMatchFn) (const NMPObject *obj, gpointer user_data);
gboolean nmp_cache_id_equal (const NMPCacheId *a, const NMPCacheId *b);
guint nmp_cache_id_hash (const NMPCacheId *id);
NMPCacheId *nmp_cache_id_clone (const NMPCacheId *id);
void nmp_cache_id_destroy (NMPCacheId *id);
NMPCacheId *nmp_cache_id_init (NMPCacheId *id, NMPCacheIdType id_type);
NMPCacheId *nmp_cache_id_init_object_type (NMPCacheId *id, ObjectType obj_type);
NMPCacheId *nmp_cache_id_init_links (NMPCacheId *id, gboolean visible_only);
NMPCacheId *nmp_cache_id_init_addrroute_by_ifindex (NMPCacheId *id, ObjectType obj_type, int ifindex);
NMPCacheId *nmp_cache_id_init_routes_visible (NMPCacheId *id, NMPCacheIdType id_type, gboolean is_v4, int ifindex);
const NMPlatformObject *const *nmp_cache_lookup_multi (const NMPCache *cache, const NMPCacheId *cache_id, guint *out_len);
GArray *nmp_cache_lookup_multi_to_array (const NMPCache *cache, ObjectType obj_type, const NMPCacheId *cache_id);
const NMPObject *nmp_cache_lookup_obj (const NMPCache *cache, const NMPObject *obj);
const NMPObject *nmp_cache_lookup_link (const NMPCache *cache, int ifindex);
const NMPObject *nmp_cache_lookup_link_full (const NMPCache *cache,
int ifindex,
const char *ifname,
gboolean visible_only,
NMLinkType link_type,
NMPObjectMatchFn match_fn,
gpointer user_data);
GHashTable *nmp_cache_lookup_all_to_hash (const NMPCache *cache,
NMPCacheId *cache_id,
GHashTable *hash);
gboolean nmp_cache_link_connected_needs_toggle (const NMPCache *cache, const NMPObject *master, const NMPObject *potential_slave, const NMPObject *ignore_slave);
const NMPObject *nmp_cache_link_connected_needs_toggle_by_ifindex (const NMPCache *cache, int master_ifindex, const NMPObject *potential_slave, const NMPObject *ignore_slave);
gboolean nmp_cache_use_udev_detect (void);
gboolean nmp_cache_use_udev_get (const NMPCache *cache);
gboolean nmp_cache_use_udev_set (NMPCache *cache, gboolean use_udev);
void ASSERT_nmp_cache_is_consistent (const NMPCache *cache);
NMPCacheOpsType nmp_cache_remove (NMPCache *cache, const NMPObject *obj, gboolean equals_by_ptr, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
NMPCacheOpsType nmp_cache_remove_netlink (NMPCache *cache, const NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
NMPCacheOpsType nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache, int ifindex, GUdevDevice *udev_device, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache, int ifindex, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
NMPCache *nmp_cache_new (void);
void nmp_cache_free (NMPCache *cache);
NMPObject *nmp_object_from_nl (NMPlatform *platform, const struct nl_object *nlo, gboolean id_only, gboolean complete_from_cache);
struct nl_object *nmp_object_to_nl (NMPlatform *platform, const NMPObject *obj, gboolean id_only);
/* the following functions are currently implemented inside nm-linux-platform, because
* they depend on utility functions there. */
ObjectType _nlo_get_object_type (const struct nl_object *nlo);
gboolean _nmp_vt_cmd_plobj_init_from_nl_link (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
gboolean _nmp_vt_cmd_plobj_init_from_nl_ip4_address (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
gboolean _nmp_vt_cmd_plobj_init_from_nl_ip6_address (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
gboolean _nmp_vt_cmd_plobj_init_from_nl_ip4_route (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
gboolean _nmp_vt_cmd_plobj_init_from_nl_ip6_route (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
struct nl_object *_nmp_vt_cmd_plobj_to_nl_link (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip4_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip6_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip4_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip6_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
#endif /* __NMP_OBJECT_H__ */

View file

@ -8,5 +8,7 @@
/test-general
/test-link-fake
/test-link-linux
/test-nmp-object
/test-route-fake
/test-route-linux

View file

@ -38,6 +38,7 @@ noinst_PROGRAMS = \
test-address-fake \
test-address-linux \
test-general \
test-nmp-object \
test-route-fake \
test-route-linux \
test-cleanup-fake \
@ -110,6 +111,11 @@ test_cleanup_linux_CPPFLAGS = \
-DKERNEL_HACKS=1
test_cleanup_linux_LDADD = $(PLATFORM_LDADD)
test_nmp_object_SOURCES = \
test-nmp-object.c
test_nmp_object_LDADD = \
$(top_builddir)/src/libNetworkManager.la
test_general_SOURCES = \
test-general.c
test_general_LDADD = \
@ -125,6 +131,7 @@ TESTS = \
test-general \
test-link-fake \
test-link-linux \
test-nmp-object \
test-route-fake \
test-route-linux

View file

@ -7,6 +7,7 @@
#include "nm-platform.h"
#include "nm-linux-platform.h"
#include "nm-fake-platform.h"
#include "nm-macros-internal.h"
static void
dump_interface (NMPlatformLink *link)
@ -26,14 +27,14 @@ dump_interface (NMPlatformLink *link)
size_t addrlen;
int i;
g_assert (link->up || !link->connected);
g_assert (NM_FLAGS_HAS (link->flags, IFF_UP) || !link->connected);
printf ("%d: %s: %s", link->ifindex, link->name, nm_link_type_to_string (link->type));
if (link->up)
if (NM_FLAGS_HAS (link->flags, IFF_UP))
printf (" %s", link->connected ? "CONNECTED" : "DISCONNECTED");
else
printf (" DOWN");
if (!link->arp)
if (NM_FLAGS_HAS (link->flags, IFF_NOARP))
printf (" noarp");
if (link->master)
printf (" master %d", link->master);
@ -43,7 +44,7 @@ dump_interface (NMPlatformLink *link)
printf ("\n");
if (link->driver)
printf (" driver: %s\n", link->driver);
printf (" UDI: %s\n", link->udi);
printf (" UDI: %s\n", nm_platform_link_get_udi (NM_PLATFORM_GET, link->ifindex));
if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, link->ifindex, &vlan_parent, &vlan_id))
g_assert_not_reached ();
if (vlan_parent)

View file

@ -93,25 +93,25 @@ do_link_get_all (char **argv)
static gboolean
do_dummy_add (char **argv)
{
return nm_platform_dummy_add (NM_PLATFORM_GET, argv[0], NULL);
return nm_platform_dummy_add (NM_PLATFORM_GET, argv[0], NULL) == NM_PLATFORM_ERROR_SUCCESS;
}
static gboolean
do_bridge_add (char **argv)
{
return nm_platform_bridge_add (NM_PLATFORM_GET, argv[0], NULL, 0, NULL);
return nm_platform_bridge_add (NM_PLATFORM_GET, argv[0], NULL, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS;
}
static gboolean
do_bond_add (char **argv)
{
return nm_platform_bond_add (NM_PLATFORM_GET, argv[0], NULL);
return nm_platform_bond_add (NM_PLATFORM_GET, argv[0], NULL) == NM_PLATFORM_ERROR_SUCCESS;
}
static gboolean
do_team_add (char **argv)
{
return nm_platform_team_add (NM_PLATFORM_GET, argv[0], NULL);
return nm_platform_team_add (NM_PLATFORM_GET, argv[0], NULL) == NM_PLATFORM_ERROR_SUCCESS;
}
static gboolean
@ -122,7 +122,7 @@ do_vlan_add (char **argv)
int vlanid = strtol (*argv++, NULL, 10);
guint32 vlan_flags = strtol (*argv++, NULL, 10);
return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent, vlanid, vlan_flags, NULL);
return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent, vlanid, vlan_flags, NULL) == NM_PLATFORM_ERROR_SUCCESS;
}
static gboolean
@ -182,7 +182,14 @@ LINK_CMD_GET_FULL (get_type, decimal, value > 0)
LINK_CMD_GET (is_software, boolean)
LINK_CMD_GET (supports_slaves, boolean)
LINK_CMD (set_up)
static gboolean
do_link_set_up (char **argv)
{
int ifindex = parse_ifindex (argv[0]);
return ifindex ? nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL) : FALSE;
}
LINK_CMD (set_down)
LINK_CMD (set_arp)
LINK_CMD (set_noarp)
@ -858,7 +865,6 @@ main (int argc, char **argv)
const char *arg0 = *argv++;
const command_t *command = NULL;
gboolean status = TRUE;
int error;
#if !GLIB_CHECK_VERSION (2, 35, 0)
g_type_init ();
@ -892,12 +898,5 @@ main (int argc, char **argv)
error ("\n");
}
error = nm_platform_get_error (NM_PLATFORM_GET);
if (error) {
const char *msg = nm_platform_get_error_msg (NM_PLATFORM_GET);
error ("nm-platform: %s\n", msg);
}
return !!error;
return EXIT_SUCCESS;
}

View file

@ -65,22 +65,17 @@ test_ip4_address (void)
/* Add address */
g_assert (!nm_platform_ip4_address_exists (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN));
no_error ();
g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL));
no_error ();
g_assert (nm_platform_ip4_address_exists (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN));
no_error ();
accept_signal (address_added);
/* Add address again (aka update) */
g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL));
no_error ();
accept_signal (address_changed);
accept_signals (address_changed, 0, 1);
/* Test address listing */
addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
g_assert (addresses);
no_error ();
g_assert_cmpint (addresses->len, ==, 1);
address = &g_array_index (addresses, NMPlatformIP4Address, 0);
g_assert_cmpint (address->ifindex, ==, ifindex);
@ -90,13 +85,11 @@ test_ip4_address (void)
/* Remove address */
g_assert (nm_platform_ip4_address_delete (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0));
no_error ();
g_assert (!nm_platform_ip4_address_exists (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN));
accept_signal (address_removed);
/* Remove address again */
g_assert (nm_platform_ip4_address_delete (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0));
no_error ();
free_signal (address_added);
free_signal (address_changed);
@ -121,22 +114,17 @@ test_ip6_address (void)
/* Add address */
g_assert (!nm_platform_ip6_address_exists (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
no_error ();
g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags));
no_error ();
g_assert (nm_platform_ip6_address_exists (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
no_error ();
accept_signal (address_added);
/* Add address again (aka update) */
g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags));
no_error ();
accept_signal (address_changed);
accept_signals (address_changed, 0, 1);
/* Test address listing */
addresses = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex);
g_assert (addresses);
no_error ();
g_assert_cmpint (addresses->len, ==, 1);
address = &g_array_index (addresses, NMPlatformIP6Address, 0);
g_assert_cmpint (address->ifindex, ==, ifindex);
@ -146,13 +134,11 @@ test_ip6_address (void)
/* Remove address */
g_assert (nm_platform_ip6_address_delete (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
no_error ();
g_assert (!nm_platform_ip6_address_exists (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
accept_signal (address_removed);
/* Remove address again */
g_assert (nm_platform_ip6_address_delete (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
no_error ();
free_signal (address_added);
free_signal (address_changed);
@ -175,7 +161,7 @@ test_ip4_address_external (void)
/* Looks like addresses are not announced by kerenl when the interface
* is down. Link-local IPv6 address is automatically added.
*/
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)));
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME), NULL));
/* Add/delete notification */
run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d",
@ -190,12 +176,10 @@ test_ip4_address_external (void)
run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d",
IP4_ADDRESS, IP4_PLEN, DEVICE_NAME, lifetime, preferred);
g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL));
no_error ();
g_assert (nm_platform_ip4_address_exists (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN));
accept_signal (address_added);
/*run_command ("ip address delete %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME);
g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN, 0));
no_error ();
g_assert (!nm_platform_ip4_address_exists (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN));
accept_signal (address_removed);*/
@ -229,12 +213,10 @@ test_ip6_address_external (void)
run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d",
IP6_ADDRESS, IP6_PLEN, DEVICE_NAME, lifetime, preferred);
g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags));
no_error ();
g_assert (nm_platform_ip6_address_exists (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
accept_signal (address_added);
/*run_command ("ip address delete %s/%d dev %s", IP6_ADDRESS, IP6_PLEN, DEVICE_NAME);
g_assert (nm_platform_ip6_address_delete (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
no_error ();
g_assert (!nm_platform_ip6_address_exists (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
wait_signal (address_removed);*/
@ -255,7 +237,7 @@ setup_tests (void)
nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME));
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME));
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL));
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS);
accept_signal (link_added);
free_signal (link_added);

View file

@ -35,10 +35,10 @@ test_cleanup_internal (void)
inet_pton (AF_INET6, "2001:db8:e:f:1:2:3:4", &gateway6);
/* Create and set up device */
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL));
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS);
accept_signal (link_added);
free_signal (link_added);
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)));
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME), NULL));
ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
g_assert (ifindex > 0);
@ -58,7 +58,7 @@ test_cleanup_internal (void)
routes6 = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
g_assert_cmpint (addresses4->len, ==, 1);
g_assert_cmpint (addresses6->len, ==, 1);
g_assert_cmpint (addresses6->len, ==, 2); /* also has a IPv6 LL address. */
g_assert_cmpint (routes4->len, ==, 3);
g_assert_cmpint (routes6->len, ==, 3);

View file

@ -15,9 +15,6 @@
#define debug(...) nm_log_dbg (LOGD_PLATFORM, __VA_ARGS__)
#define error(err) g_assert (nm_platform_get_error (NM_PLATFORM_GET) == err)
#define no_error() error (NM_PLATFORM_ERROR_NONE)
typedef struct {
int handler_id;
const char *name;

View file

@ -20,11 +20,24 @@
#include "nm-platform-utils.h"
#include <linux/rtnetlink.h>
#include "nm-linux-platform.h"
#include "nm-logging.h"
#include "nm-test-utils.h"
/******************************************************************/
static void
test_init_linux_platform ()
{
gs_unref_object NMPlatform *platform = NULL;
platform = g_object_new (NM_TYPE_LINUX_PLATFORM, NULL);
}
/******************************************************************/
NMTST_DEFINE ();
@ -34,5 +47,7 @@ main (int argc, char **argv)
{
nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
g_test_add_func ("/general/init_linux_platform", test_init_linux_platform);
return g_test_run ();
}

View file

@ -22,54 +22,32 @@ test_bogus(void)
size_t addrlen;
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, BOGUS_NAME));
no_error ();
g_assert (!nm_platform_link_delete (NM_PLATFORM_GET, BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_get_ifindex (NM_PLATFORM_GET, BOGUS_NAME));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_get_name (NM_PLATFORM_GET, BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_get_type (NM_PLATFORM_GET, BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_get_type_name (NM_PLATFORM_GET, BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_set_up (NM_PLATFORM_GET, BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_set_up (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL));
g_assert (!nm_platform_link_set_down (NM_PLATFORM_GET, BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_set_arp (NM_PLATFORM_GET, BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_set_noarp (NM_PLATFORM_GET, BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_get_address (NM_PLATFORM_GET, BOGUS_IFINDEX, &addrlen));
g_assert (!addrlen);
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_get_address (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_set_mtu (NM_PLATFORM_GET, BOGUS_IFINDEX, MTU));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_get_mtu (NM_PLATFORM_GET, BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_supports_vlans (NM_PLATFORM_GET, BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_vlan_get_info (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL, NULL));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, BOGUS_IFINDEX, 0, 0));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, BOGUS_IFINDEX, 0, 0));
error (NM_PLATFORM_ERROR_NOT_FOUND);
}
static void
@ -85,48 +63,52 @@ test_loopback (void)
g_assert (!nm_platform_link_supports_vlans (NM_PLATFORM_GET, LO_INDEX));
}
static int
static gboolean
software_add (NMLinkType link_type, const char *name)
{
switch (link_type) {
case NM_LINK_TYPE_DUMMY:
return nm_platform_dummy_add (NM_PLATFORM_GET, name, NULL);
return nm_platform_dummy_add (NM_PLATFORM_GET, name, NULL) == NM_PLATFORM_ERROR_SUCCESS;
case NM_LINK_TYPE_BRIDGE:
return nm_platform_bridge_add (NM_PLATFORM_GET, name, NULL, 0, NULL);
return nm_platform_bridge_add (NM_PLATFORM_GET, name, NULL, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS;
case NM_LINK_TYPE_BOND:
{
gboolean bond0_exists = nm_platform_link_exists (NM_PLATFORM_GET, "bond0");
gboolean result = nm_platform_bond_add (NM_PLATFORM_GET, name, NULL);
NMPlatformError error = nm_platform_get_error (NM_PLATFORM_GET);
NMPlatformError plerr;
plerr = nm_platform_bond_add (NM_PLATFORM_GET, name, NULL);
/* Check that bond0 is *not* automatically created. */
if (!bond0_exists)
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, "bond0"));
nm_platform_set_error (NM_PLATFORM_GET, error);
return result;
return plerr == NM_PLATFORM_ERROR_SUCCESS;
}
case NM_LINK_TYPE_TEAM:
return nm_platform_team_add (NM_PLATFORM_GET, name, NULL);
return nm_platform_team_add (NM_PLATFORM_GET, name, NULL) == NM_PLATFORM_ERROR_SUCCESS;
case NM_LINK_TYPE_VLAN: {
SignalData *parent_added;
SignalData *parent_changed;
/* Don't call link_callback for the bridge interface */
parent_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, PARENT_NAME);
if (nm_platform_bridge_add (NM_PLATFORM_GET, PARENT_NAME, NULL, 0, NULL))
if (nm_platform_bridge_add (NM_PLATFORM_GET, PARENT_NAME, NULL, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS)
accept_signal (parent_added);
free_signal (parent_added);
{
int parent_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, PARENT_NAME);
gboolean was_up = nm_platform_link_is_up (NM_PLATFORM_GET, parent_ifindex);
parent_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, parent_ifindex);
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, parent_ifindex));
accept_signal (parent_changed);
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, parent_ifindex, NULL));
if (was_up) {
/* when NM is running in the background, it will mess with addrgenmode which might cause additional signals. */
accept_signals (parent_changed, 0, 1);
} else
accept_signal (parent_changed);
free_signal (parent_changed);
return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0, NULL);
return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS;
}
}
default:
@ -142,6 +124,9 @@ test_slave (int master, int type, SignalData *master_changed)
SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, SLAVE_NAME);
SignalData *link_changed, *link_removed;
char *value;
NMLinkType link_type = nm_platform_link_get_type (NM_PLATFORM_GET, master);
g_assert (NM_IN_SET (link_type, NM_LINK_TYPE_TEAM, NM_LINK_TYPE_BOND, NM_LINK_TYPE_BRIDGE));
g_assert (software_add (type, SLAVE_NAME));
ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, SLAVE_NAME);
@ -154,20 +139,29 @@ test_slave (int master, int type, SignalData *master_changed)
*
* See https://bugzilla.redhat.com/show_bug.cgi?id=910348
*/
g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex));
g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
accept_signal (link_changed);
ensure_no_signal (link_changed);
/* Enslave */
link_changed->ifindex = ifindex;
g_assert (nm_platform_link_enslave (NM_PLATFORM_GET, master, ifindex)); no_error ();
g_assert_cmpint (nm_platform_link_get_master (NM_PLATFORM_GET, ifindex), ==, master); no_error ();
accept_signal (link_changed);
accept_signal (master_changed);
g_assert (nm_platform_link_enslave (NM_PLATFORM_GET, master, ifindex));
g_assert_cmpint (nm_platform_link_get_master (NM_PLATFORM_GET, ifindex), ==, master);
accept_signals (link_changed, 1, 3);
accept_signals (master_changed, 0, 1);
/* enslaveing brings put the slave */
if (NM_IN_SET (link_type, NM_LINK_TYPE_BOND, NM_LINK_TYPE_TEAM))
g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
else
g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
/* Set master up */
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, master));
accept_signal (master_changed);
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, master, NULL));
g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, master));
accept_signals (master_changed, 1, 2);
/* Master with a disconnected slave is disconnected
*
@ -179,7 +173,7 @@ test_slave (int master, int type, SignalData *master_changed)
case NM_LINK_TYPE_TEAM:
g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex));
accept_signal (link_changed);
accept_signal (master_changed);
accept_signals (master_changed, 0, 2);
break;
default:
break;
@ -202,28 +196,28 @@ test_slave (int master, int type, SignalData *master_changed)
}
/* Set slave up and see if master gets up too */
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex)); no_error ();
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL));
g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, master));
accept_signal (link_changed);
accept_signal (master_changed);
accept_signals (link_changed, 1, 3);
/* NM running, can cause additional change of addrgenmode */
accept_signals (master_changed, 1, 2);
/* Enslave again
*
* Gracefully succeed if already enslaved.
*/
g_assert (nm_platform_link_enslave (NM_PLATFORM_GET, master, ifindex)); no_error ();
accept_signal (link_changed);
accept_signal (master_changed);
ensure_no_signal (link_changed);
g_assert (nm_platform_link_enslave (NM_PLATFORM_GET, master, ifindex));
accept_signals (link_changed, 0, 2);
ensure_no_signal (master_changed);
/* Set slave option */
switch (type) {
case NM_LINK_TYPE_BRIDGE:
if (nmtst_platform_is_sysfs_writable ()) {
g_assert (nm_platform_slave_set_option (NM_PLATFORM_GET, ifindex, "priority", "789"));
no_error ();
value = nm_platform_slave_get_option (NM_PLATFORM_GET, ifindex, "priority");
no_error ();
g_assert_cmpstr (value, ==, "789");
g_free (value);
}
@ -233,18 +227,28 @@ test_slave (int master, int type, SignalData *master_changed)
}
/* Release */
ensure_no_signal (link_changed);
g_assert (nm_platform_link_release (NM_PLATFORM_GET, master, ifindex));
g_assert_cmpint (nm_platform_link_get_master (NM_PLATFORM_GET, ifindex), ==, 0); no_error ();
accept_signal (link_changed);
accept_signal (master_changed);
g_assert_cmpint (nm_platform_link_get_master (NM_PLATFORM_GET, ifindex), ==, 0);
accept_signals (link_changed, 1, 3);
if (link_type != NM_LINK_TYPE_TEAM)
accept_signals (master_changed, 1, 2);
else
accept_signals (master_changed, 1, 1);
ensure_no_signal (master_changed);
/* Release again */
ensure_no_signal (link_changed);
g_assert (!nm_platform_link_release (NM_PLATFORM_GET, master, ifindex));
error (NM_PLATFORM_ERROR_NOT_SLAVE);
ensure_no_signal (master_changed);
/* Remove */
ensure_no_signal (link_changed);
g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
no_error ();
accept_signals (master_changed, 0, 1);
accept_signals (link_changed, 0, 1);
accept_signal (link_removed);
free_signal (link_added);
@ -264,7 +268,6 @@ test_software (NMLinkType link_type, const char *link_typename)
/* Add */
link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
g_assert (software_add (link_type, DEVICE_NAME));
no_error ();
accept_signal (link_added);
g_assert (nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME));
ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
@ -277,18 +280,16 @@ test_software (NMLinkType link_type, const char *link_typename)
g_assert (nm_platform_vlan_get_info (NM_PLATFORM_GET, ifindex, &vlan_parent, &vlan_id));
g_assert_cmpint (vlan_parent, ==, nm_platform_link_get_ifindex (NM_PLATFORM_GET, PARENT_NAME));
g_assert_cmpint (vlan_id, ==, VLAN_ID);
no_error ();
}
/* Add again */
g_assert (!software_add (link_type, DEVICE_NAME));
error (NM_PLATFORM_ERROR_EXISTS);
/* Set ARP/NOARP */
g_assert (nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
g_assert (nm_platform_link_set_noarp (NM_PLATFORM_GET, ifindex));
g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
accept_signal (link_changed);
accept_signals (link_changed, 1, 2);
g_assert (nm_platform_link_set_arp (NM_PLATFORM_GET, ifindex));
g_assert (nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
accept_signal (link_changed);
@ -298,9 +299,7 @@ test_software (NMLinkType link_type, const char *link_typename)
case NM_LINK_TYPE_BRIDGE:
if (nmtst_platform_is_sysfs_writable ()) {
g_assert (nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, "forward_delay", "789"));
no_error ();
value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, "forward_delay");
no_error ();
g_assert_cmpstr (value, ==, "789");
g_free (value);
}
@ -308,9 +307,7 @@ test_software (NMLinkType link_type, const char *link_typename)
case NM_LINK_TYPE_BOND:
if (nmtst_platform_is_sysfs_writable ()) {
g_assert (nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, "mode", "active-backup"));
no_error ();
value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, "mode");
no_error ();
/* When reading back, the output looks slightly different. */
g_assert (g_str_has_prefix (value, "active-backup"));
g_free (value);
@ -332,20 +329,17 @@ test_software (NMLinkType link_type, const char *link_typename)
default:
break;
}
free_signal (link_changed);
/* Delete */
g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
no_error ();
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME)); no_error ();
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME));
g_assert_cmpint (nm_platform_link_get_type (NM_PLATFORM_GET, ifindex), ==, NM_LINK_TYPE_NONE);
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_get_type (NM_PLATFORM_GET, ifindex));
error (NM_PLATFORM_ERROR_NOT_FOUND);
accept_signal (link_removed);
/* Delete again */
g_assert (!nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)));
error (NM_PLATFORM_ERROR_NOT_FOUND);
/* VLAN: Delete parent */
if (link_type == NM_LINK_TYPE_VLAN) {
@ -358,7 +352,6 @@ test_software (NMLinkType link_type, const char *link_typename)
/* No pending signal */
free_signal (link_added);
free_signal (link_changed);
free_signal (link_removed);
}
@ -404,18 +397,15 @@ test_internal (void)
int ifindex;
/* Check the functions for non-existent devices */
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME)); no_error ();
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME));
g_assert (!nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME));
error (NM_PLATFORM_ERROR_NOT_FOUND);
/* Add device */
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL));
no_error ();
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS);
accept_signal (link_added);
/* Try to add again */
g_assert (!nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL));
error (NM_PLATFORM_ERROR_EXISTS);
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_EXISTS);
/* Check device index, name and type */
ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
@ -427,15 +417,15 @@ test_internal (void)
link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex);
/* Up/connected */
g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex)); no_error ();
g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex)); no_error ();
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex)); no_error ();
g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, ifindex)); no_error ();
g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex)); no_error ();
g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL));
g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
accept_signal (link_changed);
g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex)); no_error ();
g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex)); no_error ();
g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex)); no_error ();
g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex));
g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
accept_signal (link_changed);
/* arp/noarp */
@ -462,18 +452,15 @@ test_internal (void)
/* Set MTU */
g_assert (nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, MTU));
no_error ();
g_assert_cmpint (nm_platform_link_get_mtu (NM_PLATFORM_GET, ifindex), ==, MTU);
accept_signal (link_changed);
/* Delete device */
g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
no_error ();
accept_signal (link_removed);
/* Try to delete again */
g_assert (!nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
error (NM_PLATFORM_ERROR_NOT_FOUND);
free_signal (link_added);
free_signal (link_changed);
@ -522,23 +509,17 @@ test_external (void)
wait_signal (link_changed);
g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
/* This test doesn't trigger a netlink event at least on
* 3.8.2-206.fc18.x86_64. Disabling the waiting and checking code
* because of that.
*/
run_command ("ip link set %s arp on", DEVICE_NAME);
#if 0
wait_signal (link_changed);
g_assert (nm_platform_link_uses_arp (ifindex));
#endif
g_assert (nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
run_command ("ip link set %s arp off", DEVICE_NAME);
#if 0
wait_signal (link_changed);
g_assert (!nm_platform_link_uses_arp (ifindex));
#endif
g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
run_command ("ip link del %s", DEVICE_NAME);
wait_signal (link_removed);
accept_signals (link_changed, 0, 1);
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME));
free_signal (link_added);

View file

@ -0,0 +1,426 @@
/* -*- 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 "nmp-object.h"
#include "nm-logging.h"
#include "nm-test-utils.h"
struct {
GList *udev_devices;
} global;
/******************************************************************/
static gboolean
_nmp_object_id_equal (const NMPObject *a, const NMPObject *b)
{
gboolean a_b = nmp_object_id_equal (a, b);
g_assert (NM_IN_SET (a_b, FALSE, TRUE) && a_b == nmp_object_id_equal (b, a));
return a_b;
}
#define nmp_object_id_equal _nmp_object_id_equal
static gboolean
_nmp_object_equal (const NMPObject *a, const NMPObject *b)
{
gboolean a_b = nmp_object_equal (a, b);
g_assert (NM_IN_SET (a_b, FALSE, TRUE) && a_b == nmp_object_equal (b, a));
return a_b;
}
#define nmp_object_equal _nmp_object_equal
/******************************************************************/
static void
_assert_cache_multi_lookup_contains (const NMPCache *cache, const NMPCacheId *cache_id, const NMPObject *obj, gboolean contains)
{
const NMPlatformObject *const *objects;
guint i, len;
gboolean found;
g_assert (cache_id);
g_assert (NMP_OBJECT_IS_VALID (obj));
g_assert (nmp_cache_lookup_obj (cache, obj) == obj);
objects = nmp_cache_lookup_multi (cache, cache_id, &len);
g_assert ((len == 0 && !objects) || (len > 0 && objects && !objects[len]));
found = FALSE;
for (i = 0; i < len; i++) {
NMPObject *o;
g_assert (objects[i]);
o = NMP_OBJECT_UP_CAST (objects[i]);
g_assert (NMP_OBJECT_IS_VALID (o));
if (obj == o) {
g_assert (!found);
found = TRUE;
}
}
g_assert (!!contains == found);
}
/******************************************************************/
typedef struct {
NMPCache *cache;
NMPCacheOpsType expected_ops_type;
const NMPObject *obj_clone;
NMPObject *new_clone;
gboolean was_visible;
gboolean called;
} _NMPCacheUpdateData;
static void
_nmp_cache_update_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data)
{
_NMPCacheUpdateData *data = user_data;
g_assert (data);
g_assert (!data->called);
g_assert (data->cache == cache);
g_assert_cmpint (data->expected_ops_type, ==, ops_type);
switch (ops_type) {
case NMP_CACHE_OPS_ADDED:
g_assert (!old);
g_assert (NMP_OBJECT_IS_VALID (new));
g_assert (nmp_object_is_alive (new));
g_assert (nmp_object_id_equal (data->obj_clone, new));
g_assert (nmp_object_equal (data->obj_clone, new));
break;
case NMP_CACHE_OPS_UPDATED:
g_assert (NMP_OBJECT_IS_VALID (old));
g_assert (NMP_OBJECT_IS_VALID (new));
g_assert (nmp_object_is_alive (old));
g_assert (nmp_object_is_alive (new));
g_assert (nmp_object_id_equal (data->obj_clone, new));
g_assert (nmp_object_id_equal (data->obj_clone, old));
g_assert (nmp_object_id_equal (old, new));
g_assert (nmp_object_equal (data->obj_clone, new));
g_assert (!nmp_object_equal (data->obj_clone, old));
g_assert (!nmp_object_equal (old, new));
break;
case NMP_CACHE_OPS_REMOVED:
g_assert (!new);
g_assert (NMP_OBJECT_IS_VALID (old));
g_assert (nmp_object_is_alive (old));
g_assert (nmp_object_id_equal (data->obj_clone, old));
break;
default:
g_assert_not_reached ();
}
data->was_visible = old ? nmp_object_is_visible (old) : FALSE;
data->new_clone = new ? nmp_object_clone (new, FALSE) : NULL;
data->called = TRUE;
}
static void
_nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCacheOpsType expected_ops_type)
{
NMPCacheOpsType ops_type;
NMPObject *obj2;
gboolean was_visible;
auto_nmp_obj NMPObject *obj_clone = nmp_object_clone (obj, FALSE);
auto_nmp_obj NMPObject *new_clone = NULL;
const NMPObject *obj_old;
_NMPCacheUpdateData data = {
.cache = cache,
.expected_ops_type = expected_ops_type,
.obj_clone = obj_clone,
};
obj_old = nmp_cache_lookup_link (cache, obj->object.ifindex);
if (obj_old && obj_old->_link.udev.device)
obj_clone->_link.udev.device = g_object_ref (obj_old->_link.udev.device);
_nmp_object_fixup_link_udev_fields (obj_clone, nmp_cache_use_udev_get (cache));
g_assert (cache);
g_assert (NMP_OBJECT_IS_VALID (obj));
ops_type = nmp_cache_update_netlink (cache, obj, &obj2, &was_visible, _nmp_cache_update_hook, &data);
new_clone = data.new_clone;
g_assert_cmpint (ops_type, ==, expected_ops_type);
if (ops_type != NMP_CACHE_OPS_UNCHANGED) {
g_assert (NMP_OBJECT_IS_VALID (obj2));
g_assert (data.called);
g_assert_cmpint (data.was_visible, ==, was_visible);
if (ops_type == NMP_CACHE_OPS_REMOVED)
g_assert (!data.new_clone);
else {
g_assert (data.new_clone);
g_assert (nmp_object_equal (obj2, data.new_clone));
}
} else {
g_assert (!data.called);
g_assert (!obj2 || was_visible == nmp_object_is_visible (obj2));
}
g_assert (!obj2 || nmp_object_id_equal (obj, obj2));
if (ops_type != NMP_CACHE_OPS_REMOVED && obj2)
g_assert (nmp_object_equal (obj, obj2));
if (out_obj)
*out_obj = obj2;
else
nmp_object_unref (obj2);
if (out_was_visible)
*out_was_visible = was_visible;
}
static const NMPlatformLink pl_link_2 = {
.ifindex = 2,
.name = "eth0",
.type = NM_LINK_TYPE_ETHERNET,
};
static const NMPlatformLink pl_link_3 = {
.ifindex = 3,
.name = "wlan0",
.type = NM_LINK_TYPE_WIFI,
};
static void
test_cache_link ()
{
NMPCache *cache;
NMPObject *obj1, *obj2;
NMPObject objs1;
gboolean was_visible;
NMPCacheId cache_id_storage;
GUdevDevice *udev_device_2 = g_list_nth_data (global.udev_devices, 0);
GUdevDevice *udev_device_3 = g_list_nth_data (global.udev_devices, 0);
NMPCacheOpsType ops_type;
cache = nmp_cache_new ();
nmp_cache_use_udev_set (cache, g_rand_int_range (nmtst_get_rand (), 0, 2));
/* if we have a link, and don't set is_in_netlink, adding it has no effect. */
obj1 = nmp_object_new (OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
g_assert (NMP_OBJECT_UP_CAST (&obj1->object) == obj1);
g_assert (!nmp_object_is_alive (obj1));
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UNCHANGED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (!obj2);
g_assert (!was_visible);
g_assert (!nmp_cache_lookup_obj (cache, obj1));
g_assert (!nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)));
nmp_object_unref (obj1);
/* Only when setting @is_in_netlink the link is added. */
obj1 = nmp_object_new (OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
obj1->_link.netlink.is_in_netlink = TRUE;
g_assert (nmp_object_is_alive (obj1));
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_ADDED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (nmp_object_equal (obj1, obj2));
g_assert (!was_visible);
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
g_assert (nmp_object_is_visible (obj2));
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, TRUE), obj2, TRUE);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, FALSE), obj2, TRUE);
nmp_object_unref (obj1);
nmp_object_unref (obj2);
/* updating the same link with identical value, has no effect. */
obj1 = nmp_object_new (OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
obj1->_link.netlink.is_in_netlink = TRUE;
g_assert (nmp_object_is_alive (obj1));
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UNCHANGED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (obj2 != obj1);
g_assert (nmp_object_equal (obj1, obj2));
g_assert (was_visible);
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
nmp_object_unref (obj1);
nmp_object_unref (obj2);
/* remove the link from netlink */
obj1 = nmp_object_new (OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
g_assert (!nmp_object_is_alive (obj1));
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_REMOVED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (obj2 != obj1);
g_assert (was_visible);
g_assert (!nmp_cache_lookup_obj (cache, obj1));
g_assert (!nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)));
nmp_object_unref (obj1);
nmp_object_unref (obj2);
udev_device_2 = NULL;
if (udev_device_2) {
/* now add the link only with aspect UDEV. */
ops_type = nmp_cache_update_link_udev (cache, pl_link_2.ifindex, udev_device_2, &obj2, &was_visible, NULL, NULL);
ASSERT_nmp_cache_is_consistent (cache);
g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_ADDED);
g_assert (!was_visible);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
g_assert (!nmp_object_is_visible (obj2));
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, TRUE), obj2, FALSE);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, FALSE), obj2, TRUE);
nmp_object_unref (obj2);
}
/* add it in netlink too. */
obj1 = nmp_object_new (OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
obj1->_link.netlink.is_in_netlink = TRUE;
g_assert (nmp_object_is_alive (obj1));
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, udev_device_2 ? NMP_CACHE_OPS_UPDATED : NMP_CACHE_OPS_ADDED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (nmp_object_equal (obj1, obj2));
g_assert (!was_visible);
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
g_assert (nmp_object_is_visible (obj2));
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, TRUE), obj2, TRUE);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, FALSE), obj2, TRUE);
nmp_object_unref (obj1);
nmp_object_unref (obj2);
/* remove again from netlink. */
obj1 = nmp_object_new (OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
obj1->_link.netlink.is_in_netlink = FALSE;
g_assert (!nmp_object_is_alive (obj1));
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, udev_device_2 ? NMP_CACHE_OPS_UPDATED : NMP_CACHE_OPS_REMOVED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (obj2 != obj1);
g_assert (was_visible);
if (udev_device_2) {
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
g_assert (!nmp_object_is_visible (obj2));
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, TRUE), obj2, FALSE);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, FALSE), obj2, TRUE);
} else {
g_assert (nmp_cache_lookup_obj (cache, obj1) == NULL);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == NULL);
g_assert (nmp_object_is_visible (obj2));
}
nmp_object_unref (obj1);
nmp_object_unref (obj2);
/* now another link only with aspect UDEV. */
if (udev_device_3) {
/* now add the link only with aspect UDEV. */
ops_type = nmp_cache_update_link_udev (cache, pl_link_3.ifindex, udev_device_3, &obj2, &was_visible, NULL, NULL);
g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_ADDED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (NMP_OBJECT_IS_VALID (obj2));
g_assert (!was_visible);
g_assert (!nmp_object_is_visible (obj2));
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, TRUE), obj2, FALSE);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, FALSE), obj2, TRUE);
g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, FALSE);
g_assert_cmpint (obj2->link.initialized, ==, FALSE);
nmp_object_unref (obj2);
/* add it in netlink too. */
obj1 = nmp_object_new (OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_3);
obj1->_link.netlink.is_in_netlink = TRUE;
g_assert (nmp_object_is_alive (obj1));
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UPDATED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (obj2 != obj1);
g_assert (nmp_object_equal (obj1, obj2));
g_assert (!was_visible);
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2);
g_assert (nmp_object_is_visible (obj2));
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, TRUE), obj2, TRUE);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, FALSE), obj2, TRUE);
g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, TRUE);
g_assert_cmpint (obj2->link.initialized, ==, TRUE);
nmp_object_unref (obj1);
nmp_object_unref (obj2);
/* remove UDEV. */
ops_type = nmp_cache_update_link_udev (cache, pl_link_3.ifindex, NULL, &obj2, &was_visible, NULL, NULL);
g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_UPDATED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (was_visible);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2);
g_assert (nmp_object_is_visible (obj2));
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, TRUE), obj2, TRUE);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_links (&cache_id_storage, FALSE), obj2, TRUE);
g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, TRUE);
g_assert_cmpint (obj2->link.initialized, ==, !nmp_cache_use_udev_get (cache));
nmp_object_unref (obj2);
}
nmp_cache_free (cache);
}
/******************************************************************/
NMTST_DEFINE ();
int
main (int argc, char **argv)
{
int result;
gs_unref_object GUdevClient *udev_client = NULL;
nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
udev_client = g_udev_client_new ((const char *[]) { "net", NULL });
{
gs_unref_object GUdevEnumerator *udev_enumerator = g_udev_enumerator_new (udev_client);
g_udev_enumerator_add_match_subsystem (udev_enumerator, "net");
/* Demand that the device is initialized (udev rules ran,
* device has a stable name now) in case udev is running
* (not in a container). */
if (access ("/sys", W_OK) == 0)
g_udev_enumerator_add_match_is_initialized (udev_enumerator);
global.udev_devices = g_udev_enumerator_execute (udev_enumerator);
}
g_test_add_func ("/nmp-object/cache_link", test_cache_link);
result = g_test_run ();
while (global.udev_devices) {
g_object_unref (global.udev_devices->data);
global.udev_devices = g_list_remove (global.udev_devices, global.udev_devices->data);
}
return result;
}

View file

@ -1,5 +1,7 @@
#include "config.h"
#include <linux/rtnetlink.h>
#include "test-common.h"
#include "nm-test-utils.h"
#include "NetworkManagerUtils.h"
@ -64,7 +66,6 @@ test_ip4_route_metric0 (void)
/* add the first route */
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, metric, mss));
no_error ();
accept_signal (route_added);
assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
@ -72,7 +73,6 @@ test_ip4_route_metric0 (void)
/* Deleting route with metric 0 does nothing */
g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0));
no_error ();
ensure_no_signal (route_removed);
assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
@ -80,7 +80,6 @@ test_ip4_route_metric0 (void)
/* add the second route */
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, 0, mss));
no_error ();
accept_signal (route_added);
assert_ip4_route_exists (TRUE, DEVICE_NAME, network, plen, 0);
@ -88,7 +87,6 @@ test_ip4_route_metric0 (void)
/* Delete route with metric 0 */
g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0));
no_error ();
accept_signal (route_removed);
assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
@ -96,7 +94,6 @@ test_ip4_route_metric0 (void)
/* Delete route with metric 0 again (we expect nothing to happen) */
g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0));
no_error ();
ensure_no_signal (route_removed);
assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
@ -104,7 +101,6 @@ test_ip4_route_metric0 (void)
/* Delete the other route */
g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
no_error ();
accept_signal (route_removed);
assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
@ -136,36 +132,27 @@ test_ip4_route (void)
/* Add route to gateway */
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 32, INADDR_ANY, 0, metric, mss));
no_error ();
accept_signal (route_added);
/* Add route */
assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, metric);
no_error ();
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss));
no_error ();
assert_ip4_route_exists (TRUE, DEVICE_NAME, network, plen, metric);
no_error ();
accept_signal (route_added);
/* Add route again */
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss));
no_error ();
accept_signal (route_changed);
accept_signals (route_changed, 0, 1);
/* Add default route */
assert_ip4_route_exists (FALSE, DEVICE_NAME, 0, 0, metric);
no_error ();
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss));
no_error ();
assert_ip4_route_exists (TRUE, DEVICE_NAME, 0, 0, metric);
no_error ();
accept_signal (route_added);
/* Add default route again */
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss));
no_error ();
accept_signal (route_changed);
accept_signals (route_changed, 0, 1);
/* Test route listing */
routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
@ -177,6 +164,7 @@ test_ip4_route (void)
rts[0].gateway = INADDR_ANY;
rts[0].metric = metric;
rts[0].mss = mss;
rts[0].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK);
rts[1].source = NM_IP_CONFIG_SOURCE_USER;
rts[1].network = network;
rts[1].plen = plen;
@ -184,6 +172,7 @@ test_ip4_route (void)
rts[1].gateway = gateway;
rts[1].metric = metric;
rts[1].mss = mss;
rts[1].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE);
rts[2].source = NM_IP_CONFIG_SOURCE_USER;
rts[2].network = 0;
rts[2].plen = 0;
@ -191,20 +180,18 @@ test_ip4_route (void)
rts[2].gateway = gateway;
rts[2].metric = metric;
rts[2].mss = mss;
rts[2].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE);
g_assert_cmpint (routes->len, ==, 3);
g_assert (!memcmp (routes->data, rts, sizeof (rts)));
nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, rts, routes->len, TRUE);
g_array_unref (routes);
/* Remove route */
g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
no_error ();
assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, metric);
accept_signal (route_removed);
/* Remove route again */
g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
no_error ();
free_signal (route_added);
free_signal (route_changed);
@ -232,36 +219,27 @@ test_ip6_route (void)
/* Add route to gateway */
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, metric, mss));
no_error ();
accept_signal (route_added);
/* Add route */
g_assert (!nm_platform_ip6_route_exists (NM_PLATFORM_GET, ifindex, network, plen, metric));
no_error ();
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss));
no_error ();
g_assert (nm_platform_ip6_route_exists (NM_PLATFORM_GET, ifindex, network, plen, metric));
no_error ();
accept_signal (route_added);
/* Add route again */
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss));
no_error ();
accept_signal (route_changed);
accept_signals (route_changed, 0, 1);
/* Add default route */
g_assert (!nm_platform_ip6_route_exists (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric));
no_error ();
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss));
no_error ();
g_assert (nm_platform_ip6_route_exists (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric));
no_error ();
accept_signal (route_added);
/* Add default route again */
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss));
no_error ();
accept_signal (route_changed);
accept_signals (route_changed, 0, 1);
/* Test route listing */
routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
@ -288,19 +266,16 @@ test_ip6_route (void)
rts[2].metric = nm_utils_ip6_route_metric_normalize (metric);
rts[2].mss = mss;
g_assert_cmpint (routes->len, ==, 3);
g_assert (!memcmp (routes->data, rts, sizeof (rts)));
nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, rts, routes->len, TRUE);
g_array_unref (routes);
/* Remove route */
g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
no_error ();
g_assert (!nm_platform_ip6_route_exists (NM_PLATFORM_GET, ifindex, network, plen, metric));
accept_signal (route_removed);
/* Remove route again */
g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
no_error ();
free_signal (route_added);
free_signal (route_changed);
@ -320,11 +295,11 @@ setup_tests (void)
nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME));
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME));
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL));
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS);
accept_signal (link_added);
free_signal (link_added);
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)));
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME), NULL));
g_test_add_func ("/route/ip4", test_ip4_route);
g_test_add_func ("/route/ip6", test_ip6_route);

View file

@ -29,6 +29,7 @@
#include "NetworkManagerUtils.h"
#include "nm-logging.h"
#include "nm-multi-index.h"
#include "nm-test-utils.h"
@ -494,6 +495,362 @@ test_nm_ethernet_address_is_valid (void)
/*******************************************/
typedef struct {
union {
NMMultiIndexId id_base;
guint bucket;
};
} NMMultiIndexIdTest;
typedef struct {
guint64 buckets;
gpointer ptr_value;
} NMMultiIndexTestValue;
static gboolean
_mi_value_bucket_has (const NMMultiIndexTestValue *value, guint bucket)
{
g_assert (value);
g_assert (bucket < 64);
return (value->buckets & (((guint64) 0x01) << bucket)) != 0;
}
static gboolean
_mi_value_bucket_set (NMMultiIndexTestValue *value, guint bucket)
{
g_assert (value);
g_assert (bucket < 64);
if (_mi_value_bucket_has (value, bucket))
return FALSE;
value->buckets |= (((guint64) 0x01) << bucket);
return TRUE;
}
static gboolean
_mi_value_bucket_unset (NMMultiIndexTestValue *value, guint bucket)
{
g_assert (value);
g_assert (bucket < 64);
if (!_mi_value_bucket_has (value, bucket))
return FALSE;
value->buckets &= ~(((guint64) 0x01) << bucket);
return TRUE;
}
static guint
_mi_idx_hash (const NMMultiIndexIdTest *id)
{
g_assert (id && id->bucket < 64);
return id->bucket;
}
static gboolean
_mi_idx_equal (const NMMultiIndexIdTest *a, const NMMultiIndexIdTest *b)
{
g_assert (a && a->bucket < 64);
g_assert (b && b->bucket < 64);
return a->bucket == b->bucket;
}
static NMMultiIndexIdTest *
_mi_idx_clone (const NMMultiIndexIdTest *id)
{
NMMultiIndexIdTest *n;
g_assert (id && id->bucket < 64);
n = g_new0 (NMMultiIndexIdTest, 1);
n->bucket = id->bucket;
return n;
}
static void
_mi_idx_destroy (NMMultiIndexIdTest *id)
{
g_assert (id && id->bucket < 64);
g_free (id);
}
static NMMultiIndexTestValue *
_mi_create_array (guint num_values)
{
NMMultiIndexTestValue *array = g_new0 (NMMultiIndexTestValue, num_values);
guint i;
g_assert (num_values > 0);
for (i = 0; i < num_values; i++) {
array[i].buckets = 0;
array[i].ptr_value = GUINT_TO_POINTER (i + 1);
}
return array;
}
typedef struct {
guint num_values;
guint num_buckets;
NMMultiIndexTestValue *array;
int test_idx;
} NMMultiIndexAssertData;
static gboolean
_mi_assert_index_equals_array_cb (const NMMultiIndexIdTest *id, void *const* values, guint len, NMMultiIndexAssertData *data)
{
guint i;
gboolean has_test_idx = FALSE;
g_assert (id && id->bucket < 64);
g_assert (data);
g_assert (values);
g_assert (len > 0);
g_assert (values[len] == NULL);
g_assert (data->test_idx >= -1 || data->test_idx < data->num_buckets);
g_assert (id->bucket < data->num_buckets);
for (i = 0; i < data->num_values; i++)
g_assert (!_mi_value_bucket_has (&data->array[i], id->bucket));
for (i = 0; i < len; i++) {
guint vi = GPOINTER_TO_UINT (values[i]);
g_assert (vi >= 1);
g_assert (vi <= data->num_values);
vi--;
if (data->test_idx == vi)
has_test_idx = TRUE;
g_assert (data->array[vi].ptr_value == values[i]);
if (!_mi_value_bucket_set (&data->array[vi], id->bucket))
g_assert_not_reached ();
}
g_assert ((data->test_idx == -1 && !has_test_idx) || has_test_idx);
return TRUE;
}
static void
_mi_assert_index_equals_array (guint num_values, guint num_buckets, int test_idx, const NMMultiIndexTestValue *array, const NMMultiIndex *index)
{
NMMultiIndexAssertData data = {
.num_values = num_values,
.num_buckets = num_buckets,
.test_idx = test_idx,
};
NMMultiIndexIter iter;
const NMMultiIndexIdTest *id;
void *const* values;
guint len;
NMMultiIndexTestValue *v;
data.array = _mi_create_array (num_values);
v = test_idx >= 0 ? data.array[test_idx].ptr_value : NULL;
nm_multi_index_foreach (index, v, (NMMultiIndexFuncForeach) _mi_assert_index_equals_array_cb, &data);
if (test_idx >= 0)
g_assert (memcmp (&data.array[test_idx], &array[test_idx], sizeof (NMMultiIndexTestValue)) == 0);
else
g_assert (memcmp (data.array, array, sizeof (NMMultiIndexTestValue) * num_values) == 0);
g_free (data.array);
data.array = _mi_create_array (num_values);
v = test_idx >= 0 ? data.array[test_idx].ptr_value : NULL;
nm_multi_index_iter_init (&iter, index, v);
while (nm_multi_index_iter_next (&iter, (gpointer) &id, &values, &len))
_mi_assert_index_equals_array_cb (id, values, len, &data);
if (test_idx >= 0)
g_assert (memcmp (&data.array[test_idx], &array[test_idx], sizeof (NMMultiIndexTestValue)) == 0);
else
g_assert (memcmp (data.array, array, sizeof (NMMultiIndexTestValue) * num_values) == 0);
g_free (data.array);
}
typedef enum {
MI_OP_ADD,
MI_OP_REMOVE,
MI_OP_MOVE,
} NMMultiIndexOperation;
static void
_mi_rebucket (GRand *rand, guint num_values, guint num_buckets, NMMultiIndexOperation op, guint bucket, guint bucket_old, guint array_idx, NMMultiIndexTestValue *array, NMMultiIndex *index)
{
NMMultiIndexTestValue *v;
NMMultiIndexIdTest id, id_old;
const NMMultiIndexIdTest *id_reverse;
guint64 buckets_old;
guint i;
gboolean had_bucket, had_bucket_old;
g_assert (array_idx < num_values);
g_assert (bucket < (int) num_buckets);
v = &array[array_idx];
buckets_old = v->buckets;
if (op == MI_OP_MOVE)
had_bucket_old = _mi_value_bucket_has (v, bucket_old);
else
had_bucket_old = FALSE;
had_bucket = _mi_value_bucket_has (v, bucket);
switch (op) {
case MI_OP_ADD:
_mi_value_bucket_set (v, bucket);
id.bucket = bucket;
if (nm_multi_index_add (index, &id.id_base, v->ptr_value))
g_assert (!had_bucket);
else
g_assert (had_bucket);
break;
case MI_OP_REMOVE:
_mi_value_bucket_unset (v, bucket);
id.bucket = bucket;
if (nm_multi_index_remove (index, &id.id_base, v->ptr_value))
g_assert (had_bucket);
else
g_assert (!had_bucket);
break;
case MI_OP_MOVE:
_mi_value_bucket_unset (v, bucket_old);
_mi_value_bucket_set (v, bucket);
id.bucket = bucket;
id_old.bucket = bucket_old;
if (nm_multi_index_move (index, &id_old.id_base, &id.id_base, v->ptr_value)) {
if (bucket == bucket_old)
g_assert (had_bucket_old && had_bucket);
else
g_assert (had_bucket_old && !had_bucket);
} else {
if (bucket == bucket_old)
g_assert (!had_bucket_old && !had_bucket);
else
g_assert (!had_bucket_old || had_bucket);
}
break;
default:
g_assert_not_reached ();
}
#if 0
g_print (">>> rebucket: idx=%3u, op=%3s, bucket=%3i%c -> %3i%c, buckets=%08llx -> %08llx %s\n", array_idx,
op == MI_OP_ADD ? "ADD" : (op == MI_OP_REMOVE ? "REM" : "MOV"),
bucket_old, had_bucket_old ? '*' : ' ',
bucket, had_bucket ? '*' : ' ',
(long long unsigned) buckets_old, (long long unsigned) v->buckets,
buckets_old != v->buckets ? "(changed)" : "(unchanged)");
#endif
id_reverse = (const NMMultiIndexIdTest *) nm_multi_index_lookup_first_by_value (index, v->ptr_value);
if (id_reverse)
g_assert (_mi_value_bucket_has (v, id_reverse->bucket));
else
g_assert (v->buckets == 0);
for (i = 0; i < 64; i++) {
id.bucket = i;
if (nm_multi_index_contains (index, &id.id_base, v->ptr_value))
g_assert (_mi_value_bucket_has (v, i));
else
g_assert (!_mi_value_bucket_has (v, i));
}
_mi_assert_index_equals_array (num_values, num_buckets, -1, array, index);
_mi_assert_index_equals_array (num_values, num_buckets, array_idx, array, index);
_mi_assert_index_equals_array (num_values, num_buckets, g_rand_int_range (rand, 0, num_values), array, index);
}
static void
_mi_test_run (guint num_values, guint num_buckets)
{
NMMultiIndex *index = nm_multi_index_new ((NMMultiIndexFuncHash) _mi_idx_hash,
(NMMultiIndexFuncEqual) _mi_idx_equal,
(NMMultiIndexFuncClone) _mi_idx_clone,
(NMMultiIndexFuncDestroy) _mi_idx_destroy);
gs_free NMMultiIndexTestValue *array = _mi_create_array (num_values);
GRand *rand = nmtst_get_rand ();
guint i, i_rd, i_idx, i_bucket;
guint num_buckets_all = num_values * num_buckets;
g_assert (array[0].ptr_value == GUINT_TO_POINTER (1));
_mi_assert_index_equals_array (num_values, num_buckets, -1, array, index);
_mi_rebucket (rand, num_values, num_buckets, MI_OP_ADD, 0, 0, 0, array, index);
_mi_rebucket (rand, num_values, num_buckets, MI_OP_REMOVE, 0, 0, 0, array, index);
if (num_buckets >= 3) {
_mi_rebucket (rand, num_values, num_buckets, MI_OP_ADD, 0, 0, 0, array, index);
_mi_rebucket (rand, num_values, num_buckets, MI_OP_MOVE, 2, 0, 0, array, index);
_mi_rebucket (rand, num_values, num_buckets, MI_OP_REMOVE, 2, 0, 0, array, index);
}
g_assert (nm_multi_index_get_num_groups (index) == 0);
/* randomly change the bucket of entries. */
for (i = 0; i < 5 * num_values; i++) {
guint array_idx = g_rand_int_range (rand, 0, num_values);
guint bucket = g_rand_int_range (rand, 0, num_buckets);
NMMultiIndexOperation op = g_rand_int_range (rand, 0, MI_OP_MOVE + 1);
guint bucket_old = 0;
if (op == MI_OP_MOVE) {
if ((g_rand_int (rand) % 2) && array[array_idx].buckets != 0) {
guint64 b;
/* choose the highest (existing) bucket. */
bucket_old = 0;
for (b = array[array_idx].buckets; b; b >>= 1)
bucket_old++;
} else {
/* choose a random bucket (even if the item is currently not in that bucket). */
bucket_old = g_rand_int_range (rand, 0, num_buckets);
}
}
_mi_rebucket (rand, num_values, num_buckets, op, bucket, bucket_old, array_idx, array, index);
}
/* remove all elements from all buckets */
i_rd = g_rand_int (rand);
for (i = 0; i < num_buckets_all; i++) {
i_rd = (i_rd + 101) % num_buckets_all;
i_idx = i_rd / num_buckets;
i_bucket = i_rd % num_buckets;
if (_mi_value_bucket_has (&array[i_idx], i_bucket))
_mi_rebucket (rand, num_values, num_buckets, MI_OP_REMOVE, i_bucket, 0, i_idx, array, index);
}
g_assert (nm_multi_index_get_num_groups (index) == 0);
nm_multi_index_free (index);
}
static void
test_nm_multi_index (void)
{
guint i, j;
for (i = 1; i < 7; i++) {
for (j = 1; j < 6; j++)
_mi_test_run (i, j);
}
_mi_test_run (50, 3);
_mi_test_run (50, 18);
}
/*******************************************/
NMTST_DEFINE ();
int
@ -505,6 +862,7 @@ main (int argc, char **argv)
g_test_add_func ("/general/nm_utils_kill_child", test_nm_utils_kill_child);
g_test_add_func ("/general/nm_utils_array_remove_at_indexes", test_nm_utils_array_remove_at_indexes);
g_test_add_func ("/general/nm_ethernet_address_is_valid", test_nm_ethernet_address_is_valid);
g_test_add_func ("/general/nm_multi_index", test_nm_multi_index);
return g_test_run ();
}

View file

@ -22,6 +22,7 @@
#include <glib.h>
#include <arpa/inet.h>
#include <linux/rtnetlink.h>
#include "test-common.h"
@ -168,6 +169,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data)
.gateway = INADDR_ANY,
.metric = 20,
.mss = 1000,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
{
.source = NM_IP_CONFIG_SOURCE_USER,
@ -177,6 +179,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data)
.gateway = nmtst_inet4_from_string ("6.6.6.1"),
.metric = 21021,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE),
},
{
.source = NM_IP_CONFIG_SOURCE_USER,
@ -186,6 +189,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data)
.gateway = INADDR_ANY,
.metric = 22,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
};
@ -198,6 +202,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data)
.gateway = INADDR_ANY,
.metric = 20,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
{
.source = NM_IP_CONFIG_SOURCE_USER,
@ -207,6 +212,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data)
.gateway = INADDR_ANY,
.metric = 21,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
{
.source = NM_IP_CONFIG_SOURCE_USER,
@ -216,6 +222,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data)
.gateway = INADDR_ANY,
.metric = 22,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
};
@ -228,6 +235,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data)
.gateway = INADDR_ANY,
.metric = 22,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
{
.source = NM_IP_CONFIG_SOURCE_USER,
@ -237,11 +245,12 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data)
.gateway = INADDR_ANY,
.metric = 20,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
};
setup_dev0_ip4 (fixture->ifindex0, 1000, 21021);
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*error adding 8.0.0.0/8 via 6.6.6.2 dev *");
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*failure adding ip4-route '*: 8.0.0.0/8 22': *");
setup_dev1_ip4 (fixture->ifindex1);
g_test_assert_expected_messages ();
@ -253,7 +262,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data)
nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, state1, routes->len, TRUE);
g_array_free (routes, TRUE);
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*error adding 8.0.0.0/8 via 6.6.6.2 dev *");
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*failure adding ip4-route '*: 8.0.0.0/8 22': *");
setup_dev1_ip4 (fixture->ifindex1);
g_test_assert_expected_messages ();
@ -575,7 +584,7 @@ test_ip6 (test_fixture *fixture, gconstpointer user_data)
};
setup_dev0_ip6 (fixture->ifindex0);
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*error adding 2001:db8:d34d::/64 via 2001:db8:8086::2 dev *");
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*failure adding ip6-route '*: 2001:db8:d34d::/64 20': *");
setup_dev1_ip6 (fixture->ifindex1);
g_test_assert_expected_messages ();
@ -589,7 +598,7 @@ test_ip6 (test_fixture *fixture, gconstpointer user_data)
g_array_free (routes, TRUE);
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*error adding 2001:db8:d34d::/64 via 2001:db8:8086::2 dev *");
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*failure adding ip6-route '*: 2001:db8:d34d::/64 20': *");
setup_dev1_ip6 (fixture->ifindex1);
g_test_assert_expected_messages ();
setup_dev0_ip6 (fixture->ifindex0);
@ -639,11 +648,11 @@ fixture_setup (test_fixture *fixture, gconstpointer user_data)
"nm-test-device0");
nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device0"));
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, "nm-test-device0"));
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device0", NULL));
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device0", NULL) == NM_PLATFORM_ERROR_SUCCESS);
accept_signal (link_added);
free_signal (link_added);
fixture->ifindex0 = nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device0");
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex0));
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex0, NULL));
link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED,
NM_PLATFORM_SIGNAL_ADDED,
@ -651,11 +660,11 @@ fixture_setup (test_fixture *fixture, gconstpointer user_data)
"nm-test-device1");
nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device1"));
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, "nm-test-device1"));
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device1", NULL));
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device1", NULL) == NM_PLATFORM_ERROR_SUCCESS);
accept_signal (link_added);
free_signal (link_added);
fixture->ifindex1 = nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device1");
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex1));
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex1, NULL));
}
static void

View file

@ -921,7 +921,7 @@ nm_vpn_connection_apply_config (NMVpnConnection *connection)
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
if (priv->ip_ifindex > 0) {
nm_platform_link_set_up (NM_PLATFORM_GET, priv->ip_ifindex);
nm_platform_link_set_up (NM_PLATFORM_GET, priv->ip_ifindex, NULL);
if (priv->ip4_config) {
if (!nm_ip4_config_commit (priv->ip4_config, priv->ip_ifindex,

View file

@ -417,24 +417,6 @@
# libnl3
###############################################################
{
# fixed by https://github.com/thom311/libnl/commit/d65c32a7205e679c7fc13f0e4565b13e698ba906
libnl_rtnl_link_set_type_01
Memcheck:Leak
match-leak-kinds: definite
fun:calloc
fun:vlan_alloc
fun:rtnl_link_set_type
fun:link_msg_parser
fun:__pickup_answer
fun:nl_cb_call
fun:recvmsgs
fun:nl_recvmsgs_report
fun:nl_recvmsgs
fun:nl_pickup
fun:rtnl_link_get_kernel
...
}
{
# fixed by https://github.com/thom311/libnl/commit/d65c32a7205e679c7fc13f0e4565b13e698ba906
# Same issue as libnl_rtnl_link_set_type_01, but different backtrace by calling nl_msg_parse().