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-head
mailing list