From 5ad9fec40da13c449d50def12f9cea6e24b6a708 Mon Sep 17 00:00:00 2001 From: marta Date: Thu, 10 Dec 2009 10:30:48 +0000 Subject: [PATCH] Update the work on ipfw tables, reduce diffs. Create a new directory with PlanetLab stuff and changed specfiles accordingly. --- Makefile.openwrt | 79 ++ NOTES | 190 ++++ README | 28 +- README.openwrt | 29 + dummynet/Makefile | 13 +- dummynet/hashtable.c | 2 +- dummynet/include/net/radix.h | 179 ++++ dummynet/include/netinet/ip_dummynet.h | 4 - dummynet/include/netinet/ip_fw.h | 42 +- dummynet/include/sys/mbuf.h | 2 +- dummynet/ip_dummynet.c | 10 +- dummynet/ip_fw2.c | 131 ++- dummynet/ip_fw_pfil.c | 21 +- dummynet/ipfw2_mod.c | 8 +- dummynet/missing.h | 32 +- dummynet/new_glue.c | 70 +- dummynet/radix.c | 1188 ++++++++++++++++++++++++ glue.h | 7 +- ipfw-slice.spec | 6 +- ipfw.spec | 4 +- ipfw/Makefile | 4 +- ipfw/dummynet.c | 8 +- ipfw/ipfw2.c | 57 +- ipfw/ipfw2.h | 1 + ipfw-cleanup => planetlab/ipfw-cleanup | 0 {slice => planetlab}/ipfw.8.gz | Bin ipfw.cron => planetlab/ipfw.cron | 0 {slice => planetlab}/netconfig | 0 sample_hook => planetlab/sample_hook | 0 29 files changed, 1972 insertions(+), 143 deletions(-) create mode 100644 Makefile.openwrt create mode 100644 NOTES create mode 100644 README.openwrt create mode 100644 dummynet/include/net/radix.h create mode 100644 dummynet/radix.c rename ipfw-cleanup => planetlab/ipfw-cleanup (100%) rename {slice => planetlab}/ipfw.8.gz (100%) rename ipfw.cron => planetlab/ipfw.cron (100%) rename {slice => planetlab}/netconfig (100%) rename sample_hook => planetlab/sample_hook (100%) diff --git a/Makefile.openwrt b/Makefile.openwrt new file mode 100644 index 0000000..50dae83 --- /dev/null +++ b/Makefile.openwrt @@ -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 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 + +--- 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 --- 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 index 0000000..dcf8194 --- /dev/null +++ b/README.openwrt @@ -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 diff --git a/dummynet/Makefile b/dummynet/Makefile index e732601..eab794a 100644 --- a/dummynet/Makefile +++ b/dummynet/Makefile @@ -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 diff --git a/dummynet/hashtable.c b/dummynet/hashtable.c index 517cec6..30c3b4c 100644 --- a/dummynet/hashtable.c +++ b/dummynet/hashtable.c @@ -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 index 0000000..5d99a2f --- /dev/null +++ b/dummynet/include/net/radix.h @@ -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 +#include +#include +#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_ */ diff --git a/dummynet/include/netinet/ip_dummynet.h b/dummynet/include/netinet/ip_dummynet.h index 4f8291f..81ebb33 100644 --- a/dummynet/include/netinet/ip_dummynet.h +++ b/dummynet/include/netinet/ip_dummynet.h @@ -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. diff --git a/dummynet/include/netinet/ip_fw.h b/dummynet/include/netinet/ip_fw.h index a19a6df..694983a 100644 --- a/dummynet/include/netinet/ip_fw.h +++ b/dummynet/include/netinet/ip_fw.h @@ -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 */ diff --git a/dummynet/include/sys/mbuf.h b/dummynet/include/sys/mbuf.h index a7f95a1..ed3d3a1 100644 --- a/dummynet/include/sys/mbuf.h +++ b/dummynet/include/sys/mbuf.h @@ -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 diff --git a/dummynet/ip_dummynet.c b/dummynet/ip_dummynet.c index 473a761..5b36ecc 100644 --- a/dummynet/ip_dummynet.c +++ b/dummynet/ip_dummynet.c @@ -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 #include #include @@ -64,9 +66,9 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.110.2.4 2008/10/31 12:58:1 #include #include #include -#include #include #include +#include #include #include #include @@ -85,8 +87,6 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.110.2.4 2008/10/31 12:58:1 #include /* for ip6_input, ip6_output prototypes */ #include -#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; } } diff --git a/dummynet/ip_fw2.c b/dummynet/ip_fw2.c index 19d4d94..50e8701 100644 --- a/dummynet/ip_fw2.c +++ b/dummynet/ip_fw2.c @@ -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 #include +#include +#include #include #include #include @@ -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 #include #include +#include #include #include #include @@ -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 #include +#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 @@ -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 #ifdef INET6 #include +#include #endif #include /* 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 #endif -#ifdef linux -//#include /* 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 /* 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 diff --git a/dummynet/ip_fw_pfil.c b/dummynet/ip_fw_pfil.c index 4e3568a..3fa643c 100644 --- a/dummynet/ip_fw_pfil.c +++ b/dummynet/ip_fw_pfil.c @@ -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 #include +#include "missing.h" + #include #include #include @@ -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 -#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; diff --git a/dummynet/ipfw2_mod.c b/dummynet/ipfw2_mod.c index ee4eeba..f47d365 100644 --- a/dummynet/ipfw2_mod.c +++ b/dummynet/ipfw2_mod.c @@ -49,6 +49,8 @@ #include /* sizeof struct mbuf */ #include /* NGROUPS */ +#include "missing.h" + #ifdef __linux__ #include #include @@ -75,10 +77,12 @@ /* * 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 *); diff --git a/dummynet/missing.h b/dummynet/missing.h index c6bb4f3..1d2f2ec 100644 --- a/dummynet/missing.h +++ b/dummynet/missing.h @@ -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) diff --git a/dummynet/new_glue.c b/dummynet/new_glue.c index 52a1a7f..ce0a5a3 100644 --- a/dummynet/new_glue.c +++ b/dummynet/new_glue.c @@ -1,24 +1,4 @@ #include "missing.h" -//#include -//#include -//#include -// #include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include /* for ETHERTYPE_IP */ -//#include -//#include -//#include -//#include #define IPFW_INTERNAL #include @@ -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 index 0000000..2a5fcc3 --- /dev/null +++ b/dummynet/radix.c @@ -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 +#ifdef _KERNEL +#include +#include +#include +#include +#include +// #include +#else +#include +#endif +#include +#include +#endif + +// #include "opt_mpath.h" + +#ifdef RADIX_MPATH +#include +#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 ) 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 --- 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, diff --git a/ipfw-slice.spec b/ipfw-slice.spec index bdef328..9023db8 100644 --- a/ipfw-slice.spec +++ b/ipfw-slice.spec @@ -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 diff --git a/ipfw.spec b/ipfw.spec index 1b20e61..212efb7 100644 --- 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 diff --git a/ipfw/Makefile b/ipfw/Makefile index 2a5e08e..807f2d1 100644 --- a/ipfw/Makefile +++ b/ipfw/Makefile @@ -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/ diff --git a/ipfw/dummynet.c b/ipfw/dummynet.c index 12625fe..6cfbff0 100644 --- a/ipfw/dummynet.c +++ b/ipfw/dummynet.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -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" diff --git a/ipfw/ipfw2.c b/ipfw/ipfw2.c index e9b3fb3..571ff39 100644 --- a/ipfw/ipfw2.c +++ b/ipfw/ipfw2.c @@ -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 = ""; + + 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); } diff --git a/ipfw/ipfw2.h b/ipfw/ipfw2.h index bd80cff..0d59e11 100644 --- a/ipfw/ipfw2.h +++ b/ipfw/ipfw2.h @@ -186,6 +186,7 @@ enum tokens { TOK_FIB, TOK_SETFIB, + TOK_LOOKUP, }; /* * the following macro returns an error message if we run out of diff --git a/ipfw-cleanup b/planetlab/ipfw-cleanup similarity index 100% rename from ipfw-cleanup rename to planetlab/ipfw-cleanup diff --git a/slice/ipfw.8.gz b/planetlab/ipfw.8.gz similarity index 100% rename from slice/ipfw.8.gz rename to planetlab/ipfw.8.gz diff --git a/ipfw.cron b/planetlab/ipfw.cron similarity index 100% rename from ipfw.cron rename to planetlab/ipfw.cron diff --git a/slice/netconfig b/planetlab/netconfig similarity index 100% rename from slice/netconfig rename to planetlab/netconfig diff --git a/sample_hook b/planetlab/sample_hook similarity index 100% rename from sample_hook rename to planetlab/sample_hook -- 2.43.0