Blob Blame History Raw
commit 7546434030d456b13b2eda6138f183ac3bf29751
Author: Feras Daoud <ferasda@mellanox.com>
Date:   Wed Aug 9 18:27:32 2017 +0300

    ptp4l: Add IPoIB interface support for ptp4l
    
    The current implementation of ptp4l always assumes 6 octets MAC
    address, which is correct for Ethernet interfaces but not for IPoIB
    interfaces (that have 20 octets MAC), therefore running ptp4l over
    IPoIB interface does not function correctly.
    
    In Infiniband, every interface has three identifiers:
    GUID, GID, and LID.
    The GUID is similar in concept to a MAC address. From RFC4392:
    The EUI-64 portion of a GID is referred to as the Global Unique
    Identifier (GUID) and is the only persistent identifier of a port.
    
    Therefore, to support IPoIB interfaces, the GUID of the port should
    be used instead of the MAC.
    This patch checks the interface type before creating the clock identity,
    for Infiniband ports, it retrieves the GUID of the port using sysfs
    and use it to create the clock identity.
    
    sysfs method was chosen since the GUID is the 6 lsb bytes of
    the 20 byte device address, and SIOCGIFHWADDR ioctl call returns
    the 14 msb bytes of the device address, so it is not possible to
    get the GUID using SIOCGIFHWADDR ioctl call.
    
    [ RC: fixed trivial coding style error, space after switch keyword. ]
    
    Signed-off-by: Feras Daoud <ferasda@mellanox.com>
    Reviewed-by: Alex Vesker <valex@mellanox.com>

diff --git a/address.h b/address.h
index 7578f91..35ef05f 100644
--- a/address.h
+++ b/address.h
@@ -24,6 +24,7 @@
 #include <netpacket/packet.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <net/if_arp.h>
 
 struct address {
 	socklen_t len;
diff --git a/ether.h b/ether.h
index ce3d663..8ec9669 100644
--- a/ether.h
+++ b/ether.h
@@ -22,7 +22,13 @@
 
 #include <stdint.h>
 
-#define MAC_LEN 6
+#define EUI48 6
+#define EUI64 8
+
+#define MAC_LEN  EUI48
+#define GUID_LEN EUI64
+
+#define GUID_OFFSET 36
 
 typedef uint8_t eth_addr[MAC_LEN];
 
diff --git a/sk.c b/sk.c
index 63ec206..0cf55c5 100644
--- a/sk.c
+++ b/sk.c
@@ -159,10 +159,55 @@ failed:
 	return -1;
 }
 
+static int sk_interface_guidaddr(const char *name, unsigned char *guid)
+{
+	char file_name[64], buf[64], addr[8];
+	FILE *f;
+	char *err;
+	int res;
+
+	snprintf(file_name, sizeof buf, "/sys/class/net/%s/address", name);
+	f = fopen(file_name, "r");
+	if (!f) {
+		pr_err("failed to open %s: %m", buf);
+		return -1;
+	}
+
+	/* Set the file position to the beginning of the GUID */
+	res = fseek(f, GUID_OFFSET, SEEK_SET);
+	if (res) {
+		pr_err("fseek failed: %m");
+		goto error;
+	}
+
+	err = fgets(buf, sizeof buf, f);
+	if (err == NULL) {
+		pr_err("fseek failed: %m");
+		goto error;
+	}
+
+	res = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+			   &addr[0], &addr[1], &addr[2], &addr[3],
+			   &addr[4], &addr[5], &addr[6], &addr[7]);
+	if (res != GUID_LEN) {
+		pr_err("sscanf failed: %m");
+		goto error;
+	}
+
+	memcpy(guid, addr, GUID_LEN);
+	fclose(f);
+
+	return 0;
+
+error:
+	fclose(f);
+	return -1;
+}
+
 int sk_interface_macaddr(const char *name, struct address *mac)
 {
 	struct ifreq ifreq;
-	int err, fd;
+	int err, fd, type;
 
 	memset(&ifreq, 0, sizeof(ifreq));
 	strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name) - 1);
@@ -180,9 +225,23 @@ int sk_interface_macaddr(const char *name, struct address *mac)
 		return -1;
 	}
 
+	/* Get interface type */
+	type = ifreq.ifr_hwaddr.sa_family;
+	switch (type) {
+		case ARPHRD_INFINIBAND:
+			err = sk_interface_guidaddr(name, mac->sll.sll_addr);
+			if (err) {
+				pr_err("fail to get address using sysfs: %m");
+				return -1;
+			}
+			mac->sll.sll_halen = EUI64;
+			break;
+		default:
+			memcpy(mac->sll.sll_addr, &ifreq.ifr_hwaddr.sa_data, MAC_LEN);
+			mac->sll.sll_halen = EUI48;
+	}
+
 	mac->sll.sll_family = AF_PACKET;
-	mac->sll.sll_halen = MAC_LEN;
-	memcpy(mac->sll.sll_addr, &ifreq.ifr_hwaddr.sa_data, MAC_LEN);
 	mac->len = sizeof(mac->sll);
 	close(fd);
 	return 0;
diff --git a/util.c b/util.c
index 2b880ff..62f2638 100644
--- a/util.c
+++ b/util.c
@@ -135,14 +135,32 @@ int generate_clock_identity(struct ClockIdentity *ci, const char *name)
 
 	if (sk_interface_macaddr(name, &addr))
 		return -1;
-	ci->id[0] = addr.sll.sll_addr[0];
-	ci->id[1] = addr.sll.sll_addr[1];
-	ci->id[2] = addr.sll.sll_addr[2];
-	ci->id[3] = 0xFF;
-	ci->id[4] = 0xFE;
-	ci->id[5] = addr.sll.sll_addr[3];
-	ci->id[6] = addr.sll.sll_addr[4];
-	ci->id[7] = addr.sll.sll_addr[5];
+
+	switch (addr.sll.sll_halen) {
+		case EUI48:
+			ci->id[0] = addr.sll.sll_addr[0];
+			ci->id[1] = addr.sll.sll_addr[1];
+			ci->id[2] = addr.sll.sll_addr[2];
+			ci->id[3] = 0xFF;
+			ci->id[4] = 0xFE;
+			ci->id[5] = addr.sll.sll_addr[3];
+			ci->id[6] = addr.sll.sll_addr[4];
+			ci->id[7] = addr.sll.sll_addr[5];
+			break;
+		case EUI64:
+			ci->id[0] = addr.sll.sll_addr[0];
+			ci->id[1] = addr.sll.sll_addr[1];
+			ci->id[2] = addr.sll.sll_addr[2];
+			ci->id[3] = addr.sll.sll_addr[3];
+			ci->id[4] = addr.sll.sll_addr[4];
+			ci->id[5] = addr.sll.sll_addr[5];
+			ci->id[6] = addr.sll.sll_addr[6];
+			ci->id[7] = addr.sll.sll_addr[7];
+			break;
+		default:
+			return -1;
+	}
+
 	return 0;
 }
 
commit fd2646263f0fb1a31dde53e67ac24971ab1f90f4
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date:   Mon Oct 16 11:29:48 2017 +0200

    sk: don't leak socket when reading of IB GUID fails.
    
    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>

diff --git a/sk.c b/sk.c
index 0cf55c5..2c7593b 100644
--- a/sk.c
+++ b/sk.c
@@ -225,6 +225,8 @@ int sk_interface_macaddr(const char *name, struct address *mac)
 		return -1;
 	}
 
+	close(fd);
+
 	/* Get interface type */
 	type = ifreq.ifr_hwaddr.sa_family;
 	switch (type) {
@@ -243,7 +245,6 @@ int sk_interface_macaddr(const char *name, struct address *mac)
 
 	mac->sll.sll_family = AF_PACKET;
 	mac->len = sizeof(mac->sll);
-	close(fd);
 	return 0;
 }