Feras Daoud
2017-07-24 14:07:46 UTC
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.
Signed-off-by: Feras Daoud <***@mellanox.com>
---
address.h | 1 +
ether.h | 8 +++++++-
raw.c | 2 +-
sk.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++------
sk.h | 6 +++---
udp.c | 2 +-
udp6.c | 2 +-
util.c | 36 +++++++++++++++++++++++++++---------
8 files changed, 91 insertions(+), 22 deletions(-)
diff --git a/address.h b/address.h
index 7578f9148c3e..35ef05f66291 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 ce3d6630a839..8ec96691468b 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/raw.c b/raw.c
index 73e45b45bd25..559c93315154 100644
--- a/raw.c
+++ b/raw.c
@@ -220,7 +220,7 @@ static int raw_open(struct transport *t, const char *name,
mac_to_addr(&raw->ptp_addr, ptp_dst_mac);
mac_to_addr(&raw->p2p_addr, p2p_dst_mac);
- if (sk_interface_macaddr(name, &raw->src_addr))
+ if (sk_interface_hwaddr(name, &raw->src_addr))
goto no_mac;
efd = open_socket(name, 1, ptp_dst_mac, p2p_dst_mac);
diff --git a/sk.c b/sk.c
index 63ec20688efc..62bf759079d4 100644
--- a/sk.c
+++ b/sk.c
@@ -159,10 +159,40 @@ failed:
return -1;
}
-int sk_interface_macaddr(const char *name, struct address *mac)
+static int sk_interface_guidaddr(const char *name, unsigned char *guid)
+{
+ char file_name[64], buf[64], addr[8];
+ FILE *f;
+
+ snprintf(file_name, sizeof buf, "//sys//class//net//%s//address", name);
+ f = fopen(file_name, "r");
+ if (!f) {
+ printf("failed to open %s\n", buf);
+ return -1;
+ }
+
+ /* Set the file position to the beginning of the GUID */
+ fseek(f, GUID_OFFSET, SEEK_SET);
+
+ if (fgets(buf, sizeof buf, f) > 0) {
+ 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]);
+ } else {
+ fclose(f);
+ return -1;
+ }
+
+ memcpy(guid, addr, GUID_LEN);
+ fclose(f);
+
+ return 0;
+}
+
+int sk_interface_hwaddr(const char *name, struct address *addr)
{
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,10 +210,24 @@ int sk_interface_macaddr(const char *name, struct address *mac)
return -1;
}
- 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);
+ /* Get interface type */
+ type = ifreq.ifr_hwaddr.sa_family;
+ switch(type) {
+ case ARPHRD_INFINIBAND:
+ err = sk_interface_guidaddr(name, addr->sll.sll_addr);
+ if (err) {
+ pr_err("fail to get address using sysfs: %m");
+ return -1;
+ }
+ addr->sll.sll_halen = EUI64;
+ break;
+ default:
+ memcpy(addr->sll.sll_addr, &ifreq.ifr_hwaddr.sa_data, MAC_LEN);
+ addr->sll.sll_halen = EUI48;
+ }
+
+ addr->sll.sll_family = AF_PACKET;
+ addr->len = sizeof(addr->sll);
close(fd);
return 0;
}
diff --git a/sk.h b/sk.h
index d91d5d8640fd..a70beede7854 100644
--- a/sk.h
+++ b/sk.h
@@ -69,12 +69,12 @@ int sk_general_init(int fd);
int sk_get_ts_info(const char *name, struct sk_ts_info *sk_info);
/**
- * Obtain the MAC address of a network interface.
+ * Obtain the HW address of a network interface.
* @param name The name of the interface
- * @param mac Buffer to hold the result
+ * @param addr Buffer to hold the result
* @return Zero on success, non-zero otherwise.
*/
-int sk_interface_macaddr(const char *name, struct address *mac);
+int sk_interface_hwaddr(const char *name, struct address *addr);
/**
* Obtains the first IP address assigned to a network interface.
diff --git a/udp.c b/udp.c
index 530a2ee3748d..a549e5868a4f 100644
--- a/udp.c
+++ b/udp.c
@@ -161,7 +161,7 @@ static int udp_open(struct transport *t, const char *name, struct fdarray *fda,
ttl = config_get_int(t->cfg, name, "udp_ttl");
udp->mac.len = 0;
- sk_interface_macaddr(name, &udp->mac);
+ sk_interface_hwaddr(name, &udp->mac);
udp->ip.len = 0;
sk_interface_addr(name, AF_INET, &udp->ip);
diff --git a/udp6.c b/udp6.c
index 89e27bf9e863..90f82bfcd9d7 100644
--- a/udp6.c
+++ b/udp6.c
@@ -169,7 +169,7 @@ static int udp6_open(struct transport *t, const char *name, struct fdarray *fda,
hop_limit = config_get_int(t->cfg, name, "udp_ttl");
udp6->mac.len = 0;
- sk_interface_macaddr(name, &udp6->mac);
+ sk_interface_hwaddr(name, &udp6->mac);
udp6->ip.len = 0;
sk_interface_addr(name, AF_INET6, &udp6->ip);
diff --git a/util.c b/util.c
index 2b880ff3e46d..dd477638203b 100644
--- a/util.c
+++ b/util.c
@@ -133,16 +133,34 @@ int generate_clock_identity(struct ClockIdentity *ci, const char *name)
{
struct address addr;
- if (sk_interface_macaddr(name, &addr))
+ if (sk_interface_hwaddr(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;
}
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.
Signed-off-by: Feras Daoud <***@mellanox.com>
---
address.h | 1 +
ether.h | 8 +++++++-
raw.c | 2 +-
sk.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++------
sk.h | 6 +++---
udp.c | 2 +-
udp6.c | 2 +-
util.c | 36 +++++++++++++++++++++++++++---------
8 files changed, 91 insertions(+), 22 deletions(-)
diff --git a/address.h b/address.h
index 7578f9148c3e..35ef05f66291 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 ce3d6630a839..8ec96691468b 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/raw.c b/raw.c
index 73e45b45bd25..559c93315154 100644
--- a/raw.c
+++ b/raw.c
@@ -220,7 +220,7 @@ static int raw_open(struct transport *t, const char *name,
mac_to_addr(&raw->ptp_addr, ptp_dst_mac);
mac_to_addr(&raw->p2p_addr, p2p_dst_mac);
- if (sk_interface_macaddr(name, &raw->src_addr))
+ if (sk_interface_hwaddr(name, &raw->src_addr))
goto no_mac;
efd = open_socket(name, 1, ptp_dst_mac, p2p_dst_mac);
diff --git a/sk.c b/sk.c
index 63ec20688efc..62bf759079d4 100644
--- a/sk.c
+++ b/sk.c
@@ -159,10 +159,40 @@ failed:
return -1;
}
-int sk_interface_macaddr(const char *name, struct address *mac)
+static int sk_interface_guidaddr(const char *name, unsigned char *guid)
+{
+ char file_name[64], buf[64], addr[8];
+ FILE *f;
+
+ snprintf(file_name, sizeof buf, "//sys//class//net//%s//address", name);
+ f = fopen(file_name, "r");
+ if (!f) {
+ printf("failed to open %s\n", buf);
+ return -1;
+ }
+
+ /* Set the file position to the beginning of the GUID */
+ fseek(f, GUID_OFFSET, SEEK_SET);
+
+ if (fgets(buf, sizeof buf, f) > 0) {
+ 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]);
+ } else {
+ fclose(f);
+ return -1;
+ }
+
+ memcpy(guid, addr, GUID_LEN);
+ fclose(f);
+
+ return 0;
+}
+
+int sk_interface_hwaddr(const char *name, struct address *addr)
{
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,10 +210,24 @@ int sk_interface_macaddr(const char *name, struct address *mac)
return -1;
}
- 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);
+ /* Get interface type */
+ type = ifreq.ifr_hwaddr.sa_family;
+ switch(type) {
+ case ARPHRD_INFINIBAND:
+ err = sk_interface_guidaddr(name, addr->sll.sll_addr);
+ if (err) {
+ pr_err("fail to get address using sysfs: %m");
+ return -1;
+ }
+ addr->sll.sll_halen = EUI64;
+ break;
+ default:
+ memcpy(addr->sll.sll_addr, &ifreq.ifr_hwaddr.sa_data, MAC_LEN);
+ addr->sll.sll_halen = EUI48;
+ }
+
+ addr->sll.sll_family = AF_PACKET;
+ addr->len = sizeof(addr->sll);
close(fd);
return 0;
}
diff --git a/sk.h b/sk.h
index d91d5d8640fd..a70beede7854 100644
--- a/sk.h
+++ b/sk.h
@@ -69,12 +69,12 @@ int sk_general_init(int fd);
int sk_get_ts_info(const char *name, struct sk_ts_info *sk_info);
/**
- * Obtain the MAC address of a network interface.
+ * Obtain the HW address of a network interface.
* @param name The name of the interface
- * @param mac Buffer to hold the result
+ * @param addr Buffer to hold the result
* @return Zero on success, non-zero otherwise.
*/
-int sk_interface_macaddr(const char *name, struct address *mac);
+int sk_interface_hwaddr(const char *name, struct address *addr);
/**
* Obtains the first IP address assigned to a network interface.
diff --git a/udp.c b/udp.c
index 530a2ee3748d..a549e5868a4f 100644
--- a/udp.c
+++ b/udp.c
@@ -161,7 +161,7 @@ static int udp_open(struct transport *t, const char *name, struct fdarray *fda,
ttl = config_get_int(t->cfg, name, "udp_ttl");
udp->mac.len = 0;
- sk_interface_macaddr(name, &udp->mac);
+ sk_interface_hwaddr(name, &udp->mac);
udp->ip.len = 0;
sk_interface_addr(name, AF_INET, &udp->ip);
diff --git a/udp6.c b/udp6.c
index 89e27bf9e863..90f82bfcd9d7 100644
--- a/udp6.c
+++ b/udp6.c
@@ -169,7 +169,7 @@ static int udp6_open(struct transport *t, const char *name, struct fdarray *fda,
hop_limit = config_get_int(t->cfg, name, "udp_ttl");
udp6->mac.len = 0;
- sk_interface_macaddr(name, &udp6->mac);
+ sk_interface_hwaddr(name, &udp6->mac);
udp6->ip.len = 0;
sk_interface_addr(name, AF_INET6, &udp6->ip);
diff --git a/util.c b/util.c
index 2b880ff3e46d..dd477638203b 100644
--- a/util.c
+++ b/util.c
@@ -133,16 +133,34 @@ int generate_clock_identity(struct ClockIdentity *ci, const char *name)
{
struct address addr;
- if (sk_interface_macaddr(name, &addr))
+ if (sk_interface_hwaddr(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;
}
--
1.8.3.1
1.8.3.1