From 9a7ded387a87accd6437b3e36748d4451e8135f4 Mon Sep 17 00:00:00 2001 From: Erik Ekman Date: Tue, 2 Nov 2021 14:56:25 +0100 Subject: [PATCH 65/65] merge Github PR#77 --- src/core/network.cc | 128 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/src/core/network.cc b/src/core/network.cc index 01a1f51..746ac1b 100644 --- a/src/core/network.cc +++ b/src/core/network.cc @@ -93,6 +93,41 @@ struct ethtool_link_settings supported, advertised, peer advertised. */ }; +/* Recognized module eeprom standards. */ +#define ETH_MODULE_SFF_8079 0x1 +#define ETH_MODULE_SFF_8472 0x2 +#define ETH_MODULE_SFF_8636 0x3 +#define ETH_MODULE_SFF_8436 0x4 + +struct ethtool_modinfo { + u32 cmd; + u32 type; /* SFF standard used in module */ + u32 eeprom_len; /* Length of module eeprom */ + u32 reserved[8]; +}; + +/* Known id types. */ +#define SFF_8024_ID_SOLDERED 0x2 +#define SFF_8024_ID_SFP 0x3 +#define SFF_8024_EXT_ID_DEFINED_BY_2WIRE_ID 0x4 + +/* Common connector types. */ +#define SFF_8024_CONNECTOR_SC 0x1 +#define SFF_8024_CONNECTOR_LC 0x7 +#define SFF_8024_CONNECTOR_OPTICAL_PIGTAIL 0xb +#define SFF_8024_CONNECTOR_COPPER_PIGTAIL 0x21 +#define SFF_8024_CONNECTOR_RJ45 0x22 +#define SFF_8024_CONNECTOR_NON_SEPARABLE 0x23 + +#define MAX_EEPROM_SIZE 256 +struct ethtool_eeprom { + u32 cmd; + u32 magic; /* Only used for eeprom writes */ + u32 offset; /* Read or write offset */ + u32 len; /* Length of read/write */ + u8 data[MAX_EEPROM_SIZE]; /* Buffer */ +}; + #ifndef IFNAMSIZ #define IFNAMSIZ 32 #endif @@ -131,6 +166,8 @@ struct ethtool_value #define ETHTOOL_GSET 0x00000001 /* Get settings. */ #define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */ #define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */ +#define ETHTOOL_GMODULEINFO 0x00000042 /* Get plug-in module information */ +#define ETHTOOL_GMODULEEEPROM 0x00000043 /* Get plug-in module eeprom */ #define ETHTOOL_GLINKSETTINGS 0x0000004c /* Get link mode settings. */ /* Indicates what features are supported by the interface. */ @@ -358,6 +395,96 @@ static bool isVirtual(const string & MAC) } +// Get data for connected transceiver module. +static void scan_module(hwNode & interface, int fd) +{ + struct ifreq ifr; + struct ethtool_modinfo emodinfo; + struct ethtool_eeprom eeeprom; + + emodinfo.cmd = ETHTOOL_GMODULEINFO; + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, interface.getLogicalName().c_str()); + ifr.ifr_data = (caddr_t) &emodinfo; + // Skip interface if module info not supported. + if (ioctl(fd, SIOCETHTOOL, &ifr) != 0) + return; + + eeeprom.cmd = ETHTOOL_GMODULEEEPROM; + eeeprom.offset = 0; + eeeprom.len = emodinfo.eeprom_len; + if (eeeprom.len > MAX_EEPROM_SIZE) + eeeprom.len = MAX_EEPROM_SIZE; + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, interface.getLogicalName().c_str()); + ifr.ifr_data = (caddr_t) &eeeprom; + if (ioctl(fd, SIOCETHTOOL, &ifr) != 0) + return; + + switch (emodinfo.type) + { + /* SFF 8472 eeprom layout starts with same data as SFF 8079. */ + case ETH_MODULE_SFF_8079: + case ETH_MODULE_SFF_8472: + if ((eeeprom.data[0] == SFF_8024_ID_SOLDERED || eeeprom.data[0] == SFF_8024_ID_SFP) && + eeeprom.data[1] == SFF_8024_EXT_ID_DEFINED_BY_2WIRE_ID) + { + char buffer[32]; + /* Get part number (padded with space). String is stripped inside setConfig. */ + interface.setConfig("module", string((const char*)&eeeprom.data[40], 16)); + int wavelength = eeeprom.data[60] << 8 | eeeprom.data[61]; + /* Skip wavelength for SFP+ cables, they use byte 60 for other data. */ + if ((eeeprom.data[8] & 0x0C) == 0 && wavelength > 0) + { + snprintf(buffer, sizeof(buffer), "%dnm", wavelength); + interface.setConfig("wavelength", buffer); + } + int max_length = 0; + int length; + length = eeeprom.data[14] * 1000; /* SMF, km */ + if (length > max_length) max_length = length; + length = eeeprom.data[15] * 100; /* SMF, meter */ + if (length > max_length) max_length = length; + length = eeeprom.data[16] * 10; /* 50um (OM2), meter */ + if (length > max_length) max_length = length; + length = eeeprom.data[17] * 10; /* 62.5um (OM1), meter */ + if (length > max_length) max_length = length; + length = eeeprom.data[18]; /* Copper, meter */ + if (length > max_length) max_length = length; + length = eeeprom.data[19] * 10; /* OM3, meter */ + if (length > max_length) max_length = length; + if (max_length > 0) + { + snprintf(buffer, sizeof(buffer), "%dm", max_length); + interface.setConfig("maxlength", buffer); + } + switch (eeeprom.data[2]) + { + case SFF_8024_CONNECTOR_SC: + interface.setConfig("connector", "SC"); + break; + case SFF_8024_CONNECTOR_LC: + interface.setConfig("connector", "LC"); + break; + case SFF_8024_CONNECTOR_OPTICAL_PIGTAIL: + interface.setConfig("connector", "optical pigtail"); + break; + case SFF_8024_CONNECTOR_COPPER_PIGTAIL: + interface.setConfig("connector", "copper pigtail"); + break; + case SFF_8024_CONNECTOR_RJ45: + interface.setConfig("connector", "RJ45"); + break; + case SFF_8024_CONNECTOR_NON_SEPARABLE: + interface.setConfig("connector", "non separable"); + break; + } + } + break; + } +} + + static void updateCapabilities(hwNode & interface, u32 supported, u32 supported2, u32 speed, u8 duplex, u8 port, u8 autoneg) { if(supported & SUPPORTED_TP) @@ -666,6 +793,7 @@ bool scan_network(hwNode & n) } scan_modes(interface, fd); + scan_module(interface, fd); drvinfo.cmd = ETHTOOL_GDRVINFO; memset(&ifr, 0, sizeof(ifr)); -- 2.33.1