svn commit: r318160 - in head: sbin/ifconfig sys/net sys/sys

Ravi Pokala rpokala at FreeBSD.org
Wed May 10 22:13:49 UTC 2017


Author: rpokala
Date: Wed May 10 22:13:47 2017
New Revision: 318160
URL: https://svnweb.freebsd.org/changeset/base/318160

Log:
  Persistently store NIC's hardware MAC address, and add a way to retrive it
  
  The MAC address reported by `ifconfig ${nic} ether' does not always match
  the address in the hardware, as reported by the driver during attach. In
  particular, NICs which are components of a lagg(4) interface all report the
  same MAC.
  
  When attaching, the NIC driver passes the MAC address it read from the
  hardware as an argument to ether_ifattach(). Keep a second copy of it, and
  create ioctl(SIOCGHWADDR) to return it. Teach `ifconfig' to report it along
  with the active MAC address.
  
  PR:		194386
  Reviewed by:	glebius
  MFC after:	1 week
  Sponsored by:	Panasas
  Differential Revision:	https://reviews.freebsd.org/D10609

Modified:
  head/sbin/ifconfig/af_link.c
  head/sys/net/if.c
  head/sys/net/if_ethersubr.c
  head/sys/net/if_var.h
  head/sys/sys/sockio.h

Modified: head/sbin/ifconfig/af_link.c
==============================================================================
--- head/sbin/ifconfig/af_link.c	Wed May 10 21:42:16 2017	(r318159)
+++ head/sbin/ifconfig/af_link.c	Wed May 10 22:13:47 2017	(r318160)
@@ -42,6 +42,7 @@ static const char rcsid[] =
 #include <stdlib.h>
 #include <string.h>
 #include <ifaddrs.h>
+#include <unistd.h>
 
 #include <net/if_dl.h>
 #include <net/if_types.h>
@@ -67,7 +68,7 @@ link_status(int s __unused, const struct
 		    sdl->sdl_alen == ETHER_ADDR_LEN) {
 			ether_format = ether_ntoa((struct ether_addr *)LLADDR(sdl));
 			if (f_ether != NULL && strcmp(f_ether, "dash") == 0) {
-				for (format_char = strchr(ether_format, ':'); 
+				for (format_char = strchr(ether_format, ':');
 				    format_char != NULL; 
 				    format_char = strchr(ether_format, ':'))
 					*format_char = '-';
@@ -78,6 +79,48 @@ link_status(int s __unused, const struct
 
 			printf("\tlladdr %s\n", link_ntoa(sdl) + n);
 		}
+		/* Best-effort (i.e. failures are silent) to get original
+		 * hardware address, as read by NIC driver at attach time. Only
+		 * applies to Ethernet NICs (IFT_ETHER). However, laggX
+		 * interfaces claim to be IFT_ETHER, and re-type their component
+		 * Ethernet NICs as IFT_IEEE8023ADLAG. So, check for both. If
+		 * the MAC is zeroed, then it's actually a lagg.
+		 */
+		if ((sdl->sdl_type == IFT_ETHER ||
+		    sdl->sdl_type == IFT_IEEE8023ADLAG) &&
+		    sdl->sdl_alen == ETHER_ADDR_LEN) {
+			struct ifreq ifr;
+			int sock_hw;
+			int rc;
+			static const u_char laggaddr[6] = {0};
+
+			strncpy(ifr.ifr_name, ifa->ifa_name,
+			    sizeof(ifr.ifr_name));
+			memcpy(&ifr.ifr_addr, ifa->ifa_addr,
+			    sizeof(ifa->ifa_addr->sa_len));
+			ifr.ifr_addr.sa_family = AF_LOCAL;
+			if ((sock_hw = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
+				warn("socket(AF_LOCAL,SOCK_DGRAM)");
+				return;
+			}
+			rc = ioctl(sock_hw, SIOCGHWADDR, &ifr);
+			close(sock_hw);
+			if (rc != 0) {
+				return;
+			}
+			if (memcmp(ifr.ifr_addr.sa_data, laggaddr, sdl->sdl_alen) == 0) {
+				return;
+			}
+			ether_format = ether_ntoa((const struct ether_addr *)
+			    &ifr.ifr_addr.sa_data);
+			if (f_ether != NULL && strcmp(f_ether, "dash") == 0) {
+				for (format_char = strchr(ether_format, ':');
+				    format_char != NULL; 
+				    format_char = strchr(ether_format, ':'))
+					*format_char = '-';
+			}
+			printf("\thwaddr %s\n", ether_format);
+		}
 	}
 }
 

Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c	Wed May 10 21:42:16 2017	(r318159)
+++ head/sys/net/if.c	Wed May 10 22:13:47 2017	(r318160)
@@ -744,6 +744,11 @@ if_attach_internal(struct ifnet *ifp, in
 		/* Reliably crash if used uninitialized. */
 		ifp->if_broadcastaddr = NULL;
 
+		if (ifp->if_type == IFT_ETHER) {
+			ifp->if_hw_addr = malloc(ifp->if_addrlen, M_IFADDR,
+			    M_WAITOK | M_ZERO);
+		}
+
 #if defined(INET) || defined(INET6)
 		/* Use defaults for TSO, if nothing is set */
 		if (ifp->if_hw_tsomax == 0 &&
@@ -1059,6 +1064,8 @@ if_detach_internal(struct ifnet *ifp, in
 		 * Remove link ifaddr pointer and maybe decrement if_index.
 		 * Clean up all addresses.
 		 */
+		free(ifp->if_hw_addr, M_IFADDR);
+		ifp->if_hw_addr = NULL;
 		ifp->if_addr = NULL;
 
 		/* We can now free link ifaddr. */
@@ -2667,6 +2674,10 @@ ifhwioctl(u_long cmd, struct ifnet *ifp,
 		    ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len);
 		break;
 
+	case SIOCGHWADDR:
+		error = if_gethwaddr(ifp, ifr);
+		break;
+
 	case SIOCAIFGROUP:
 	{
 		struct ifgroupreq *ifgr = (struct ifgroupreq *)ifr;
@@ -3584,6 +3595,29 @@ if_requestencap_default(struct ifnet *if
 }
 
 /*
+ * Get the link layer address that was read from the hardware at attach.
+ *
+ * This is only set by Ethernet NICs (IFT_ETHER), but laggX interfaces re-type
+ * their component interfaces as IFT_IEEE8023ADLAG.
+ */
+int
+if_gethwaddr(struct ifnet *ifp, struct ifreq *ifr)
+{
+
+	if (ifp->if_hw_addr == NULL)
+		return (ENODEV);
+
+	switch (ifp->if_type) {
+	case IFT_ETHER:
+	case IFT_IEEE8023ADLAG:
+		bcopy(ifp->if_hw_addr, ifr->ifr_addr.sa_data, ifp->if_addrlen);
+		return (0);
+	default:
+		return (ENODEV);
+	}
+}
+
+/*
  * The name argument must be a pointer to storage which will last as
  * long as the interface does.  For physical devices, the result of
  * device_get_name(dev) is a good choice and for pseudo-devices a

Modified: head/sys/net/if_ethersubr.c
==============================================================================
--- head/sys/net/if_ethersubr.c	Wed May 10 21:42:16 2017	(r318159)
+++ head/sys/net/if_ethersubr.c	Wed May 10 22:13:47 2017	(r318160)
@@ -916,6 +916,8 @@ ether_ifattach(struct ifnet *ifp, const 
 	sdl->sdl_alen = ifp->if_addrlen;
 	bcopy(lla, LLADDR(sdl), ifp->if_addrlen);
 
+	bcopy(lla, ifp->if_hw_addr, ifp->if_addrlen);
+
 	bpfattach(ifp, DLT_EN10MB, ETHER_HDR_LEN);
 	if (ng_ether_attach_p != NULL)
 		(*ng_ether_attach_p)(ifp);

Modified: head/sys/net/if_var.h
==============================================================================
--- head/sys/net/if_var.h	Wed May 10 21:42:16 2017	(r318159)
+++ head/sys/net/if_var.h	Wed May 10 22:13:47 2017	(r318160)
@@ -281,6 +281,7 @@ struct ifnet {
 	struct	ifmultihead if_multiaddrs; /* multicast addresses configured */
 	int	if_amcount;		/* number of all-multicast requests */
 	struct	ifaddr	*if_addr;	/* pointer to link-level address */
+	void	*if_hw_addr;		/* hardware link-level address */
 	const u_int8_t *if_broadcastaddr; /* linklevel broadcast bytestring */
 	struct	rwlock if_afdata_lock;
 	void	*if_afdata[AF_MAX];
@@ -650,6 +651,7 @@ int if_gethwassist(if_t ifp);
 int if_setsoftc(if_t ifp, void *softc);
 void *if_getsoftc(if_t ifp);
 int if_setflags(if_t ifp, int flags);
+int if_gethwaddr(if_t ifp, struct ifreq *);
 int if_setmtu(if_t ifp, int mtu);
 int if_getmtu(if_t ifp);
 int if_getmtu_family(if_t ifp, int family);

Modified: head/sys/sys/sockio.h
==============================================================================
--- head/sys/sys/sockio.h	Wed May 10 21:42:16 2017	(r318159)
+++ head/sys/sys/sockio.h	Wed May 10 22:13:47 2017	(r318160)
@@ -97,6 +97,7 @@
 #define	SIOCGIFSTATUS	_IOWR('i', 59, struct ifstat)	/* get IF status */
 #define	SIOCSIFLLADDR	 _IOW('i', 60, struct ifreq)	/* set linklevel addr */
 #define	SIOCGI2C	_IOWR('i', 61, struct ifreq)	/* get I2C data  */
+#define	SIOCGHWADDR	_IOWR('i', 62, struct ifreq)	/* get hardware lladdr */
 
 #define	SIOCSIFPHYADDR	 _IOW('i', 70, struct ifaliasreq) /* set gif address */
 #define	SIOCGIFPSRCADDR	_IOWR('i', 71, struct ifreq)	/* get gif psrc addr */


More information about the svn-src-all mailing list