Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/lkm/net/ethfoo Add ethfoo LKM example. It implements a ...



details:   https://anonhg.NetBSD.org/src/rev/19d81539a8c7
branches:  trunk
changeset: 555670:19d81539a8c7
user:      cube <cube%NetBSD.org@localhost>
date:      Mon Nov 24 21:58:45 2003 +0000

description:
Add ethfoo LKM example.  It implements a cloning interface for fake
Ethernet devices that can be assigned an Ethernet address using the
included setaddr utility.

diffstat:

 sys/lkm/net/ethfoo/Makefile            |    6 +
 sys/lkm/net/ethfoo/README              |   42 ++
 sys/lkm/net/ethfoo/ethfoo/Makefile     |    7 +
 sys/lkm/net/ethfoo/ethfoo/ethfoo_lkm.c |  518 +++++++++++++++++++++++++++++++++
 sys/lkm/net/ethfoo/setaddr/Makefile    |    6 +
 sys/lkm/net/ethfoo/setaddr/setaddr.c   |   76 ++++
 6 files changed, 655 insertions(+), 0 deletions(-)

diffs (truncated from 679 to 300 lines):

diff -r 0af95834d21c -r 19d81539a8c7 sys/lkm/net/ethfoo/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/lkm/net/ethfoo/Makefile       Mon Nov 24 21:58:45 2003 +0000
@@ -0,0 +1,6 @@
+# $NetBSD: Makefile,v 1.1 2003/11/24 21:58:45 cube Exp $
+
+SUBDIR=                ethfoo
+SUBDIR+=       setaddr
+
+.include <bsd.subdir.mk>
diff -r 0af95834d21c -r 19d81539a8c7 sys/lkm/net/ethfoo/README
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/lkm/net/ethfoo/README Mon Nov 24 21:58:45 2003 +0000
@@ -0,0 +1,42 @@
+$NetBSD: README,v 1.1 2003/11/24 21:58:45 cube Exp $
+
+ethfoo is meant to be an example of a few features of the NetBSD kernel.
+The module, once loaded, emulates one or several Ethernet devices, each
+one having its own Ethernet address.  You can do most of what can be
+done with a real Ethernet device, but no packet can be received.
+
+On the network layer, ethfoo is a convenient skeleton for an Ethernet
+device driver, and demonstrates how an interface should be attached and
+manipulated inside the kernel.  It also implements a cloning interface,
+making it possible for the administrator to create and destroy ethfoo
+interfaces at will, using the 'create' keyword of ifconfig:
+
+       # ifconfig ethfoo15 create
+       # ifconfig ethfoo15 inet 192.168.23.45
+       # ifconfig ethfoo15 destroy
+
+ethfoo is also a demonstration of what can be done with autoconf(9) from
+a Loadable Kernel Module.  It uses Jason R. Thorpe's idea of adding a
+pseudo-device to the autoconf tables to avoid any attachment troubles,
+as seen in sys/dev/ata/ata_raid.c.
+
+A cfdriver structure and a cfdata structure are registered to the system
+at load time, making it possible to creates instances of the pseudo-
+device when the administrator uses the ifconfig create command.  When a
+new ethfoo device is attached, the usual standard autoconf routines are
+called: match() and attach().  Since we registered the cf structures,
+we don't have to care about allocating structures such as the softc, it
+has already been done by the kernel.
+
+At that point it would even be possible to pass more parameters to the
+new device, using the custom argument through a ethfoo_attach_args
+structure.  It could be useful to pass an Ethernet address, for example.
+
+ethfoo is not supposed to be anything more than an example of how to
+write a simple but complete LKM, though it can be good to have a fake
+Ethernet device when using software such as FlexLM.
+
+It would be a good idea to pull up parts of ethfoo into tun(4), to make
+it possible to read and write packets through a character device.  It is
+also possible to extend ethfoo in that direction using MOD_DEV instead
+of MOD_MISC.
diff -r 0af95834d21c -r 19d81539a8c7 sys/lkm/net/ethfoo/ethfoo/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/lkm/net/ethfoo/ethfoo/Makefile        Mon Nov 24 21:58:45 2003 +0000
@@ -0,0 +1,7 @@
+# $NetBSD: Makefile,v 1.1 2003/11/24 21:58:45 cube Exp $
+
+SRCS=  ethfoo_lkm.c
+KMOD=  ethfoo
+MAN=   #
+
+.include <bsd.kmod.mk>
diff -r 0af95834d21c -r 19d81539a8c7 sys/lkm/net/ethfoo/ethfoo/ethfoo_lkm.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/lkm/net/ethfoo/ethfoo/ethfoo_lkm.c    Mon Nov 24 21:58:45 2003 +0000
@@ -0,0 +1,518 @@
+/*     $NetBSD: ethfoo_lkm.c,v 1.1 2003/11/24 21:58:45 cube Exp $      */
+
+/*
+ *  Copyright (c) 2003, Quentin Garnier.  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ *  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ *  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * ethfoo is a NetBSD Loadable Kernel Module that demonstrates the use of
+ * several kernel mechanisms, mostly in the networking subsytem.
+ *
+ * First, it is sample LKM, with the standard LKM management routines and
+ * Second, sample Ethernet driver.
+ * Third, sample of use of autoconf stuff inside a LKM.
+ * Fourth, sample clonable interface
+ *
+ * XXX Hacks
+ * 1. NetBSD doesn't offer a way to change an Ethernet address, so I chose
+ *    to use the SIOCSIFPHYADDR ioctl() normally used by gif(4).
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#if __NetBSD_Version__ > 106200000
+#include <sys/ksyms.h>
+#endif
+#include <sys/lkm.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_ether.h>
+#include <net/if_media.h>
+
+/* autoconf(9) structures */
+
+CFDRIVER_DECL(ethfoo, DV_DULL, NULL);
+
+static struct cfdata ethfoo_cfdata = {
+       "ethfoo", "ethfoo", 0, FSTATE_STAR,
+};
+
+/*
+ * Since we're an Ethernet device, we need the 3 following
+ * components: a leading struct device, a struct ethercom,
+ * and also a struct ifmedia since we don't attach a PHY to
+ * ourselves. We could emulate one, but there's no real
+ * point.
+ *
+ * sc_bpf_mtap is here to optionnally depend on BPF, to make
+ * our faked interface available to BPF listeners. Here, ksyms
+ * is used to check if BPF was compiled in, so it is only
+ * available in -current.
+ */
+
+struct ethfoo_softc {
+       struct device   sc_dev;
+       struct ifmedia  sc_im;
+       struct ethercom sc_ec;
+       void            (*sc_bpf_mtap)(caddr_t, struct mbuf *);
+};
+
+/* LKM management routines */
+
+int            ethfoo_lkmentry(struct lkm_table *, int, int);
+static int     ethfoo_lkmload(struct lkm_table *, int);
+static int     ethfoo_lkmunload(struct lkm_table *, int);
+
+/* autoconf(9) glue */
+
+static int     ethfoo_match(struct device *, struct cfdata *, void *);
+static void    ethfoo_attach(struct device *, struct device *, void *);
+static int     ethfoo_detach(struct device*, int);
+
+CFATTACH_DECL(ethfoo, sizeof(struct ethfoo_softc),
+    ethfoo_match, ethfoo_attach, ethfoo_detach, NULL);
+
+/*
+ * We don't need any particular functionality available to LKMs,
+ * such as a device number or a syscall number, thus MOD_MISC is
+ * enough.
+ */
+
+MOD_MISC("ethfoo");
+
+/*
+ * Those are needed by the if_media interface.
+ */
+
+static int     ethfoo_mediachange(struct ifnet *);
+static void    ethfoo_mediastatus(struct ifnet *, struct ifmediareq *);
+
+/*
+ * Those are needed by the ifnet interface, and would typically be
+ * there for any network interface driver.
+ * Some other routines are optional: watchdog and drain.
+ */
+
+static void    ethfoo_start(struct ifnet *);
+static void    ethfoo_stop(struct ifnet *, int);
+static int     ethfoo_init(struct ifnet *);
+static int     ethfoo_ioctl(struct ifnet *, u_long, caddr_t);
+
+/* This is an internal function to keep ethfoo_ioctl readable */
+static int     ethfoo_lifaddr(struct ifnet *, u_long, struct ifaliasreq *);
+
+/*
+ * ethfoo is a clonable interface, although it is highly unrealistic for
+ * an Ethernet device.
+ *
+ * Here are the bits needed for a clonable interface.
+ */
+static int     ethfoo_clone_create(struct if_clone *, int);
+static void    ethfoo_clone_destroy(struct ifnet *);
+
+struct if_clone ethfoo_cloners = IF_CLONE_INITIALIZER("ethfoo",
+                                       ethfoo_clone_create,
+                                       ethfoo_clone_destroy);
+
+/* We don't have anything to do on 'modstat' */
+int
+ethfoo_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
+{
+       DISPATCH(lkmtp, cmd, ver, ethfoo_lkmload, ethfoo_lkmunload, lkm_nofunc);
+}
+
+/*
+ * autoconf(9) is a rather complicated piece of work, but in the end
+ * it is rather flexible, so you can easily add a device somewhere in
+ * the tree, and make almost anything attach to something known.
+ *
+ * Here the idea is taken from Jason R. Thorpe's ataraid(4) pseudo-
+ * device.  Instead of needing a declaration in the kernel
+ * configuration, we teach autoconf(9) the availability of the
+ * pseudo-device at run time.
+ *
+ * Once our autoconf(9) structures are committed to the kernel's
+ * arrays, we can attach a device.  It is done through config_attach
+ * for a real device, but for a pseudo-device it is a bit different
+ * and one has to use config_pseudo_attach.
+ *
+ * And since we want the user to be responsible for creating device,
+ * we use the interface cloning mechanism, and advertise our interface
+ * to the kernel.
+ */
+static int
+ethfoo_lkmload(struct lkm_table *lkmtp, int cmd)
+{
+       int error = 0;
+
+       error = config_cfdriver_attach(&ethfoo_cd);
+       if (error) {
+               aprint_error("%s: unable to register cfdriver\n",
+                   ethfoo_cd.cd_name);
+               goto out;
+       }
+
+       error = config_cfattach_attach(ethfoo_cd.cd_name, &ethfoo_ca);
+       if (error) {
+               aprint_error("%s: unable to register cfattach\n",
+                   ethfoo_cd.cd_name);
+               (void)config_cfdriver_detach(&ethfoo_cd);
+               goto out;
+       }
+
+       if_clone_attach(&ethfoo_cloners);
+
+out:
+       return error;
+}
+
+/*
+ * Cleaning up is the most critical part of a LKM, since a module is not
+ * actually made to be loadable, but rather "unloadable".  If it is only
+ * to be loaded, you'd better link it to the kernel in the first place,
+ * either through compilation or through static linking (I think modload
+ * allows that).
+ *
+ * The interface cloning mechanism is really simple, with only two void
+ * returning functions.  It will always do its job. You should note though
+ * that if an instance of ethfoo can't be detached, the module won't
+ * unload and you won't be able to create interfaces anymore.
+ *
+ * We have to make sure the devices really exist, because they can be
+ * destroyed through ifconfig, hence the test whether cd_devs[i] is NULL
+ * or not.
+ *
+ * The cd_devs array is somehow the downside of the whole autoconf(9)
+ * mechanism, since if you only create 'ethfoo150', you'll get an array of
+ * 150 elements which 149 of them are NULL.
+ */
+static int
+ethfoo_lkmunload(struct lkm_table *lkmtp, int cmd)
+{
+       int error, i;
+
+       if_clone_detach(&ethfoo_cloners);
+
+       for (i = 0; i < ethfoo_cd.cd_ndevs; i++)
+               if (ethfoo_cd.cd_devs[i] != NULL &&
+                   (error = config_detach(ethfoo_cd.cd_devs[i], 0)) != 0) {
+                       aprint_error("%s: unable to detach instance\n",
+                           ((struct device *)ethfoo_cd.cd_devs[i])->dv_xname);
+                       return error;



Home | Main Index | Thread Index | Old Index