summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2015-03-27 15:14:25 -0500
committerDan Williams <dcbw@redhat.com>2015-03-27 15:15:29 -0500
commitd997cde995ecf8b75ac46f3c63abd13956262782 (patch)
tree81d5f08cd40ee9c5b2db4e96b8710f5b029099b1
parent8173f0f9e8045638f491e55150352576682879dd (diff)
parent99a620126448101a64515957c3882f3ea8ec9151 (diff)
downloadNetworkManager-d997cde995ecf8b75ac46f3c63abd13956262782.tar.gz
merge: use dev_id when constructing interface identifiers (rh #1101809)
Some devices (s390 and ipvlan) use the same MAC address for different interfaces, but dev_id differentiates them. So we must use dev_id to avoid IID conflicts. https://bugzilla.redhat.com/show_bug.cgi?id=1101809
-rw-r--r--src/NetworkManagerUtils.c17
-rw-r--r--src/NetworkManagerUtils.h1
-rw-r--r--src/devices/nm-device.c4
-rw-r--r--src/platform/nm-fake-platform.c10
-rw-r--r--src/platform/nm-linux-platform.c25
-rw-r--r--src/platform/nm-platform.c30
-rw-r--r--src/platform/nm-platform.h4
7 files changed, 85 insertions, 6 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 57f817649e..f28b783e58 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -2351,6 +2351,7 @@ get_gre_eui64_u_bit (guint32 addr)
* @link_type: the hardware link type
* @hwaddr: the hardware address of the interface
* @hwaddr_len: the length (in bytes) of @hwaddr
+ * @dev_id: the device identifier, if any
* @out_iid: on success, filled with the interface identifier; on failure
* zeroed out
*
@@ -2365,6 +2366,7 @@ gboolean
nm_utils_get_ipv6_interface_identifier (NMLinkType link_type,
const guint8 *hwaddr,
guint hwaddr_len,
+ guint dev_id,
NMUtilsIPv6IfaceId *out_iid)
{
guint32 addr;
@@ -2399,13 +2401,20 @@ nm_utils_get_ipv6_interface_identifier (NMLinkType link_type,
default:
if (hwaddr_len == ETH_ALEN) {
/* Translate 48-bit MAC address to a 64-bit Modified EUI-64. See
- * http://tools.ietf.org/html/rfc4291#appendix-A
+ * http://tools.ietf.org/html/rfc4291#appendix-A and the Linux
+ * kernel's net/ipv6/addrconf.c::ipv6_generate_eui64() function.
*/
- out_iid->id_u8[0] = hwaddr[0] ^ 0x02;
+ out_iid->id_u8[0] = hwaddr[0];
out_iid->id_u8[1] = hwaddr[1];
out_iid->id_u8[2] = hwaddr[2];
- out_iid->id_u8[3] = 0xff;
- out_iid->id_u8[4] = 0xfe;
+ if (dev_id) {
+ out_iid->id_u8[3] = (dev_id >> 8) & 0xff;
+ out_iid->id_u8[4] = dev_id & 0xff;
+ } else {
+ out_iid->id_u8[0] ^= 0x02;
+ out_iid->id_u8[3] = 0xff;
+ out_iid->id_u8[4] = 0xfe;
+ }
out_iid->id_u8[5] = hwaddr[3];
out_iid->id_u8[6] = hwaddr[4];
out_iid->id_u8[7] = hwaddr[5];
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index 23d8330a34..11dc496b4f 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -198,6 +198,7 @@ struct _NMUtilsIPv6IfaceId {
gboolean nm_utils_get_ipv6_interface_identifier (NMLinkType link_type,
const guint8 *hwaddr,
guint len,
+ guint dev_id,
NMUtilsIPv6IfaceId *out_iid);
void nm_utils_ipv6_addr_set_interface_identfier (struct in6_addr *addr,
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index ddc213c0a4..bf10abe6c5 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -201,6 +201,7 @@ typedef struct {
char * hw_addr;
guint hw_addr_len;
char * physical_port_id;
+ guint dev_id;
NMUnmanagedFlags unmanaged_flags;
gboolean is_nm_owned; /* whether the device is a device owned and created by NM */
@@ -600,6 +601,7 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface)
static gboolean
get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid)
{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMLinkType link_type;
const guint8 *hwaddr = NULL;
size_t hwaddr_len = 0;
@@ -620,6 +622,7 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid)
success = nm_utils_get_ipv6_interface_identifier (link_type,
hwaddr,
hwaddr_len,
+ priv->dev_id,
out_iid);
if (!success) {
_LOGW (LOGD_HW, "failed to generate interface identifier "
@@ -8472,6 +8475,7 @@ constructed (GObject *object)
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);
+ priv->dev_id = nm_platform_link_get_dev_id (priv->ifindex);
priv->mtu = nm_platform_link_get_mtu (priv->ifindex);
}
/* Indicate software device in capabilities. */
diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c
index 7194707b29..8288fb9fc4 100644
--- a/src/platform/nm-fake-platform.c
+++ b/src/platform/nm-fake-platform.c
@@ -488,6 +488,15 @@ link_get_physical_port_id (NMPlatform *platform, int ifindex)
return NULL;
}
+static guint
+link_get_dev_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 0;
+}
+
static gboolean
link_get_wake_on_lan (NMPlatform *platform, int ifindex)
{
@@ -1406,6 +1415,7 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
platform_class->link_set_mtu = link_set_mtu;
platform_class->link_get_physical_port_id = link_get_physical_port_id;
+ platform_class->link_get_dev_id = link_get_dev_id;
platform_class->link_get_wake_on_lan = link_get_wake_on_lan;
platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 14f791106d..76a2feb52b 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -2744,6 +2744,30 @@ link_get_physical_port_id (NMPlatform *platform, int ifindex)
return id;
}
+static guint
+link_get_dev_id (NMPlatform *platform, int ifindex)
+{
+ const char *ifname;
+ gs_free char *path = NULL, *id = NULL;
+ gint64 int_val;
+
+ ifname = nm_platform_link_get_name (ifindex);
+ if (!ifname)
+ return 0;
+
+ ifname = ASSERT_VALID_PATH_COMPONENT (ifname);
+
+ path = g_strdup_printf ("/sys/class/net/%s/dev_id", ifname);
+ id = sysctl_get (platform, path);
+ if (!id || !*id)
+ return 0;
+
+ /* Value is reported as hex */
+ int_val = _nm_utils_ascii_str_to_int64 (id, 16, 0, G_MAXUINT16, 0);
+
+ return errno ? 0 : (int) int_val;
+}
+
static int
vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags)
{
@@ -4608,6 +4632,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->link_set_mtu = link_set_mtu;
platform_class->link_get_physical_port_id = link_get_physical_port_id;
+ platform_class->link_get_dev_id = link_get_dev_id;
platform_class->link_get_wake_on_lan = link_get_wake_on_lan;
platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index d51c142e04..e4e5dbaa6a 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -1008,9 +1008,15 @@ nm_platform_link_get_mtu (int ifindex)
}
/**
- * nm_platform_link_get_mtu:
+ * nm_platform_link_get_physical_port_id:
* @ifindex: Interface index
*
+ * The physical port ID, if present, indicates some unique identifier of
+ * the parent interface (eg, the physical port of which this link is a child).
+ * Two links that report the same physical port ID can be assumed to be
+ * children of the same physical port and may share resources that limit
+ * their abilities.
+ *
* Returns: physical port ID for the interface, or %NULL on error
* or if the interface has no physical port ID.
*/
@@ -1026,6 +1032,28 @@ nm_platform_link_get_physical_port_id (int ifindex)
}
/**
+ * nm_platform_link_get_dev_id:
+ * @ifindex: Interface index
+ *
+ * In contrast to the physical device ID (which indicates which parent a
+ * child has) the device ID differentiates sibling devices that may share
+ * the same MAC address.
+ *
+ * Returns: device ID for the interface, or 0 on error or if the
+ * interface has no device ID.
+ */
+guint
+nm_platform_link_get_dev_id (int ifindex)
+{
+ reset_error ();
+
+ g_return_val_if_fail (ifindex >= 0, 0);
+ g_return_val_if_fail (klass->link_get_dev_id, 0);
+
+ return klass->link_get_dev_id (platform, ifindex);
+}
+
+/**
* nm_platform_link_get_wake_onlan:
* @ifindex: Interface index
*
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index bc7b84c9ff..b90343d79f 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -373,7 +373,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);
+ char * (*link_get_physical_port_id) (NMPlatform *, int ifindex);
+ guint (*link_get_dev_id) (NMPlatform *, int ifindex);
gboolean (*link_get_wake_on_lan) (NMPlatform *, int ifindex);
gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex);
@@ -524,6 +525,7 @@ 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);
+guint nm_platform_link_get_dev_id (int ifindex);
gboolean nm_platform_link_get_wake_on_lan (int ifindex);
gboolean nm_platform_link_supports_carrier_detect (int ifindex);