mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-06 16:21:50 +00:00
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:
parent
a4dcd66698
commit
b7300bbe5a
|
@ -125,6 +125,14 @@
|
|||
An array of object paths of every configured connection that is currently 'available' through this device.
|
||||
</tp:docstring>
|
||||
</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">
|
||||
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_device_disconnect"/>
|
||||
|
|
|
@ -364,6 +364,8 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
|
|||
const char *iface = nm_device_get_ip_iface (device);
|
||||
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);
|
||||
|
||||
success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device),
|
||||
|
|
|
@ -92,6 +92,9 @@ gboolean nm_device_get_enslaved (NMDevice *device);
|
|||
|
||||
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);
|
||||
|
||||
#endif /* NM_DEVICE_PRIVATE_H */
|
||||
|
|
|
@ -546,6 +546,8 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
|
|||
const char *slave_iface = nm_device_get_ip_iface (slave);
|
||||
NMSettingTeamPort *s_team_port;
|
||||
|
||||
nm_device_master_check_slave_physical_port (device, slave, LOGD_TEAM);
|
||||
|
||||
nm_device_take_down (slave, TRUE);
|
||||
|
||||
s_team_port = nm_connection_get_setting_team_port (connection);
|
||||
|
|
|
@ -129,6 +129,7 @@ enum {
|
|||
PROP_RFKILL_TYPE,
|
||||
PROP_IFINDEX,
|
||||
PROP_AVAILABLE_CONNECTIONS,
|
||||
PROP_PHYSICAL_PORT_ID,
|
||||
PROP_IS_MASTER,
|
||||
PROP_HW_ADDRESS,
|
||||
PROP_HAS_PENDING_ACTION,
|
||||
|
@ -202,6 +203,7 @@ typedef struct {
|
|||
GHashTable * available_connections;
|
||||
guint8 hw_addr[NM_UTILS_HWADDR_LEN_MAX];
|
||||
guint hw_addr_len;
|
||||
char * physical_port_id;
|
||||
|
||||
gboolean manager_managed; /* whether managed by NMManager or not */
|
||||
gboolean default_unmanaged; /* whether unmanaged by default */
|
||||
|
@ -589,8 +591,10 @@ constructed (GObject *object)
|
|||
priv->carrier = TRUE;
|
||||
}
|
||||
|
||||
if (priv->ifindex > 0)
|
||||
if (priv->ifindex > 0) {
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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:
|
||||
* @dev: the device
|
||||
|
@ -5172,6 +5219,8 @@ dispose (GObject *object)
|
|||
g_hash_table_unref (priv->available_connections);
|
||||
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_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_value_take_boxed (value, array);
|
||||
break;
|
||||
case PROP_PHYSICAL_PORT_ID:
|
||||
g_value_set_string (value, priv->physical_port_id);
|
||||
break;
|
||||
case PROP_IS_MASTER:
|
||||
g_value_set_boolean (value, priv->is_master);
|
||||
break;
|
||||
|
@ -5688,6 +5740,14 @@ nm_device_class_init (NMDeviceClass *klass)
|
|||
DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH,
|
||||
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
|
||||
(object_class, PROP_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;
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_device_get_physical_port_id (NMDevice *device)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
|
||||
|
||||
return priv->physical_port_id;
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
#define NM_DEVICE_AUTOCONNECT "autoconnect"
|
||||
#define NM_DEVICE_FIRMWARE_MISSING "firmware-missing"
|
||||
#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_RFKILL_TYPE "rfkill-type" /* 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,
|
||||
const char *specific_object);
|
||||
|
||||
const char *nm_device_get_physical_port_id (NMDevice *device);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
/* For testing only */
|
||||
|
|
|
@ -466,6 +466,15 @@ link_get_mtu (NMPlatform *platform, int ifindex)
|
|||
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
|
||||
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_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_vlans = link_supports_vlans;
|
||||
|
||||
|
|
|
@ -1725,6 +1725,26 @@ link_get_mtu (NMPlatform *platform, int ifindex)
|
|||
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
|
||||
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_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_vlans = link_supports_vlans;
|
||||
|
||||
|
|
|
@ -733,6 +733,24 @@ nm_platform_link_get_mtu (int 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:
|
||||
* @master: Interface index of the master
|
||||
|
|
|
@ -251,6 +251,8 @@ typedef struct {
|
|||
guint32 (*link_get_mtu) (NMPlatform *, int ifindex);
|
||||
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_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);
|
||||
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_vlans (int ifindex);
|
||||
|
||||
|
|
Loading…
Reference in a new issue