diff options
author | Dan Williams <dcbw@redhat.com> | 2015-03-27 15:14:25 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2015-03-27 15:15:29 -0500 |
commit | d997cde995ecf8b75ac46f3c63abd13956262782 (patch) | |
tree | 81d5f08cd40ee9c5b2db4e96b8710f5b029099b1 | |
parent | 8173f0f9e8045638f491e55150352576682879dd (diff) | |
parent | 99a620126448101a64515957c3882f3ea8ec9151 (diff) | |
download | NetworkManager-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.c | 17 | ||||
-rw-r--r-- | src/NetworkManagerUtils.h | 1 | ||||
-rw-r--r-- | src/devices/nm-device.c | 4 | ||||
-rw-r--r-- | src/platform/nm-fake-platform.c | 10 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 25 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 30 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 4 |
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); |