mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-11 01:40:19 +01:00
platform: master and slave devices
This commit is contained in:
parent
649d2e4c1b
commit
81bf475b78
6 changed files with 524 additions and 0 deletions
|
|
@ -171,7 +171,26 @@ link_get_type (NMPlatform *platform, int ifindex)
|
|||
static void
|
||||
link_changed (NMPlatform *platform, NMPlatformLink *device)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
int i;
|
||||
|
||||
g_signal_emit_by_name (platform, "link-changed", device);
|
||||
|
||||
if (device->master) {
|
||||
NMPlatformLink *master = link_get (platform, device->master);
|
||||
|
||||
g_return_if_fail (master != device);
|
||||
|
||||
master->connected = FALSE;
|
||||
for (i = 0; i < priv->links->len; i++) {
|
||||
NMPlatformLink *slave = &g_array_index (priv->links, NMPlatformLink, i);
|
||||
|
||||
if (slave && slave->master == master->ifindex && slave->connected)
|
||||
master->connected = TRUE;
|
||||
}
|
||||
|
||||
link_changed (platform, master);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
@ -188,6 +207,11 @@ link_set_up (NMPlatform *platform, int ifindex)
|
|||
case NM_LINK_TYPE_DUMMY:
|
||||
device->connected = TRUE;
|
||||
break;
|
||||
case NM_LINK_TYPE_BRIDGE:
|
||||
case NM_LINK_TYPE_BOND:
|
||||
case NM_LINK_TYPE_TEAM:
|
||||
device->connected = FALSE;
|
||||
break;
|
||||
default:
|
||||
device->connected = FALSE;
|
||||
g_error ("Unexpected device type: %d", device->type);
|
||||
|
|
@ -300,6 +324,53 @@ link_supports_vlans (NMPlatform *platform, int ifindex)
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_enslave (NMPlatform *platform, int master, int slave)
|
||||
{
|
||||
NMPlatformLink *device = link_get (platform, slave);
|
||||
|
||||
g_return_val_if_fail (device, FALSE);
|
||||
|
||||
device->master = master;
|
||||
|
||||
link_changed (platform, device);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_release (NMPlatform *platform, int master_idx, int slave_idx)
|
||||
{
|
||||
NMPlatformLink *master = link_get (platform, master_idx);
|
||||
NMPlatformLink *slave = link_get (platform, slave_idx);
|
||||
|
||||
g_return_val_if_fail (master, FALSE);
|
||||
g_return_val_if_fail (slave, FALSE);
|
||||
|
||||
if (slave->master != master->ifindex) {
|
||||
platform->error = NM_PLATFORM_ERROR_NOT_SLAVE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
slave->master = 0;
|
||||
|
||||
link_changed (platform, slave);
|
||||
link_changed (platform, master);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
link_get_master (NMPlatform *platform, int slave)
|
||||
{
|
||||
NMPlatformLink *device = link_get (platform, slave);
|
||||
|
||||
g_return_val_if_fail (device, FALSE);
|
||||
|
||||
return device->master;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static GArray *
|
||||
|
|
@ -733,6 +804,10 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
|
|||
platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
|
||||
platform_class->link_supports_vlans = link_supports_vlans;
|
||||
|
||||
platform_class->link_enslave = link_enslave;
|
||||
platform_class->link_release = link_release;
|
||||
platform_class->link_get_master = link_get_master;
|
||||
|
||||
platform_class->ip4_address_get_all = ip4_address_get_all;
|
||||
platform_class->ip6_address_get_all = ip6_address_get_all;
|
||||
platform_class->ip4_address_add = ip4_address_add;
|
||||
|
|
|
|||
|
|
@ -266,6 +266,12 @@ type_to_string (NMLinkType type)
|
|||
switch (type) {
|
||||
case NM_LINK_TYPE_DUMMY:
|
||||
return "dummy";
|
||||
case NM_LINK_TYPE_BRIDGE:
|
||||
return "bridge";
|
||||
case NM_LINK_TYPE_BOND:
|
||||
return "bond";
|
||||
case NM_LINK_TYPE_TEAM:
|
||||
return "team";
|
||||
default:
|
||||
g_warning ("Wrong type: %d", type);
|
||||
return NULL;
|
||||
|
|
@ -293,6 +299,12 @@ link_extract_type (struct rtnl_link *rtnllink)
|
|||
}
|
||||
else if (!g_strcmp0 (type, "dummy"))
|
||||
return NM_LINK_TYPE_DUMMY;
|
||||
else if (!g_strcmp0 (type, "bridge"))
|
||||
return NM_LINK_TYPE_BRIDGE;
|
||||
else if (!g_strcmp0 (type, "bond"))
|
||||
return NM_LINK_TYPE_BOND;
|
||||
else if (!g_strcmp0 (type, "team"))
|
||||
return NM_LINK_TYPE_TEAM;
|
||||
else
|
||||
return NM_LINK_TYPE_UNKNOWN;
|
||||
}
|
||||
|
|
@ -310,6 +322,53 @@ link_init (NMPlatformLink *info, struct rtnl_link *rtnllink)
|
|||
info->up = !!(rtnl_link_get_flags (rtnllink) & IFF_UP);
|
||||
info->connected = !!(rtnl_link_get_flags (rtnllink) & IFF_LOWER_UP);
|
||||
info->arp = !(rtnl_link_get_flags (rtnllink) & IFF_NOARP);
|
||||
info->master = rtnl_link_get_master (rtnllink);
|
||||
}
|
||||
|
||||
/* Hack: Empty bridges and bonds have IFF_LOWER_UP flag and therefore they break
|
||||
* the carrier detection. This hack makes nm-platform think they don't have the
|
||||
* IFF_LOWER_UP flag. This seems to also apply to bonds (specifically) with all
|
||||
* slaves down.
|
||||
*
|
||||
* Note: This is still a bit racy but when NetworkManager asks for enslaving a slave,
|
||||
* nm-platform will do that synchronously and will immediately ask for both master
|
||||
* and slave information after the enslaving request. After the synchronous call, the
|
||||
* master carrier is already updated with the slave carrier in mind.
|
||||
*
|
||||
* https://bugzilla.redhat.com/show_bug.cgi?id=910348
|
||||
*/
|
||||
static void
|
||||
hack_empty_master_iff_lower_up (NMPlatform *platform, struct nl_object *object)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
struct rtnl_link *rtnllink;
|
||||
int ifindex;
|
||||
struct nl_object *slave;
|
||||
|
||||
if (!object)
|
||||
return;
|
||||
if (strcmp (nl_object_get_type (object), "route/link"))
|
||||
return;
|
||||
|
||||
rtnllink = (struct rtnl_link *) object;
|
||||
|
||||
ifindex = rtnl_link_get_ifindex (rtnllink);
|
||||
|
||||
switch (link_extract_type (rtnllink)) {
|
||||
case NM_LINK_TYPE_BRIDGE:
|
||||
case NM_LINK_TYPE_BOND:
|
||||
for (slave = nl_cache_get_first (priv->link_cache); slave; slave = nl_cache_get_next (slave)) {
|
||||
struct rtnl_link *rtnlslave = (struct rtnl_link *) slave;
|
||||
if (rtnl_link_get_master (rtnlslave) == ifindex
|
||||
&& rtnl_link_get_flags (rtnlslave) & IFF_LOWER_UP)
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
rtnl_link_unset_flags (rtnllink, IFF_LOWER_UP);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -480,6 +539,8 @@ process_nl_error (NMPlatform *platform, int nle)
|
|||
}
|
||||
}
|
||||
|
||||
static struct nl_object * build_rtnl_link (int ifindex, const char *name, NMLinkType type);
|
||||
|
||||
static gboolean
|
||||
refresh_object (NMPlatform *platform, struct nl_object *object, int nle)
|
||||
{
|
||||
|
|
@ -497,6 +558,8 @@ refresh_object (NMPlatform *platform, struct nl_object *object, int nle)
|
|||
|
||||
g_return_val_if_fail (kernel_object, FALSE);
|
||||
|
||||
hack_empty_master_iff_lower_up (platform, kernel_object);
|
||||
|
||||
if (cached_object) {
|
||||
nl_cache_remove (cached_object);
|
||||
nle = nl_cache_add (cache, kernel_object);
|
||||
|
|
@ -508,6 +571,24 @@ refresh_object (NMPlatform *platform, struct nl_object *object, int nle)
|
|||
|
||||
announce_object (platform, kernel_object, cached_object ? CHANGED : ADDED);
|
||||
|
||||
/* Refresh the master device (even on enslave/release) */
|
||||
if (object_type_from_nl_object (kernel_object) == LINK) {
|
||||
int kernel_master = rtnl_link_get_master ((struct rtnl_link *) kernel_object);
|
||||
int cached_master = cached_object ? rtnl_link_get_master ((struct rtnl_link *) cached_object) : 0;
|
||||
struct nl_object *master_object;
|
||||
|
||||
if (kernel_master) {
|
||||
master_object = build_rtnl_link (kernel_master, NULL, NM_LINK_TYPE_NONE);
|
||||
refresh_object (platform, master_object, 0);
|
||||
nl_object_put (master_object);
|
||||
}
|
||||
if (cached_master && cached_master != kernel_master) {
|
||||
master_object = build_rtnl_link (cached_master, NULL, NM_LINK_TYPE_NONE);
|
||||
refresh_object (platform, master_object, 0);
|
||||
nl_object_put (master_object);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -578,6 +659,8 @@ event_notification (struct nl_msg *msg, gpointer user_data)
|
|||
|
||||
debug ("netlink event (type %d)", event);
|
||||
|
||||
hack_empty_master_iff_lower_up (platform, kernel_object);
|
||||
|
||||
/* Removed object */
|
||||
switch (event) {
|
||||
case RTM_DELLINK:
|
||||
|
|
@ -884,6 +967,46 @@ link_supports_vlans (NMPlatform *platform, int ifindex)
|
|||
return !(edata.features.features[0].active & NETIF_F_VLAN_CHALLENGED);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_refresh (NMPlatform *platform, int ifindex, int nle)
|
||||
{
|
||||
auto_nl_object struct nl_object *object = build_rtnl_link (ifindex, NULL, NM_LINK_TYPE_NONE);
|
||||
|
||||
return refresh_object (platform, object, nle);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_enslave (NMPlatform *platform, int master, int slave)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
|
||||
return link_refresh (platform, slave, rtnl_link_enslave_ifindex (priv->nlh, master, slave));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_release (NMPlatform *platform, int master, int slave)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
|
||||
return link_refresh (platform, slave, rtnl_link_release_ifindex (priv->nlh, slave));
|
||||
}
|
||||
|
||||
static int
|
||||
link_get_master (NMPlatform *platform, int slave)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
auto_nl_object struct rtnl_link *rtnllink;
|
||||
int result;
|
||||
|
||||
rtnllink = rtnl_link_get (priv->link_cache, slave);
|
||||
g_assert (rtnllink);
|
||||
|
||||
result = rtnl_link_get_master (rtnllink);
|
||||
g_assert (result >= 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static int
|
||||
|
|
@ -1345,6 +1468,10 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
|
|||
platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
|
||||
platform_class->link_supports_vlans = link_supports_vlans;
|
||||
|
||||
platform_class->link_enslave = link_enslave;
|
||||
platform_class->link_release = link_release;
|
||||
platform_class->link_get_master = link_get_master;
|
||||
|
||||
platform_class->ip4_address_get_all = ip4_address_get_all;
|
||||
platform_class->ip6_address_get_all = ip6_address_get_all;
|
||||
platform_class->ip4_address_add = ip4_address_add;
|
||||
|
|
|
|||
|
|
@ -502,6 +502,118 @@ nm_platform_link_set_noarp (int ifindex)
|
|||
return klass->link_set_noarp (platform, ifindex);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_link_enslave:
|
||||
* @master: Interface index of the master
|
||||
* @slave: Interface index of the slave
|
||||
*
|
||||
* Enslave @slave to @master.
|
||||
*/
|
||||
gboolean
|
||||
nm_platform_link_enslave (int master, int slave)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_assert (platform);
|
||||
g_return_val_if_fail (master > 0, FALSE);
|
||||
g_return_val_if_fail (slave> 0, FALSE);
|
||||
g_return_val_if_fail (klass->link_enslave, FALSE);
|
||||
|
||||
debug ("link: enslaving '%s' (%d) to master '%s' (%d)",
|
||||
nm_platform_link_get_name (slave), slave,
|
||||
nm_platform_link_get_name (master), master);
|
||||
return klass->link_enslave (platform, master, slave);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_link_release:
|
||||
* @master: Interface index of the master
|
||||
* @slave: Interface index of the slave
|
||||
*
|
||||
* Release @slave from @master.
|
||||
*/
|
||||
gboolean
|
||||
nm_platform_link_release (int master, int slave)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_assert (platform);
|
||||
g_return_val_if_fail (master > 0, FALSE);
|
||||
g_return_val_if_fail (slave > 0, FALSE);
|
||||
g_return_val_if_fail (klass->link_release, FALSE);
|
||||
|
||||
if (nm_platform_link_get_master (slave) != master) {
|
||||
platform->error = NM_PLATFORM_ERROR_NOT_SLAVE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
debug ("link: releasing '%s' (%d) from master '%s' (%d)",
|
||||
nm_platform_link_get_name (slave), slave,
|
||||
nm_platform_link_get_name (master), master);
|
||||
return klass->link_release (platform, master, slave);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_link_get_master:
|
||||
* @slave: Interface index of the slave.
|
||||
*
|
||||
* Returns: Interfase index of the slave's master.
|
||||
*/
|
||||
int
|
||||
nm_platform_link_get_master (int slave)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_assert (platform);
|
||||
g_return_val_if_fail (slave >= 0, FALSE);
|
||||
g_return_val_if_fail (klass->link_get_master, FALSE);
|
||||
|
||||
if (!nm_platform_link_get_name (slave)) {
|
||||
platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
|
||||
return 0;
|
||||
}
|
||||
return klass->link_get_master (platform, slave);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_bridge_add:
|
||||
* @name: New interface name
|
||||
*
|
||||
* Create a virtual bridge.
|
||||
*/
|
||||
gboolean
|
||||
nm_platform_bridge_add (const char *name)
|
||||
{
|
||||
debug ("link: adding bridge '%s'", name);
|
||||
return nm_platform_link_add (name, NM_LINK_TYPE_BRIDGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_bond_add:
|
||||
* @name: New interface name
|
||||
*
|
||||
* Create a virtual bonding device.
|
||||
*/
|
||||
gboolean
|
||||
nm_platform_bond_add (const char *name)
|
||||
{
|
||||
debug ("link: adding bond '%s'", name);
|
||||
return nm_platform_link_add (name, NM_LINK_TYPE_BOND);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_team_add:
|
||||
* @name: New interface name
|
||||
*
|
||||
* Create a virtual teaming device.
|
||||
*/
|
||||
gboolean
|
||||
nm_platform_team_add (const char *name)
|
||||
{
|
||||
debug ("link: adding team '%s'", name);
|
||||
return nm_platform_link_add (name, NM_LINK_TYPE_TEAM);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
GArray *
|
||||
|
|
|
|||
|
|
@ -41,12 +41,16 @@ typedef enum {
|
|||
NM_LINK_TYPE_LOOPBACK,
|
||||
NM_LINK_TYPE_ETHERNET,
|
||||
NM_LINK_TYPE_DUMMY,
|
||||
NM_LINK_TYPE_BRIDGE,
|
||||
NM_LINK_TYPE_BOND,
|
||||
NM_LINK_TYPE_TEAM,
|
||||
} NMLinkType;
|
||||
|
||||
typedef struct {
|
||||
int ifindex;
|
||||
char name[IFNAMSIZ];
|
||||
NMLinkType type;
|
||||
int master;
|
||||
gboolean up;
|
||||
gboolean connected;
|
||||
gboolean arp;
|
||||
|
|
@ -139,6 +143,10 @@ typedef struct {
|
|||
gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex);
|
||||
gboolean (*link_supports_vlans) (NMPlatform *, int ifindex);
|
||||
|
||||
gboolean (*link_enslave) (NMPlatform *, int master, int slave);
|
||||
gboolean (*link_release) (NMPlatform *, int master, int slave);
|
||||
gboolean (*link_get_master) (NMPlatform *, int slave);
|
||||
|
||||
GArray * (*ip4_address_get_all) (NMPlatform *, int ifindex);
|
||||
GArray * (*ip6_address_get_all) (NMPlatform *, int ifindex);
|
||||
gboolean (*ip4_address_add) (NMPlatform *, int ifindex, in_addr_t address, int plen);
|
||||
|
|
@ -199,6 +207,8 @@ enum {
|
|||
NM_PLATFORM_ERROR_NOT_FOUND,
|
||||
/* object already exists */
|
||||
NM_PLATFORM_ERROR_EXISTS,
|
||||
/* object is not a slave */
|
||||
NM_PLATFORM_ERROR_NOT_SLAVE
|
||||
};
|
||||
|
||||
/******************************************************************/
|
||||
|
|
@ -216,6 +226,9 @@ const char *nm_platform_get_error_msg (void);
|
|||
|
||||
GArray *nm_platform_link_get_all (void);
|
||||
gboolean nm_platform_dummy_add (const char *name);
|
||||
gboolean nm_platform_bridge_add (const char *name);
|
||||
gboolean nm_platform_bond_add (const char *name);
|
||||
gboolean nm_platform_team_add (const char *name);
|
||||
gboolean nm_platform_link_exists (const char *name);
|
||||
gboolean nm_platform_link_delete (int ifindex);
|
||||
gboolean nm_platform_link_delete_by_name (const char *ifindex);
|
||||
|
|
@ -234,6 +247,10 @@ gboolean nm_platform_link_uses_arp (int ifindex);
|
|||
gboolean nm_platform_link_supports_carrier_detect (int ifindex);
|
||||
gboolean nm_platform_link_supports_vlans (int ifindex);
|
||||
|
||||
gboolean nm_platform_link_enslave (int master, int slave);
|
||||
gboolean nm_platform_link_release (int master, int slave);
|
||||
int nm_platform_link_get_master (int slave);
|
||||
|
||||
GArray *nm_platform_ip4_address_get_all (int ifindex);
|
||||
GArray *nm_platform_ip6_address_get_all (int ifindex);
|
||||
gboolean nm_platform_ip4_address_add (int ifindex, in_addr_t address, int plen);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@ type_to_string (NMLinkType type)
|
|||
return "ethernet";
|
||||
case NM_LINK_TYPE_DUMMY:
|
||||
return "dummy";
|
||||
case NM_LINK_TYPE_BRIDGE:
|
||||
return "bridge";
|
||||
case NM_LINK_TYPE_BOND:
|
||||
return "bond";
|
||||
case NM_LINK_TYPE_TEAM:
|
||||
return "team";
|
||||
default:
|
||||
return "unknown-type";
|
||||
}
|
||||
|
|
@ -46,6 +52,8 @@ dump_interface (NMPlatformLink *link)
|
|||
printf (" DOWN");
|
||||
if (!link->arp)
|
||||
printf (" noarp");
|
||||
if (link->master)
|
||||
printf (" master %d", link->master);
|
||||
printf ("\n");
|
||||
|
||||
if (nm_platform_link_supports_carrier_detect (link->ifindex))
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#define DEVICE_NAME "nm-test-device"
|
||||
#define BOGUS_NAME "nm-bogus-device"
|
||||
#define BOGUS_IFINDEX INT_MAX
|
||||
#define SLAVE_NAME "nm-test-slave"
|
||||
|
||||
static void
|
||||
link_callback (NMPlatform *platform, NMPlatformLink *received, SignalData *data)
|
||||
|
|
@ -97,6 +98,185 @@ test_loopback (void)
|
|||
g_assert (!nm_platform_link_supports_vlans (LO_INDEX));
|
||||
}
|
||||
|
||||
static int
|
||||
virtual_add (NMLinkType link_type, const char *name, SignalData *link_added, SignalData *link_changed)
|
||||
{
|
||||
switch (link_type) {
|
||||
case NM_LINK_TYPE_DUMMY:
|
||||
return nm_platform_dummy_add (name);
|
||||
case NM_LINK_TYPE_BRIDGE:
|
||||
return nm_platform_bridge_add (name);
|
||||
case NM_LINK_TYPE_BOND:
|
||||
return nm_platform_bond_add (name);
|
||||
case NM_LINK_TYPE_TEAM:
|
||||
return nm_platform_team_add (name);
|
||||
default:
|
||||
g_error ("Link type %d unhandled.", link_type);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_slave (int master, int type, SignalData *link_added, SignalData *master_changed, SignalData *link_removed)
|
||||
{
|
||||
int ifindex;
|
||||
SignalData *link_changed = add_signal ("link-changed", link_callback);
|
||||
|
||||
g_assert (virtual_add (type, SLAVE_NAME, link_added, link_changed));
|
||||
ifindex = nm_platform_link_get_ifindex (SLAVE_NAME);
|
||||
g_assert (ifindex > 0);
|
||||
accept_signal (link_added);
|
||||
|
||||
/* Set the slave up to see whether master's IFF_LOWER_UP is set correctly.
|
||||
*
|
||||
* See https://bugzilla.redhat.com/show_bug.cgi?id=910348
|
||||
*/
|
||||
g_assert (nm_platform_link_set_down (ifindex));
|
||||
g_assert (!nm_platform_link_is_up (ifindex));
|
||||
accept_signal (link_changed);
|
||||
|
||||
/* Enslave */
|
||||
link_changed->ifindex = ifindex;
|
||||
g_assert (nm_platform_link_enslave (master, ifindex)); no_error ();
|
||||
g_assert (nm_platform_link_get_master (ifindex) == master); no_error ();
|
||||
accept_signal (link_changed);
|
||||
accept_signal (master_changed);
|
||||
|
||||
/* Set master up */
|
||||
g_assert (nm_platform_link_set_up (master));
|
||||
accept_signal (master_changed);
|
||||
|
||||
/* Master with a disconnected slave is disconnected
|
||||
*
|
||||
* For some reason, bonding and teaming slaves are automatically set up. We
|
||||
* need to set them back down for this test.
|
||||
*/
|
||||
switch (nm_platform_link_get_type (master)) {
|
||||
case NM_LINK_TYPE_BOND:
|
||||
case NM_LINK_TYPE_TEAM:
|
||||
g_assert (nm_platform_link_set_down (ifindex));
|
||||
accept_signal (link_changed);
|
||||
accept_signal (master_changed);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
g_assert (!nm_platform_link_is_up (ifindex));
|
||||
g_assert (!nm_platform_link_is_connected (ifindex));
|
||||
g_assert (!nm_platform_link_is_connected (master));
|
||||
|
||||
/* Set slave up and see if master gets up too */
|
||||
g_assert (nm_platform_link_set_up (ifindex)); no_error ();
|
||||
g_assert (nm_platform_link_is_connected (ifindex));
|
||||
g_assert (nm_platform_link_is_connected (master));
|
||||
accept_signal (link_changed);
|
||||
accept_signal (master_changed);
|
||||
|
||||
/* Enslave again
|
||||
*
|
||||
* Gracefully succeed if already enslaved.
|
||||
*/
|
||||
g_assert (nm_platform_link_enslave (master, ifindex)); no_error ();
|
||||
accept_signal (link_changed);
|
||||
accept_signal (master_changed);
|
||||
|
||||
/* Release */
|
||||
g_assert (nm_platform_link_release (master, ifindex));
|
||||
g_assert (nm_platform_link_get_master (ifindex) == 0); no_error ();
|
||||
accept_signal (link_changed);
|
||||
accept_signal (master_changed);
|
||||
|
||||
/* Release again */
|
||||
g_assert (!nm_platform_link_release (master, ifindex));
|
||||
error (NM_PLATFORM_ERROR_NOT_SLAVE);
|
||||
|
||||
/* Remove */
|
||||
g_assert (nm_platform_link_delete (ifindex));
|
||||
no_error ();
|
||||
accept_signal (link_removed);
|
||||
|
||||
free_signal (link_changed);
|
||||
}
|
||||
|
||||
static void
|
||||
test_virtual (NMLinkType link_type)
|
||||
{
|
||||
int ifindex;
|
||||
|
||||
SignalData *link_added = add_signal ("link-added", link_callback);
|
||||
SignalData *link_changed = add_signal ("link-changed", link_callback);
|
||||
SignalData *link_removed = add_signal ("link-removed", link_callback);
|
||||
|
||||
/* Add */
|
||||
g_assert (virtual_add (link_type, DEVICE_NAME, link_added, link_changed));
|
||||
no_error ();
|
||||
g_assert (nm_platform_link_exists (DEVICE_NAME));
|
||||
ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
|
||||
g_assert (ifindex >= 0);
|
||||
g_assert (nm_platform_link_get_type (ifindex) == link_type);
|
||||
accept_signal (link_added);
|
||||
|
||||
/* Add again */
|
||||
g_assert (!virtual_add (link_type, DEVICE_NAME, link_added, link_changed));
|
||||
error (NM_PLATFORM_ERROR_EXISTS);
|
||||
|
||||
/* Set ARP/NOARP */
|
||||
g_assert (nm_platform_link_uses_arp (ifindex));
|
||||
g_assert (nm_platform_link_set_noarp (ifindex));
|
||||
g_assert (!nm_platform_link_uses_arp (ifindex));
|
||||
accept_signal (link_changed);
|
||||
g_assert (nm_platform_link_set_arp (ifindex));
|
||||
g_assert (nm_platform_link_uses_arp (ifindex));
|
||||
accept_signal (link_changed);
|
||||
|
||||
/* Enslave and release */
|
||||
switch (link_type) {
|
||||
case NM_LINK_TYPE_BRIDGE:
|
||||
case NM_LINK_TYPE_BOND:
|
||||
case NM_LINK_TYPE_TEAM:
|
||||
link_changed->ifindex = ifindex;
|
||||
test_slave (ifindex, NM_LINK_TYPE_DUMMY, link_added, link_changed, link_removed);
|
||||
link_changed->ifindex = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Delete */
|
||||
g_assert (nm_platform_link_delete_by_name (DEVICE_NAME));
|
||||
no_error ();
|
||||
g_assert (!nm_platform_link_exists (DEVICE_NAME)); no_error ();
|
||||
g_assert (nm_platform_link_get_type (ifindex) == NM_LINK_TYPE_NONE);
|
||||
error (NM_PLATFORM_ERROR_NOT_FOUND);
|
||||
accept_signal (link_removed);
|
||||
|
||||
/* Delete again */
|
||||
g_assert (!nm_platform_link_delete_by_name (DEVICE_NAME));
|
||||
error (NM_PLATFORM_ERROR_NOT_FOUND);
|
||||
|
||||
/* No pending signal */
|
||||
free_signal (link_added);
|
||||
free_signal (link_changed);
|
||||
free_signal (link_removed);
|
||||
}
|
||||
|
||||
static void
|
||||
test_bridge (void)
|
||||
{
|
||||
test_virtual (NM_LINK_TYPE_BRIDGE);
|
||||
}
|
||||
|
||||
static void
|
||||
test_bond (void)
|
||||
{
|
||||
test_virtual (NM_LINK_TYPE_BOND);
|
||||
}
|
||||
|
||||
static void
|
||||
test_team (void)
|
||||
{
|
||||
test_virtual (NM_LINK_TYPE_TEAM);
|
||||
}
|
||||
|
||||
static void
|
||||
test_internal (void)
|
||||
{
|
||||
|
|
@ -249,11 +429,16 @@ main (int argc, char **argv)
|
|||
|
||||
/* Clean up */
|
||||
nm_platform_link_delete_by_name (DEVICE_NAME);
|
||||
nm_platform_link_delete_by_name (SLAVE_NAME);
|
||||
g_assert (!nm_platform_link_exists (DEVICE_NAME));
|
||||
g_assert (!nm_platform_link_exists (SLAVE_NAME));
|
||||
|
||||
g_test_add_func ("/link/bogus", test_bogus);
|
||||
g_test_add_func ("/link/loopback", test_loopback);
|
||||
g_test_add_func ("/link/internal", test_internal);
|
||||
g_test_add_func ("/link/virtual/bridge", test_bridge);
|
||||
g_test_add_func ("/link/virtual/bond", test_bond);
|
||||
g_test_add_func ("/link/virtual/team", test_team);
|
||||
|
||||
if (strcmp (g_type_name (G_TYPE_FROM_INSTANCE (nm_platform_get ())), "NMFakePlatform"))
|
||||
g_test_add_func ("/link/external", test_external);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue