Subject: lo(4) as a clonable interface
To: None <tech-net@NetBSD.org>
From: Peter Postma <peter@pointless.nl>
List: tech-net
Date: 07/23/2004 18:34:58
--W/nzBZO5zC0uMSeA
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi all,

The attached patch converts lo(4) into a clonable interface.
So there's no longer need to rebuild the kernel to add additional loopback
interfaces.

Can someone please review the patch before I'm going send-pr it?

-- 
Peter Postma

--W/nzBZO5zC0uMSeA
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="if_loop.diff"

Index: net/if.c
===================================================================
RCS file: /cvsroot/src/sys/net/if.c,v
retrieving revision 1.143
diff -u -r1.143 if.c
--- net/if.c	22 Jun 2004 12:50:41 -0000	1.143
+++ net/if.c	23 Jul 2004 15:42:06 -0000
@@ -271,6 +271,7 @@
 size_t if_indexlim = 0;
 struct ifaddr **ifnet_addrs = NULL;
 struct ifnet **ifindex2ifnet = NULL;
+struct ifnet *lo0ifp;
 
 /*
  * Allocate the link level name for the specified interface.  This
Index: net/if.h
===================================================================
RCS file: /cvsroot/src/sys/net/if.h,v
retrieving revision 1.96
diff -u -r1.96 if.h
--- net/if.h	21 Apr 2004 04:17:28 -0000	1.96
+++ net/if.h	23 Jul 2004 15:42:06 -0000
@@ -733,9 +733,7 @@
 
 extern struct ifnet_head ifnet;
 extern struct ifnet **ifindex2ifnet;
-#if 0
-struct ifnet loif[];
-#endif
+extern struct ifnet *lo0ifp;
 extern size_t if_indexlim;
 
 char	*ether_sprintf __P((const u_char *));
Index: net/if_loop.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_loop.c,v
retrieving revision 1.50
diff -u -r1.50 if_loop.c
--- net/if_loop.c	21 Apr 2004 18:40:39 -0000	1.50
+++ net/if_loop.c	23 Jul 2004 15:42:07 -0000
@@ -75,7 +75,6 @@
 #include "opt_mbuftrace.h"
 
 #include "bpfilter.h"
-#include "loop.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -140,50 +139,99 @@
 #define	LOMTU_MAX	(65536 +  MHLEN + MLEN)
 #endif
 
-struct	ifnet loif[NLOOP];
-#ifdef MBUFTRACE
-struct	mowner lomowner[NLOOP];
-#endif
-
 #ifdef ALTQ
 void	lostart(struct ifnet *);
 #endif
 
+struct loop_softc {
+	LIST_ENTRY(loop_softc) sc_list;
+	struct ifnet sc_if;
+};
+
+LIST_HEAD(, loop_softc) loop_softc_list;
+
+int loop_clone_create(struct if_clone *, int);
+void loop_clone_destroy(struct ifnet *);
+
+struct if_clone loop_cloner =
+    IF_CLONE_INITIALIZER("lo", loop_clone_create, loop_clone_destroy);
+
 void
-loopattach(n)
-	int n;
+loopattach(int n)
 {
-	int i;
-	struct ifnet *ifp;
+	LIST_INIT(&loop_softc_list);
+
+	(void)loop_clone_create(&loop_cloner, 0);	/* lo0 always exists */
+	if_clone_attach(&loop_cloner);
+}
 
-	for (i = 0; i < NLOOP; i++) {
-		ifp = &loif[i];
-		snprintf(ifp->if_xname, sizeof(ifp->if_xname), "lo%d", i);
-		ifp->if_softc = NULL;
-		ifp->if_mtu = LOMTU;
-		ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
-		ifp->if_ioctl = loioctl;
-		ifp->if_output = looutput;
+int
+loop_clone_create(struct if_clone *ifc, int unit)
+{
+	struct loop_softc *sc;
+
+	sc = malloc(sizeof(struct loop_softc), M_DEVBUF, M_WAITOK);
+	if (sc == NULL)
+		return (ENOMEM);
+	(void)memset(sc, 0, sizeof(struct loop_softc));
+
+	snprintf(sc->sc_if.if_xname, sizeof(sc->sc_if.if_xname), "%s%d",
+	    ifc->ifc_name, unit);
+
+	sc->sc_if.if_softc = sc;
+	sc->sc_if.if_mtu = LOMTU;
+	sc->sc_if.if_flags = IFF_LOOPBACK | IFF_MULTICAST;
+	sc->sc_if.if_ioctl = loioctl;
+	sc->sc_if.if_output = looutput;
 #ifdef ALTQ
-		ifp->if_start = lostart;
+	sc->sc_if.if_start = lostart;
 #endif
-		ifp->if_type = IFT_LOOP;
-		ifp->if_hdrlen = 0;
-		ifp->if_addrlen = 0;
-		ifp->if_dlt = DLT_NULL;
-		IFQ_SET_READY(&ifp->if_snd);
-		if_attach(ifp);
-		if_alloc_sadl(ifp);
+	sc->sc_if.if_type = IFT_LOOP;
+	sc->sc_if.if_hdrlen = 0;
+	sc->sc_if.if_addrlen = 0;
+	sc->sc_if.if_dlt = DLT_NULL;
+	IFQ_SET_READY(&sc->sc_if.if_snd);
+	if (unit == 0)
+		lo0ifp = &sc->sc_if;
+	if_attach(&sc->sc_if);
+	if_alloc_sadl(&sc->sc_if);
 #if NBPFILTER > 0
-		bpfattach(ifp, DLT_NULL, sizeof(u_int));
+	bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
 #endif
 #ifdef MBUFTRACE
-		ifp->if_mowner = &lomowner[i];
-		strlcpy(ifp->if_mowner->mo_name, ifp->if_xname,
-		    sizeof(ifp->if_mowner->mo_name));
-		MOWNER_ATTACH(&lomowner[i]);
+	sc->sc_if.if_mowner = malloc(sizeof(struct mowner), M_DEVBUF, M_WAITOK);
+	if (sc->sc_if.if_mowner == NULL)
+		return (ENOMEM);
+	(void)memset(sc->sc_if.if_mowner, 0, sizeof(struct mowner));
+	strlcpy(sc->sc_if.if_mowner->mo_name, sc->sc_if.if_xname,
+	    sizeof(sc->sc_if.if_mowner->mo_name));
+	MOWNER_ATTACH(sc->sc_if.if_mowner);
 #endif
-	}
+	LIST_INSERT_HEAD(&loop_softc_list, sc, sc_list);
+
+	return (0);
+}
+
+void
+loop_clone_destroy(struct ifnet *ifp)
+{
+	struct loop_softc *sc = ifp->if_softc;
+
+	if (ifp == lo0ifp)		/* don't kill lo0 */
+		return;
+
+#ifdef MBUFTRACE
+	MOWNER_DETACH(ifp->if_mowner);
+	free(ifp->if_mowner, M_DEVBUF);
+#endif
+
+#if NBPFILTER > 0
+	bpfdetach(ifp);
+#endif
+	if_detach(ifp);
+
+	LIST_REMOVE(sc, sc_list);
+	free(sc, M_DEVBUF);
 }
 
 int
@@ -406,9 +454,8 @@
 	struct rt_addrinfo *info;
 {
 
-	struct ifnet *ifp = &loif[0];
 	if (rt)
-		rt->rt_rmx.rmx_mtu = ifp->if_mtu;
+		rt->rt_rmx.rmx_mtu = lo0ifp->if_mtu;
 
 }
 
Index: net/net_osdep.h
===================================================================
RCS file: /cvsroot/src/sys/net/net_osdep.h,v
retrieving revision 1.8
diff -u -r1.8 net_osdep.h
--- net/net_osdep.h	14 May 2003 22:45:02 -0000	1.8
+++ net/net_osdep.h	23 Jul 2004 15:42:07 -0000
@@ -195,8 +195,8 @@
  * - struct ifnet for loopback interface
  *	BSDI3: struct ifnet loif;
  *	BSDI4: struct ifnet *loifp;
- *	NetBSD, OpenBSD 2.8, FreeBSD2: struct ifnet loif[NLOOP];
- *	OpenBSD 2.9: struct ifnet *lo0ifp;
+ *	NetBSD 2.0, OpenBSD 2.8, FreeBSD2: struct ifnet loif[NLOOP];
+ *	NetBSD 3.0, OpenBSD 2.9: struct ifnet *lo0ifp;
  *
  *	odd thing is that many of them refers loif as ifnet *loif,
  *	not loif[NLOOP], from outside of if_loop.c.
Index: netinet/if_arp.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/if_arp.c,v
retrieving revision 1.98
diff -u -r1.98 if_arp.c
--- netinet/if_arp.c	25 May 2004 04:33:59 -0000	1.98
+++ netinet/if_arp.c	23 Jul 2004 15:42:08 -0000
@@ -152,9 +152,6 @@
 					  int, int));
 static	void in_arpinput __P((struct mbuf *));
 
-#if NLOOP > 0
-extern	struct ifnet loif[NLOOP];
-#endif
 LIST_HEAD(, llinfo_arp) llinfo_arp;
 struct	ifqueue arpintrq = {0, 0, 0, 50};
 int	arp_inuse, arp_allocated, arp_intimer;
@@ -552,7 +549,7 @@
 		if (ia) {
 			/*
 			 * This test used to be
-			 *	if (loif.if_flags & IFF_UP)
+			 *	if (lo0ifp->if_flags & IFF_UP)
 			 * It allowed local traffic to be forced through
 			 * the hardware by configuring the loopback down.
 			 * However, it causes problems during network
@@ -573,7 +570,7 @@
 			    SDL(gate)->sdl_alen = rt->rt_ifp->if_addrlen);
 #if NLOOP > 0
 			if (useloopback)
-				rt->rt_ifp = &loif[0];
+				rt->rt_ifp = lo0ifp;
 #endif
 			/*
 			 * make sure to set rt->rt_ifa to the interface
Index: netinet/ip_output.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_output.c,v
retrieving revision 1.134
diff -u -r1.134 ip_output.c
--- netinet/ip_output.c	6 Jul 2004 04:30:27 -0000	1.134
+++ netinet/ip_output.c	23 Jul 2004 15:42:09 -0000
@@ -1832,7 +1832,7 @@
  * Routine called from ip_output() to loop back a copy of an IP multicast
  * packet to the input queue of a specified interface.  Note that this
  * calls the output routine of the loopback "driver", but with an interface
- * pointer that might NOT be &loif -- easier than replicating that code here.
+ * pointer that might NOT be lo0ifp -- easier than replicating that code here.
  */
 static void
 ip_mloopback(ifp, m, dst)
Index: netinet6/in6_pcb.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/in6_pcb.c,v
retrieving revision 1.65
diff -u -r1.65 in6_pcb.c
--- netinet6/in6_pcb.c	24 Jun 2004 16:49:51 -0000	1.65
+++ netinet6/in6_pcb.c	23 Jul 2004 15:42:09 -0000
@@ -92,8 +92,6 @@
 #include <netinet6/in6_pcb.h>
 #include <netinet6/nd6.h>
 
-#include "loop.h"
-extern struct ifnet loif[NLOOP];
 #include "faith.h"
 
 #ifdef IPSEC
Index: netinet6/in6_src.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/in6_src.c,v
retrieving revision 1.18
diff -u -r1.18 in6_src.c
--- netinet6/in6_src.c	10 Dec 2003 11:46:33 -0000	1.18
+++ netinet6/in6_src.c	23 Jul 2004 15:42:09 -0000
@@ -97,9 +97,6 @@
 
 #include <net/net_osdep.h>
 
-#include "loop.h"
-extern struct ifnet loif[NLOOP];
-
 /*
  * Return an IPv6 address, which is the most appropriate for a given
  * destination and user specified options.
@@ -195,9 +192,8 @@
 	if (IN6_IS_ADDR_MULTICAST(dst)) {
 		struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
 
-		if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) {
-			ifp = &loif[0];
-		}
+		if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst))
+			ifp = lo0ifp;
 
 		if (ifp) {
 			ia6 = in6_ifawithscope(ifp, dst);
Index: netinet6/ip6_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.75
diff -u -r1.75 ip6_input.c
--- netinet6/ip6_input.c	1 Jun 2004 03:13:22 -0000	1.75
+++ netinet6/ip6_input.c	23 Jul 2004 15:42:10 -0000
@@ -112,8 +112,6 @@
 
 #include <netinet6/ip6protosw.h>
 
-/* we need it for NLOOP. */
-#include "loop.h"
 #include "faith.h"
 #include "gif.h"
 #include "bpfilter.h"
@@ -131,7 +129,6 @@
 struct in6_ifaddr *in6_ifaddr;
 struct ifqueue ip6intrq;
 
-extern struct ifnet loif[NLOOP];
 int ip6_forward_srcrt;			/* XXX */
 int ip6_sourcecheck;			/* XXX */
 int ip6_sourcecheck_interval;		/* XXX */
@@ -248,7 +245,7 @@
 #define M2MMAX	(sizeof(ip6stat.ip6s_m2m)/sizeof(ip6stat.ip6s_m2m[0]))
 		if (m->m_next) {
 			if (m->m_flags & M_LOOP) {
-				ip6stat.ip6s_m2m[loif[0].if_index]++; /* XXX */
+				ip6stat.ip6s_m2m[lo0ifp->if_index]++; /* XXX */
 			} else if (m->m_pkthdr.rcvif->if_index < M2MMAX)
 				ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++;
 			else
Index: netinet6/ip6_output.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.85
diff -u -r1.85 ip6_output.c
--- netinet6/ip6_output.c	14 Jul 2004 03:06:08 -0000	1.85
+++ netinet6/ip6_output.c	23 Jul 2004 15:42:12 -0000
@@ -98,8 +98,6 @@
 #include <netkey/key.h>
 #endif /* IPSEC */
 
-#include "loop.h"
-
 #include <net/net_osdep.h>
 
 #ifdef PFIL_HOOKS
@@ -124,8 +122,6 @@
 static int ip6_insert_jumboopt __P((struct ip6_exthdrs *, u_int32_t));
 static int ip6_splithdr __P((struct mbuf *, struct ip6_exthdrs *));
 
-extern struct ifnet loif[NLOOP];
-
 /*
  * IP6 output. The packet in mbuf chain m contains a skeletal IP6
  * header (with pri, len, nxt, hlim, src, dst).
@@ -624,9 +620,8 @@
 				/* XXX correct ifp? */
 				in6_ifstat_inc(ifp, ifs6_out_discard);
 				goto bad;
-			} else {
-				ifp = &loif[0];
-			}
+			} else
+				ifp = lo0ifp;
 		}
 
 		if (opt && opt->ip6po_hlim != -1)
@@ -1912,7 +1907,7 @@
 			 *   XXX: is it a good approach?
 			 */
 			if (IN6_IS_ADDR_MC_NODELOCAL(&mreq->ipv6mr_multiaddr)) {
-				ifp = &loif[0];
+				ifp = lo0ifp;
 			} else {
 				ro.ro_rt = NULL;
 				dst = (struct sockaddr_in6 *)&ro.ro_dst;
@@ -2309,7 +2304,7 @@
  * Routine called from ip6_output() to loop back a copy of an IP6 multicast
  * packet to the input queue of a specified interface.  Note that this
  * calls the output routine of the loopback "driver", but with an interface
- * pointer that might NOT be &loif -- easier than replicating that code here.
+ * pointer that might NOT be lo0ifp -- easier than replicating that code here.
  */
 void
 ip6_mloopback(ifp, m, dst)
Index: netinet6/nd6.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/nd6.c,v
retrieving revision 1.90
diff -u -r1.90 nd6.c
--- netinet6/nd6.c	19 May 2004 17:45:05 -0000	1.90
+++ netinet6/nd6.c	23 Jul 2004 15:42:13 -0000
@@ -69,9 +69,6 @@
 #include <netinet6/ipsec.h>
 #endif
 
-#include "loop.h"
-extern struct ifnet loif[NLOOP];
-
 #include <net/net_osdep.h>
 
 #define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */
@@ -1177,7 +1174,7 @@
 				SDL(gate)->sdl_alen = ifp->if_addrlen;
 			}
 			if (nd6_useloopback) {
-				rt->rt_ifp = &loif[0];	/* XXX */
+				rt->rt_ifp = lo0ifp;	/* XXX */
 				/*
 				 * Make sure rt_ifa be equal to the ifaddr
 				 * corresponding to the address.
Index: netiso/if_eon.c
===================================================================
RCS file: /cvsroot/src/sys/netiso/if_eon.c,v
retrieving revision 1.45
diff -u -r1.45 if_eon.c
--- netiso/if_eon.c	21 Apr 2004 18:40:41 -0000	1.45
+++ netiso/if_eon.c	23 Jul 2004 15:42:13 -0000
@@ -109,10 +109,6 @@
 
 #include <machine/stdarg.h>
 
-#include "loop.h"
-
-extern struct ifnet loif[NLOOP];
-
 extern struct timeval time;
 
 #define EOK 0
@@ -294,7 +290,7 @@
 
 	case RTM_ADD:
 	case RTM_RESOLVE:
-		rt->rt_rmx.rmx_mtu = loif[0].if_mtu;	/* unless better below */
+		rt->rt_rmx.rmx_mtu = lo0ifp->if_mtu;	/* unless better below */
 		R_Malloc(el, struct eon_llinfo *, sizeof(*el));
 		rt->rt_llinfo = (caddr_t) el;
 		if (el == 0)

--W/nzBZO5zC0uMSeA--