git: 87bea33a67ca - main - nd6: Remove DRAFT_IETF_6MAN_IPV6ONLY_FLAG and EXPERIMENTAL options

From: Pouria Mousavizadeh Tehrani <pouria_at_FreeBSD.org>
Date: Fri, 10 Apr 2026 20:33:16 UTC
The branch main has been updated by pouria:

URL: https://cgit.FreeBSD.org/src/commit/?id=87bea33a67cad31661a6fb9ea4c62a5fc266cd98

commit 87bea33a67cad31661a6fb9ea4c62a5fc266cd98
Author:     Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
AuthorDate: 2026-04-02 20:01:55 +0000
Commit:     Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
CommitDate: 2026-04-10 20:12:09 +0000

    nd6: Remove DRAFT_IETF_6MAN_IPV6ONLY_FLAG and EXPERIMENTAL options
    
    The draft-ietf-6man-ipv6only-flag has been obsoleted by RFC 8925.
    Remove the EXPERIMENTAL compile option from the kernel and remove
    DRAFT_IETF_6MAN_IPV6ONLY_FLAG from userland.
    This compile option was not enabled by default.
    Also regenerate src.conf.5.
    
    Reviewed by: bz
    Differential Revision: https://reviews.freebsd.org/D56228
---
 sbin/ifconfig/Makefile                |   4 --
 sbin/ifconfig/af_inet6.c              |   4 --
 sbin/ifconfig/af_nd6.c                |   4 --
 share/man/man5/src.conf.5             |   4 +-
 share/mk/src.opts.mk                  |   1 -
 sys/conf/options                      |   1 -
 sys/net/if_ethersubr.c                |  39 ------------
 sys/netinet/icmp6.h                   |   4 --
 sys/netinet6/nd6.h                    |   6 --
 sys/netinet6/nd6_rtr.c                | 112 ----------------------------------
 tools/build/options/WITH_EXPERIMENTAL |   1 -
 usr.sbin/ndp/Makefile                 |   5 --
 usr.sbin/ndp/ndp.c                    |   7 +--
 usr.sbin/rtadvd/Makefile              |   5 --
 usr.sbin/rtadvd/config.c              |  11 ----
 usr.sbin/rtadvd/rtadvd.c              |  13 ----
 usr.sbin/rtadvd/rtadvd.h              |   3 -
 17 files changed, 2 insertions(+), 222 deletions(-)

diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile
index 2553e61b5e9e..b777d875f966 100644
--- a/sbin/ifconfig/Makefile
+++ b/sbin/ifconfig/Makefile
@@ -52,10 +52,6 @@ SRCS+=	ifpfsync.c		# pfsync(4) support
 SRCS+=	ifbridge.c		# bridge support
 SRCS+=	iflagg.c		# lagg support
 
-.if ${MK_EXPERIMENTAL} != "no"
-CFLAGS+= -DDRAFT_IETF_6MAN_IPV6ONLY_FLAG
-CFLAGS+= -DEXPERIMENTAL
-.endif
 .if ${MK_INET6_SUPPORT} != "no"
 CFLAGS+= -DINET6
 .endif
diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c
index 365f01be9590..492ee5bbbed0 100644
--- a/sbin/ifconfig/af_inet6.c
+++ b/sbin/ifconfig/af_inet6.c
@@ -730,10 +730,6 @@ static struct cmd inet6_cmds[] = {
 	DEF_CMD("eui64",	0,			setip6eui64),
 	DEF_CMD("stableaddr",	ND6_IFF_STABLEADDR,	setnd6flags),
 	DEF_CMD("-stableaddr",	-ND6_IFF_STABLEADDR,	setnd6flags),
-#ifdef EXPERIMENTAL
-	DEF_CMD("ipv6_only",	ND6_IFF_IPV6_ONLY_MANUAL,setnd6flags),
-	DEF_CMD("-ipv6_only",	-ND6_IFF_IPV6_ONLY_MANUAL,setnd6flags),
-#endif
 };
 
 static struct afswtch af_inet6 = {
diff --git a/sbin/ifconfig/af_nd6.c b/sbin/ifconfig/af_nd6.c
index fb7e72028e2e..199523450dca 100644
--- a/sbin/ifconfig/af_nd6.c
+++ b/sbin/ifconfig/af_nd6.c
@@ -62,10 +62,6 @@ static const char *ND6BITS[] = {
 	[6]  = "NO_RADR",
 	[7]  = "NO_PREFER_IFACE",
 	[8]  = "NO_DAD",
-#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
-	[9]  = "IPV6_ONLY",
-	[10] = "IPV6_ONLY_MANUAL",
-#endif
 	[11]  = "STABLEADDR",
 	[15] = "DEFAULTIF",
 };
diff --git a/share/man/man5/src.conf.5 b/share/man/man5/src.conf.5
index a94c5d6177b4..65fbcf2e69a4 100644
--- a/share/man/man5/src.conf.5
+++ b/share/man/man5/src.conf.5
@@ -1,5 +1,5 @@
 .\" DO NOT EDIT-- this file is @generated by tools/build/options/makeman.
-.Dd April 3, 2026
+.Dd April 10, 2026
 .Dt SRC.CONF 5
 .Os
 .Sh NAME
@@ -721,8 +721,6 @@ An alternate bootstrap tool chain must be provided.
 .It Va WITHOUT_EXAMPLES
 Avoid installing examples to
 .Pa /usr/share/examples/ .
-.It Va WITH_EXPERIMENTAL
-Include experimental features in the build.
 .It Va WITHOUT_FDT
 Do not build Flattened Device Tree support as part of the base system.
 This includes the device tree compiler (dtc) and libfdt support library.
diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk
index 5c3e3bb31a7f..ab774d44c283 100644
--- a/share/mk/src.opts.mk
+++ b/share/mk/src.opts.mk
@@ -206,7 +206,6 @@ __DEFAULT_NO_OPTIONS = \
     DISK_IMAGE_TOOLS_BOOTSTRAP \
     DTRACE_ASAN \
     DTRACE_TESTS \
-    EXPERIMENTAL \
     HESIOD \
     IPFILTER_IPFS \
     LOADER_VERBOSE \
diff --git a/sys/conf/options b/sys/conf/options
index 155fbf8e6c8a..54994503ad65 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -104,7 +104,6 @@ COMPAT_LINUXKPI	opt_dontuse.h
 COMPILING_LINT	opt_global.h
 CY_PCI_FASTINTR
 DEADLKRES	opt_watchdog.h
-EXPERIMENTAL	opt_global.h
 DIRECTIO
 FFCLOCK
 FULL_PREEMPTION	opt_sched.h
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 812a31595df9..bbaf798b49f2 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -475,27 +475,6 @@ ether_output_frame(struct ifnet *ifp, struct mbuf *m)
 			return (0);
 		}
 
-#ifdef EXPERIMENTAL
-#if defined(INET6) && defined(INET)
-	/* draft-ietf-6man-ipv6only-flag */
-	/* Catch ETHERTYPE_IP, and ETHERTYPE_[REV]ARP if we are v6-only. */
-	if ((ifp->if_inet6->nd_flags & ND6_IFF_IPV6_ONLY_MASK) != 0) {
-		struct ether_header *eh;
-
-		eh = mtod(m, struct ether_header *);
-		switch (ntohs(eh->ether_type)) {
-		case ETHERTYPE_IP:
-		case ETHERTYPE_ARP:
-		case ETHERTYPE_REVARP:
-			m_freem(m);
-			return (EAFNOSUPPORT);
-			/* NOTREACHED */
-			break;
-		};
-	}
-#endif
-#endif
-
 	/*
 	 * Queue message on interface, update output statistics if successful,
 	 * and start output if interface not yet active.
@@ -541,24 +520,6 @@ ether_input_internal(struct ifnet *ifp, struct mbuf *m)
 	etype = ntohs(eh->ether_type);
 	random_harvest_queue_ether(m, sizeof(*m));
 
-#ifdef EXPERIMENTAL
-#if defined(INET6) && defined(INET)
-	/* draft-ietf-6man-ipv6only-flag */
-	/* Catch ETHERTYPE_IP, and ETHERTYPE_[REV]ARP if we are v6-only. */
-	if ((ifp->if_inet6->nd_flags & ND6_IFF_IPV6_ONLY_MASK) != 0) {
-		switch (etype) {
-		case ETHERTYPE_IP:
-		case ETHERTYPE_ARP:
-		case ETHERTYPE_REVARP:
-			m_freem(m);
-			return;
-			/* NOTREACHED */
-			break;
-		};
-	}
-#endif
-#endif
-
 	CURVNET_SET_QUIET(ifp->if_vnet);
 
 	if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
diff --git a/sys/netinet/icmp6.h b/sys/netinet/icmp6.h
index 9ed39d118c16..9508f221ba10 100644
--- a/sys/netinet/icmp6.h
+++ b/sys/netinet/icmp6.h
@@ -243,10 +243,6 @@ struct nd_router_advert {	/* router advertisement */
 #define ND_RA_FLAG_RTPREF_LOW	0x18 /* 00011000 */
 #define ND_RA_FLAG_RTPREF_RSV	0x10 /* 00010000 */
 
-#ifdef EXPERIMENTAL
-#define	ND_RA_FLAG_IPV6_ONLY	0x02 /* draft-ietf-6man-ipv6only-flag */
-#endif
-
 #define nd_ra_router_lifetime	nd_ra_hdr.icmp6_data16[1]
 
 struct nd_neighbor_solicit {	/* neighbor solicitation */
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index 8c069c294593..8c8d5a3236ca 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -74,12 +74,6 @@ struct llentry;
 #define ND6_IFF_NO_PREFER_IFACE	0x80 /* XXX: not related to ND. */
 #define ND6_IFF_NO_DAD		0x100
 #define ND6_IFF_STABLEADDR	0x800
-#ifdef EXPERIMENTAL
-/* XXX: not related to ND. */
-#define	ND6_IFF_IPV6_ONLY	0x200 /* draft-ietf-6man-ipv6only-flag */
-#define	ND6_IFF_IPV6_ONLY_MANUAL	0x400
-#define	ND6_IFF_IPV6_ONLY_MASK	(ND6_IFF_IPV6_ONLY|ND6_IFF_IPV6_ONLY_MANUAL)
-#endif
 
 struct in6_nbrinfo {
 	char ifname[IFNAMSIZ];	/* if name, e.g. "en0" */
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
index 6f415408daae..5819370a3011 100644
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -104,16 +104,6 @@ VNET_DEFINE(u_int32_t, ip6_temp_valid_lifetime) = DEF_TEMP_VALID_LIFETIME;
 
 VNET_DEFINE(int, ip6_temp_regen_advance) = TEMPADDR_REGEN_ADVANCE;
 
-#ifdef EXPERIMENTAL
-VNET_DEFINE_STATIC(int, nd6_ignore_ipv6_only_ra) = 1;
-#define	V_nd6_ignore_ipv6_only_ra	VNET(nd6_ignore_ipv6_only_ra)
-SYSCTL_INT(_net_inet6_icmp6, OID_AUTO,
-    nd6_ignore_ipv6_only_ra, CTLFLAG_VNET | CTLFLAG_RW,
-    &VNET_NAME(nd6_ignore_ipv6_only_ra), 0,
-    "Ignore the 'IPv6-Only flag' in RA messages in compliance with "
-    "draft-ietf-6man-ipv6only-flag");
-#endif
-
 /* RTPREF_MEDIUM has to be 0! */
 #define RTPREF_HIGH	1
 #define RTPREF_MEDIUM	0
@@ -248,97 +238,6 @@ nd6_rs_input(struct mbuf *m, int off, int icmp6len)
 	m_freem(m);
 }
 
-#ifdef EXPERIMENTAL
-/*
- * An initial update routine for draft-ietf-6man-ipv6only-flag.
- * We need to iterate over all default routers for the given
- * interface to see whether they are all advertising the "S"
- * (IPv6-Only) flag.  If they do set, otherwise unset, the
- * interface flag we later use to filter on.
- *
- * XXXGL: The use of IF_ADDR_WLOCK (previously it was IF_AFDATA_LOCK) in this
- * function is quite strange.
- */
-static void
-defrtr_ipv6_only_ifp(struct ifnet *ifp)
-{
-	struct nd_defrouter *dr;
-	bool ipv6_only, ipv6_only_old;
-#ifdef INET
-	struct epoch_tracker et;
-	struct ifaddr *ifa;
-	bool has_ipv4_addr;
-#endif
-
-	if (V_nd6_ignore_ipv6_only_ra != 0)
-		return;
-
-	ipv6_only = true;
-	ND6_RLOCK();
-	TAILQ_FOREACH(dr, &V_nd6_defrouter, dr_entry)
-		if (dr->ifp == ifp &&
-		    (dr->raflags & ND_RA_FLAG_IPV6_ONLY) == 0)
-			ipv6_only = false;
-	ND6_RUNLOCK();
-
-	IF_ADDR_WLOCK(ifp);
-	ipv6_only_old = ifp->if_inet6->nd_flags & ND6_IFF_IPV6_ONLY;
-	IF_ADDR_WUNLOCK(ifp);
-
-	/* If nothing changed, we have an early exit. */
-	if (ipv6_only == ipv6_only_old)
-		return;
-
-#ifdef INET
-	/*
-	 * Should we want to set the IPV6-ONLY flag, check if the
-	 * interface has a non-0/0 and non-link-local IPv4 address
-	 * configured on it.  If it has we will assume working
-	 * IPv4 operations and will clear the interface flag.
-	 */
-	has_ipv4_addr = false;
-	if (ipv6_only) {
-		NET_EPOCH_ENTER(et);
-		CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
-			if (ifa->ifa_addr->sa_family != AF_INET)
-				continue;
-			if (in_canforward(
-			    satosin(ifa->ifa_addr)->sin_addr)) {
-				has_ipv4_addr = true;
-				break;
-			}
-		}
-		NET_EPOCH_EXIT(et);
-	}
-	if (ipv6_only && has_ipv4_addr) {
-		log(LOG_NOTICE, "%s rcvd RA w/ IPv6-Only flag set but has IPv4 "
-		    "configured, ignoring IPv6-Only flag.\n", ifp->if_xname);
-		ipv6_only = false;
-	}
-#endif
-
-	IF_ADDR_WLOCK(ifp);
-	if (ipv6_only)
-		ifp->if_inet6->nd_flags |= ND6_IFF_IPV6_ONLY;
-	else
-		ifp->if_inet6->nd_flags &= ~ND6_IFF_IPV6_ONLY;
-	IF_ADDR_WUNLOCK(ifp);
-
-#ifdef notyet
-	/* Send notification of flag change. */
-#endif
-}
-
-static void
-defrtr_ipv6_only_ipf_down(struct ifnet *ifp)
-{
-
-	IF_ADDR_WLOCK(ifp);
-	ifp->if_inet6->nd_flags &= ~ND6_IFF_IPV6_ONLY;
-	IF_ADDR_WUNLOCK(ifp);
-}
-#endif	/* EXPERIMENTAL */
-
 void
 nd6_ifnet_link_event(void *arg __unused, struct ifnet *ifp, int linkstate)
 {
@@ -349,10 +248,6 @@ nd6_ifnet_link_event(void *arg __unused, struct ifnet *ifp, int linkstate)
 	 * unreachable but a different interface might still have connectivity.
 	 */
 
-#ifdef EXPERIMENTAL
-	if (linkstate == LINK_STATE_DOWN)
-		defrtr_ipv6_only_ipf_down(ifp);
-#endif
 }
 
 static void
@@ -599,9 +494,6 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
 		}
 	}
 	dr = defrtrlist_update(&dr0);
-#ifdef EXPERIMENTAL
-	defrtr_ipv6_only_ifp(ifp);
-#endif
 	/* Prefix Information */
 	if (ndopts.nd_opts_pi != NULL) {
 		/*
@@ -779,10 +671,6 @@ defrouter_del(struct nd_defrouter *dr)
 	if (dr->ifp->if_inet6->nd_flags & ND6_IFF_ACCEPT_RTADV)
 		rt6_flush(&dr->rtaddr, dr->ifp);
 
-#ifdef EXPERIMENTAL
-	defrtr_ipv6_only_ifp(dr->ifp);
-#endif
-
 	if (dr->installed) {
 		deldr = dr;
 		defrouter_delreq(dr);
diff --git a/tools/build/options/WITH_EXPERIMENTAL b/tools/build/options/WITH_EXPERIMENTAL
deleted file mode 100644
index a5f41addee52..000000000000
--- a/tools/build/options/WITH_EXPERIMENTAL
+++ /dev/null
@@ -1 +0,0 @@
-Include experimental features in the build.
diff --git a/usr.sbin/ndp/Makefile b/usr.sbin/ndp/Makefile
index 998860d00a69..aad2380bc879 100644
--- a/usr.sbin/ndp/Makefile
+++ b/usr.sbin/ndp/Makefile
@@ -23,11 +23,6 @@ LIBADD=	xo
 CFLAGS+= -I. -I${.CURDIR}
 CFLAGS+= -D_U_=""
 
-.if ${MK_EXPERIMENTAL} != "no"
-CFLAGS+=	-DEXPERIMENTAL
-CFLAGS+=	-DDRAFT_IETF_6MAN_IPV6ONLY_FLAG
-.endif
-
 .if ${MK_NETLINK_SUPPORT} != "no"
 SRCS+=	ndp_netlink.c
 .else
diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c
index cbca8ec20941..7521be752c80 100644
--- a/usr.sbin/ndp/ndp.c
+++ b/usr.sbin/ndp/ndp.c
@@ -1225,12 +1225,7 @@ rtrlist(void)
 			*pflags++ = 'O';
 			xo_emit("{el:%s}", "other");
 		}
-#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
-		if (p->flags & ND_RA_FLAG_IPV6_ONLY) {
-			*pflags++ = 'S';
-			xo_emit("{el:%s}", "ipv6only");
-		}
-#endif
+
 		xo_close_list("flags_pretty");
 		xo_emit(", flags={:flags/%s}", rflags);
 
diff --git a/usr.sbin/rtadvd/Makefile b/usr.sbin/rtadvd/Makefile
index 583f9db88ceb..4ed2d7182a6b 100644
--- a/usr.sbin/rtadvd/Makefile
+++ b/usr.sbin/rtadvd/Makefile
@@ -20,11 +20,6 @@ MAN=	rtadvd.conf.5 rtadvd.8
 SRCS=	rtadvd.c rrenum.c advcap.c if.c config.c timer.c timer_subr.c	\
 	control.c control_server.c
 
-.if ${MK_EXPERIMENTAL} != "no"
-CFLAGS+=	-DEXPERIMENTAL
-CFLAGS+=	-DDRAFT_IETF_6MAN_IPV6ONLY_FLAG
-.endif
-
 LIBADD=	util
 
 WARNS?=	1
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c
index c0af8f76ca49..70fb2ed7dc28 100644
--- a/usr.sbin/rtadvd/config.c
+++ b/usr.sbin/rtadvd/config.c
@@ -442,10 +442,6 @@ getconfig(struct ifinfo *ifi)
 			}
 			val |= ND_RA_FLAG_RTPREF_LOW;
 		}
-#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
-		if (strchr(flagstr, 'S'))
-			val |= ND_RA_FLAG_IPV6_ONLY;
-#endif
 	} else
 		MAYHAVE(val, "raflags", 0);
 
@@ -461,9 +457,6 @@ getconfig(struct ifinfo *ifi)
 		    __func__, rai->rai_rtpref, ifi->ifi_ifname);
 		goto getconfig_free_rai;
 	}
-#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
-	rai->rai_ipv6onlyflg = val & ND_RA_FLAG_IPV6_ONLY;
-#endif
 
 	MAYHAVE(val, "rltime", rai->rai_maxinterval * 3);
 	if ((uint16_t)val && ((uint16_t)val < rai->rai_maxinterval ||
@@ -1485,10 +1478,6 @@ make_packet(struct rainfo *rai)
 		rai->rai_managedflg ? ND_RA_FLAG_MANAGED : 0;
 	ra->nd_ra_flags_reserved |=
 		rai->rai_otherflg ? ND_RA_FLAG_OTHER : 0;
-#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
-	ra->nd_ra_flags_reserved |=
-		rai->rai_ipv6onlyflg ? ND_RA_FLAG_IPV6_ONLY : 0;
-#endif
 	ra->nd_ra_router_lifetime = htons(rai->rai_lifetime);
 	ra->nd_ra_reachable = htonl(rai->rai_reachabletime);
 	ra->nd_ra_retransmit = htonl(rai->rai_retranstimer);
diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c
index 1eb8f12a7338..2e9bced7c00e 100644
--- a/usr.sbin/rtadvd/rtadvd.c
+++ b/usr.sbin/rtadvd/rtadvd.c
@@ -1148,19 +1148,6 @@ ra_input(int len, struct nd_router_advert *nra,
 			sizeof(ntopbuf)), on_off[rai->rai_otherflg]);
 		inconsistent++;
 	}
-#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
-	/* S "IPv6-Only" (Six, Silence-IPv4) flag */
-	if ((nra->nd_ra_flags_reserved & ND_RA_FLAG_IPV6_ONLY) !=
-	    rai->rai_ipv6onlyflg) {
-		syslog(LOG_NOTICE,
-		    "S flag inconsistent on %s:"
-		    " %s from %s, %s from us",
-		    ifi->ifi_ifname, on_off[!rai->rai_ipv6onlyflg],
-		    inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf,
-			sizeof(ntopbuf)), on_off[rai->rai_ipv6onlyflg]);
-		inconsistent++;
-	}
-#endif
 	/* Reachable Time */
 	reachabletime = ntohl(nra->nd_ra_reachable);
 	if (reachabletime && rai->rai_reachabletime &&
diff --git a/usr.sbin/rtadvd/rtadvd.h b/usr.sbin/rtadvd/rtadvd.h
index 5ecfd1b56423..5b9037b2dcf3 100644
--- a/usr.sbin/rtadvd/rtadvd.h
+++ b/usr.sbin/rtadvd/rtadvd.h
@@ -204,9 +204,6 @@ struct	rainfo {
 	uint16_t	rai_mininterval;	/* MinRtrAdvInterval */
 	int 	rai_managedflg;		/* AdvManagedFlag */
 	int	rai_otherflg;		/* AdvOtherConfigFlag */
-#ifdef DRAFT_IETF_6MAN_IPV6ONLY_FLAG
-	int	rai_ipv6onlyflg;	/* AdvIPv6OnlyFlag */
-#endif
 
 	int	rai_rtpref;		/* router preference */
 	uint32_t	rai_linkmtu;		/* AdvLinkMTU */