git: 02f70f6633fd - stable/14 - 590493c1: if_epair(4): use ether_gen_addr(9) for stable MAC address

From: Ronald Klop <ronald_at_FreeBSD.org>
Date: Sat, 13 Sep 2025 13:26:19 UTC
The branch stable/14 has been updated by ronald:

URL: https://cgit.FreeBSD.org/src/commit/?id=02f70f6633fd4a96a0dad69f97a855867caea491

commit 02f70f6633fd4a96a0dad69f97a855867caea491
Author:     Ronald Klop <ronald@FreeBSD.org>
AuthorDate: 2025-07-03 16:33:03 +0000
Commit:     Ronald Klop <ronald@FreeBSD.org>
CommitDate: 2025-09-13 13:24:16 +0000

    590493c1:
    if_epair(4): use ether_gen_addr(9) for stable MAC address
    
    Before this change epair interfaces get a random MAC. This does
    not help dhcp/dyndns when an epair gets destroyed/recreated
    after restart of a jail.
    
    With this change:
    $ sysctl net.link.epair.ether_gen_addr=0
    $ ifconfig epair8 create > /dev/null; ifconfig epair8a | grep ether; ifconfig epair8b | grep ether; ifconfig epair8a destroy
            ether 02:cb:78:56:e4:0a
            ether 02:cb:78:56:e4:0b
    $ ifconfig epair8 create > /dev/null; ifconfig epair8a | grep ether; ifconfig epair8b | grep ether; ifconfig epair8a destroy
            ether 02:8b:9b:6a:8f:0a
            ether 02:8b:9b:6a:8f:0b
    
    $ sysctl net.link.epair.ether_gen_addr=1
    $ ifconfig epair8 create > /dev/null; ifconfig epair8a | grep ether; ifconfig epair8b | grep ether; ifconfig epair8a destroy
            ether 58:9c:fc:10:2b:b4
            ether 58:9c:fc:00:39:10
    $ ifconfig epair8 create > /dev/null; ifconfig epair8a | grep ether; ifconfig epair8b | grep ether; ifconfig epair8a destroy
            ether 58:9c:fc:10:2b:b4
            ether 58:9c:fc:00:39:10
    
    A follow up commit will change the default to 1 in main.
    
    Approved by:    bz,ivy,kp
    Relnotes:       yes
    Differential Revision: https://reviews.freebsd.org/D51157
    
    78537728:
    Document tunable net.link.epair.ether_gen_addr
    
    Approved by:    hrs
    Fixes:  590493c1419092e98f7ad1dcadb886973502341e ("if_epair(4): use ether_gen_addr(9) for stable MAC address")
    Differential Revision: https://reviews.freebsd.org/D51861
    
    (cherry picked from commit 590493c1419092e98f7ad1dcadb886973502341e)
    (cherry picked from commit 78537728efc5387558c97ba2730ce746d6259013)
---
 share/man/man4/epair.4 | 22 +++++++++++++++++-----
 sys/net/if_epair.c     | 35 +++++++++++++++++++++++++++++++----
 2 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/share/man/man4/epair.4 b/share/man/man4/epair.4
index 4bcb54c936cb..342b15b5612a 100644
--- a/share/man/man4/epair.4
+++ b/share/man/man4/epair.4
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd March 18, 2015
+.Dd August 12, 2025
 .Dt EPAIR 4
 .Os
 .Sh NAME
@@ -79,12 +79,24 @@ and
 Like any other Ethernet interface, an
 .Nm
 needs to have a network address.
-Each
+If the tunable
+.Va net.link.epair.ether_gen_addr Ns
+=0, each
 .Nm
-will be assigned a locally administered address by default,
+will be assigned a random locally administered address,
 that is only guaranteed to be unique within one network stack.
-To change the default addresses one may use the SIOCSIFADDR ioctl(2) or
-ifconfig(8) utility.
+The tunable
+.Va net.link.epair.ether_gen_addr Ns
+=1 will generate a stable MAC address with
+.Fx
+OUI using
+.Xr ether_gen_addr 9 .
+This tunable defaults to 1 in
+.Fx 15.0 and might be removed in
+.Fx 16.0 .
+To change the default addresses one may use the SIOCSIFADDR
+.Xr ioctl 2 or
+.Xr ifconfig 8 utility.
 .Pp
 The basic intent is to provide connectivity between two virtual
 network stack instances.
diff --git a/sys/net/if_epair.c b/sys/net/if_epair.c
index 988930998dad..e7327ec71a42 100644
--- a/sys/net/if_epair.c
+++ b/sys/net/if_epair.c
@@ -58,6 +58,7 @@
 #include <sys/smp.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
+#include <sys/sysctl.h>
 #include <sys/taskqueue.h>
 
 #include <net/bpf.h>
@@ -96,6 +97,15 @@ static unsigned int next_index = 0;
 #define	EPAIR_LOCK()			mtx_lock(&epair_n_index_mtx)
 #define	EPAIR_UNLOCK()			mtx_unlock(&epair_n_index_mtx)
 
+SYSCTL_DECL(_net_link);
+static SYSCTL_NODE(_net_link, OID_AUTO, epair, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+	"Pair of virtual cross-over connected Ethernet-like interfaces");
+
+static bool use_ether_gen_addr = false;
+SYSCTL_BOOL(_net_link_epair, OID_AUTO, ether_gen_addr, CTLFLAG_RWTUN,
+	&use_ether_gen_addr, false,
+	"Generate MAC with FreeBSD OUI using ether_gen_addr(9)");
+
 struct epair_softc;
 struct epair_queue {
 	struct mtx		 mtx;
@@ -494,6 +504,17 @@ epair_clone_match(struct if_clone *ifc, const char *name)
 	return (1);
 }
 
+static void
+epair_generate_mac_byname(struct epair_softc *sc, uint8_t eaddr[])
+{
+	struct ether_addr gen_eaddr;
+	int i;
+
+	ether_gen_addr_byname(if_name(sc->ifp), &gen_eaddr);
+	for (i = 0; i < ETHER_ADDR_LEN; i++)
+		eaddr[i] = gen_eaddr.octet[i];
+}
+
 static void
 epair_clone_add(struct if_clone *ifc, struct epair_softc *scb)
 {
@@ -501,9 +522,12 @@ epair_clone_add(struct if_clone *ifc, struct epair_softc *scb)
 	uint8_t eaddr[ETHER_ADDR_LEN];	/* 00:00:00:00:00:00 */
 
 	ifp = scb->ifp;
-	/* Copy epairNa etheraddr and change the last byte. */
-	memcpy(eaddr, scb->oifp->if_hw_addr, ETHER_ADDR_LEN);
-	eaddr[5] = 0x0b;
+	if (!use_ether_gen_addr) {
+		/* Copy epairNa etheraddr and change the last byte. */
+		memcpy(eaddr, scb->oifp->if_hw_addr, ETHER_ADDR_LEN);
+		eaddr[5] = 0x0b;
+	} else
+		epair_generate_mac_byname(scb, eaddr);
 	ether_ifattach(ifp, eaddr);
 
 	if_clone_addif(ifc, ifp);
@@ -718,7 +742,10 @@ epair_clone_create(struct if_clone *ifc, char *name, size_t len,
 	/* Finish initialization of interface <n>a. */
 	ifp = sca->ifp;
 	epair_setup_ifp(sca, name, unit);
-	epair_generate_mac(sca, eaddr);
+	if (!use_ether_gen_addr)
+		epair_generate_mac(sca, eaddr);
+	else
+		epair_generate_mac_byname(sca, eaddr);
 
 	ether_ifattach(ifp, eaddr);