Subject: ppp(4) made clonable
To: None <tech-net@netbsd.org>
From: Quentin Garnier <cube@cubidou.net>
List: tech-net
Date: 08/13/2003 15:55:50
This is a multi-part message in MIME format.

--Multipart_Wed__13_Aug_2003_15:55:50_+0200_081f3e00
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit

Hi,

I've been wondering why ppp(4) isn't clonable, which in my mind means
"dynamically allocatable". Right now a static array of ppp_softcs is
allocated, whereas some other devices such as gre(4) were made clonable
some time ago.

Maybe there is a good reason for this situation, maybe not. I'm sure
someone here will tell me.

Anyway, the attached patch makes ppp(4) clonable, and pppalloc()
now allocates a new interface when it needs a new one, making pppd(8)
usable without having to type 'ifconfig ppp%d create' for each
interface before launching it.

I have not tested it extensively yet (notably the unit number selection
may be a bit unefficient), but it worked very well for the tests I made.

There is still an issue with pppd(8) though, because at startup it tests
for kernel PPP support by making an ioctl on ppp0, which may not exist.
I don't know how to solve this yet, but for now the patch takes in
account the value of NPPP to create some interfaces, starting with ppp0.

The code should recycle unit numbers to not make it grow when
connections are made and then shut down.

I made the patch usable as a kernel option, PPP_CLONABLE.

If anyone could at least tell me why this haven't been done before,
since it only took a few hours to code.

Quentin Garnier.

--Multipart_Wed__13_Aug_2003_15:55:50_+0200_081f3e00
Content-Type: text/plain;
 name="ppp_clonable.diff"
Content-Disposition: attachment;
 filename="ppp_clonable.diff"
Content-Transfer-Encoding: quoted-printable

Index: net/if_ppp.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/net/if_ppp.c,v
retrieving revision 1.84
diff -u -r1.84 if_ppp.c
--- net/if_ppp.c	2003/05/02 03:15:24	1.84
+++ net/if_ppp.c	2003/08/13 13:41:36
@@ -202,7 +202,19 @@
 #define	M_HIGHPRI	M_LINK0	/* output packet for sc_fastq */
 #define	M_ERRMARK	M_LINK1	/* rx packet following lost/corrupted pkt */
=20
+#ifdef PPP_CLONABLE
+static struct ppp_softc	*ppp_clone_create_helper(struct if_clone *, int);
+static int		ppp_clone_create(struct if_clone *, int);
+static void		ppp_clone_destroy(struct ifnet *);
+
+static LIST_HEAD(, ppp_softc) ppp_softc;
+static unsigned int ppp_ifcount =3D 0;
+
+struct if_clone ppp_cloner =3D
+    IF_CLONE_INITIALIZER("ppp", ppp_clone_create, ppp_clone_destroy);
+#else
 struct	ppp_softc ppp_softc[NPPP];
+#endif
=20
 #ifdef PPP_COMPRESS
 /*
@@ -232,9 +244,25 @@
 void
 pppattach()
 {
+#ifndef PPP_CLONABLE
     struct ppp_softc *sc;
+#endif
     int i =3D 0;
=20
+#ifdef PPP_CLONABLE
+    LIST_INIT(&ppp_softc);
+    if_clone_attach(&ppp_cloner);
+
+    /*
+     * Pre-create some interfaces.
+     * I don't know if this is TRT to do, but it should make pppd(8) work
+     * out of the box that way.
+     */
+    for (i =3D 0; i < NPPP; i++) {
+	if (ppp_clone_create(&ppp_cloner, i))
+	    aprint_error("ppp%d: couldn't create interface\n", i);
+    }
+#else
     for (sc =3D ppp_softc; i < NPPP; sc++) {
 	sc->sc_unit =3D i;	/* XXX */
 	sprintf(sc->sc_if.if_xname, "ppp%d", i++);
@@ -261,8 +289,94 @@
 	bpfattach(&sc->sc_if, DLT_NULL, 0);
 #endif
     }
+#endif /* PPP_CLONABLE */
+}
+
+#ifdef PPP_CLONABLE
+static struct ppp_softc *
+ppp_clone_create_helper(struct if_clone *ifc, int unit)
+{
+    struct ppp_softc *sc, *scl;
+    int s;
+
+    MALLOC(sc, struct ppp_softc *, sizeof(struct ppp_softc), M_DEVBUF, M_W=
AITOK);
+    memset(sc, 0, sizeof(struct ppp_softc));
+
+    sc->sc_unit =3D unit;	/* XXX */
+    sprintf(sc->sc_if.if_xname, "ppp%d", unit);
+    callout_init(&sc->sc_timo_ch);
+    sc->sc_if.if_softc =3D sc;
+    sc->sc_if.if_mtu =3D PPP_MTU;
+    sc->sc_if.if_flags =3D IFF_POINTOPOINT | IFF_MULTICAST;
+    sc->sc_if.if_type =3D IFT_PPP;
+    sc->sc_if.if_hdrlen =3D PPP_HDRLEN;
+    sc->sc_if.if_dlt =3D DLT_NULL;
+    sc->sc_if.if_ioctl =3D pppsioctl;
+    sc->sc_if.if_output =3D pppoutput;
+#ifdef ALTQ
+    sc->sc_if.if_start =3D ppp_ifstart;
+#endif
+    IFQ_SET_MAXLEN(&sc->sc_if.if_snd, IFQ_MAXLEN);
+    sc->sc_inq.ifq_maxlen =3D IFQ_MAXLEN;
+    sc->sc_fastq.ifq_maxlen =3D IFQ_MAXLEN;
+    sc->sc_rawq.ifq_maxlen =3D IFQ_MAXLEN;
+    IFQ_SET_READY(&sc->sc_if.if_snd);
+    if_attach(&sc->sc_if);
+    if_alloc_sadl(&sc->sc_if);
+#if NBPFILTER > 0
+    bpfattach(&sc->sc_if, DLT_NULL, 0);
+#endif
+
+    /*
+     * Search for the correct place to insert the new interface.
+     * The list is numbered, HEAD being the highest number
+     *
+     * XXX i don't really understand how unit conflicts can be avoided
+     */
+    LIST_FOREACH(scl, &ppp_softc, sc_iflist)
+	if (unit < scl->sc_unit)
+	    break;
+
+    s =3D splnet();
+    if (scl =3D=3D NULL)
+    	LIST_INSERT_HEAD(&ppp_softc, sc, sc_iflist);
+    else
+	LIST_INSERT_BEFORE(scl, sc, sc_iflist);
+    splx(s);
+    ppp_ifcount++;
+
+    return (sc);
+}
+
+static int
+ppp_clone_create(struct if_clone *ifc, int unit)
+{
+    if (ppp_clone_create_helper(ifc, unit) !=3D NULL)
+	return (0);
+    else
+	return (1);
 }
=20
+static void
+ppp_clone_destroy(struct ifnet *ifp)
+{
+    struct ppp_softc *sc =3D (struct ppp_softc *)ifp->if_softc;
+    int s;
+
+    if (sc->sc_devp !=3D NULL)
+	return; /* Not removing it */
+
+    s =3D splnet();
+    LIST_REMOVE(sc, sc_iflist);
+    splx(s);
+    ppp_ifcount--;
+
+    if_detach(ifp);
+
+    FREE(sc, M_DEVBUF);
+}
+#endif
+
 /*
  * Allocate a ppp interface unit and initialize it.
  */
@@ -270,19 +384,45 @@
 pppalloc(pid)
     pid_t pid;
 {
+#ifdef PPP_CLONABLE
+    int i;
+    int freeunit =3D ppp_ifcount - 1;
+#else
     int nppp, i;
+#endif
     struct ppp_softc *sc;
=20
+#ifdef PPP_CLONABLE
+    LIST_FOREACH(sc, &ppp_softc, sc_iflist)
+#else
     for (nppp =3D 0, sc =3D ppp_softc; nppp < NPPP; nppp++, sc++)
+#endif
 	if (sc->sc_xfer =3D=3D pid) {
 	    sc->sc_xfer =3D 0;
 	    return sc;
 	}
+#ifdef PPP_CLONABLE
+    LIST_FOREACH(sc, &ppp_softc, sc_iflist) {
+	if (sc->sc_devp =3D=3D NULL)
+	    break;
+	if (sc->sc_unit =3D=3D freeunit)
+	    freeunit--;
+    }
+    if (freeunit < 0)
+	freeunit =3D ppp_ifcount;
+#else
     for (nppp =3D 0, sc =3D ppp_softc; nppp < NPPP; nppp++, sc++)
 	if (sc->sc_devp =3D=3D NULL)
 	    break;
+#endif
+#ifdef PPP_CLONABLE
+    if (sc =3D=3D NULL)
+	if ((sc =3D ppp_clone_create_helper(&ppp_cloner, freeunit)) =3D=3D NULL)
+	    return NULL;
+#else
     if (nppp >=3D NPPP)
 	return NULL;
+#endif /* PPP_CLONABLE */
=20
 #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
     sc->sc_si =3D softintr_establish(IPL_SOFTNET, pppintr, sc);
@@ -389,6 +529,9 @@
 	FREE(sc->sc_comp, M_DEVBUF);
 	sc->sc_comp =3D 0;
     }
+#endif
+#ifdef PPP_CLONABLE
+    ppp_clone_destroy(&sc->sc_if);
 #endif
 }
=20
Index: net/if_pppvar.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/net/if_pppvar.h,v
retrieving revision 1.17
diff -u -r1.17 if_pppvar.h
--- net/if_pppvar.h	2003/07/08 07:13:51	1.17
+++ net/if_pppvar.h	2003/08/13 13:41:36
@@ -130,6 +130,9 @@
 #ifdef	VJC
 	struct	slcompress *sc_comp; 	/* vjc control buffer */
 #endif
+#ifdef PPP_CLONABLE
+	LIST_ENTRY(ppp_softc) sc_iflist;
+#endif
=20
 	/* Device-dependent part for async lines. */
 	ext_accm sc_asyncmap;		/* async control character map */
@@ -146,7 +149,9 @@
 };
=20
 #ifdef _KERNEL
+#ifndef PPP_CLONABLE
 extern	struct	ppp_softc ppp_softc[];
+#endif
=20
 struct	ppp_softc *pppalloc __P((pid_t));
 void	pppdealloc __P((struct ppp_softc *));

--Multipart_Wed__13_Aug_2003_15:55:50_+0200_081f3e00--