Update the work on ipfw tables, reduce diffs.
marta [Thu, 10 Dec 2009 10:30:48 +0000 (10:30 +0000)]
Create a new directory with PlanetLab stuff and changed specfiles accordingly.

29 files changed:
Makefile.openwrt [new file with mode: 0644]
NOTES [new file with mode: 0644]
README
README.openwrt [new file with mode: 0644]
dummynet/Makefile
dummynet/hashtable.c
dummynet/include/net/radix.h [new file with mode: 0644]
dummynet/include/netinet/ip_dummynet.h
dummynet/include/netinet/ip_fw.h
dummynet/include/sys/mbuf.h
dummynet/ip_dummynet.c
dummynet/ip_fw2.c
dummynet/ip_fw_pfil.c
dummynet/ipfw2_mod.c
dummynet/missing.h
dummynet/new_glue.c
dummynet/radix.c [new file with mode: 0644]
glue.h
ipfw-slice.spec
ipfw.spec
ipfw/Makefile
ipfw/dummynet.c
ipfw/ipfw2.c
ipfw/ipfw2.h
planetlab/ipfw-cleanup [moved from ipfw-cleanup with 100% similarity]
planetlab/ipfw.8.gz [moved from slice/ipfw.8.gz with 100% similarity]
planetlab/ipfw.cron [moved from ipfw.cron with 100% similarity]
planetlab/netconfig [moved from slice/netconfig with 100% similarity]
planetlab/sample_hook [moved from sample_hook with 100% similarity]

diff --git a/Makefile.openwrt b/Makefile.openwrt
new file mode 100644 (file)
index 0000000..50dae83
--- /dev/null
@@ -0,0 +1,79 @@
+# Makefile to build the package in openwrt.
+# goes into package/ipfw2/Makefile
+#
+# Edit IPFW_DIR to point to the directory with the sources for ipfw
+
+IPFW_DIR := $(TOPDIR)/../ipfw_mod
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=kmod-ipfw2
+PKG_RELEASE:=1
+
+# MV is undefined
+MV ?= mv
+
+include $(INCLUDE_DIR)/package.mk
+
+# Description for the package.
+# The names KernelPackage/ipfw2 must match the arguments to the
+# call $(eval $(call KernelPackage,ipfw2)) used to build it
+
+
+define KernelPackage/ipfw2
+ SUBMENU:=Other modules
+ TITLE:= IPFW and dummynet
+ # FILES is what makes up the module, both kernel and userland
+ # It must be in the KernelPackage section
+ FILES := $(PKG_BUILD_DIR)/dummynet/ipfw_mod.o $(PKG_BUILD_DIR)/ipfw/ipfw
+ # AUTOLOAD:=$(call AutoLoad,80,ipfw_mod)
+endef
+
+define KernelPackage/ipfw2/description
+ This package contains the ipfw and dummynet module
+endef
+
+# Standard entries for the openwrt builds: Build/Prepare and Build/Compile
+# Remember that commands must start with a tab
+
+# 'prepare' instructions for both kernel and userland
+# We copy the entire subtree, then build include_e/ which
+# contains empty headers used by the kernel sources.
+define Build/Prepare
+  # $(warning Preparing ipfw sources)
+       mkdir -p $(PKG_BUILD_DIR)
+       $(CP) -Rp $(IPFW_DIR)/* $(PKG_BUILD_DIR)/
+       (cd $(PKG_BUILD_DIR)/dummynet && $(MAKE) include_e )
+endef
+
+define Build/Compile
+       # compile the kernel part for openwrt
+       $(MAKE) -C "$(LINUX_DIR)" \
+               CROSS_COMPILE="$(TARGET_CROSS)" \
+               ARCH="$(LINUX_KARCH)" \
+               SUBDIRS="$(PKG_BUILD_DIR)/dummynet" \
+               VER=openwrt modules
+       # compile the userland part for openwrt
+       $(MAKE) -C $(PKG_BUILD_DIR)/ipfw \
+               $(TARGET_CONFIGURE_OPTS) \
+               CFLAGS="$(TARGET_CFLAGS) -I./include -include ../glue.h" \
+               VER=openwrt all
+endef
+
+define Package/ipfw2-userland
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE := /sbin/ipfw
+  DESCRIPTION := This is the control program for ipfw and dummynet
+endef
+
+define Package/ipfw2-userland/install
+       $(INSTALL_DIR) $(1) /sbin
+endef
+
+# XXX not entirely clear why the install entry for userland works,
+# given that /sbin/ipfw is in KernelPackage/ipfw2
+
+$(eval $(call Package,ipfw2-userland))
+$(eval $(call KernelPackage,ipfw2))
diff --git a/NOTES b/NOTES
new file mode 100644 (file)
index 0000000..b00a8fd
--- /dev/null
+++ b/NOTES
@@ -0,0 +1,190 @@
+#
+# $Id: NOTES 2844 2009-06-22 10:59:35Z luigi $
+#
+
+---------------------------------------------------------------------
+---  DEVELOPER NOTES ------------------------------------------------
+
+Both the client and the kernel code use almost unmodified sources
+from FreeBSD (just a very small number of sections #ifdef'ed out
+for features not relevant or not implemented).
+
+In both cases we provide two set of headers:
+ - one set is made of empty files, automatically generated, to replace
+   FreeBSD headers not available or conflicting on the ported platforms.
+ - one set is made of custom files, sometimes copied verbatim
+   from FreeBSD, sometimes containing only the minimal set of
+   macros/ struct/ prototypes required by the port.
+
+Additionally, we have a small set of .c files providing functions not
+available in the port platforms, and hooks for the sockopt/packet
+data.
+
+
+TODO (LINUX), 20090622:
++ use an appropriate identifier instead of LINUX24
++ find the discharging module hook, in order to force a queue flush
++ use the output interface as a clock for the pipe
++ better matching on interface names (case insensitive etc ?)
++ match by interface address
++ verify path
++ send keepalives
++ tables support
++ uid/gid match (through the socket ?)
++ pullup or data in external buffers
++ O_TAG
++ O_DIVERT
++ O_TEE
++ O_SETFIB
++ kmem_cache_alloc 
+
+TODO (WINDOWS) 20090622
++ all of the above, once it works
+# svn
+https://svn.sourceforge.net/svnroot/wipfw
+
+TODO (OpenWRT) 20090622
++ add a module compilation for 2.6
+
+TODO (FreeBSD, general)
++ New features related to the forthcoming IPv6 are missing, as the IPv6
+support for lookup tables that currently support IPv4 addresses only.
+One of the goal of this project is to add the tables feature to the
+IPv6 protocol.
+
++ The current code implements rules listing requests as a single
+request returning both static and dynamic rules as a whole block. This
+operation requires a lock to be held for the time needed to get the
+full list of rules, regardless of the requested rules.  I propose to
+break up the rule request in two parts, for static and dynamic rules, in
+order to avoid to lock the whole struct for a subset of rules required.
+
++ At last, due to improvement and contribution to the code, the tool
+significantly grown over the time with new functionalities and features,
+leaving the general view aside. An example of this will be the use of
+dispatching table instead some very long switch case, making the resulting
+code more readable and hopefully a faster execution.
+
++ XXX can't find the ipfw_* indirection...
+
+DETAILED PORTING INFO
+
+--- ipfw (userland) on linux ---
+
+The port is relatively trivial. Communication with the kernel occurs
+through a raw socket using [gs]etsockopt(), and all is needed is the
+availability of ip_fw.h and ip_dummynet.h headers to describe the
+relevant data structures.
+
+--- kernel ipfw on linux ---
+
+Sources are mostly unmodified, except for commenting out
+unsupported features (tables, in-kernel nat...).
+The port requires a rather large number of empty headers.
+Other porting issues are in ipfw2_mod.c
+
+--- build as an Openwrt package
+
+------ WINDOWS PORT ------
+
+A port to windows is still in progress.
+This directory contain a port of ipfw and dummynet to Windows.
+
+--- BACKGROUND:
+
+We started from the wipfw port available at [WIPFW] , but
+most of the port is done from scratch using the most recent
+version of ipfw+dummynet from HEAD/RELENG_7 as of March 2009
+
+# WIPFW: wipfw.sourceforge.net
+#binary:
+http://downloads.sourceforge.net/wipfw/wipfw-0.3.2b.zip?use_mirror=mesh
+http://downloads.sourceforge.net/wipfw/wipfw-0.2.8-source.zip
+
+--- DEVELOPMENT TOOLS:
+
+At least initially, to build the code you need a pc with
+windows installed and the [WINDDK] from the microsoft site.
+Other tools like the new WDK should work as well.
+
+The 'standard' way used by WDK/WINDDK is to run a 'build'
+script which in turn calls nmake and then the microsoft
+compiler [CL] and linker [LINK]. See the documentation for
+command line switches for these tools, they are similar but
+not the same as the equivalent gcc switches. In particular,
+a / is often used to replace - though both forms are accepted.
+
+The steps to do in order to launch the build environment follows:
+
+ + download winddk from microsoft.com 
+ + install 
+ + run the Free Build Enviroment from:
+
+       Start -> All Program -> WINDDK ->
+       [NT|XP|2000] -> Free Build Environment
+
+ + change dir to .src and type `build' in command line
+
+For our purposes, however, it is much more convenient to use
+cygwin [CYGWIN] and invoke CL and LINK using gmake
+
+A debugging tools is:
+       http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx
+it simply display the kernel-mode debug output.
+Use the DbgPrint() function, that is something similar to printk().
+Can be lauched with dbgview.exe.
+
+After a succesfully compilation and link, you can launch the program
+in user space simply executing the binary file, while for the kernel
+space you need to do the following steps:
+
+cp ipfw.sys /cygdrive/c/WINDOWS/system32/drivers/
+ipfw install_drv System32\DRIVERS\ip_fw.sys
+net start ip_fw
+
+
+=======
+--- ARCHITECTURE ---
+
+The main part of the userland program mostly work as the
+unix equivalent, the only issue is to provide empty
+header files to replace those not available in Windows,
+and include the winsock2 headers to access some network
+related functions and headers.
+
+Communication with the kernel module does not use a raw IP socket
+as in the unix version. Instead, we inherit the same method
+used in ipfw -- a replacement for socket() creates a handle
+to access the control structure, and setsockopt/getsockopt
+replacements are also used to communicate with the kernel
+side. This is implemented in win32.c
+
+In order to load the module and activate it, we also use
+the same technique suggested in wipfw -- the main() is
+extended (with a wrapper) so that it can handle additional
+commands to install/control/deinstall the service and
+call the appropriate actions. See svcmain.c for details.
+
+--- PORTING ISSUES:
+
+Most of the unix hierarchy of headers is not available so we
+have to replicate them.
+
+gcc attributes are also not present.
+
+C99 types are not present, remapped in <sys/cdefs.h>
+
+--- USEFUL LINKS:
+
+[WIPFW]
+       http://wipfw.sourceforge.net/
+
+[WINDDK]
+       http://www.microsoft.com/whdc/devtools/ddk/default.mspx
+
+[CL]
+       http://msdn.microsoft.com/en-us/library/610ecb4h.aspx
+       command line syntax
+
+[CYGWIN]
+       http://www.cygwin.com/setup.exe
diff --git a/README b/README
index bfd3289..e5b5a4a 100644 (file)
--- a/README
+++ b/README
@@ -1,9 +1,9 @@
 #
-# $Id: README 4363 2009-12-08 16:06:54Z marta $
+# $Id: README 4396 2009-12-09 21:52:46Z luigi $
 #
 
 This directory contains a port of ipfw and dummynet to Linux and OpenWrt
-(a Windows version is in the works but not ready yet).
+(including PlanetLab).  A Windows version is in the works but not ready yet.
 Building the code produces:
 
        a kernel module,        ipfw_mod.ko
@@ -14,17 +14,15 @@ version in RELENG_7 and HEAD as of December 2009), plus some glue code
 and headers written from scratch.
 Unless specified otherwise, all the code here is under a BSD license.
 
-=== To compile for a 2.6 kernel, simply run
+=================== BUILD INSTRUCTIONS ==========================
 
-       make
+***** Linux 2.6.x ******
 
-    Make sure that kernel headers (or sources) are installed on your
-    system, and that the link "/lib/modules/`uname -r`/build" points
-    to the header/source tree matching your kernel.
+       make KERNELPATH=/path/to/linux USRDIR=/path/to/usr
 
-    You can override the default kernel tree with
-
-       make KERNELPATH=your_kernel_source_tree
+    where the two variables are optional an point to the linux kernel
+    sources and the /usr directory. Defaults are USRDIR=/usr and
+    KERNELPATH=/lib/modules/`uname -r`/build   --- XXX check ?
 
     NOTE: make sure CONFIG_NETFILTER is enabled in the kernel
     configuration file. You can enable it by doing
@@ -38,17 +36,19 @@ Unless specified otherwise, all the code here is under a BSD license.
               [*] Network packet filtering framework (Netfilter)
 
 
-=== To compile for a 2.4 kernel:
+***** Linux 2.4.x *****
+
+    Almost as above, with an additional VER=2.4
 
        make VER=2.4 KERNELPATH=...
 
     You need to follow the same instruction for the 2.6 kernel, enabling
-    the kernel options:
+    netfilter in the kernel options:
 
     Networking options  --->
       [*] Network packet filtering (replaces ipchains)
 
-=== To build an Openwrt package
+***** Openwrt package *****
 
     (Tested with kamikaze_8.09.1 and Linux 2.4)
 
@@ -104,4 +104,6 @@ Unless specified otherwise, all the code here is under a BSD license.
     /lib/modules/2.4.35.4/ipfw show             # launch the userspace tool
     rmmod ipfw_mod.o                            # remove the module
 
+***** PLANETLAB BUILD *****
+
 -----------------------------------------------------------------------------
diff --git a/README.openwrt b/README.openwrt
new file mode 100644 (file)
index 0000000..dcf8194
--- /dev/null
@@ -0,0 +1,29 @@
+OpenWrt on ASUSWL-520GC (admin, admin)
+
+Notes:
+   The firmware installed is the version: 2.0.1.1, the ip address
+   is 192.168.1.1, the web gui can be used by admin, admin.
+   After reflashing the board, the old firmware should be available
+   in the cdrom shipped with the router.
+
+OpenWRT compatility:
+1. The 2.4 kernel version has some troubles accessing the flash
+   and this will actually make the board hang after a while. 
+
+2. The 2.6 kernel does not have the same issue, except for the
+   open source b43 wireless driver, that make the board reboot
+   as soon as it is loaded.
+
+For this reason, when configuring the kernel option from the toolchain
+menu, the wireless target profile to choose should be `No WiFi'
+
+Flash the board:
+1. The compiled binary images are under the main tree, ./bin the file
+   to be used is openwrt-brcm47xx-squashfs.trx.
+2. Start the router in diag mode and goes with tftp, as follows:
+       tftp 192.168.1.1
+       tftp> bin
+       tftp> put openwrt-brcm47xx-squashfs.trx
+       Sent 1904640 bytes in 5.4 seconds
+       tftp> 
+3. Wait for 10 minutes, the reboot
index e732601..eab794a 100644 (file)
@@ -37,6 +37,7 @@ VER ?= 2.6
 obj-m := ipfw_mod.o
 
 # generic cflags used on all systems
+ipfw-cflags += -Dradix
 ipfw-cflags += -DIPFIREWALL_DEFAULT_TO_ACCEPT -DTRACE
 # _BSD_SOURCE enables __FAVOR_BSD (udp/tcp bsd structs instead of posix)
 ipfw-cflags += -D_BSD_SOURCE
@@ -133,7 +134,7 @@ ipfw_mod-y = $(IPFW_SRCS:%.c=%.o)
 
 # Original ipfw and dummynet sources + FreeBSD stuff,
 IPFW_SRCS = ip_fw2.c ip_dummynet.c ip_fw_pfil.c in_cksum.c
-
+IPFW_SRCS += radix.c
 # Module glue and functions missing in linux
 IPFW_SRCS += ipfw2_mod.c bsd_compat.c hashtable.c new_glue.c
 
@@ -148,24 +149,25 @@ $(obj-m): $(ipfw_mod-y)
        $(LD) $(LDFLAGS) -m elf_i386 -r -o $@ $^
 clean:
        -rm -f *.o *.ko Module.symvers *.mod.c
+       -rm -rf include_e
 
 distclean: clean
        -rm -f .*cmd modules.order opt_*
        -rm -rf .tmp_versions include_e
-       -rm -rf .ip_dummynet.o.d
+       -rm -rf .*.o.d
 
 # support to create empty dirs and files in include_e/
 # EDIRS is the list of directories, EFILES is the list of files.
 
 EDIRS= altq arpa machine net netinet netinet6 sys
 
-EFILES += opt_inet6.h opt_ipfw.h opt_ipsec.h opt_mac.h
+EFILES += opt_inet6.h opt_ipfw.h opt_ipsec.h
 EFILES += opt_mbuf_stress_test.h opt_param.h
 
 EFILES += altq/if_altq.h
 EFILES += arpa/inet.h
 EFILES += machine/in_cksum.h
-EFILES += net/ethernet.h net/netisr.h net/pf_mtag.h net/radix.h
+EFILES += net/ethernet.h net/netisr.h net/pf_mtag.h
 EFILES += net/vnet.h
 
 EFILES += netinet/ether.h netinet/icmp6.h netinet/if_ether.h
@@ -176,7 +178,8 @@ EFILES += netinet/udp_var.h
 
 EFILES += netinet6/ip6_var.h
 
-EFILES += sys/_lock.h sys/_mutex.h sys/jail.h
+EFILES += sys/_lock.h sys/_rwlock.h sys/_mutex.h sys/jail.h
+EFILES += sys/condvar.h sys/eventhandler.h
 EFILES += sys/limits.h sys/lock.h sys/mutex.h sys/priv.h
 EFILES += sys/proc.h sys/rwlock.h sys/socket.h sys/socketvar.h
 EFILES += sys/sysctl.h sys/time.h sys/ucred.h
index 517cec6..30c3b4c 100644 (file)
@@ -125,7 +125,7 @@ new_table_extract_obj(struct new_hash_table *h, const void *obj)
        i = h->hash(obj, h->table_size);
        for (o =  h->table_ptr[i]; o; o = o->next) {
                if (h->cmp(o->obj, obj) == 0)
-                       return obj;
+                       return o->obj;
        }
        return NULL;
 }
diff --git a/dummynet/include/net/radix.h b/dummynet/include/net/radix.h
new file mode 100644 (file)
index 0000000..5d99a2f
--- /dev/null
@@ -0,0 +1,179 @@
+/*-
+ * Copyright (c) 1988, 1989, 1993
+ *     The Regents of the University of California.  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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *     @(#)radix.h     8.2 (Berkeley) 10/31/94
+ * $FreeBSD: head/sys/net/radix.h 185747 2008-12-07 21:15:43Z kmacy $
+ */
+
+#ifndef _RADIX_H_
+#define        _RADIX_H_
+
+#ifdef _KERNEL
+#include <sys/_lock.h>
+#include <sys/_mutex.h>
+#include <sys/_rwlock.h>
+#endif
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_RTABLE);
+#endif
+
+/*
+ * Radix search tree node layout.
+ */
+
+struct radix_node {
+       struct  radix_mask *rn_mklist;  /* list of masks contained in subtree */
+       struct  radix_node *rn_parent;  /* parent */
+       short   rn_bit;                 /* bit offset; -1-index(netmask) */
+       char    rn_bmask;               /* node: mask for bit test*/
+       u_char  rn_flags;               /* enumerated next */
+#define RNF_NORMAL     1               /* leaf contains normal route */
+#define RNF_ROOT       2               /* leaf is root leaf for tree */
+#define RNF_ACTIVE     4               /* This node is alive (for rtfree) */
+       union {
+               struct {                        /* leaf only data: */
+                       caddr_t rn_Key;         /* object of search */
+                       caddr_t rn_Mask;        /* netmask, if present */
+                       struct  radix_node *rn_Dupedkey;
+               } rn_leaf;
+               struct {                        /* node only data: */
+                       int     rn_Off;         /* where to start compare */
+                       struct  radix_node *rn_L;/* progeny */
+                       struct  radix_node *rn_R;/* progeny */
+               } rn_node;
+       }               rn_u;
+#ifdef RN_DEBUG
+       int rn_info;
+       struct radix_node *rn_twin;
+       struct radix_node *rn_ybro;
+#endif
+};
+
+#define        rn_dupedkey     rn_u.rn_leaf.rn_Dupedkey
+#define        rn_key          rn_u.rn_leaf.rn_Key
+#define        rn_mask         rn_u.rn_leaf.rn_Mask
+#define        rn_offset       rn_u.rn_node.rn_Off
+#define        rn_left         rn_u.rn_node.rn_L
+#define        rn_right        rn_u.rn_node.rn_R
+
+/*
+ * Annotations to tree concerning potential routes applying to subtrees.
+ */
+
+struct radix_mask {
+       short   rm_bit;                 /* bit offset; -1-index(netmask) */
+       char    rm_unused;              /* cf. rn_bmask */
+       u_char  rm_flags;               /* cf. rn_flags */
+       struct  radix_mask *rm_mklist;  /* more masks to try */
+       union   {
+               caddr_t rmu_mask;               /* the mask */
+               struct  radix_node *rmu_leaf;   /* for normal routes */
+       }       rm_rmu;
+       int     rm_refs;                /* # of references to this struct */
+};
+
+#define        rm_mask rm_rmu.rmu_mask
+#define        rm_leaf rm_rmu.rmu_leaf         /* extra field would make 32 bytes */
+
+typedef int walktree_f_t(struct radix_node *, void *);
+
+struct radix_node_head {
+       struct  radix_node *rnh_treetop;
+       int     rnh_addrsize;           /* permit, but not require fixed keys */
+       int     rnh_pktsize;            /* permit, but not require fixed keys */
+       struct  radix_node *(*rnh_addaddr)      /* add based on sockaddr */
+               (void *v, void *mask,
+                    struct radix_node_head *head, struct radix_node nodes[]);
+       struct  radix_node *(*rnh_addpkt)       /* add based on packet hdr */
+               (void *v, void *mask,
+                    struct radix_node_head *head, struct radix_node nodes[]);
+       struct  radix_node *(*rnh_deladdr)      /* remove based on sockaddr */
+               (void *v, void *mask, struct radix_node_head *head);
+       struct  radix_node *(*rnh_delpkt)       /* remove based on packet hdr */
+               (void *v, void *mask, struct radix_node_head *head);
+       struct  radix_node *(*rnh_matchaddr)    /* locate based on sockaddr */
+               (void *v, struct radix_node_head *head);
+       struct  radix_node *(*rnh_lookup)       /* locate based on sockaddr */
+               (void *v, void *mask, struct radix_node_head *head);
+       struct  radix_node *(*rnh_matchpkt)     /* locate based on packet hdr */
+               (void *v, struct radix_node_head *head);
+       int     (*rnh_walktree)                 /* traverse tree */
+               (struct radix_node_head *head, walktree_f_t *f, void *w);
+       int     (*rnh_walktree_from)            /* traverse tree below a */
+               (struct radix_node_head *head, void *a, void *m,
+                    walktree_f_t *f, void *w);
+       void    (*rnh_close)    /* do something when the last ref drops */
+               (struct radix_node *rn, struct radix_node_head *head);
+       struct  radix_node rnh_nodes[3];        /* empty tree for common case */
+       int     rnh_multipath;                  /* multipath capable ? */
+#ifdef _KERNEL
+#if defined( __linux__ ) || defined( _WIN32 )
+        spinlock_t rnh_lock;
+#else
+       struct  rwlock rnh_lock;                /* locks entire radix tree */
+#endif /* !__linux__ */
+#endif
+};
+
+#ifndef _KERNEL
+#define R_Malloc(p, t, n) (p = (t) malloc((unsigned int)(n)))
+#define R_Zalloc(p, t, n) (p = (t) calloc(1,(unsigned int)(n)))
+#define Free(p) free((char *)p);
+#else
+#define R_Malloc(p, t, n) (p = (t) malloc((unsigned long)(n), M_RTABLE, M_NOWAIT))
+#define R_Zalloc(p, t, n) (p = (t) malloc((unsigned long)(n), M_RTABLE, M_NOWAIT | M_ZERO))
+#define Free(p) free((caddr_t)p, M_RTABLE);
+
+#define        RADIX_NODE_HEAD_LOCK_INIT(rnh)  \
+    rw_init_flags(&(rnh)->rnh_lock, "radix node head", 0)
+#define        RADIX_NODE_HEAD_LOCK(rnh)       rw_wlock(&(rnh)->rnh_lock)
+#define        RADIX_NODE_HEAD_UNLOCK(rnh)     rw_wunlock(&(rnh)->rnh_lock)
+#define        RADIX_NODE_HEAD_RLOCK(rnh)      rw_rlock(&(rnh)->rnh_lock)
+#define        RADIX_NODE_HEAD_RUNLOCK(rnh)    rw_runlock(&(rnh)->rnh_lock)
+#define        RADIX_NODE_HEAD_LOCK_TRY_UPGRADE(rnh)   rw_try_upgrade(&(rnh)->rnh_lock)
+
+
+#define        RADIX_NODE_HEAD_DESTROY(rnh)    rw_destroy(&(rnh)->rnh_lock)
+#define        RADIX_NODE_HEAD_LOCK_ASSERT(rnh) rw_assert(&(rnh)->rnh_lock, RA_LOCKED)
+#define        RADIX_NODE_HEAD_WLOCK_ASSERT(rnh) rw_assert(&(rnh)->rnh_lock, RA_WLOCKED)
+#endif /* _KERNEL */
+
+void    rn_init(void);
+int     rn_inithead(void **, int);
+int     rn_refines(void *, void *);
+struct radix_node
+        *rn_addmask(void *, int, int),
+        *rn_addroute (void *, void *, struct radix_node_head *,
+                       struct radix_node [2]),
+        *rn_delete(void *, void *, struct radix_node_head *),
+        *rn_lookup (void *v_arg, void *m_arg,
+                       struct radix_node_head *head),
+        *rn_match(void *, struct radix_node_head *);
+
+#endif /* _RADIX_H_ */
index 4f8291f..81ebb33 100644 (file)
@@ -377,12 +377,8 @@ struct dn_pipe_max {
 SLIST_HEAD(dn_pipe_head, dn_pipe);
 
 #ifdef _KERNEL
-typedef        int ip_dn_ctl_t(struct sockopt *); /* raw_ip.c */
 typedef        void ip_dn_ruledel_t(void *); /* ip_fw.c */
-typedef        int ip_dn_io_t(struct mbuf **m, int dir, struct ip_fw_args *fwa);
-extern ip_dn_ctl_t *ip_dn_ctl_ptr;
 extern ip_dn_ruledel_t *ip_dn_ruledel_ptr;
-extern ip_dn_io_t *ip_dn_io_ptr;
 
 /*
  * Return the IPFW rule associated with the dummynet tag; if any.
index a19a6df..694983a 100644 (file)
@@ -645,22 +645,30 @@ int ipfw_check_out(void *, struct mbuf **, struct ifnet *, int, struct inpcb *in
 
 int ipfw_chk(struct ip_fw_args *);
 
-int ipfw_init(void);
-void ipfw_destroy(void);
-
-typedef int ip_fw_ctl_t(struct sockopt *);
-extern ip_fw_ctl_t *ip_fw_ctl_ptr;
-extern int fw_one_pass;
-extern int fw_enable;
-#ifdef INET6
-extern int fw6_enable;
+int ipfw_hook(void);
+int ipfw6_hook(void);
+int ipfw_unhook(void);
+int ipfw6_unhook(void);
+#ifdef NOTYET
+void ipfw_nat_destroy(void);
 #endif
 
-/* For kernel ipfw_ether and ipfw_bridge. */
-typedef        int ip_fw_chk_t(struct ip_fw_args *args);
-extern ip_fw_chk_t     *ip_fw_chk_ptr;
+#define IPFW_HAVE_SKIPTO_TABLE
 
-#ifdef IPFW_INTERNAL
+struct _rulepointer {
+       struct ip_fw *rule;
+       uint32_t id;
+};
+
+VNET_DECLARE(int, fw_one_pass);
+VNET_DECLARE(int, fw_enable);
+#define        V_fw_one_pass           VNET(fw_one_pass)
+#define        V_fw_enable             VNET(fw_enable)
+
+#ifdef INET6
+VNET_DECLARE(int, fw6_enable);
+#define        V_fw6_enable            VNET(fw6_enable)
+#endif
 
 struct ip_fw_chain {
        struct ip_fw    *rules;         /* list of rules */
@@ -673,7 +681,12 @@ struct ip_fw_chain {
        struct rwlock   rwmtx;
 #endif /* !__linux__ */
        uint32_t        id;             /* ruleset id */
+       struct _rulepointer skipto_pointers[64*1024];
+       struct new_hash_table *global_tables[128];
 };
+
+#ifdef IPFW_INTERNAL
+
 #define        IPFW_LOCK_INIT(_chain) \
        rw_init(&(_chain)->rwmtx, "IPFW static rules")
 #define        IPFW_LOCK_DESTROY(_chain)       rw_destroy(&(_chain)->rwmtx)
@@ -696,5 +709,8 @@ typedef int ipfw_nat_t(struct ip_fw_args *, struct cfg_nat *, struct mbuf *);
 typedef int ipfw_nat_cfg_t(struct sockopt *);
 #endif
 
+VNET_DECLARE(struct ip_fw_chain, layer3_chain);
+#define        V_layer3_chain          VNET(layer3_chain)
+
 #endif /* _KERNEL */
 #endif /* _IPFW2_H */
index a7f95a1..ed3d3a1 100644 (file)
@@ -15,7 +15,7 @@
 #ifdef _KERNEL
 
 /* bzero not present on linux, but this should go in glue.h */
-#define bzero(s, n) memset(s, 0, n)
+// #define bzero(s, n) memset(s, 0, n)
 
 /*
  * We implement a very simplified UMA allocator where the backend
index 473a761..5b36ecc 100644 (file)
@@ -56,6 +56,8 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.110.2.4 2008/10/31 12:58:1
  * include files marked with XXX are probably not needed
  */
 
+#include "missing.h"
+
 #include <sys/limits.h>
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -64,9 +66,9 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.110.2.4 2008/10/31 12:58:1
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/module.h>
-#include <sys/mutex.h>
 #include <sys/priv.h>
 #include <sys/proc.h>
+#include <sys/rwlock.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 #include <sys/time.h>
@@ -85,8 +87,6 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.110.2.4 2008/10/31 12:58:1
 #include <netinet/ip6.h>       /* for ip6_input, ip6_output prototypes */
 #include <netinet6/ip6_var.h>
 
-#include "missing.h"
-
 /*
  * We keep a private variable for the simulation time, but we could
  * probably use an existing one ("softticks" in sys/kern/kern_timeout.c)
@@ -248,8 +248,8 @@ static void dummynet(void *);
 static void    dummynet_flush(void);
 static void    dummynet_send(struct mbuf *);
 void           dummynet_drain(void);
-static ip_dn_io_t dummynet_io;
 static void    dn_rule_delete(void *);
+static int     dummynet_io(struct mbuf **, int , struct ip_fw_args *);
 
 /*
  * Heap management functions.
@@ -1244,7 +1244,7 @@ red_drops(struct dn_flow_set *fs, struct dn_flow_queue *q, int len)
                        u_int t = div64(curr_time - q->q_time,
                            fs->lookup_step);
 
-                       q->avg = (t >= 0 && t < fs->lookup_depth) ?
+                       q->avg = (t < fs->lookup_depth) ?
                            SCALE_MUL(q->avg, fs->w_q_lookup[t]) : 0;
                }
        }
index 19d4d94..50e8701 100644 (file)
@@ -44,10 +44,11 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
 #endif
 #include "opt_inet6.h"
 #include "opt_ipsec.h"
-#include "opt_mac.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/condvar.h>
+#include <sys/eventhandler.h>
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/kernel.h>
@@ -56,6 +57,7 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
 #include <sys/module.h>
 #include <sys/priv.h>
 #include <sys/proc.h>
+#include <sys/rwlock.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 #include <sys/sysctl.h>
@@ -68,6 +70,11 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
 #include <net/pf_mtag.h>
 #include <net/vnet.h>
 
+#ifdef linux
+#define INP_LOCK_ASSERT                /* define before missing.h otherwise ? */
+#include "missing.h"
+#endif
+
 #define        IPFW_INTERNAL   /* Access to protected data structures in ip_fw.h. */
 
 #include <netinet/in.h>
@@ -92,6 +99,7 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
 #include <netinet/icmp6.h>
 #ifdef INET6
 #include <netinet6/scope6_var.h>
+#include <netinet6/ip6_var.h>
 #endif
 
 #include <machine/in_cksum.h>  /* XXX for in_cksum */
@@ -100,14 +108,6 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
 #include <security/mac/mac_framework.h>
 #endif
 
-#ifdef linux
-//#include <linux/netdevice.h>    /* XXX dev_net() is used in linux 2.6.30.5 */
-#define INP_LOCK_ASSERT                /* define before missing.h otherwise ? */
-#include "missing.h"
-#define _IPV6_H                /* prevent ipv6 inclusion from hashtables and udp.h */
-#include <net/sock.h>  /* linux - struct sock and sock_put() */
-#endif
-
 static VNET_DEFINE(int, ipfw_vnet_ready) = 0;
 #define        V_ipfw_vnet_ready       VNET(ipfw_vnet_ready)
 /*
@@ -218,6 +218,9 @@ SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs,
 
 #endif /* SYSCTL_NODE */
 
+#ifndef IPFW_NEWTABLES_MAX
+#define IPFW_NEWTABLES_MAX     256
+#endif
 /*
  * Description of dynamic rules.
  *
@@ -1912,7 +1915,7 @@ lookup_next_rule(struct ip_fw *me, u_int32_t tablearg)
        struct ip_fw *rule = NULL;
        ipfw_insn *cmd;
        u_int16_t       rulenum;
-
+printf("%s called\n", __FUNCTION__);
        /* look for action, in case it is a skipto */
        cmd = ACTION_PTR(me);
        if (cmd->opcode == O_LOG)
@@ -1939,6 +1942,37 @@ lookup_next_rule(struct ip_fw *me, u_int32_t tablearg)
        return rule;
 }
 
+#ifdef IPFW_HAVE_SKIPTO_TABLE
+struct ip_fw *lookup_skipto_table(struct ip_fw_chain *chain, uint16_t num);
+
+struct ip_fw *
+lookup_skipto_table(struct ip_fw_chain *chain, uint16_t num)
+{
+       struct ip_fw *f;
+
+       printf("--%s called\n", __FUNCTION__);
+       if (1)
+               return NULL;
+       if (chain->skipto_pointers[num].id == chain->id) {
+               printf("-- %s pointer ok, return it\n", __FUNCTION__);
+               return chain->skipto_pointers[num].rule;
+       }
+       printf("-- %s search pointer\n", __FUNCTION__);
+
+       for (f = chain->rules; f ; f = f->next) {
+               if (f->rulenum == num) {
+                       chain->skipto_pointers[num].id = chain->id;
+                       chain->skipto_pointers[num].rule = f;
+                       printf("-- %s found, set and return\n", __FUNCTION__);
+                       return f;
+               }
+       }
+       printf("-- %s NOT found return NULL\n", __FUNCTION__);
+
+       return NULL;
+}
+#endif /* IPFW_HAVE_SKIPTO_TABLE */
+
 #ifdef radix
 static int
 add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
@@ -2029,6 +2063,9 @@ extern int del_table_entry(struct ip_fw_chain *ch, uint16_t tbl,
 extern int flush_table(struct ip_fw_chain *ch, uint16_t tbl);
 extern int count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt);
 extern int dump_table(struct ip_fw_chain *ch, ipfw_table *tbl);
+extern int lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
+    uint32_t *val);
+extern int init_tables(struct ip_fw_chain *ch);
 #endif
 
 static void
@@ -2038,14 +2075,14 @@ flush_tables(struct ip_fw_chain *ch)
 
        IPFW_WLOCK_ASSERT(ch);
 
-       for (tbl = 0; tbl < IPFW_TABLES_MAX; tbl++)
+       for (tbl = IPFW_TABLES_MAX -1; tbl < IPFW_NEWTABLES_MAX; tbl++)
                flush_table(ch, tbl);
 }
 
+#ifdef radix
 static int
 init_tables(struct ip_fw_chain *ch)
 { 
-#ifdef radix
        int i;
        uint16_t j;
 
@@ -2057,7 +2094,6 @@ init_tables(struct ip_fw_chain *ch)
                        return (ENOMEM);
                }
        }
-#endif
        return (0);
 }
 
@@ -2065,7 +2101,6 @@ static int
 lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
     uint32_t *val)
 {
-#ifdef radix
        struct radix_node_head *rnh;
        struct table_entry *ent;
        struct sockaddr_in sa;
@@ -2080,9 +2115,9 @@ lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
                *val = ent->value;
                return (1);
        }
-#endif
        return (0);
 }
+#endif
 
 #ifdef radix
 static int
@@ -2909,6 +2944,37 @@ do {                                                                     \
                                            dst_ip.s_addr : src_ip.s_addr;
                                    uint32_t v = 0;
 
+                                   if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {
+                                       v = ((ipfw_insn_u32 *)cmd)->d[1];
+                                       if (v == 0)
+                                           a = dst_ip.s_addr;
+                                       else if (v == 1)
+                                           a = src_ip.s_addr;
+                                       else if (offset != 0)
+                                           break;
+                                       else if (proto != IPPROTO_TCP &&
+                                               proto != IPPROTO_UDP)
+                                           break;
+                                       else if (v == 2)
+                                           a = dst_port;
+                                       else if (v == 3)
+                                           a = src_port;
+                                       else if (v >= 4 && v <= 6) {
+                                           check_uidgid(
+                                                   (ipfw_insn_u32 *)cmd,
+                                                   proto, oif,
+                                                   dst_ip, dst_port,
+                                                   src_ip, src_port, &fw_ugid_cache,
+                                                   &ugid_lookup, (struct inpcb *)args->m);
+                                           if (v ==4 /* O_UID */)
+                                               a = fw_ugid_cache.fw_uid;
+                                           else if (v == 5 /* O_GID */)
+                                               a = fw_ugid_cache.fw_groups[0];
+                                           else if (v == 6 /* O_JAIL */)
+                                               a = fw_ugid_cache.fw_groups[1];
+                                       } else
+                                           break;
+                                   }
                                    match = lookup_table(chain, cmd->arg1, a,
                                        &v);
                                    if (!match)
@@ -3489,6 +3555,29 @@ do {                                                                     \
                                        break;
                                }
                                /* handle skipto */
+#ifdef IPFW_HAVE_SKIPTO_TABLE
+                               /* NOTE: lookup_skipto_table can return NULL
+                                *       if the rule isn't found, so the
+                                *       standard lookup function must be
+                                *       called XXX
+                                */
+                               if (cmd->arg1 == IP_FW_TABLEARG) {
+                                       f = lookup_skipto_table(chain,
+                                                                tablearg);
+                                       if (f == NULL)
+                                               f = lookup_next_rule(f, tablearg);
+                               }
+                                else {
+                                       f = lookup_skipto_table(chain,
+                                                                cmd->arg1);
+                                       if (f == NULL) {
+                                               if (f->next_rule == NULL)
+                                                       lookup_next_rule(f, 0);
+                                               f = f->next_rule;
+                                       }
+                                }
+
+#else
                                if (cmd->arg1 == IP_FW_TABLEARG) {
                                        f = lookup_next_rule(f, tablearg);
                                } else {
@@ -3496,6 +3585,7 @@ do {                                                                      \
                                                lookup_next_rule(f, 0);
                                        f = f->next_rule;
                                }
+#endif
                                /*
                                 * Skip disabled rules, and
                                 * re-enter the inner loop
@@ -4262,10 +4352,11 @@ check_ipfw_struct(struct ip_fw *rule, int size)
                case O_IP_DST_LOOKUP:
                        if (cmd->arg1 >= IPFW_TABLES_MAX) {
                                printf("ipfw: invalid table number %d\n",
-                                   cmd->arg1);
+                                       cmd->arg1);
                                return (EINVAL);
                        }
                        if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
+                           cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 &&
                            cmdlen != F_INSN_SIZE(ipfw_insn_u32))
                                goto bad_size;
                        break;
@@ -4821,7 +4912,7 @@ ipfw_ctl(struct sockopt *sopt)
  * NULL pointer, but this way we do not need to check for the special
  * case, plus here he have info on the default behaviour).
  */
-struct ip_fw *ip_fw_default_rule;
+//struct ip_fw *ip_fw_default_rule;
 
 /*
  * This procedure is only used to handle keepalives. It is invoked
@@ -5041,6 +5132,12 @@ vnet_ipfw_init(const void *unused)
        if (error) {
                panic("init_tables"); /* XXX Marko fix this ! */
        }
+
+#ifdef IPFW_HAVE_SKIPTO_TABLE
+//     for (error = 0; error < 64*1024; error++)
+//             V_layer3_chain.skipto_pointers[error].id = -1;
+#endif /* IPFW_HAVE_SKIPTO_TABLE */
+
 #ifdef IPFIREWALL_NAT
        LIST_INIT(&V_layer3_chain.nat);
 #endif
index 4e3568a..3fa643c 100644 (file)
@@ -51,6 +51,8 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw_pfil.c,v 1.25.2.2 2008/04/25 10:26:30
 #include <net/pfil.h>
 #include <net/vnet.h>
 
+#include "missing.h"
+
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <netinet/ip_var.h>
@@ -62,11 +64,9 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw_pfil.c,v 1.25.2.2 2008/04/25 10:26:30
 
 #include <machine/in_cksum.h>
 
-#include "missing.h"
-
-int fw_enable = 1;
+VNET_DEFINE(int, fw_enable) = 1;
 #ifdef INET6
-int fw6_enable = 1;
+VNET_DEFINE(int, fw6_enable) = 1;
 #endif
 
 int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
@@ -127,7 +127,7 @@ again:
        args.m = *m0;
        args.inp = inp;
        ipfw = ipfw_chk(&args);
-       *m0 = args.m;   /* args.m can be modified by ipfw_chk */
+       *m0 = args.m;
        tee = 0;
 
        KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
@@ -156,7 +156,6 @@ again:
                goto drop;
                break;                  /* not reached */
 
-       /* here packets come after the ipfw classification */
        case IP_FW_DUMMYNET:
                if (ip_dn_io_ptr == NULL)
                        goto drop;
@@ -258,7 +257,7 @@ again:
        args.oif = ifp;
        args.inp = inp;
        ipfw = ipfw_chk(&args);
-       *m0 = args.m;   /* args.m can be modified by ipfw_chk */
+       *m0 = args.m;
        tee = 0;
 
        KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
@@ -432,7 +431,7 @@ nodivert:
        return 1;
 }
 
-static int
+int
 ipfw_hook(void)
 {
        struct pfil_head *pfh_inet;
@@ -449,7 +448,7 @@ ipfw_hook(void)
        return 0;
 }
 
-static int
+int
 ipfw_unhook(void)
 {
        struct pfil_head *pfh_inet;
@@ -467,7 +466,7 @@ ipfw_unhook(void)
 }
 
 #ifdef INET6
-static int
+int
 ipfw6_hook(void)
 {
        struct pfil_head *pfh_inet6;
@@ -484,7 +483,7 @@ ipfw6_hook(void)
        return 0;
 }
 
-static int
+int
 ipfw6_unhook(void)
 {
        struct pfil_head *pfh_inet6;
index ee4eeba..f47d365 100644 (file)
@@ -49,6 +49,8 @@
 #include <sys/mbuf.h>                  /* sizeof struct mbuf */
 #include <sys/param.h>                 /* NGROUPS */
 
+#include "missing.h"
+
 #ifdef __linux__
 #include <linux/module.h>
 #include <linux/kernel.h>
 /*
  * Here we allocate some global variables used in the firewall.
  */
-ip_dn_ctl_t    *ip_dn_ctl_ptr;
+//ip_dn_ctl_t    *ip_dn_ctl_ptr;
+int (*ip_dn_ctl_ptr)(struct sockopt *);
+
 ip_fw_ctl_t    *ip_fw_ctl_ptr;
 
-ip_dn_io_t     *ip_dn_io_ptr;
+int    (*ip_dn_io_ptr)(struct mbuf **m, int dir, struct ip_fw_args *fwa);
 ip_fw_chk_t    *ip_fw_chk_ptr;
 
 void           (*bridge_dn_p)(struct mbuf *, struct ifnet *);
index c6bb4f3..1d2f2ec 100644 (file)
@@ -56,9 +56,10 @@ struct inpcb;
 
 /*
  * Kernel locking support.
- * FreeBSD uses mtx in dummynet.c, and rwlocks in ipfw.c
+ * FreeBSD uses mtx in dummynet.c and struct rwlock ip_fw2.c
  *
  * In linux we use spinlock_bh to implement both.
+ * For 'struct rwlock' we need an #ifdef to change it to spinlock_t
  */
 
 #ifndef DEFINE_SPINLOCK        /* this is for linux 2.4 */
@@ -83,6 +84,13 @@ struct inpcb;
 
 /* end of locking support */
 
+/* in netinet/in.h */
+#define        in_nullhost(x)  ((x).s_addr == INADDR_ANY)
+
+/* bzero not present on linux, but this should go in glue.h */
+#define bzero(s, n) memset(s, 0, n)
+#define bcmp(p1, p2, n) memcmp(p1, p2, n)
+
 /* ethernet stuff */
 #define        ETHERTYPE_IP            0x0800  /* IP protocol */
 #define        ETHER_ADDR_LEN          6       /* length of an Ethernet address */
@@ -264,12 +272,13 @@ struct pf_mtag {
         u_int32_t        qid;           /* queue id */
 };
 
-/* radix related */
-
+#if 0 // ndef radix
+/* radix stuff in radix.h and radix.c */
 struct radix_node {
        caddr_t rn_key;         /* object of search */
        caddr_t rn_mask;        /* netmask, if present */
 };
+#endif /* !radix */
 
 /* missing kernel functions */
 char *inet_ntoa(struct in_addr ina);
@@ -428,6 +437,11 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
        struct sk_buff *skb, int dir, struct ip_fw_ugid *ugp);
 
 /* vnet wrappers, in vnet.h and ip_var.h */
+int ipfw_init(void);
+void ipfw_destroy(void);
+struct ip_fw_args;
+extern int (*ip_dn_io_ptr)(struct mbuf **m, int dir, struct ip_fw_args *fwa);
+
 #define curvnet                 NULL
 #define        CURVNET_SET(_v)
 #define        CURVNET_RESTORE()
@@ -446,13 +460,17 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
 #define VNET_PTR(n)             (&(n))
 #define VNET(n)                 (n)
 
-VNET_DECLARE(struct ip_fw_chain, layer3_chain);
+extern int (*ip_dn_ctl_ptr)(struct sockopt *);
+typedef int ip_fw_ctl_t(struct sockopt *);
+extern ip_fw_ctl_t *ip_fw_ctl_ptr;
+
+/* For kernel ipfw_ether and ipfw_bridge. */
+struct ip_fw_args;
+typedef int ip_fw_chk_t(struct ip_fw_args *args);
+extern  ip_fw_chk_t     *ip_fw_chk_ptr;
 
-#define        V_fw_enable             VNET(fw_enable)
-#define        V_fw_one_pass           VNET(fw_one_pass)
 #define V_ip_fw_chk_ptr         VNET(ip_fw_chk_ptr)
 #define V_ip_fw_ctl_ptr         VNET(ip_fw_ctl_ptr)
-#define V_layer3_chain         VNET(layer3_chain)
 #define        V_tcbinfo               VNET(tcbinfo)
 #define        V_udbinfo               VNET(udbinfo)
 
index 52a1a7f..ce0a5a3 100644 (file)
@@ -1,24 +1,4 @@
 #include "missing.h"
-//#include <sys/param.h>
-//#include <sys/systm.h>
-//#include <sys/malloc.h>
-// #include <sys/mbuf.h>
-//#include <sys/kernel.h>
-//#include <sys/lock.h>
-//#include <sys/jail.h>
-//#include <sys/module.h>
-//#include <sys/priv.h>
-//#include <sys/proc.h>
-//#include <sys/socket.h>
-//#include <sys/socketvar.h>
-//#include <sys/sysctl.h>
-//#include <sys/syslog.h>
-//#include <sys/ucred.h>
-//#include <net/ethernet.h> /* for ETHERTYPE_IP */
-//#include <net/if.h>
-//#include <net/radix.h>
-//#include <net/route.h>
-//#include <net/pf_mtag.h>
 
 #define IPFW_INTERNAL
 #include <netinet/ip_fw.h>
@@ -35,19 +15,18 @@ struct t_o {
 
 MALLOC_DEFINE(M_IPFW_HTBL, "ipfw_tbl", "IpFw tables");
 
-static struct new_hash_table *global_tables[128];
 int add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
                        uint8_t mlen, uint32_t value);
 int new_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr);
 int del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
                     uint8_t mlen);
-int new_flush_table(uint16_t tbl);
+int new_flush_table(struct ip_fw_chain *ch, uint16_t tbl);
 int flush_table(struct ip_fw_chain *ch, uint16_t tbl);
 int lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 
                 uint32_t *val);
-int new_count_table_entry(uint32_t tbl, uint32_t *cnt);
+int new_count_table_entry(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt);
 int count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt);
-int new_dump_table_entry(ipfw_table *tbl);
+int new_dump_table_entry(struct ip_fw_chain *ch, ipfw_table *tbl);
 int dump_table(struct ip_fw_chain *ch, ipfw_table *tbl);
 int init_tables(struct ip_fw_chain *ch);
 
@@ -101,9 +80,9 @@ add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
        printf("%s called\n", __FUNCTION__);
        if (i < 0 || i > size-1) /* wrong table number */
                return 1;
-       if (global_tables[i] == NULL) {
+       if (ch->global_tables[i] == NULL) {
                printf("Creating table n %d\n", tbl);
-               global_tables[i] = new_table_init(size, obj_size,
+               ch->global_tables[i] = new_table_init(size, obj_size,
                                simple_hash32, cmp_func32, M_IPFW_HTBL);
        }
 
@@ -112,7 +91,7 @@ add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
        obj.mask = mlen;
 
        /* Insert the object in the table */
-       ret = new_table_insert_obj(global_tables[i], &obj);
+       ret = new_table_insert_obj(ch->global_tables[i], &obj);
        return ret;
 }
 
@@ -124,7 +103,7 @@ new_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr)
 
        printf("%s called\n", __FUNCTION__);
 
-       ret = new_table_delete_obj(global_tables[nr], &addr);
+       ret = new_table_delete_obj(ch->global_tables[nr], &addr);
 
        return ret;
 }
@@ -142,10 +121,10 @@ del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
 }
 
 int
-new_flush_table(uint16_t tbl)
+new_flush_table(struct ip_fw_chain *ch, uint16_t tbl)
 {
        printf("%s called\n", __FUNCTION__);
-       new_table_destroy(global_tables[tbl - IPFW_TABLES_MAX]);
+       new_table_destroy(ch->global_tables[tbl - IPFW_TABLES_MAX]);
        return 0;
 }
 
@@ -154,7 +133,7 @@ flush_table(struct ip_fw_chain *ch, uint16_t tbl)
 {
        printf("%s called\n", __FUNCTION__);
        if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX)
-               return new_flush_table(tbl);
+               return new_flush_table(ch, tbl);
        
        return (EINVAL);
 }
@@ -166,28 +145,27 @@ lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
        printf("%s called\n", __FUNCTION__);
        if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX) {
                struct new_hash_table *h;
-               struct t_o *obj;
+               const struct t_o *obj;
 
-               h = global_tables[tbl - IPFW_NEWTABLES_MAX];
+               h = ch->global_tables[tbl - IPFW_TABLES_MAX];
                printf("Search %d in table number %d\n", addr, tbl);
 
-               obj = (struct t_o *)new_table_extract_obj(h, (void *)&addr);
+               obj = new_table_extract_obj(h, (void *)&addr);
                if (obj == NULL)
-                       return 0;
+                       return 0; /* no match */
 
                *val = obj->value;
-
-               return 1;
+               printf("obj->addr=%d,obj->value=%d\n",obj->addr, obj->value);
+               return 1; /* match */
        }
-
-       return 1;
+       return 0;
 }
 
 int
-new_count_table_entry(uint32_t tbl, uint32_t *cnt)
+new_count_table_entry(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt)
 {
        printf("%s called\n", __FUNCTION__);
-       *cnt = new_table_get_element(global_tables[tbl - IPFW_TABLES_MAX]);
+       *cnt = new_table_get_element(ch->global_tables[tbl - IPFW_TABLES_MAX]);
        return 0;
 }
 
@@ -196,14 +174,14 @@ count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt)
 {
        printf("%s called\n", __FUNCTION__);
        if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX) {
-               new_count_table_entry(tbl, cnt);
+               new_count_table_entry(ch, tbl, cnt);
                return (0);
        }
        return (EINVAL);
 }
 
 int
-new_dump_table_entry(ipfw_table *tbl)
+new_dump_table_entry(struct ip_fw_chain *ch, ipfw_table *tbl)
 {
        /* fill the tbl with all entryes */
        ipfw_table_entry *ent;
@@ -211,7 +189,7 @@ new_dump_table_entry(ipfw_table *tbl)
        int i;
        int n_el;
        int nr = tbl->tbl - IPFW_TABLES_MAX;
-       struct new_hash_table *t = global_tables[nr];
+       struct new_hash_table *t = ch->global_tables[nr];
 
        printf("%s called\n", __FUNCTION__);
 
@@ -242,7 +220,7 @@ dump_table(struct ip_fw_chain *ch, ipfw_table *tbl)
 {
        printf("%s called\n", __FUNCTION__);
        if (tbl->tbl >= IPFW_TABLES_MAX && tbl->tbl < IPFW_NEWTABLES_MAX) {
-               new_dump_table_entry(tbl);
+               new_dump_table_entry(ch, tbl);
                return (0);
        }
        return (EINVAL);
@@ -256,7 +234,7 @@ init_tables(struct ip_fw_chain *ch)
        printf("%s called\n", __FUNCTION__);
        /* Initialize new tables XXXMPD */
        for (i = 0; i < IPFW_NEWTABLES_MAX - IPFW_TABLES_MAX; i++) {
-               memset(&global_tables[i], sizeof(struct new_hash_table*), 0);
+               memset(&ch->global_tables[i], sizeof(struct new_hash_table*), 0);
        }
 
        return (0);
diff --git a/dummynet/radix.c b/dummynet/radix.c
new file mode 100644 (file)
index 0000000..2a5fcc3
--- /dev/null
@@ -0,0 +1,1188 @@
+/*-
+ * Copyright (c) 1988, 1989, 1993
+ *     The Regents of the University of California.  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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *     @(#)radix.c     8.5 (Berkeley) 5/19/95
+ * $FreeBSD: head/sys/net/radix.c 186176 2008-12-16 11:01:36Z kmacy $
+ */
+
+#include "missing.h"
+/*
+ * Routines to build and maintain radix trees for routing lookups.
+ */
+#ifndef _RADIX_H_
+#include <sys/param.h>
+#ifdef _KERNEL
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+// #include <sys/domain.h>
+#else
+#include <stdlib.h>
+#endif
+#include <sys/syslog.h>
+#include <net/radix.h>
+#endif
+
+// #include "opt_mpath.h"
+
+#ifdef RADIX_MPATH
+#include <net/radix_mpath.h>
+#endif
+
+
+static int     rn_walktree_from(struct radix_node_head *h, void *a, void *m,
+                   walktree_f_t *f, void *w);
+static int rn_walktree(struct radix_node_head *, walktree_f_t *, void *);
+static struct radix_node
+        *rn_insert(void *, struct radix_node_head *, int *,
+            struct radix_node [2]),
+        *rn_newpair(void *, int, struct radix_node[2]),
+        *rn_search(void *, struct radix_node *),
+        *rn_search_m(void *, struct radix_node *, void *);
+
+static int     max_keylen;
+static struct radix_mask *rn_mkfreelist;
+static struct radix_node_head *mask_rnhead;
+/*
+ * Work area -- the following point to 3 buffers of size max_keylen,
+ * allocated in this order in a block of memory malloc'ed by rn_init.
+ */
+static char *rn_zeros, *rn_ones, *addmask_key;
+
+#define MKGet(m) {                                             \
+       if (rn_mkfreelist) {                                    \
+               m = rn_mkfreelist;                              \
+               rn_mkfreelist = (m)->rm_mklist;                 \
+       } else                                                  \
+               R_Malloc(m, struct radix_mask *, sizeof (struct radix_mask)); }
+#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);}
+
+#define rn_masktop (mask_rnhead->rnh_treetop)
+
+static int     rn_lexobetter(void *m_arg, void *n_arg);
+static struct radix_mask *
+               rn_new_radix_mask(struct radix_node *tt,
+                   struct radix_mask *next);
+static int     rn_satisfies_leaf(char *trial, struct radix_node *leaf,
+                   int skip);
+
+/*
+ * The data structure for the keys is a radix tree with one way
+ * branching removed.  The index rn_bit at an internal node n represents a bit
+ * position to be tested.  The tree is arranged so that all descendants
+ * of a node n have keys whose bits all agree up to position rn_bit - 1.
+ * (We say the index of n is rn_bit.)
+ *
+ * There is at least one descendant which has a one bit at position rn_bit,
+ * and at least one with a zero there.
+ *
+ * A route is determined by a pair of key and mask.  We require that the
+ * bit-wise logical and of the key and mask to be the key.
+ * We define the index of a route to associated with the mask to be
+ * the first bit number in the mask where 0 occurs (with bit number 0
+ * representing the highest order bit).
+ *
+ * We say a mask is normal if every bit is 0, past the index of the mask.
+ * If a node n has a descendant (k, m) with index(m) == index(n) == rn_bit,
+ * and m is a normal mask, then the route applies to every descendant of n.
+ * If the index(m) < rn_bit, this implies the trailing last few bits of k
+ * before bit b are all 0, (and hence consequently true of every descendant
+ * of n), so the route applies to all descendants of the node as well.
+ *
+ * Similar logic shows that a non-normal mask m such that
+ * index(m) <= index(n) could potentially apply to many children of n.
+ * Thus, for each non-host route, we attach its mask to a list at an internal
+ * node as high in the tree as we can go.
+ *
+ * The present version of the code makes use of normal routes in short-
+ * circuiting an explict mask and compare operation when testing whether
+ * a key satisfies a normal route, and also in remembering the unique leaf
+ * that governs a subtree.
+ */
+
+/*
+ * Most of the functions in this code assume that the key/mask arguments
+ * are sockaddr-like structures, where the first byte is an u_char
+ * indicating the size of the entire structure.
+ *
+ * To make the assumption more explicit, we use the LEN() macro to access
+ * this field. It is safe to pass an expression with side effects
+ * to LEN() as the argument is evaluated only once.
+ */
+#define LEN(x) (*(const u_char *)(x))
+
+/*
+ * XXX THIS NEEDS TO BE FIXED
+ * In the code, pointers to keys and masks are passed as either
+ * 'void *' (because callers use to pass pointers of various kinds), or
+ * 'caddr_t' (which is fine for pointer arithmetics, but not very
+ * clean when you dereference it to access data). Furthermore, caddr_t
+ * is really 'char *', while the natural type to operate on keys and
+ * masks would be 'u_char'. This mismatch require a lot of casts and
+ * intermediate variables to adapt types that clutter the code.
+ */
+
+/*
+ * Search a node in the tree matching the key.
+ */
+static struct radix_node *
+rn_search(v_arg, head)
+       void *v_arg;
+       struct radix_node *head;
+{
+       register struct radix_node *x;
+       register caddr_t v;
+
+       for (x = head, v = v_arg; x->rn_bit >= 0;) {
+               if (x->rn_bmask & v[x->rn_offset])
+                       x = x->rn_right;
+               else
+                       x = x->rn_left;
+       }
+       return (x);
+}
+
+/*
+ * Same as above, but with an additional mask.
+ * XXX note this function is used only once.
+ */
+static struct radix_node *
+rn_search_m(v_arg, head, m_arg)
+       struct radix_node *head;
+       void *v_arg, *m_arg;
+{
+       register struct radix_node *x;
+       register caddr_t v = v_arg, m = m_arg;
+
+       for (x = head; x->rn_bit >= 0;) {
+               if ((x->rn_bmask & m[x->rn_offset]) &&
+                   (x->rn_bmask & v[x->rn_offset]))
+                       x = x->rn_right;
+               else
+                       x = x->rn_left;
+       }
+       return x;
+}
+
+int
+rn_refines(m_arg, n_arg)
+       void *m_arg, *n_arg;
+{
+       register caddr_t m = m_arg, n = n_arg;
+       register caddr_t lim, lim2 = lim = n + LEN(n);
+       int longer = LEN(n++) - (int)LEN(m++);
+       int masks_are_equal = 1;
+
+       if (longer > 0)
+               lim -= longer;
+       while (n < lim) {
+               if (*n & ~(*m))
+                       return 0;
+               if (*n++ != *m++)
+                       masks_are_equal = 0;
+       }
+       while (n < lim2)
+               if (*n++)
+                       return 0;
+       if (masks_are_equal && (longer < 0))
+               for (lim2 = m - longer; m < lim2; )
+                       if (*m++)
+                               return 1;
+       return (!masks_are_equal);
+}
+
+struct radix_node *
+rn_lookup(v_arg, m_arg, head)
+       void *v_arg, *m_arg;
+       struct radix_node_head *head;
+{
+       register struct radix_node *x;
+       caddr_t netmask = 0;
+
+       if (m_arg) {
+               x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_offset);
+               if (x == 0)
+                       return (0);
+               netmask = x->rn_key;
+       }
+       x = rn_match(v_arg, head);
+       if (x && netmask) {
+               while (x && x->rn_mask != netmask)
+                       x = x->rn_dupedkey;
+       }
+       return x;
+}
+
+static int
+rn_satisfies_leaf(trial, leaf, skip)
+       char *trial;
+       register struct radix_node *leaf;
+       int skip;
+{
+       register char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask;
+       char *cplim;
+       int length = min(LEN(cp), LEN(cp2));
+
+       if (cp3 == 0)
+               cp3 = rn_ones;
+       else
+               length = min(length, (int)(*(u_char *)cp3));
+       cplim = cp + length; cp3 += skip; cp2 += skip;
+       for (cp += skip; cp < cplim; cp++, cp2++, cp3++)
+               if ((*cp ^ *cp2) & *cp3)
+                       return 0;
+       return 1;
+}
+
+struct radix_node *
+rn_match(v_arg, head)
+       void *v_arg;
+       struct radix_node_head *head;
+{
+       caddr_t v = v_arg;
+       register struct radix_node *t = head->rnh_treetop, *x;
+       register caddr_t cp = v, cp2;
+       caddr_t cplim;
+       struct radix_node *saved_t, *top = t;
+       int off = t->rn_offset, vlen = LEN(cp), matched_off;
+       register int test, b, rn_bit;
+
+       /*
+        * Open code rn_search(v, top) to avoid overhead of extra
+        * subroutine call.
+        */
+       for (; t->rn_bit >= 0; ) {
+               if (t->rn_bmask & cp[t->rn_offset])
+                       t = t->rn_right;
+               else
+                       t = t->rn_left;
+       }
+       /*
+        * See if we match exactly as a host destination
+        * or at least learn how many bits match, for normal mask finesse.
+        *
+        * It doesn't hurt us to limit how many bytes to check
+        * to the length of the mask, since if it matches we had a genuine
+        * match and the leaf we have is the most specific one anyway;
+        * if it didn't match with a shorter length it would fail
+        * with a long one.  This wins big for class B&C netmasks which
+        * are probably the most common case...
+        */
+       if (t->rn_mask)
+               vlen = *(u_char *)t->rn_mask;
+       cp += off; cp2 = t->rn_key + off; cplim = v + vlen;
+       for (; cp < cplim; cp++, cp2++)
+               if (*cp != *cp2)
+                       goto on1;
+       /*
+        * This extra grot is in case we are explicitly asked
+        * to look up the default.  Ugh!
+        *
+        * Never return the root node itself, it seems to cause a
+        * lot of confusion.
+        */
+       if (t->rn_flags & RNF_ROOT)
+               t = t->rn_dupedkey;
+       return t;
+on1:
+       test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */
+       for (b = 7; (test >>= 1) > 0;)
+               b--;
+       matched_off = cp - v;
+       b += matched_off << 3;
+       rn_bit = -1 - b;
+       /*
+        * If there is a host route in a duped-key chain, it will be first.
+        */
+       if ((saved_t = t)->rn_mask == 0)
+               t = t->rn_dupedkey;
+       for (; t; t = t->rn_dupedkey)
+               /*
+                * Even if we don't match exactly as a host,
+                * we may match if the leaf we wound up at is
+                * a route to a net.
+                */
+               if (t->rn_flags & RNF_NORMAL) {
+                       if (rn_bit <= t->rn_bit)
+                               return t;
+               } else if (rn_satisfies_leaf(v, t, matched_off))
+                               return t;
+       t = saved_t;
+       /* start searching up the tree */
+       do {
+               register struct radix_mask *m;
+               t = t->rn_parent;
+               m = t->rn_mklist;
+               /*
+                * If non-contiguous masks ever become important
+                * we can restore the masking and open coding of
+                * the search and satisfaction test and put the
+                * calculation of "off" back before the "do".
+                */
+               while (m) {
+                       if (m->rm_flags & RNF_NORMAL) {
+                               if (rn_bit <= m->rm_bit)
+                                       return (m->rm_leaf);
+                       } else {
+                               off = min(t->rn_offset, matched_off);
+                               x = rn_search_m(v, t, m->rm_mask);
+                               while (x && x->rn_mask != m->rm_mask)
+                                       x = x->rn_dupedkey;
+                               if (x && rn_satisfies_leaf(v, x, off))
+                                       return x;
+                       }
+                       m = m->rm_mklist;
+               }
+       } while (t != top);
+       return 0;
+}
+
+#ifdef RN_DEBUG
+int    rn_nodenum;
+struct radix_node *rn_clist;
+int    rn_saveinfo;
+int    rn_debug =  1;
+#endif
+
+/*
+ * Whenever we add a new leaf to the tree, we also add a parent node,
+ * so we allocate them as an array of two elements: the first one must be
+ * the leaf (see RNTORT() in route.c), the second one is the parent.
+ * This routine initializes the relevant fields of the nodes, so that
+ * the leaf is the left child of the parent node, and both nodes have
+ * (almost) all all fields filled as appropriate.
+ * (XXX some fields are left unset, see the '#if 0' section).
+ * The function returns a pointer to the parent node.
+ */
+
+static struct radix_node *
+rn_newpair(v, b, nodes)
+       void *v;
+       int b;
+       struct radix_node nodes[2];
+{
+       register struct radix_node *tt = nodes, *t = tt + 1;
+       t->rn_bit = b;
+       t->rn_bmask = 0x80 >> (b & 7);
+       t->rn_left = tt;
+       t->rn_offset = b >> 3;
+
+#if 0  /* XXX perhaps we should fill these fields as well. */
+       t->rn_parent = t->rn_right = NULL;
+
+       tt->rn_mask = NULL;
+       tt->rn_dupedkey = NULL;
+       tt->rn_bmask = 0;
+#endif
+       tt->rn_bit = -1;
+       tt->rn_key = (caddr_t)v;
+       tt->rn_parent = t;
+       tt->rn_flags = t->rn_flags = RNF_ACTIVE;
+       tt->rn_mklist = t->rn_mklist = 0;
+#ifdef RN_DEBUG
+       tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
+       tt->rn_twin = t;
+       tt->rn_ybro = rn_clist;
+       rn_clist = tt;
+#endif
+       return t;
+}
+
+static struct radix_node *
+rn_insert(v_arg, head, dupentry, nodes)
+       void *v_arg;
+       struct radix_node_head *head;
+       int *dupentry;
+       struct radix_node nodes[2];
+{
+       caddr_t v = v_arg;
+       struct radix_node *top = head->rnh_treetop;
+       int head_off = top->rn_offset, vlen = (int)LEN(v);
+       register struct radix_node *t = rn_search(v_arg, top);
+       register caddr_t cp = v + head_off;
+       register int b;
+       struct radix_node *tt;
+       /*
+        * Find first bit at which v and t->rn_key differ
+        */
+    {
+       register caddr_t cp2 = t->rn_key + head_off;
+       register int cmp_res;
+       caddr_t cplim = v + vlen;
+
+       while (cp < cplim)
+               if (*cp2++ != *cp++)
+                       goto on1;
+       *dupentry = 1;
+       return t;
+on1:
+       *dupentry = 0;
+       cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
+       for (b = (cp - v) << 3; cmp_res; b--)
+               cmp_res >>= 1;
+    }
+    {
+       register struct radix_node *p, *x = top;
+       cp = v;
+       do {
+               p = x;
+               if (cp[x->rn_offset] & x->rn_bmask)
+                       x = x->rn_right;
+               else
+                       x = x->rn_left;
+       } while (b > (unsigned) x->rn_bit);
+                               /* x->rn_bit < b && x->rn_bit >= 0 */
+#ifdef RN_DEBUG
+       if (rn_debug)
+               log(LOG_DEBUG, "rn_insert: Going In:\n"), traverse(p);
+#endif
+       t = rn_newpair(v_arg, b, nodes); 
+       tt = t->rn_left;
+       if ((cp[p->rn_offset] & p->rn_bmask) == 0)
+               p->rn_left = t;
+       else
+               p->rn_right = t;
+       x->rn_parent = t;
+       t->rn_parent = p; /* frees x, p as temp vars below */
+       if ((cp[t->rn_offset] & t->rn_bmask) == 0) {
+               t->rn_right = x;
+       } else {
+               t->rn_right = tt;
+               t->rn_left = x;
+       }
+#ifdef RN_DEBUG
+       if (rn_debug)
+               log(LOG_DEBUG, "rn_insert: Coming Out:\n"), traverse(p);
+#endif
+    }
+       return (tt);
+}
+
+struct radix_node *
+rn_addmask(n_arg, search, skip)
+       int search, skip;
+       void *n_arg;
+{
+       caddr_t netmask = (caddr_t)n_arg;
+       register struct radix_node *x;
+       register caddr_t cp, cplim;
+       register int b = 0, mlen, j;
+       int maskduplicated, m0, isnormal;
+       struct radix_node *saved_x;
+       static int last_zeroed = 0;
+
+       if ((mlen = LEN(netmask)) > max_keylen)
+               mlen = max_keylen;
+       if (skip == 0)
+               skip = 1;
+       if (mlen <= skip)
+               return (mask_rnhead->rnh_nodes);
+       if (skip > 1)
+               bcopy(rn_ones + 1, addmask_key + 1, skip - 1);
+       if ((m0 = mlen) > skip)
+               bcopy(netmask + skip, addmask_key + skip, mlen - skip);
+       /*
+        * Trim trailing zeroes.
+        */
+       for (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0;)
+               cp--;
+       mlen = cp - addmask_key;
+       if (mlen <= skip) {
+               if (m0 >= last_zeroed)
+                       last_zeroed = mlen;
+               return (mask_rnhead->rnh_nodes);
+       }
+       if (m0 < last_zeroed)
+               bzero(addmask_key + m0, last_zeroed - m0);
+       *addmask_key = last_zeroed = mlen;
+       x = rn_search(addmask_key, rn_masktop);
+       if (bcmp(addmask_key, x->rn_key, mlen) != 0)
+               x = 0;
+       if (x || search)
+               return (x);
+       R_Zalloc(x, struct radix_node *, max_keylen + 2 * sizeof (*x));
+       if ((saved_x = x) == 0)
+               return (0);
+       netmask = cp = (caddr_t)(x + 2);
+       bcopy(addmask_key, cp, mlen);
+       x = rn_insert(cp, mask_rnhead, &maskduplicated, x);
+       if (maskduplicated) {
+               log(LOG_ERR, "rn_addmask: mask impossibly already in tree");
+               Free(saved_x);
+               return (x);
+       }
+       /*
+        * Calculate index of mask, and check for normalcy.
+        * First find the first byte with a 0 bit, then if there are
+        * more bits left (remember we already trimmed the trailing 0's),
+        * the pattern must be one of those in normal_chars[], or we have
+        * a non-contiguous mask.
+        */
+       cplim = netmask + mlen;
+       isnormal = 1;
+       for (cp = netmask + skip; (cp < cplim) && *(u_char *)cp == 0xff;)
+               cp++;
+       if (cp != cplim) {
+               static char normal_chars[] = {
+                       0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
+
+               for (j = 0x80; (j & *cp) != 0; j >>= 1)
+                       b++;
+               if (*cp != normal_chars[b] || cp != (cplim - 1))
+                       isnormal = 0;
+       }
+       b += (cp - netmask) << 3;
+       x->rn_bit = -1 - b;
+       if (isnormal)
+               x->rn_flags |= RNF_NORMAL;
+       return (x);
+}
+
+static int     /* XXX: arbitrary ordering for non-contiguous masks */
+rn_lexobetter(m_arg, n_arg)
+       void *m_arg, *n_arg;
+{
+       register u_char *mp = m_arg, *np = n_arg, *lim;
+
+       if (LEN(mp) > LEN(np))
+               return 1;  /* not really, but need to check longer one first */
+       if (LEN(mp) == LEN(np))
+               for (lim = mp + LEN(mp); mp < lim;)
+                       if (*mp++ > *np++)
+                               return 1;
+       return 0;
+}
+
+static struct radix_mask *
+rn_new_radix_mask(tt, next)
+       register struct radix_node *tt;
+       register struct radix_mask *next;
+{
+       register struct radix_mask *m;
+
+       MKGet(m);
+       if (m == 0) {
+               log(LOG_ERR, "Mask for route not entered\n");
+               return (0);
+       }
+       bzero(m, sizeof *m);
+       m->rm_bit = tt->rn_bit;
+       m->rm_flags = tt->rn_flags;
+       if (tt->rn_flags & RNF_NORMAL)
+               m->rm_leaf = tt;
+       else
+               m->rm_mask = tt->rn_mask;
+       m->rm_mklist = next;
+       tt->rn_mklist = m;
+       return m;
+}
+
+struct radix_node *
+rn_addroute(v_arg, n_arg, head, treenodes)
+       void *v_arg, *n_arg;
+       struct radix_node_head *head;
+       struct radix_node treenodes[2];
+{
+       caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg;
+       register struct radix_node *t, *x = 0, *tt;
+       struct radix_node *saved_tt, *top = head->rnh_treetop;
+       short b = 0, b_leaf = 0;
+       int keyduplicated;
+       caddr_t mmask;
+       struct radix_mask *m, **mp;
+
+       /*
+        * In dealing with non-contiguous masks, there may be
+        * many different routes which have the same mask.
+        * We will find it useful to have a unique pointer to
+        * the mask to speed avoiding duplicate references at
+        * nodes and possibly save time in calculating indices.
+        */
+       if (netmask)  {
+               if ((x = rn_addmask(netmask, 0, top->rn_offset)) == 0)
+                       return (0);
+               b_leaf = x->rn_bit;
+               b = -1 - x->rn_bit;
+               netmask = x->rn_key;
+       }
+       /*
+        * Deal with duplicated keys: attach node to previous instance
+        */
+       saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes);
+       if (keyduplicated) {
+               for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) {
+#ifdef RADIX_MPATH
+                       /* permit multipath, if enabled for the family */
+                       if (rn_mpath_capable(head) && netmask == tt->rn_mask) {
+                               /*
+                                * go down to the end of multipaths, so that
+                                * new entry goes into the end of rn_dupedkey
+                                * chain.
+                                */
+                               do {
+                                       t = tt;
+                                       tt = tt->rn_dupedkey;
+                               } while (tt && t->rn_mask == tt->rn_mask);
+                               break;
+                       }
+#endif
+                       if (tt->rn_mask == netmask)
+                               return (0);
+                       if (netmask == 0 ||
+                           (tt->rn_mask &&
+                            ((b_leaf < tt->rn_bit) /* index(netmask) > node */
+                             || rn_refines(netmask, tt->rn_mask)
+                             || rn_lexobetter(netmask, tt->rn_mask))))
+                               break;
+               }
+               /*
+                * If the mask is not duplicated, we wouldn't
+                * find it among possible duplicate key entries
+                * anyway, so the above test doesn't hurt.
+                *
+                * We sort the masks for a duplicated key the same way as
+                * in a masklist -- most specific to least specific.
+                * This may require the unfortunate nuisance of relocating
+                * the head of the list.
+                *
+                * We also reverse, or doubly link the list through the
+                * parent pointer.
+                */
+               if (tt == saved_tt) {
+                       struct  radix_node *xx = x;
+                       /* link in at head of list */
+                       (tt = treenodes)->rn_dupedkey = t;
+                       tt->rn_flags = t->rn_flags;
+                       tt->rn_parent = x = t->rn_parent;
+                       t->rn_parent = tt;                      /* parent */
+                       if (x->rn_left == t)
+                               x->rn_left = tt;
+                       else
+                               x->rn_right = tt;
+                       saved_tt = tt; x = xx;
+               } else {
+                       (tt = treenodes)->rn_dupedkey = t->rn_dupedkey;
+                       t->rn_dupedkey = tt;
+                       tt->rn_parent = t;                      /* parent */
+                       if (tt->rn_dupedkey)                    /* parent */
+                               tt->rn_dupedkey->rn_parent = tt; /* parent */
+               }
+#ifdef RN_DEBUG
+               t=tt+1; tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
+               tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;
+#endif
+               tt->rn_key = (caddr_t) v;
+               tt->rn_bit = -1;
+               tt->rn_flags = RNF_ACTIVE;
+       }
+       /*
+        * Put mask in tree.
+        */
+       if (netmask) {
+               tt->rn_mask = netmask;
+               tt->rn_bit = x->rn_bit;
+               tt->rn_flags |= x->rn_flags & RNF_NORMAL;
+       }
+       t = saved_tt->rn_parent;
+       if (keyduplicated)
+               goto on2;
+       b_leaf = -1 - t->rn_bit;
+       if (t->rn_right == saved_tt)
+               x = t->rn_left;
+       else
+               x = t->rn_right;
+       /* Promote general routes from below */
+       if (x->rn_bit < 0) {
+           for (mp = &t->rn_mklist; x; x = x->rn_dupedkey)
+               if (x->rn_mask && (x->rn_bit >= b_leaf) && x->rn_mklist == 0) {
+                       *mp = m = rn_new_radix_mask(x, 0);
+                       if (m)
+                               mp = &m->rm_mklist;
+               }
+       } else if (x->rn_mklist) {
+               /*
+                * Skip over masks whose index is > that of new node
+                */
+               for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
+                       if (m->rm_bit >= b_leaf)
+                               break;
+               t->rn_mklist = m; *mp = 0;
+       }
+on2:
+       /* Add new route to highest possible ancestor's list */
+       if ((netmask == 0) || (b > t->rn_bit ))
+               return tt; /* can't lift at all */
+       b_leaf = tt->rn_bit;
+       do {
+               x = t;
+               t = t->rn_parent;
+       } while (b <= t->rn_bit && x != top);
+       /*
+        * Search through routes associated with node to
+        * insert new route according to index.
+        * Need same criteria as when sorting dupedkeys to avoid
+        * double loop on deletion.
+        */
+       for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) {
+               if (m->rm_bit < b_leaf)
+                       continue;
+               if (m->rm_bit > b_leaf)
+                       break;
+               if (m->rm_flags & RNF_NORMAL) {
+                       mmask = m->rm_leaf->rn_mask;
+                       if (tt->rn_flags & RNF_NORMAL) {
+                           log(LOG_ERR,
+                               "Non-unique normal route, mask not entered\n");
+                               return tt;
+                       }
+               } else
+                       mmask = m->rm_mask;
+               if (mmask == netmask) {
+                       m->rm_refs++;
+                       tt->rn_mklist = m;
+                       return tt;
+               }
+               if (rn_refines(netmask, mmask)
+                   || rn_lexobetter(netmask, mmask))
+                       break;
+       }
+       *mp = rn_new_radix_mask(tt, *mp);
+       return tt;
+}
+
+struct radix_node *
+rn_delete(v_arg, netmask_arg, head)
+       void *v_arg, *netmask_arg;
+       struct radix_node_head *head;
+{
+       register struct radix_node *t, *p, *x, *tt;
+       struct radix_mask *m, *saved_m, **mp;
+       struct radix_node *dupedkey, *saved_tt, *top;
+       caddr_t v, netmask;
+       int b, head_off, vlen;
+
+       v = v_arg;
+       netmask = netmask_arg;
+       x = head->rnh_treetop;
+       tt = rn_search(v, x);
+       head_off = x->rn_offset;
+       vlen =  LEN(v);
+       saved_tt = tt;
+       top = x;
+       if (tt == 0 ||
+           bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off))
+               return (0);
+       /*
+        * Delete our route from mask lists.
+        */
+       if (netmask) {
+               if ((x = rn_addmask(netmask, 1, head_off)) == 0)
+                       return (0);
+               netmask = x->rn_key;
+               while (tt->rn_mask != netmask)
+                       if ((tt = tt->rn_dupedkey) == 0)
+                               return (0);
+       }
+       if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0)
+               goto on1;
+       if (tt->rn_flags & RNF_NORMAL) {
+               if (m->rm_leaf != tt || m->rm_refs > 0) {
+                       log(LOG_ERR, "rn_delete: inconsistent annotation\n");
+                       return 0;  /* dangling ref could cause disaster */
+               }
+       } else {
+               if (m->rm_mask != tt->rn_mask) {
+                       log(LOG_ERR, "rn_delete: inconsistent annotation\n");
+                       goto on1;
+               }
+               if (--m->rm_refs >= 0)
+                       goto on1;
+       }
+       b = -1 - tt->rn_bit;
+       t = saved_tt->rn_parent;
+       if (b > t->rn_bit)
+               goto on1; /* Wasn't lifted at all */
+       do {
+               x = t;
+               t = t->rn_parent;
+       } while (b <= t->rn_bit && x != top);
+       for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
+               if (m == saved_m) {
+                       *mp = m->rm_mklist;
+                       MKFree(m);
+                       break;
+               }
+       if (m == 0) {
+               log(LOG_ERR, "rn_delete: couldn't find our annotation\n");
+               if (tt->rn_flags & RNF_NORMAL)
+                       return (0); /* Dangling ref to us */
+       }
+on1:
+       /*
+        * Eliminate us from tree
+        */
+       if (tt->rn_flags & RNF_ROOT)
+               return (0);
+#ifdef RN_DEBUG
+       /* Get us out of the creation list */
+       for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) {}
+       if (t) t->rn_ybro = tt->rn_ybro;
+#endif
+       t = tt->rn_parent;
+       dupedkey = saved_tt->rn_dupedkey;
+       if (dupedkey) {
+               /*
+                * Here, tt is the deletion target and
+                * saved_tt is the head of the dupekey chain.
+                */
+               if (tt == saved_tt) {
+                       /* remove from head of chain */
+                       x = dupedkey; x->rn_parent = t;
+                       if (t->rn_left == tt)
+                               t->rn_left = x;
+                       else
+                               t->rn_right = x;
+               } else {
+                       /* find node in front of tt on the chain */
+                       for (x = p = saved_tt; p && p->rn_dupedkey != tt;)
+                               p = p->rn_dupedkey;
+                       if (p) {
+                               p->rn_dupedkey = tt->rn_dupedkey;
+                               if (tt->rn_dupedkey)            /* parent */
+                                       tt->rn_dupedkey->rn_parent = p;
+                                                               /* parent */
+                       } else log(LOG_ERR, "rn_delete: couldn't find us\n");
+               }
+               t = tt + 1;
+               if  (t->rn_flags & RNF_ACTIVE) {
+#ifndef RN_DEBUG
+                       *++x = *t;
+                       p = t->rn_parent;
+#else
+                       b = t->rn_info;
+                       *++x = *t;
+                       t->rn_info = b;
+                       p = t->rn_parent;
+#endif
+                       if (p->rn_left == t)
+                               p->rn_left = x;
+                       else
+                               p->rn_right = x;
+                       x->rn_left->rn_parent = x;
+                       x->rn_right->rn_parent = x;
+               }
+               goto out;
+       }
+       if (t->rn_left == tt)
+               x = t->rn_right;
+       else
+               x = t->rn_left;
+       p = t->rn_parent;
+       if (p->rn_right == t)
+               p->rn_right = x;
+       else
+               p->rn_left = x;
+       x->rn_parent = p;
+       /*
+        * Demote routes attached to us.
+        */
+       if (t->rn_mklist) {
+               if (x->rn_bit >= 0) {
+                       for (mp = &x->rn_mklist; (m = *mp);)
+                               mp = &m->rm_mklist;
+                       *mp = t->rn_mklist;
+               } else {
+                       /* If there are any key,mask pairs in a sibling
+                          duped-key chain, some subset will appear sorted
+                          in the same order attached to our mklist */
+                       for (m = t->rn_mklist; m && x; x = x->rn_dupedkey)
+                               if (m == x->rn_mklist) {
+                                       struct radix_mask *mm = m->rm_mklist;
+                                       x->rn_mklist = 0;
+                                       if (--(m->rm_refs) < 0)
+                                               MKFree(m);
+                                       m = mm;
+                               }
+                       if (m)
+                               log(LOG_ERR,
+                                   "rn_delete: Orphaned Mask %p at %p\n",
+                                   (void *)m, (void *)x);
+               }
+       }
+       /*
+        * We may be holding an active internal node in the tree.
+        */
+       x = tt + 1;
+       if (t != x) {
+#ifndef RN_DEBUG
+               *t = *x;
+#else
+               b = t->rn_info;
+               *t = *x;
+               t->rn_info = b;
+#endif
+               t->rn_left->rn_parent = t;
+               t->rn_right->rn_parent = t;
+               p = x->rn_parent;
+               if (p->rn_left == x)
+                       p->rn_left = t;
+               else
+                       p->rn_right = t;
+       }
+out:
+       tt->rn_flags &= ~RNF_ACTIVE;
+       tt[1].rn_flags &= ~RNF_ACTIVE;
+       return (tt);
+}
+
+/*
+ * This is the same as rn_walktree() except for the parameters and the
+ * exit.
+ */
+static int
+rn_walktree_from(h, a, m, f, w)
+       struct radix_node_head *h;
+       void *a, *m;
+       walktree_f_t *f;
+       void *w;
+{
+       int error;
+       struct radix_node *base, *next;
+       u_char *xa = (u_char *)a;
+       u_char *xm = (u_char *)m;
+       register struct radix_node *rn, *last = 0 /* shut up gcc */;
+       int stopping = 0;
+       int lastb;
+
+       /*
+        * rn_search_m is sort-of-open-coded here. We cannot use the
+        * function because we need to keep track of the last node seen.
+        */
+       /* printf("about to search\n"); */
+       for (rn = h->rnh_treetop; rn->rn_bit >= 0; ) {
+               last = rn;
+               /* printf("rn_bit %d, rn_bmask %x, xm[rn_offset] %x\n",
+                      rn->rn_bit, rn->rn_bmask, xm[rn->rn_offset]); */
+               if (!(rn->rn_bmask & xm[rn->rn_offset])) {
+                       break;
+               }
+               if (rn->rn_bmask & xa[rn->rn_offset]) {
+                       rn = rn->rn_right;
+               } else {
+                       rn = rn->rn_left;
+               }
+       }
+       /* printf("done searching\n"); */
+
+       /*
+        * Two cases: either we stepped off the end of our mask,
+        * in which case last == rn, or we reached a leaf, in which
+        * case we want to start from the last node we looked at.
+        * Either way, last is the node we want to start from.
+        */
+       rn = last;
+       lastb = rn->rn_bit;
+
+       /* printf("rn %p, lastb %d\n", rn, lastb);*/
+
+       /*
+        * This gets complicated because we may delete the node
+        * while applying the function f to it, so we need to calculate
+        * the successor node in advance.
+        */
+       while (rn->rn_bit >= 0)
+               rn = rn->rn_left;
+
+       while (!stopping) {
+               /* printf("node %p (%d)\n", rn, rn->rn_bit); */
+               base = rn;
+               /* If at right child go back up, otherwise, go right */
+               while (rn->rn_parent->rn_right == rn
+                      && !(rn->rn_flags & RNF_ROOT)) {
+                       rn = rn->rn_parent;
+
+                       /* if went up beyond last, stop */
+                       if (rn->rn_bit <= lastb) {
+                               stopping = 1;
+                               /* printf("up too far\n"); */
+                               /*
+                                * XXX we should jump to the 'Process leaves'
+                                * part, because the values of 'rn' and 'next'
+                                * we compute will not be used. Not a big deal
+                                * because this loop will terminate, but it is
+                                * inefficient and hard to understand!
+                                */
+                       }
+               }
+               
+               /* 
+                * At the top of the tree, no need to traverse the right
+                * half, prevent the traversal of the entire tree in the
+                * case of default route.
+                */
+               if (rn->rn_parent->rn_flags & RNF_ROOT)
+                       stopping = 1;
+
+               /* Find the next *leaf* since next node might vanish, too */
+               for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;)
+                       rn = rn->rn_left;
+               next = rn;
+               /* Process leaves */
+               while ((rn = base) != 0) {
+                       base = rn->rn_dupedkey;
+                       /* printf("leaf %p\n", rn); */
+                       if (!(rn->rn_flags & RNF_ROOT)
+                           && (error = (*f)(rn, w)))
+                               return (error);
+               }
+               rn = next;
+
+               if (rn->rn_flags & RNF_ROOT) {
+                       /* printf("root, stopping"); */
+                       stopping = 1;
+               }
+
+       }
+       return 0;
+}
+
+static int
+rn_walktree(h, f, w)
+       struct radix_node_head *h;
+       walktree_f_t *f;
+       void *w;
+{
+       int error;
+       struct radix_node *base, *next;
+       register struct radix_node *rn = h->rnh_treetop;
+       /*
+        * This gets complicated because we may delete the node
+        * while applying the function f to it, so we need to calculate
+        * the successor node in advance.
+        */
+
+       /* First time through node, go left */
+       while (rn->rn_bit >= 0)
+               rn = rn->rn_left;
+       for (;;) {
+               base = rn;
+               /* If at right child go back up, otherwise, go right */
+               while (rn->rn_parent->rn_right == rn
+                      && (rn->rn_flags & RNF_ROOT) == 0)
+                       rn = rn->rn_parent;
+               /* Find the next *leaf* since next node might vanish, too */
+               for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;)
+                       rn = rn->rn_left;
+               next = rn;
+               /* Process leaves */
+               while ((rn = base)) {
+                       base = rn->rn_dupedkey;
+                       if (!(rn->rn_flags & RNF_ROOT)
+                           && (error = (*f)(rn, w)))
+                               return (error);
+               }
+               rn = next;
+               if (rn->rn_flags & RNF_ROOT)
+                       return (0);
+       }
+       /* NOTREACHED */
+}
+
+/*
+ * Allocate and initialize an empty tree. This has 3 nodes, which are
+ * part of the radix_node_head (in the order <left,root,right>) and are
+ * marked RNF_ROOT so they cannot be freed.
+ * The leaves have all-zero and all-one keys, with significant
+ * bits starting at 'off'.
+ * Return 1 on success, 0 on error.
+ */
+int
+rn_inithead(head, off)
+       void **head;
+       int off;
+{
+       register struct radix_node_head *rnh;
+       register struct radix_node *t, *tt, *ttt;
+       if (*head)
+               return (1);
+       R_Zalloc(rnh, struct radix_node_head *, sizeof (*rnh));
+       if (rnh == 0)
+               return (0);
+#ifdef _KERNEL
+       RADIX_NODE_HEAD_LOCK_INIT(rnh);
+#endif
+       *head = rnh;
+       t = rn_newpair(rn_zeros, off, rnh->rnh_nodes);
+       ttt = rnh->rnh_nodes + 2;
+       t->rn_right = ttt;
+       t->rn_parent = t;
+       tt = t->rn_left;        /* ... which in turn is rnh->rnh_nodes */
+       tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE;
+       tt->rn_bit = -1 - off;
+       *ttt = *tt;
+       ttt->rn_key = rn_ones;
+       rnh->rnh_addaddr = rn_addroute;
+       rnh->rnh_deladdr = rn_delete;
+       rnh->rnh_matchaddr = rn_match;
+       rnh->rnh_lookup = rn_lookup;
+       rnh->rnh_walktree = rn_walktree;
+       rnh->rnh_walktree_from = rn_walktree_from;
+       rnh->rnh_treetop = t;
+       return (1);
+}
+
+void
+rn_init()
+{
+       char *cp, *cplim;
+#ifdef _KERNEL
+       struct domain *dom;
+
+       for (dom = domains; dom; dom = dom->dom_next)
+               if (dom->dom_maxrtkey > max_keylen)
+                       max_keylen = dom->dom_maxrtkey;
+#endif
+       if (max_keylen == 0) {
+               log(LOG_ERR,
+                   "rn_init: radix functions require max_keylen be set\n");
+               return;
+       }
+       R_Malloc(rn_zeros, char *, 3 * max_keylen);
+       if (rn_zeros == NULL)
+               panic("rn_init");
+       bzero(rn_zeros, 3 * max_keylen);
+       rn_ones = cp = rn_zeros + max_keylen;
+       addmask_key = cplim = rn_ones + max_keylen;
+       while (cp < cplim)
+               *cp++ = -1;
+       if (rn_inithead((void **)(void *)&mask_rnhead, 0) == 0)
+               panic("rn_init 2");
+}
diff --git a/glue.h b/glue.h
index bf7043d..c05ee4a 100644 (file)
--- a/glue.h
+++ b/glue.h
@@ -23,7 +23,7 @@
  * SUCH DAMAGE.
  */
 /*
- * $Id: glue.h 4363 2009-12-08 16:06:54Z marta $
+ * $Id: glue.h 4413 2009-12-10 08:57:02Z luigi $
  *
  * glue code to adapt the FreeBSD version to linux and windows,
  * userland and kernel.
@@ -260,6 +260,11 @@ struct route_in6 { };
 
 #define INET_ADDRSTRLEN                16
 
+#ifdef linux
+/* linux does not have sin_len in sockaddr */
+#define        sin_len __pad[0]
+#endif /* linux */
+
 /*
  * List of values used for set/getsockopt options.
  * The base value on FreeBSD is defined as a macro,
index bdef328..9023db8 100644 (file)
@@ -34,7 +34,7 @@ Distribution: PlanetLab %{plrelease}
 URL: %(echo %{url} | cut -d ' ' -f 2)
 
 %description
-the frontent part of the ipfw planetlab package
+the frontend part of the ipfw planetlab package
 
 %prep
 %setup
@@ -43,8 +43,8 @@ the frontent part of the ipfw planetlab package
 rm -rf $RPM_BUILD_ROOT
 
 %install
-install -D -m 755 slice/netconfig $RPM_BUILD_ROOT/sbin/netconfig
-install -D -m 755 slice/ipfw.8.gz $RPM_BUILD_ROOT/%{_mandir}/man8/ipfw.8.gz
+install -D -m 755 planetlab/netconfig $RPM_BUILD_ROOT/sbin/netconfig
+install -D -m 755 planetlab/ipfw.8.gz $RPM_BUILD_ROOT/%{_mandir}/man8/ipfw.8.gz
 
 %clean
 rm -rf $RPM_BUILD_ROOT
index 1b20e61..212efb7 100644 (file)
--- a/ipfw.spec
+++ b/ipfw.spec
@@ -58,8 +58,8 @@ rm -rf $RPM_BUILD_ROOT
 %install
 install -D -m 755 dummynet/ipfw_mod.ko $RPM_BUILD_ROOT/lib/modules/%{kernel_id}/net/netfilter/ipfw_mod.ko
 install -D -m 755 ipfw/ipfw $RPM_BUILD_ROOT/sbin/ipfw
-install -D -m 755 ipfw-cleanup $RPM_BUILD_ROOT/usr/bin/ipfw-cleanup
-install -D -m 755 ipfw.cron $RPM_BUILD_ROOT/%{_sysconfdir}/cron.d/ipfw.cron
+install -D -m 755 planetlab/ipfw-cleanup $RPM_BUILD_ROOT/usr/bin/ipfw-cleanup
+install -D -m 755 planetlab/ipfw.cron $RPM_BUILD_ROOT/%{_sysconfdir}/cron.d/ipfw.cron
 
 %clean
 rm -rf $RPM_BUILD_ROOT
index 2a5e08e..807f2d1 100644 (file)
@@ -7,8 +7,7 @@
 # Do not set with = or := so we can inherit from the caller
 $(warning Building userland ipfw for $(VER))
 EXTRA_CFLAGS += -O1
-# comment this on planetlab
-#EXTRA_CFLAGS += -Wall -Werror
+EXTRA_CFLAGS += -Wall -Werror
 EXTRA_CFLAGS += -include ../glue.h
 EXTRA_CFLAGS += -I ./include
 
@@ -53,3 +52,4 @@ include/netinet:
 
 clean distclean:
        -rm -f $(OBJS) ipfw
+       -rm -rf include/netinet/
index 12625fe..6cfbff0 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <ctype.h>
 #include <err.h>
+#include <errno.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -75,12 +76,8 @@ static struct _s_x dummynet_params[] = {
        { NULL, 0 }     /* terminator */
 };
 
-/* 
- * XXX to be updated to the new version,
- * without the global struct command_opts variable
- */
 static int
-sort_q(void * to_be_done, const void *pa, const void *pb)
+sort_q(void *arg, const void *pa, const void *pb)
 {
        int rev = (co.do_sort < 0);
        int field = rev ? -co.do_sort : co.do_sort;
@@ -458,7 +455,6 @@ ipfw_delete_pipe(int pipe_or_queue, int i)
  *
  */
 
-/* XXX move to an array definition ? */
 #define ED_MAX_LINE_LEN        256+ED_MAX_NAME_LEN
 #define ED_TOK_SAMPLES "samples"
 #define ED_TOK_LOSS    "loss-level"
index e9b3fb3..571ff39 100644 (file)
@@ -224,6 +224,12 @@ static struct _s_x rule_action_params[] = {
        { NULL, 0 }     /* terminator */
 };
 
+/* index of 'lookup ... ' keys in the kernel */
+static int lookup_key[] = {
+       TOK_DSTIP, TOK_SRCIP, TOK_DSTPORT, TOK_SRCPORT,
+       TOK_UID, TOK_GID, TOK_JAIL,
+       TOK_PROTO, TOK_MACTYPE, 0, };
+
 static struct _s_x rule_options[] = {
        { "tagged",             TOK_TAGGED },
        { "uid",                TOK_UID },
@@ -290,6 +296,7 @@ static struct _s_x rule_options[] = {
        { "dst-ip6",            TOK_DSTIP6},
        { "src-ipv6",           TOK_SRCIP6},
        { "src-ip6",            TOK_SRCIP6},
+       { "lookup",             TOK_LOOKUP},
        { "//",                 TOK_COMMENT },
 
        { "not",                TOK_NOT },              /* pseudo option */
@@ -743,6 +750,16 @@ print_ip(ipfw_insn_ip *cmd, char const *s)
        int len = F_LEN((ipfw_insn *)cmd);
        uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
 
+       if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) {
+               uint32_t d = a[1];
+               const char *arg = "<invalid>";
+
+               if (d < sizeof(lookup_key)/sizeof(lookup_key[0]))
+                       arg = match_value(rule_options, lookup_key[d]);
+               printf("%s lookup %s %d,%d", cmd->o.len & F_NOT ? " not": "",
+                       arg, cmd->o.arg1, a[0]);
+               return;
+       }
        printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
 
        if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) {
@@ -2756,9 +2773,11 @@ chkarg:
 
                /*
                 * In the kernel we assume AF_INET and use only
-                * sin_port and sin_addr.
+                * sin_port and sin_addr. Remember to set sin_len as
+                * the routing code seems to use it too.
                 */
                p->sa.sin_family = AF_INET;
+               //p->sa.sin_len = sizeof(struct sockaddr_in);
                p->sa.sin_port = 0;
                /*
                 * locate the address-port separator (':' or ',')
@@ -2875,7 +2894,7 @@ chkarg:
                        if (have_tag)
                                errx(EX_USAGE, "tag and untag cannot be "
                                    "specified more than once");
-                       GET_UINT_ARG(tag, 1, IPFW_DEFAULT_RULE - 1, i,
+                       GET_UINT_ARG(tag, IPFW_ARG_MIN, IPFW_ARG_MAX, i,
                           rule_action_params);
                        have_tag = cmd;
                        fill_cmd(cmd, O_TAG, (i == TOK_TAG) ? 0: F_NOT, tag);
@@ -3352,7 +3371,7 @@ read_options:
                        if (c->limit_mask == 0)
                                errx(EX_USAGE, "limit: missing limit mask");
 
-                       GET_UINT_ARG(c->conn_limit, 1, IPFW_DEFAULT_RULE - 1,
+                       GET_UINT_ARG(c->conn_limit, IPFW_ARG_MIN, IPFW_ARG_MAX,
                            TOK_LIMIT, rule_options);
 
                        ac--; av++;
@@ -3480,7 +3499,7 @@ read_options:
                        else {
                                uint16_t tag;
 
-                               GET_UINT_ARG(tag, 1, IPFW_DEFAULT_RULE - 1,
+                               GET_UINT_ARG(tag, IPFW_ARG_MIN, IPFW_ARG_MAX,
                                    TOK_TAGGED, rule_options);
                                fill_cmd(cmd, O_TAGGED, 0, tag);
                        }
@@ -3493,6 +3512,36 @@ read_options:
                        ac--; av++;
                        break;
 
+               case TOK_LOOKUP: {
+                       ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd;
+                       char *p;
+                       int j;
+
+                       if (ac < 2)
+                               errx(EX_USAGE, "format: lookup argument tablenum[,arg]");
+                       cmd->opcode = O_IP_DST_LOOKUP;
+                       cmd->len |= F_INSN_SIZE(ipfw_insn) + 2;
+                       i = match_token(rule_options, *av);
+                       for (j = 0; lookup_key[j] ; j++) {
+                               if (i == lookup_key[j])
+                                       break;
+                       }
+                       if (lookup_key[j] == 0)
+                               errx(EX_USAGE, "format: cannot lookup on %s", *av);
+                       c->d[1] = j; // i converted to option
+                       ac--; av++;
+                       p = strchr(*av, ',');
+                       if (p) {
+                               *p++ = '\0';
+                               c->d[0] = strtoul(p, NULL, 0);
+                       } else {
+                               c->d[0] = ~0;
+                       }
+                       cmd->arg1 = strtoul(*av, NULL, 0);
+                       ac--; av++;
+                   }
+                       break;
+
                default:
                        errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
                }
index bd80cff..0d59e11 100644 (file)
@@ -186,6 +186,7 @@ enum tokens {
 
        TOK_FIB,
        TOK_SETFIB,
+       TOK_LOOKUP,
 };
 /*
  * the following macro returns an error message if we run out of
similarity index 100%
rename from ipfw-cleanup
rename to planetlab/ipfw-cleanup
similarity index 100%
rename from slice/ipfw.8.gz
rename to planetlab/ipfw.8.gz
similarity index 100%
rename from ipfw.cron
rename to planetlab/ipfw.cron
similarity index 100%
rename from slice/netconfig
rename to planetlab/netconfig
similarity index 100%
rename from sample_hook
rename to planetlab/sample_hook