core: improve handling of NPAR/SR-IOV devices (rh #804527)

Use the new kernel physical_port_id interface property to recognize
when two devices are just virtual devices sharing the same physical
port, and refuse to bond/team multiple slaves on the same port.
This commit is contained in:
Dan Winship
2013-10-11 14:59:26 -04:00
parent a4dcd66698
commit b7300bbe5a
10 changed files with 142 additions and 1 deletions

View File

@@ -125,6 +125,14 @@
An array of object paths of every configured connection that is currently 'available' through this device. An array of object paths of every configured connection that is currently 'available' through this device.
</tp:docstring> </tp:docstring>
</property> </property>
<property name="PhysicalPortId" type="s" access="read">
<tp:docstring>
If non-empty, an (opaque) indicator of the physical network
port associated with the device. This can be used to recognize
when two seemingly-separate hardware devices are actually just
different virtual interfaces to the same physical port.
</tp:docstring>
</property>
<method name="Disconnect"> <method name="Disconnect">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_device_disconnect"/> <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_device_disconnect"/>

View File

@@ -364,6 +364,8 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
const char *iface = nm_device_get_ip_iface (device); const char *iface = nm_device_get_ip_iface (device);
const char *slave_iface = nm_device_get_ip_iface (slave); const char *slave_iface = nm_device_get_ip_iface (slave);
nm_device_master_check_slave_physical_port (device, slave, LOGD_BOND);
nm_device_take_down (slave, TRUE); nm_device_take_down (slave, TRUE);
success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device), success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device),

View File

@@ -92,6 +92,9 @@ gboolean nm_device_get_enslaved (NMDevice *device);
NMDevice *nm_device_master_get_slave_by_ifindex (NMDevice *dev, int ifindex); NMDevice *nm_device_master_get_slave_by_ifindex (NMDevice *dev, int ifindex);
void nm_device_master_check_slave_physical_port (NMDevice *dev, NMDevice *slave,
guint64 log_domain);
void nm_device_set_carrier (NMDevice *device, gboolean carrier); void nm_device_set_carrier (NMDevice *device, gboolean carrier);
#endif /* NM_DEVICE_PRIVATE_H */ #endif /* NM_DEVICE_PRIVATE_H */

View File

@@ -546,6 +546,8 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
const char *slave_iface = nm_device_get_ip_iface (slave); const char *slave_iface = nm_device_get_ip_iface (slave);
NMSettingTeamPort *s_team_port; NMSettingTeamPort *s_team_port;
nm_device_master_check_slave_physical_port (device, slave, LOGD_TEAM);
nm_device_take_down (slave, TRUE); nm_device_take_down (slave, TRUE);
s_team_port = nm_connection_get_setting_team_port (connection); s_team_port = nm_connection_get_setting_team_port (connection);

View File

@@ -129,6 +129,7 @@ enum {
PROP_RFKILL_TYPE, PROP_RFKILL_TYPE,
PROP_IFINDEX, PROP_IFINDEX,
PROP_AVAILABLE_CONNECTIONS, PROP_AVAILABLE_CONNECTIONS,
PROP_PHYSICAL_PORT_ID,
PROP_IS_MASTER, PROP_IS_MASTER,
PROP_HW_ADDRESS, PROP_HW_ADDRESS,
PROP_HAS_PENDING_ACTION, PROP_HAS_PENDING_ACTION,
@@ -202,6 +203,7 @@ typedef struct {
GHashTable * available_connections; GHashTable * available_connections;
guint8 hw_addr[NM_UTILS_HWADDR_LEN_MAX]; guint8 hw_addr[NM_UTILS_HWADDR_LEN_MAX];
guint hw_addr_len; guint hw_addr_len;
char * physical_port_id;
gboolean manager_managed; /* whether managed by NMManager or not */ gboolean manager_managed; /* whether managed by NMManager or not */
gboolean default_unmanaged; /* whether unmanaged by default */ gboolean default_unmanaged; /* whether unmanaged by default */
@@ -589,8 +591,10 @@ constructed (GObject *object)
priv->carrier = TRUE; priv->carrier = TRUE;
} }
if (priv->ifindex > 0) if (priv->ifindex > 0) {
priv->is_software = nm_platform_link_is_software (priv->ifindex); priv->is_software = nm_platform_link_is_software (priv->ifindex);
priv->physical_port_id = nm_platform_link_get_physical_port_id (priv->ifindex);
}
if (G_OBJECT_CLASS (nm_device_parent_class)->constructed) if (G_OBJECT_CLASS (nm_device_parent_class)->constructed)
G_OBJECT_CLASS (nm_device_parent_class)->constructed (object); G_OBJECT_CLASS (nm_device_parent_class)->constructed (object);
@@ -1337,6 +1341,49 @@ nm_device_master_get_slave_by_ifindex (NMDevice *dev, int ifindex)
return NULL; return NULL;
} }
/**
* nm_device_master_check_slave_physical_port:
* @dev: the master device
* @slave: a slave device
* @log_domain: domain to log a warning in
*
* Checks if @dev already has a slave with the same #NMDevice:physical-port-id
* as @slave, and logs a warning if so.
*/
void
nm_device_master_check_slave_physical_port (NMDevice *dev, NMDevice *slave,
guint64 log_domain)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev);
const char *slave_physical_port_id, *existing_physical_port_id;
SlaveInfo *info;
GSList *iter;
slave_physical_port_id = nm_device_get_physical_port_id (slave);
if (!slave_physical_port_id)
return;
for (iter = priv->slaves; iter; iter = iter->next) {
info = iter->data;
if (info->slave == slave)
continue;
existing_physical_port_id = nm_device_get_physical_port_id (info->slave);
if (!g_strcmp0 (slave_physical_port_id, existing_physical_port_id)) {
nm_log_warn (log_domain, "(%s): slave %s shares a physical port with existing slave %s",
nm_device_get_ip_iface (dev),
nm_device_get_ip_iface (slave),
nm_device_get_ip_iface (info->slave));
/* Since this function will get called for every slave, we only have
* to warn about the first match we find; if there are other matches
* later in the list, we will have already warned about them matching
* @existing earlier.
*/
return;
}
}
}
/** /**
* nm_device_is_master: * nm_device_is_master:
* @dev: the device * @dev: the device
@@ -5172,6 +5219,8 @@ dispose (GObject *object)
g_hash_table_unref (priv->available_connections); g_hash_table_unref (priv->available_connections);
priv->available_connections = NULL; priv->available_connections = NULL;
g_clear_pointer (&priv->physical_port_id, g_free);
activation_source_clear (self, TRUE, AF_INET); activation_source_clear (self, TRUE, AF_INET);
activation_source_clear (self, TRUE, AF_INET6); activation_source_clear (self, TRUE, AF_INET6);
@@ -5432,6 +5481,9 @@ get_property (GObject *object, guint prop_id,
g_ptr_array_add (array, g_strdup (nm_connection_get_path (connection))); g_ptr_array_add (array, g_strdup (nm_connection_get_path (connection)));
g_value_take_boxed (value, array); g_value_take_boxed (value, array);
break; break;
case PROP_PHYSICAL_PORT_ID:
g_value_set_string (value, priv->physical_port_id);
break;
case PROP_IS_MASTER: case PROP_IS_MASTER:
g_value_set_boolean (value, priv->is_master); g_value_set_boolean (value, priv->is_master);
break; break;
@@ -5688,6 +5740,14 @@ nm_device_class_init (NMDeviceClass *klass)
DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH,
G_PARAM_READABLE)); G_PARAM_READABLE));
g_object_class_install_property
(object_class, PROP_PHYSICAL_PORT_ID,
g_param_spec_string (NM_DEVICE_PHYSICAL_PORT_ID,
"PhysicalPortId",
"PhysicalPortId",
NULL,
G_PARAM_READABLE));
g_object_class_install_property g_object_class_install_property
(object_class, PROP_IS_MASTER, (object_class, PROP_IS_MASTER,
g_param_spec_boolean (NM_DEVICE_IS_MASTER, g_param_spec_boolean (NM_DEVICE_IS_MASTER,
@@ -6908,3 +6968,11 @@ nm_device_has_pending_action (NMDevice *device)
return priv->pending_actions > 0; return priv->pending_actions > 0;
} }
const char *
nm_device_get_physical_port_id (NMDevice *device)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
return priv->physical_port_id;
}

View File

@@ -60,6 +60,7 @@
#define NM_DEVICE_AUTOCONNECT "autoconnect" #define NM_DEVICE_AUTOCONNECT "autoconnect"
#define NM_DEVICE_FIRMWARE_MISSING "firmware-missing" #define NM_DEVICE_FIRMWARE_MISSING "firmware-missing"
#define NM_DEVICE_AVAILABLE_CONNECTIONS "available-connections" #define NM_DEVICE_AVAILABLE_CONNECTIONS "available-connections"
#define NM_DEVICE_PHYSICAL_PORT_ID "physical-port-id"
#define NM_DEVICE_TYPE_DESC "type-desc" /* Internal only */ #define NM_DEVICE_TYPE_DESC "type-desc" /* Internal only */
#define NM_DEVICE_RFKILL_TYPE "rfkill-type" /* Internal only */ #define NM_DEVICE_RFKILL_TYPE "rfkill-type" /* Internal only */
#define NM_DEVICE_IFINDEX "ifindex" /* Internal only */ #define NM_DEVICE_IFINDEX "ifindex" /* Internal only */
@@ -337,6 +338,8 @@ gboolean nm_device_has_pending_action (NMDevice *device);
GPtrArray *nm_device_get_available_connections (NMDevice *device, GPtrArray *nm_device_get_available_connections (NMDevice *device,
const char *specific_object); const char *specific_object);
const char *nm_device_get_physical_port_id (NMDevice *device);
G_END_DECLS G_END_DECLS
/* For testing only */ /* For testing only */

View File

@@ -466,6 +466,15 @@ link_get_mtu (NMPlatform *platform, int ifindex)
return device ? device->link.mtu : 0; return device ? device->link.mtu : 0;
} }
static char *
link_get_physical_port_id (NMPlatform *platform, int ifindex)
{
/* We call link_get just to cause an error to be set if @ifindex is bad. */
link_get (platform, ifindex);
return NULL;
}
static gboolean static gboolean
link_supports_carrier_detect (NMPlatform *platform, int ifindex) link_supports_carrier_detect (NMPlatform *platform, int ifindex)
{ {
@@ -1189,6 +1198,8 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
platform_class->link_get_mtu = link_get_mtu; platform_class->link_get_mtu = link_get_mtu;
platform_class->link_set_mtu = link_set_mtu; platform_class->link_set_mtu = link_set_mtu;
platform_class->link_get_physical_port_id = link_get_physical_port_id;
platform_class->link_supports_carrier_detect = link_supports_carrier_detect; platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
platform_class->link_supports_vlans = link_supports_vlans; platform_class->link_supports_vlans = link_supports_vlans;

View File

@@ -1725,6 +1725,26 @@ link_get_mtu (NMPlatform *platform, int ifindex)
return rtnllink ? rtnl_link_get_mtu (rtnllink) : 0; return rtnllink ? rtnl_link_get_mtu (rtnllink) : 0;
} }
static char *
link_get_physical_port_id (NMPlatform *platform, int ifindex)
{
const char *ifname;
char *path, *id;
ifname = nm_platform_link_get_name (ifindex);
if (!ifname)
return NULL;
path = g_strdup_printf ("/sys/class/net/%s/physical_port_id", ifname);
if (g_file_test (path, G_FILE_TEST_EXISTS))
id = sysctl_get (platform, path);
else
id = NULL;
g_free (path);
return id;
}
static int static int
vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags) vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags)
{ {
@@ -2719,6 +2739,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->link_get_mtu = link_get_mtu; platform_class->link_get_mtu = link_get_mtu;
platform_class->link_set_mtu = link_set_mtu; platform_class->link_set_mtu = link_set_mtu;
platform_class->link_get_physical_port_id = link_get_physical_port_id;
platform_class->link_supports_carrier_detect = link_supports_carrier_detect; platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
platform_class->link_supports_vlans = link_supports_vlans; platform_class->link_supports_vlans = link_supports_vlans;

View File

@@ -733,6 +733,24 @@ nm_platform_link_get_mtu (int ifindex)
return klass->link_get_mtu (platform, ifindex); return klass->link_get_mtu (platform, ifindex);
} }
/**
* nm_platform_link_get_mtu:
* @ifindex: Interface index
*
* Returns: physical port ID for the interface, or %NULL on error
* or if the interface has no physical port ID.
*/
char *
nm_platform_link_get_physical_port_id (int ifindex)
{
reset_error ();
g_return_val_if_fail (ifindex >= 0, NULL);
g_return_val_if_fail (klass->link_get_physical_port_id, NULL);
return klass->link_get_physical_port_id (platform, ifindex);
}
/** /**
* nm_platform_link_enslave: * nm_platform_link_enslave:
* @master: Interface index of the master * @master: Interface index of the master

View File

@@ -251,6 +251,8 @@ typedef struct {
guint32 (*link_get_mtu) (NMPlatform *, int ifindex); guint32 (*link_get_mtu) (NMPlatform *, int ifindex);
gboolean (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu); gboolean (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu);
char * (*link_get_physical_port_id) (NMPlatform *, int ifindex);
gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex); gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex);
gboolean (*link_supports_vlans) (NMPlatform *, int ifindex); gboolean (*link_supports_vlans) (NMPlatform *, int ifindex);
@@ -370,6 +372,8 @@ gboolean nm_platform_link_set_address (int ifindex, const void *address, size_t
guint32 nm_platform_link_get_mtu (int ifindex); guint32 nm_platform_link_get_mtu (int ifindex);
gboolean nm_platform_link_set_mtu (int ifindex, guint32 mtu); gboolean nm_platform_link_set_mtu (int ifindex, guint32 mtu);
char *nm_platform_link_get_physical_port_id (int ifindex);
gboolean nm_platform_link_supports_carrier_detect (int ifindex); gboolean nm_platform_link_supports_carrier_detect (int ifindex);
gboolean nm_platform_link_supports_vlans (int ifindex); gboolean nm_platform_link_supports_vlans (int ifindex);