sync the code with FreeBSD-head.
Changed the directory structure moving the planetlab files
into a separate directory.
# We assume that $(USRDIR) contains include/ and lib/ used to build userland.
DATE ?= $(shell date +%Y%m%d)
-SNAPSHOT_NAME=ipfw_linux-$(DATE)
+SNAPSHOT_NAME=ipfw_mod-$(DATE)
_all: all
(cd dummynet && $(MAKE) $(@) )
snapshot:
- -ln -s `pwd` /tmp/$(SNAPSHOT_NAME)
- (cd /tmp; tar cvzhf $(SNAPSHOT_NAME).tgz --exclude .svn \
+ (cd ..; tar cvzhf /tmp/$(SNAPSHOT_NAME).tgz --exclude .svn \
--exclude README.openwrt --exclude tags --exclude NOTES \
- $(SNAPSHOT_NAME) )
- -rm /tmp/$(SNAPSHOT_NAME)
+ ipfw_mod )
install:
#
-# $Id: README 4396 2009-12-09 21:52:46Z luigi $
+# $Id: README 4502 2009-12-15 11:10:33Z marta $
#
This directory contains a port of ipfw and dummynet to Linux and OpenWrt
make VER=2.4 KERNELPATH=...
+ For 2.4, if KERNELPATH is not specified then we use
+ KERNELPATH ?= /usr/src/`uname -r`/build
+
You need to follow the same instruction for the 2.6 kernel, enabling
netfilter in the kernel options:
+ Add ipfw2 to the openwrt package, as follows:
- - fetch and extract the code e.g.
+ - copy the code from this directory to the place used for the build:
- (cd ..; \
- wget http://info.iet.unipi.it/~luigi/dummynet/ipfw_linux-20090724.tgz;\
- tar xvzf ipfw_linux-20090724.tgz; mv ipfw_linux-20090724 ipfw_mod;)
+ cp -Rp /path_to_ipfw_mod ../ipfw_mod;
- (but you should have done it already)
+ If you want, you can fetch a newer version from the web
+ (cd ..; rm -rf ipfw_mod;
+ wget http://info.iet.unipi.it/~luigi/dummynet/ipfw_mod-latest.tgz;\
+ tar xvzf ipfw_mod-latest.tgz)
- run the following commands:
(mkdir package/ipfw2;
- cp ../ipfw_linux/Makefile.openwrt package/ipfw2/Makefile)
+ cp ../ipfw_mod/Makefile.openwrt package/ipfw2/Makefile)
to create the package/ipfw2 directory in the OpenWrt source
directory, and copy Makefile.openwrt to package/ipfw2/Makefile:
- if necessary, edit package/ipfw2/Makefile and set IPFW_DIR to point to
- the directory with the ipfw sources (the directory
- which contains this README, dummynet/ ipfw/ and so on);
+ the directory ipfw_mod, which contains the ipfw sources
- run "make menuconfig" and select ipfw2 as a module <M> in
- Kernel Modules -> Other modules -> ipfw2
+ Kernel Modules -> Other modules -> kmod-ipfw2
- run "make" to build the package, "make V=99" for verbose build.
+ - to modify the code, assuming you are in directory "kamikaze_8.09.1"
+
+ (cd ../ipfw_mod && vi ...the files you are interested in )
+ rm -rf build_dir/linux-brcm-2.4/kmod-ipfw2
+ make package/ipfw2/compile V=99
+
The resulting package is located in bin/packages/mipsel/kmod-ipfw2*,
upload the file and install on the target system, as follows:
/lib/modules/2.4.35.4/ipfw show # launch the userspace tool
rmmod ipfw_mod.o # remove the module
-***** PLANETLAB BUILD *****
+***** PLANETLAB BUILD (within a slice) *****
+
+ Follow the instructions below. You can just cut&paste
+
+ # install the various tools if not available
+ sudo yum -y install subversion rpm-build rpm-devel m4 redhat-rpm-config make gcc
+ # new build installation requires the gnupg package
+ sudo yum -y install gnupg
+
+ # create and move to a work directory
+ mkdir -p test
+ # extract a planetlab distribution to directory XYZ
+ (cd test; svn co http://svn.planet-lab.org/svn/build/trunk XYZ)
+ # copy the planetlab/*mk files here, overriding existing ones
+ cp planetlab/*mk test/XYZ
+ # download the specfiles and do some patching.
+ # Results are into SPEC/ (takes 5 minutes)
+ (cd test/XYZ; make stage1=true PLDISTRO=planetlab )
+ # Building the slice code is fast, the root code takes longer
+ # as it needs to rebuild the whole kernel
+ (cd test/XYZ; sudo make ipfwslice ipfwroot)
+
+ The kernel dependency phase is a bit time consuming, but does not
+ need to be redone if we are changing the ipfw sources only.
+ To clean up the code do
+ (cd test/XYZ; sudo make ipfwroot-clean ipfwslice-clean)
+ then after you have updated the repository again
+ (cd test/XYZ; sudo make ipfwslice ipfwroot)
+
+--- other, instructions (to be verified) ---
+
+To build a kernel module for the PlanetLab distribution you need a build system.
+For an up-to-date and detailed information on how to build a local myplc installation,
+a local mirror, a PlanetLab test system see[1]
+
+To create a build system you need to do the following steps:
+
+ 1. install CentOS 5, detailed information[2]
+
+ 1.A download the image from the main site[3] for example:
+
+ wget http://mi.mirror.garr.it/mirrors/CentOS/5.4/isos/i386/CentOS-5.4-i386-netinstall.iso
+
+ 1.B Add the repository
+
+ cat >> /etc/yum.repos.d/dhozac-vserver.repo <<EOF
+ [dhozac-vserver]
+name=Linux-VServer related packages for CentOS $releasever - $basearch
+baseurl=http://rpm.hozac.com/dhozac/centos/$releasever/vserver/$basearch
+gpgkey=http://rpm.hozac.com/conf/keys/RPM-DHOZAC-GPG-KEY
+EOF
+
+ 1.C Update, install and config the system
+
+ yum update yum
+ yum install kernel
+ yum install util-vserver{,-core,-lib,-sysv,-build}
+ yum install vim
+ yum install subversion
+ /etc/init.d/vprocunhide start
+ chkconfig vservers-default on
+
+ 2. create a vserver
+
+ 2.A Checkout the planetlab build
+
+ cd
+ svn co http://svn.planet-lab.org/svn/build/trunk svn-build
+
+ 2.B Search for a working RPM distribution in:
+
+ http://build.onelab.eu/onelab/
+ # good distribution ends in .ok, bad in .ko
+ # in this example we used the following:
+ http://build.onelab.eu/onelab/2008.03.02--onelab-f8-linux32/RPMS/
+
+ 2.C Creating a vserver
+
+ cd ~/svn-build
+ ./vtest-init-vserver.sh -f f8 -d onelab -p linux32 mybuild \
+ http://build.onelab.eu/onelab/2008.03.02--onelab-f8-linux32/RPMS/ \
+ -- --interface eth0:138.96.255.221 --hostname vnode01.inria.fr &> mybuild.log&
+
+ 3. create the build
+
+ 3.A Enter on the vserver, and create the build
+
+ vserver mybuild enter
+ cd \
+ svn co http://svn.planet-lab.org/svn/build/trunk build
+
+ 4. build
+
+ 4.A build[4]
+ cd /build
+
+ # full cleanup
+ make distclean
+
+ # the compilation is composed by several steps,
+ # make help for more information
+ # the first for the onelab compilation will download
+ # the SPEC file from the repository specified in
+ # onelab-tags.mk
+ make stage1=true PLDISTRO=onelab
+
+ # to download and build a module, for example ipfw:
+ make ipfw
+
+ # to do local changes
+ cd /build/CODEBASE
+ rm -rf ipfw
+ # download the ipfw sources and extract it into ./ipfw
+ # by svn
+ svn+ssh://onelab2.iet.unipi.it/home/svn/ports-luigi/dummynet-branches/ipfw_mod ./ipfw
+ # from web
+ wget http://info.iet.unipi.it/~luigi/dummynet/ipfw_mod-latest.tgz
+ tar xvzf ipfw_mod-latest.tgz
+
+ # start the compilation
+ rm -rf SOURCES/ipfw*
+ rm -rf BUILD/ipfw-0.1/
+ rm -rf SRPMS/ipfw*
+ rm -rf RPMS/i386/ipfw*
+ make ipfw
+
+ 5. download and install sources into a node
+
+ 5.A Copy RPMS into the node and install it:
+ # exit from the root context
+ exit
+ scp /vserver/mybuild/build/RPMS/i386/ipfw-* root@node.iet.unipi.it:
+ ssh root@node.iet.unipi.it
+ rpm -e ipfw
+ rpm -ivh ./ipfw-0-9...TAB
+ modprobe ipfw_mod
+
+ # the ipfw package should be installed
+ ipfw show
------------------------------------------------------------------------------
+--- References
+[1] https://svn.planet-lab.org/wiki/VserverCentos
+[2] http://wiki.linux-vserver.org/Installation_on_CentOS
+[3] http://mirror.centos.org/centos/5/isos/
+[4] More information are in /build/README* files
obj-m := ipfw_mod.o
# generic cflags used on all systems
-#ipfw-cflags += -Dradix
+#ipfw-cflags += -DIPFW_HASHTABLES
ipfw-cflags += -DIPFIREWALL_DEFAULT_TO_ACCEPT -DTRACE
# _BSD_SOURCE enables __FAVOR_BSD (udp/tcp bsd structs instead of posix)
ipfw-cflags += -D_BSD_SOURCE
ifeq ($(VER),openwrt)
M=.
obj-y := ipfw2_mod.o bsd_compat.o \
- in_cksum.o ip_dummynet.o ip_fw2.o ip_fw_pfil.o
+ in_cksum.o ip_dummynet.o ip_fw2.o ip_fw_pfil.o radix.o
O_TARGET := ipfw_mod.o
# xcflags-y is a temporary variable where we store build options
# 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
+IPFW_SRCS += radix.c
# Module glue and functions missing in linux
-IPFW_SRCS += ipfw2_mod.c bsd_compat.c hashtable.c new_glue.c
+IPFW_SRCS += ipfw2_mod.c bsd_compat.c hashtable.c
# additional $(CC) flags
ccflags-y += $(WARN)
EDIRS= altq arpa machine net netinet netinet6 sys
-EFILES += opt_inet6.h opt_ipfw.h opt_ipsec.h
+EFILES += opt_inet6.h opt_ipfw.h opt_ipsec.h opt_mpath.h
EFILES += opt_mbuf_stress_test.h opt_param.h
EFILES += altq/if_altq.h
EFILES += netinet/ether.h netinet/icmp6.h netinet/if_ether.h
EFILES += netinet/in.h netinet/in_pcb.h netinet/in_var.h
-EFILES += netinet/ip_carp.h netinet/ip_var.h netinet/pim.h
+EFILES += netinet/ip_carp.h netinet/ip_var.h netinet/pim.h
EFILES += netinet/sctp.h netinet/tcp_timer.h netinet/tcpip.h
EFILES += netinet/udp_var.h
EFILES += netinet6/ip6_var.h
EFILES += sys/_lock.h sys/_rwlock.h sys/_mutex.h sys/jail.h
-EFILES += sys/condvar.h sys/eventhandler.h
+EFILES += sys/condvar.h sys/eventhandler.h sys/domain.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
-@(cd $(M)/include_e; mkdir -p $(EDIRS); touch $(EFILES) )
endif # !openwrt
+
+test_radix: test_radix.o radix.o
+test_radix: CFLAGS=-Wall -Werror -O1
};
/* Hash table */
-struct new_hash_table {
+struct ipfw_ht {
int table_size; /* Size of the table (buckets) */
int table_obj; /* number of object in the table */
int obj_size; /* size of object (key + value) */
/* Hash function for this table */
uint32_t (*hash)(const void *key, uint32_t size);
- int (*cmp)(const void *obj1, const void *obj2);
+ int (*cmp)(const void *obj1, const void *obj2, int sz);
int hash_arg; /* hash function parameter */
struct malloc_type *mtype;
struct new_obj **table_ptr; /* Pointer to the table */
*
* Return value: pointer to the hash table, NULL if error occurs
*/
-struct new_hash_table *
-new_table_init (int size, int obj_size,
+struct ipfw_ht *
+ipfw_ht_new(int size, int obj_size,
uint32_t (hf)(const void *, uint32_t size),
- int (compare)(const void *, const void *),
+ int (compare)(const void *, const void *, int),
struct malloc_type *mtype)
{
- struct new_hash_table *h;
+ struct ipfw_ht *h;
- printf("%s called\n", __FUNCTION__);
-
- h = malloc(sizeof(struct new_hash_table), mtype, M_NOWAIT | M_ZERO);
+ h = malloc(sizeof(*h), mtype, M_NOWAIT | M_ZERO);
if (h == NULL)
return NULL;
}
int
-new_table_insert_obj (struct new_hash_table *h, const void *obj)
+ipfw_ht_insert(struct ipfw_ht *h, const void *obj)
{
int i; /* array index */
struct new_obj *o, *ot;
/* same key not allowed */
for (ot = h->table_ptr[i]; ot; ot = ot->next) {
- if (h->cmp(obj, ot->obj) == 0)
+ if (h->cmp(obj, ot->obj, h->obj_size) == 0)
return 1; /* error */
}
/* allocate a single chunk of memory */
}
int
-new_table_delete_obj(struct new_hash_table *h, const void *obj)
+ipfw_ht_remove(struct ipfw_ht *h, const void *obj)
{
int i;
struct new_obj *obj1, *prev;
i = h->hash(obj, h->table_size);
for (prev = NULL, obj1 = h->table_ptr[i]; obj1; obj1 = obj1->next) {
- if (h->cmp(obj, (void *)obj1->obj) != 0)
+ if (h->cmp(obj, obj1->obj, h->obj_size) != 0)
continue;
/* Object found, delete */
if (prev != NULL)
}
const void *
-new_table_extract_obj(struct new_hash_table *h, const void *obj)
+ipfw_ht_extract(struct ipfw_ht *h, const void *obj)
{
struct new_obj *o;
int i;
i = h->hash(obj, h->table_size);
for (o = h->table_ptr[i]; o; o = o->next) {
- if (h->cmp(o->obj, obj) == 0)
+ if (h->cmp(o->obj, obj, h->obj_size) == 0)
return o->obj;
}
return NULL;
}
void *
-new_table_destroy(struct new_hash_table *h)
+ipfw_ht_destroy(struct ipfw_ht *h)
{
int i;
struct new_obj *cur, *next;
/* returns the number of elements in the table */
int
-new_table_get_element(const struct new_hash_table *h)
+ipfw_ht_count(const struct ipfw_ht *h)
{
return h ? h->table_obj : 0;
}
const void *
-table_next(struct new_hash_table *h, const void *o)
+table_next(struct ipfw_ht *h, const void *o)
{
int i;
struct new_obj *obj;
- printf("%s called\n", __FUNCTION__);
if (h == NULL || h->table_obj == 0)
return NULL;
if (o == NULL) {
*/
i = h->hash(o, h->table_size);
for (obj = h->table_ptr[i]; obj; obj = obj->next) {
- if (h->cmp(obj->obj, o) == 0)
+ if (h->cmp(obj->obj, o, h->obj_size) == 0)
break;
}
if (obj && obj->next != NULL)
* objects are the same (XXX we could spare this if we also
* pass a key_size and use a bcmp for comparisons)
* Not extensible at the moment.
- * max_el and max_ratio currently unused.
*/
struct malloc_type;
-struct new_hash_table * new_table_init (int size, int obj_size,
+struct ipfw_ht;
+struct ipfw_ht* ipfw_ht_new(int size, int obj_size,
uint32_t (hash_fn)(const void *, uint32_t size),
- int (cmp_fn)(const void*, const void*),
+ int (cmp_fn)(const void*, const void*, int sz),
struct malloc_type *mtype);
+void *ipfw_ht_destroy(struct ipfw_ht *h);
/* add a new object to the table, return success/failure */
-int new_table_insert_obj (struct new_hash_table *h, const void *obj);
+int ipfw_ht_insert(struct ipfw_ht *h, const void *obj);
/*
* returns a pointer to the matching object or NULL if not found.
* No refcounts.
*/
-const void *new_table_extract_obj(struct new_hash_table *h, const void *key);
+const void *ipfw_ht_extract(struct ipfw_ht *h, const void *key);
/* remove an object from the table */
-int new_table_delete_obj(struct new_hash_table *h, const void *key);
-void *new_table_destroy(struct new_hash_table *h);
+int ipfw_ht_remove(struct ipfw_ht *h, const void *key);
/* return the number of elements in the table */
-int new_table_get_element(const struct new_hash_table *h);
+int ipfw_ht_count(const struct ipfw_ht *h);
/* returns the first or next element. Works by hashing the
* current object and then finds the next one.
* If obj == NULL returns the first object in the table
*/
-const void *table_next(struct new_hash_table *h, const void *obj);
+const void *ipfw_ht_next(struct ipfw_ht *h, const void *obj);
#endif
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 */
#define RADIX_NODE_HEAD_WLOCK_ASSERT(rnh) rw_assert(&(rnh)->rnh_lock, RA_WLOCKED)
#endif /* _KERNEL */
-void rn_init(void);
+void rn_init(int);
int rn_inithead(void **, int);
int rn_refines(void *, void *);
struct radix_node
int avg ; /* average queue length est. (scaled) */
int count ; /* arrivals since last RED drop */
int random ; /* random value (scaled) */
- dn_key q_time; /* start of queue idle time */
+ dn_key idle_time; /* start of queue idle time */
/* WF2Q+ support */
struct dn_flow_set *fs ; /* parent flow set */
void ipfw_nat_destroy(void);
#endif
-#define IPFW_HAVE_SKIPTO_TABLE
-
-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)
struct ip_fw_chain {
struct ip_fw *rules; /* list of rules */
+ struct ip_fw *default_rule;
struct ip_fw *reap; /* list of rules to reap */
LIST_HEAD(, cfg_nat) nat; /* list of nat entries */
struct radix_node_head *tables[IPFW_TABLES_MAX];
struct rwlock rwmtx;
#endif /* !__linux__ */
uint32_t id; /* ruleset id */
- struct _rulepointer skipto_pointers[64*1024];
- struct new_hash_table *global_tables[128];
+ /*
+ * To optimize jumps, we use a table with skipto_entries pointers
+ * (a power of 2, set with a sysctl depending on available memory).
+ * Entry i points to the first rule i*64k/n <= n < (i+1)*64k/n.
+ * On insert/delete we simply update the relevant entry
+ * with O(1) additional cost. Updates to the sysctl variable
+ * that controls the table are managed at the next add/delete.
+ */
+ int skipto_shift; /* shifts to compute the index in skipto-ptrs */
+ int skipto_size; /* number of entries in the table */
+ struct ip_fw **skipto_ptrs;
+#ifdef IPFW_HASHTABLES
+ struct ipfw_ht *hashtab[IPFW_TABLES_MAX];
+#endif
};
#ifdef IPFW_INTERNAL
#include "missing.h"
-#include <sys/limits.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
static void dummynet_flush(void);
static void dummynet_send(struct mbuf *);
void dummynet_drain(void);
-static void dn_rule_delete(void *);
static int dummynet_io(struct mbuf **, int , struct ip_fw_args *);
+/*
+ * Flow queue is idle if:
+ * 1) it's empty for at least 1 tick
+ * 2) it has invalid timestamp (WF2Q case)
+ * 3) parent pipe has no 'exhausted' burst.
+ */
+#define QUEUE_IS_IDLE(q) ((q)->head == NULL && (q)->S == (q)->F + 1 && \
+ curr_time > (q)->idle_time + 1 && \
+ ((q)->numbytes + (curr_time - (q)->idle_time - 1) * \
+ (q)->fs->pipe->bandwidth >= (q)->fs->pipe->burst))
+
/*
* Heap management functions.
*
* --- end of heap management functions ---
*/
+/*
+ * Dispose a packet in dummynet. Use an inline functions so if we
+ * need to free extra state associated to a packet, this is a
+ * central point to do it.
+ */
+static __inline void *dn_free_pkt(struct mbuf *m)
+{
+#ifdef __linux__
+ netisr_dispatch(-1, m); /* -1 drop the packet */
+#else
+ m_freem(m);
+#endif
+ return NULL;
+}
+
+static __inline void dn_free_pkts(struct mbuf *mnext)
+{
+ struct mbuf *m;
+
+ while ((m = mnext) != NULL) {
+ mnext = m->m_nextpkt;
+ dn_free_pkt(m);
+ }
+}
+
/*
* Return the mbuf tag holding the dummynet state. As an optimization
* this is assumed to be the first tag on the list. If this turns out
* queue on error hoping next time we are luckier.
*/
} else /* RED needs to know when the queue becomes empty. */
- q->q_time = curr_time;
+ q->idle_time = curr_time;
/*
* If the delay line was empty call transmit_event() now.
break;
}
}
- if (sch->elements == 0 && neh->elements == 0 && p_numbytes >= 0 &&
- p->idle_heap.elements > 0) {
+ if (sch->elements == 0 && neh->elements == 0 && p_numbytes >= 0) {
+ p->idle_time = curr_time;
/*
* No traffic and no events scheduled.
* We can get rid of idle-heap.
*/
- int i;
+ if (p->idle_heap.elements > 0) {
+ int i;
- for (i = 0; i < p->idle_heap.elements; i++) {
- struct dn_flow_queue *q = p->idle_heap.p[i].object;
+ for (i = 0; i < p->idle_heap.elements; i++) {
+ struct dn_flow_queue *q;
- q->F = 0;
- q->S = q->F + 1;
+ q = p->idle_heap.p[i].object;
+ q->F = 0;
+ q->S = q->F + 1;
+ }
+ p->sum = 0;
+ p->V = 0;
+ p->idle_heap.elements = 0;
}
- p->sum = 0;
- p->V = 0;
- p->idle_heap.elements = 0;
}
/*
* If we are getting clocks from dummynet (not a real interface) and
case DN_TO_DROP:
/* drop the packet after some time */
-#ifdef __linux__
- netisr_dispatch(-1, m); /* -1 drop the packet */
-#else
- m_freem(m);
-#endif
+ dn_free_pkt(m);
break;
default:
printf("dummynet: bad switch %d!\n", pkt->dn_dir);
- m_freem(m);
+ dn_free_pkt(m);
break;
}
}
fs->last_expired = time_uptime ;
for (i = 0 ; i <= fs->rq_size ; i++) /* last one is overflow */
for (prev=NULL, q = fs->rq[i] ; q != NULL ; )
- if (q->head != NULL || q->S != q->F+1) {
+ if (!QUEUE_IS_IDLE(q)) {
prev = q ;
q = q->next ;
} else { /* entry is idle, expire it */
q->hash_slot = i;
q->next = fs->rq[i];
q->S = q->F + 1; /* hack - mark timestamp as invalid. */
- q->numbytes = io_fast ? fs->pipe->bandwidth : 0;
+ q->numbytes = fs->pipe->burst + (io_fast ? fs->pipe->bandwidth : 0);
fs->rq[i] = q;
fs->rq_elements++;
return (q);
break ; /* found */
/* No match. Check if we can expire the entry */
- if (pipe_expire && q->head == NULL && q->S == q->F+1 ) {
+ if (pipe_expire && QUEUE_IS_IDLE(q)) {
/* entry is idle and not in any heap, expire it */
struct dn_flow_queue *old_q = q ;
* XXX check wraps...
*/
if (q->avg) {
- u_int t = div64(curr_time - q->q_time,
+ u_int t = div64(curr_time - q->idle_time,
fs->lookup_step);
q->avg = (t < fs->lookup_depth) ?
if (q->head != m) /* Flow was not idle, we are done. */
goto done;
- if (q->q_time < (uint32_t)curr_time)
- q->numbytes = io_fast ? fs->pipe->bandwidth : 0;
- q->q_time = curr_time;
+ if (is_pipe) { /* Fixed rate queues. */
+ if (q->idle_time < curr_time) {
+ /* Calculate available burst size. */
+ q->numbytes +=
+ (curr_time - q->idle_time - 1) * pipe->bandwidth;
+ if (q->numbytes > pipe->burst)
+ q->numbytes = pipe->burst;
+ if (io_fast)
+ q->numbytes += pipe->bandwidth;
+ }
+ } else { /* WF2Q. */
+ if (pipe->idle_time < curr_time &&
+ pipe->scheduler_heap.elements == 0 &&
+ pipe->not_eligible_heap.elements == 0) {
+ /* Calculate available burst size. */
+ pipe->numbytes +=
+ (curr_time - pipe->idle_time - 1) * pipe->bandwidth;
+ if (pipe->numbytes > 0 && pipe->numbytes > pipe->burst)
+ pipe->numbytes = pipe->burst;
+ if (io_fast)
+ pipe->numbytes += pipe->bandwidth;
+ }
+ pipe->idle_time = curr_time;
+ }
+ /* Necessary for both: fixed rate & WF2Q queues. */
+ q->idle_time = curr_time;
/*
* If we reach this point the flow was previously idle, so we need
if (q)
q->drops++;
DUMMYNET_UNLOCK();
- /*
- * set the tag, if present. dn_tag_get cannot fail
- * so we need to check first
- */
- if (m_tag_first(m)) {
- pkt = dn_tag_get(m);
- pkt->dn_dir = DN_TO_DROP;
- }
- dummynet_send(m); /* drop the packet */
- *m0 = NULL;
+ *m0 = dn_free_pkt(m);
return ((fs && (fs->flags_fs & DN_NOERROR)) ? 0 : ENOBUFS);
}
-/*
- * Below, the rt_unref is only needed when (pkt->dn_dir == DN_TO_IP_OUT)
- * Doing this would probably save us the initial bzero of dn_pkt
- */
-#if defined( __linux__ )
-#define DN_FREE_PKT(_m) do { \
- netisr_dispatch(-1, _m); \
-} while (0)
-#else
-#define DN_FREE_PKT(_m) do { \
- m_freem(_m); \
-} while (0)
-#endif
-
/*
* Dispose all packets and flow_queues on a flow_set.
* If all=1, also remove red lookup table and other storage,
for (i = 0; i <= fs->rq_size; i++) {
for (q = fs->rq[i]; q != NULL; q = qn) {
- struct mbuf *m, *mnext;
-
- mnext = q->head;
- while ((m = mnext) != NULL) {
- mnext = m->m_nextpkt;
- DN_FREE_PKT(m);
- }
+ dn_free_pkts(q->head);
qn = q->next;
free(q, M_DUMMYNET);
}
static void
purge_pipe(struct dn_pipe *pipe)
{
- struct mbuf *m, *mnext;
purge_flow_set( &(pipe->fs), 1 );
- mnext = pipe->head;
- while ((m = mnext) != NULL) {
- mnext = m->m_nextpkt;
- DN_FREE_PKT(m);
- }
+ dn_free_pkts(pipe->head);
heap_free( &(pipe->scheduler_heap) );
heap_free( &(pipe->not_eligible_heap) );
DUMMYNET_UNLOCK();
}
-extern struct ip_fw *ip_fw_default_rule;
-static void
-dn_rule_delete_fs(struct dn_flow_set *fs, void *r)
-{
- int i ;
- struct dn_flow_queue *q ;
- struct mbuf *m ;
-
- for (i = 0 ; i <= fs->rq_size ; i++) /* last one is ovflow */
- for (q = fs->rq[i] ; q ; q = q->next )
- for (m = q->head ; m ; m = m->m_nextpkt ) {
- struct dn_pkt_tag *pkt = dn_tag_get(m) ;
- if (pkt->rule == r)
- pkt->rule = ip_fw_default_rule ;
- }
-}
-
-/*
- * When a firewall rule is deleted, scan all queues and remove the pointer
- * to the rule from matching packets, making them point to the default rule.
- * The pointer is used to reinject packets in case one_pass = 0.
- */
-void
-dn_rule_delete(void *r)
-{
- struct dn_pipe *pipe;
- struct dn_flow_set *fs;
- struct dn_pkt_tag *pkt;
- struct mbuf *m;
- int i;
-
- DUMMYNET_LOCK();
- /*
- * If the rule references a queue (dn_flow_set), then scan
- * the flow set, otherwise scan pipes. Should do either, but doing
- * both does not harm.
- */
- for (i = 0; i < HASHSIZE; i++)
- SLIST_FOREACH(fs, &flowsethash[i], next)
- dn_rule_delete_fs(fs, r);
-
- for (i = 0; i < HASHSIZE; i++)
- SLIST_FOREACH(pipe, &pipehash[i], next) {
- fs = &(pipe->fs);
- dn_rule_delete_fs(fs, r);
- for (m = pipe->head ; m ; m = m->m_nextpkt ) {
- pkt = dn_tag_get(m);
- if (pkt->rule == r)
- pkt->rule = ip_fw_default_rule;
- }
- }
- DUMMYNET_UNLOCK();
-}
-
/*
* setup RED parameters
*/
} else
/* Flush accumulated credit for all queues. */
for (i = 0; i <= pipe->fs.rq_size; i++)
- for (q = pipe->fs.rq[i]; q; q = q->next)
- q->numbytes = io_fast ? p->bandwidth : 0;
+ for (q = pipe->fs.rq[i]; q; q = q->next) {
+ q->numbytes = p->burst +
+ (io_fast ? p->bandwidth : 0);
+ }
pipe->bandwidth = p->bandwidth;
- pipe->numbytes = 0; /* just in case... */
+ pipe->burst = p->burst;
+ pipe->numbytes = pipe->burst + (io_fast ? pipe->bandwidth : 0);
bcopy(p->if_name, pipe->if_name, sizeof(p->if_name));
pipe->ifp = NULL; /* reset interface ptr */
pipe->delay = p->delay;
{
struct dn_flow_set *fs;
struct dn_pipe *pipe;
- struct mbuf *m, *mnext;
int i;
DUMMYNET_LOCK_ASSERT();
for (i = 0; i < HASHSIZE; i++) {
SLIST_FOREACH(pipe, &pipehash[i], next) {
purge_flow_set(&(pipe->fs), 0);
-
- mnext = pipe->head;
- while ((m = mnext) != NULL) {
- mnext = m->m_nextpkt;
- DN_FREE_PKT(m);
- }
+ dn_free_pkts(pipe->head);
pipe->head = pipe->tail = NULL;
}
}
ip_dn_ctl_ptr = ip_dn_ctl;
ip_dn_io_ptr = dummynet_io;
- ip_dn_ruledel_ptr = dn_rule_delete;
TASK_INIT(&dn_task, 0, dummynet_task, NULL);
dn_tq = taskqueue_create_fast("dummynet", M_NOWAIT,
{
ip_dn_ctl_ptr = NULL;
ip_dn_io_ptr = NULL;
- ip_dn_ruledel_ptr = NULL;
DUMMYNET_LOCK();
callout_stop(&dn_timeout);
#include <machine/in_cksum.h> /* XXX for in_cksum */
+#ifdef IPFW_HASHTABLES
+#include "hashtable.h"
+#endif
+
#ifdef MAC
#include <security/mac/mac_framework.h>
#endif
#endif
static uma_zone_t ipfw_dyn_rule_zone;
-struct ip_fw *ip_fw_default_rule;
-
-/*
- * Data structure to cache our ucred related
- * information. This structure only gets used if
- * the user specified UID/GID based constraints in
- * a firewall rule.
- */
-struct ip_fw_ugid {
- gid_t fw_groups[NGROUPS];
- int fw_ngroups;
- uid_t fw_uid;
- int fw_prid;
-};
-
/*
* list of rules for layer 3
*/
SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit,
CTLFLAG_RW, &VNET_NAME(verbose_limit), 0,
"Set upper limit of matches of ipfw rules logged");
+static unsigned int dummy_default_rule = IPFW_DEFAULT_RULE;
SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, default_rule, CTLFLAG_RD,
- NULL, IPFW_DEFAULT_RULE,
+ &dummy_default_rule, IPFW_DEFAULT_RULE,
"The default/max possible rule number.");
+static unsigned int dummy_tables_max = IPFW_TABLES_MAX;
SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, tables_max, CTLFLAG_RD,
- NULL, IPFW_TABLES_MAX,
+ &dummy_tables_max, IPFW_TABLES_MAX,
"The maximum number of tables.");
+static unsigned int skipto_entries = 256;
+SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, skipto_entries,
+ CTLFLAG_RW, &skipto_entries, 0,
+ "Number of entries in the skipto cache");
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN,
&default_to_accept, 0,
"Make the default rule accept all packets.");
#endif /* SYSCTL_NODE */
-#ifndef IPFW_NEWTABLES_MAX
-#define IPFW_NEWTABLES_MAX 256
-#endif
/*
* Description of dynamic rules.
*
args->m = NULL;
}
+static void
+set_skipto_table(struct ip_fw_chain *ch)
+{
+ int i, n, sh;
+ struct ip_fw *f, **t, **oldt;
+
+ for (sh = 15; sh > 0; sh--)
+ if (skipto_entries > 1<<sh)
+ break;
+ sh++;
+ skipto_entries = 1<< (16 - sh) ;
+ /* XXX unsafe and too long */
+ t = malloc(skipto_entries * sizeof(*t), M_IPFW_TBL, M_WAITOK | M_ZERO);
+ if (t == NULL)
+ return;
+ IPFW_RLOCK(ch);
+ /* Store pointers in the table. In the loop i is the next
+ * free slot, n is the slot where the current rule goes.
+ */
+ for (i = 0, f = ch->rules; f; f = f->next) {
+ n = f->rulenum >> sh ;
+ while (i <= n)
+ t[i++] = f;
+ }
+ V_layer3_chain.skipto_shift = sh;
+ V_layer3_chain.skipto_size = skipto_entries;
+ oldt = V_layer3_chain.skipto_ptrs;
+ V_layer3_chain.skipto_ptrs = t;
+ IPFW_RUNLOCK(ch);
+ if (oldt) {
+ IPFW_WLOCK(ch);
+ IPFW_WUNLOCK(ch);
+ /* now can free oldt */
+ free(oldt, M_IPFW_TBL);
+ }
+}
+#if 0
+/*
+ * Map a rule number to a rule pointer, using the skipto table.
+ * First lookup the slot, then follow the chain until we find a
+ * non-null entry with rulenum >= num. Return default_rule on error.
+ */
+static struct ip_fw *
+rule2ptr(struct ip_fw_chain *ch, int num)
+{
+ struct ip_fw *r = NULL;
+ int ix = (num & 0xffff) >> ch->skipto_shift;
+
+ while (ix < ch->skipto_size && (r = ch->skipto_ptrs[ix]) == NULL)
+ ix++;
+ while (r && num < r->rulenum)
+ r = r->next;
+ return (r ? r : ch->default_rule);
+}
+#endif
/**
*
* Given an ip_fw *, lookup_next_rule will return a pointer
*/
static struct ip_fw *
-lookup_next_rule(struct ip_fw *me, u_int32_t tablearg)
+lookup_next_rule(struct ip_fw_chain *ch, struct ip_fw *me, uint32_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)
cmd += F_LEN(cmd);
if (cmd->opcode == O_TAG)
cmd += F_LEN(cmd);
- if (cmd->opcode == O_SKIPTO ) {
- if (tablearg != 0) {
- rulenum = (u_int16_t)tablearg;
- } else {
- rulenum = cmd->arg1;
- }
+ if (cmd->opcode != O_SKIPTO ) {
+ rule = me->next;
+ } else {
+ tablearg = tablearg ? tablearg : cmd->arg1;
for (rule = me->next; rule ; rule = rule->next) {
- if (rule->rulenum >= rulenum) {
+ if (rule->rulenum >= tablearg) {
break;
}
}
- }
- if (rule == NULL) /* failure or not a skipto */
- rule = me->next;
- me->next_rule = rule;
- 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;
+// rule = rule2ptr(ch, tablearg ? tablearg : cmd->arg1);
}
- 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;
+ me->next_rule = rule; /* XXX perhaps unnecessary ? */
+ return rule;
}
-#endif /* IPFW_HAVE_SKIPTO_TABLE */
-#ifdef radix
static int
add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
uint8_t mlen, uint32_t value)
struct table_entry *ent;
struct radix_node *rn;
+#ifdef IPFW_HASHTABLES
+ if (tbl >= 2*IPFW_TABLES_MAX)
+ return EINVAL;
+ return EINVAL; // XXX to be completed
+#endif
if (tbl >= IPFW_TABLES_MAX)
return (EINVAL);
rnh = ch->tables[tbl];
if (ent == NULL)
return (ENOMEM);
ent->value = value;
+#ifdef linux
+ /* there is no sin_len on linux, and the code assumes the first
+ * byte in the sockaddr to contain the length in bits.
+ * So we just dump the number right there
+ */
+ *((uint8_t *)&(ent->addr)) = 8;
+ *((uint8_t *)&(ent->mask)) = 8;
+#else
ent->addr.sin_len = ent->mask.sin_len = 8;
+#endif
ent->mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr;
IPFW_WLOCK(ch);
struct table_entry *ent;
struct sockaddr_in sa, mask;
+#ifdef IPFW_HASHTABLES
+ if (tbl >= 2*IPFW_TABLES_MAX)
+ return EINVAL;
+ return EINVAL; // XXX to be completed
+#endif
if (tbl >= IPFW_TABLES_MAX)
return (EINVAL);
rnh = ch->tables[tbl];
+#ifdef linux
+ /* there is no sin_len on linux, see above */
+ *((uint8_t *)&sa) = 8;
+ *((uint8_t *)&mask) = 8;
+#else
sa.sin_len = mask.sin_len = 8;
+#endif
mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr;
IPFW_WLOCK(ch);
IPFW_WLOCK_ASSERT(ch);
+#ifdef IPFW_HASHTABLES
+ if (tbl >= 2*IPFW_TABLES_MAX)
+ return EINVAL;
+ return EINVAL; // XXX to be completed
+#endif
if (tbl >= IPFW_TABLES_MAX)
return (EINVAL);
rnh = ch->tables[tbl];
rnh->rnh_walktree(rnh, flush_table_entry, rnh);
return (0);
}
-#else
-extern int add_table_entry(struct ip_fw_chain *ch, uint16_t tbl,
- in_addr_t addr, uint8_t mlen, uint32_t value);
-extern int del_table_entry(struct ip_fw_chain *ch, uint16_t tbl,
- in_addr_t addr, uint8_t mlen);
-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
flush_tables(struct ip_fw_chain *ch)
IPFW_WLOCK_ASSERT(ch);
- for (tbl = IPFW_TABLES_MAX -1; tbl < IPFW_NEWTABLES_MAX; tbl++)
+ for (tbl = 0; tbl < IPFW_TABLES_MAX; tbl++)
flush_table(ch, tbl);
+#ifdef IPFW_HASHTABLES
+ for (tbl = 0; tbl < IPFW_TABLES_MAX; tbl++)
+ ch->hashtab[tbl] = ipfw_ht_destroy(ch->hashtab[tbl]);
+#endif
}
-#ifdef radix
static int
init_tables(struct ip_fw_chain *ch)
{
return (ENOMEM);
}
}
+#ifdef IPFW_HASHTABLES
+ for (i = 0; i < IPFW_TABLES_MAX; i++)
+ ch->hashtab[i] = ipfw_ht_destroy(ch->hashtab[i]);
+#endif
return (0);
}
if (tbl >= IPFW_TABLES_MAX)
return (0);
rnh = ch->tables[tbl];
+#ifdef linux
+ /* there is no sin_len on linux, see above */
+ *((uint8_t *)&sa) = 8;
+#else
sa.sin_len = 8;
+#endif
sa.sin_addr.s_addr = addr;
ent = (struct table_entry *)(rnh->rnh_lookup(&sa, NULL, rnh));
if (ent != NULL) {
}
return (0);
}
-#endif
-#ifdef radix
static int
count_table_entry(struct radix_node *rn, void *arg)
{
rnh->rnh_walktree(rnh, dump_table_entry, tbl);
return (0);
}
-#endif
-
-#ifndef linux /* FreeBSD */
-static void
-fill_ugid_cache(struct inpcb *inp, struct ip_fw_ugid *ugp)
-{
- struct ucred *cr;
-
- cr = inp->inp_cred;
- ugp->fw_prid = jailed(cr) ? cr->cr_prison->pr_id : -1;
- ugp->fw_uid = cr->cr_uid;
- ugp->fw_ngroups = cr->cr_ngroups;
- bcopy(cr->cr_groups, ugp->fw_groups, sizeof(ugp->fw_groups));
-}
-#endif
static int
check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip,
- u_int16_t src_port, struct ip_fw_ugid *ugp, int *ugid_lookupp,
+ u_int16_t src_port, struct ucred **uc, int *ugid_lookup,
struct inpcb *inp)
{
#ifdef linux
int match = 0;
struct sk_buff *skb = ((struct mbuf *)inp)->m_skb;
+ struct bsd_ucred *u = (struct bsd_ucred *)uc;
- if (*ugid_lookupp == 0) { /* actively lookup and copy in cache */
-
+ if (*ugid_lookup == 0) { /* actively lookup and copy in cache */
/* returns null if any element of the chain up to file is null.
* if sk != NULL then we also have a reference
*/
- *ugid_lookupp = linux_lookup(proto,
+ *ugid_lookup = linux_lookup(proto,
src_ip.s_addr, htons(src_port),
dst_ip.s_addr, htons(dst_port),
- skb, oif ? 1 : 0, ugp);
+ skb, oif ? 1 : 0, u);
}
- if (*ugid_lookupp < 0)
+ if (*ugid_lookup < 0)
return 0;
if (insn->o.opcode == O_UID)
- match = (ugp->fw_uid == (uid_t)insn->d[0]);
+ match = (u->uid == (uid_t)insn->d[0]);
else if (insn->o.opcode == O_JAIL)
- match = (ugp->fw_groups[1] == (uid_t)insn->d[0]);
+ match = (u->xid == (uid_t)insn->d[0]);
else if (insn->o.opcode == O_GID)
- match = (ugp->fw_groups[0] == (uid_t)insn->d[0]);
+ match = (u->gid == (uid_t)insn->d[0]);
return match;
int wildcard;
struct inpcb *pcb;
int match;
- gid_t *gp;
/*
* Check to see if the UDP or TCP stack supplied us with
if (inp && *ugid_lookupp == 0) {
INP_LOCK_ASSERT(inp);
if (inp->inp_socket != NULL) {
- fill_ugid_cache(inp, ugp);
+ *uc = crhold(inp->inp_cred);
*ugid_lookupp = 1;
} else
*ugid_lookupp = -1;
dst_ip, htons(dst_port),
wildcard, NULL);
if (pcb != NULL) {
- fill_ugid_cache(pcb, ugp);
+ *uc = crhold(pcb->inp_cred);
*ugid_lookupp = 1;
}
INP_INFO_RUNLOCK(pi);
}
}
if (insn->o.opcode == O_UID)
- match = (ugp->fw_uid == (uid_t)insn->d[0]);
- else if (insn->o.opcode == O_GID) {
- for (gp = ugp->fw_groups;
- gp < &ugp->fw_groups[ugp->fw_ngroups]; gp++)
- if (*gp == (gid_t)insn->d[0]) {
- match = 1;
- break;
- }
- } else if (insn->o.opcode == O_JAIL)
- match = (ugp->fw_prid == (int)insn->d[0]);
+ match = ((*uc)->cr_uid == (uid_t)insn->d[0]);
+ else if (insn->o.opcode == O_GID)
+ match = groupmember((gid_t)insn->d[0], *uc);
+ else if (insn->o.opcode == O_JAIL)
+ match = ((*uc)->cr_prison->pr_id == (int)insn->d[0]);
return match;
#endif
}
* these types of constraints, as well as decrease contention
* on pcb related locks.
*/
- struct ip_fw_ugid fw_ugid_cache;
- int ugid_lookup = 0;
+ struct bsd_ucred ucred_cache;
+ int ucred_lookup = 0;
/*
* divinput_flags If non-zero, set to the IP_FW_DIVERT_*_FLAG
IPFW_RUNLOCK(chain);
return (IP_FW_PASS);
}
+ if (chain->id != args->chain_id) {
+ for (f = chain->rules; f != NULL; f = f->next)
+ if (f == args->rule && f->id == args->rule_id)
+ break;
- f = args->rule->next_rule;
+ if (f != NULL)
+ f = f->next_rule;
+ else
+ f = chain->default_rule;
+ } else
+ f = args->rule->next_rule;
if (f == NULL)
- f = lookup_next_rule(args->rule, 0);
+ f = lookup_next_rule(chain, args->rule, 0);
} else {
/*
* Find the starting rule. It can be either the first
IPFW_RUNLOCK(chain);
return (IP_FW_DENY); /* invalid */
}
+// f = rule2ptr(chain, skipto+1);
while (f && f->rulenum <= skipto)
f = f->next;
- if (f == NULL) { /* drop packet */
- IPFW_RUNLOCK(chain);
- return (IP_FW_DENY);
- }
}
}
/* reset divert rule to avoid confusion later */
(ipfw_insn_u32 *)cmd,
proto, oif,
dst_ip, dst_port,
- src_ip, src_port, &fw_ugid_cache,
- &ugid_lookup, (struct inpcb *)args->m);
+ src_ip, src_port, (struct ucred **)&ucred_cache,
+ &ucred_lookup, (struct inpcb *)args->m);
break;
case O_RECV:
(ipfw_insn_u32 *)cmd,
proto, oif,
dst_ip, dst_port,
- src_ip, src_port, &fw_ugid_cache,
- &ugid_lookup, (struct inpcb *)args->m);
+ src_ip, src_port, (struct ucred **)&ucred_cache,
+ &ucred_lookup, (struct inpcb *)args->m);
+#ifdef linux
+ if (v ==4 /* O_UID */)
+ a = ucred_cache.uid;
+ else if (v == 5 /* O_GID */)
+ a = ucred_cache.gid;
+ else if (v == 6 /* O_JAIL */)
+ a = ucred_cache.xid;
+#else
if (v ==4 /* O_UID */)
- a = fw_ugid_cache.fw_uid;
+ a = (*uc)->cr_uid;
else if (v == 5 /* O_GID */)
- a = fw_ugid_cache.fw_groups[0];
+ ; // a = groupmember((gid_t)insn->d[0], *uc);
else if (v == 6 /* O_JAIL */)
- a = fw_ugid_cache.fw_groups[1];
+ a = (*uc)->cr_prison->pr_id;
+#endif
} else
break;
}
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);
+ f = lookup_next_rule(chain, f, tablearg);
} else {
if (f->next_rule == NULL)
- lookup_next_rule(f, 0);
+ lookup_next_rule(chain, f, 0);
f = f->next_rule;
}
-#endif
/*
* Skip disabled rules, and
* re-enter the inner loop
printf("ipfw: ouch!, skip past end of rules, denying packet\n");
}
IPFW_RUNLOCK(chain);
+#ifdef __FreeBSD__
+ if (ucred_cache != NULL)
+ crfree(ucred_cache);
+#endif
return (retval);
pullup_failed:
goto done;
}
- /*
- * If rulenum is 0, find highest numbered rule before the
- * default rule, and add autoinc_step
- */
if (V_autoinc_step < 1)
V_autoinc_step = 1;
else if (V_autoinc_step > 1000)
V_autoinc_step = 1000;
if (rule->rulenum == 0) {
/*
- * locate the highest numbered rule before default
+ * If rulenum is 0, use highest numbered rule before
+ * the default, adding autoinc_step if room.
+ * Also set the number in the caller.
*/
for (f = chain->rules; f; f = f->next) {
if (f->rulenum == IPFW_DEFAULT_RULE)
/*
* Now insert the new rule in the right place in the sorted list.
+ * XXX TODO also put in the skipto table.
*/
for (prev = NULL, f = chain->rules; f; prev = f, f = f->next) {
if (f->rulenum > rule->rulenum) { /* found the location */
prev->next = n;
V_static_count--;
V_static_len -= l;
+ // XXX remove from the skipto table
rule->next = chain->reap;
chain->reap = rule;
}
/*
- * Hook for cleaning up dummynet when an ipfw rule is deleted.
- * Set/cleared when dummynet module is loaded/unloaded.
- */
-void (*ip_dn_ruledel_ptr)(void *) = NULL;
-
-/**
* Reclaim storage associated with a list of rules. This is
* typically the list created using remove_rule.
* A NULL pointer on input is handled correctly.
while ((rule = head) != NULL) {
head = head->next;
- if (ip_dn_ruledel_ptr)
- ip_dn_ruledel_ptr(rule);
free(rule, M_IPFW);
}
}
IPFW_WLOCK_ASSERT(chain);
+ chain->reap = NULL;
flush_rule_ptrs(chain); /* more efficient to do outside the loop */
for (prev = NULL, rule = chain->rules; rule ; )
if (kill_default || rule->set != RESVD_SET)
* avoid a LOR with dummynet.
*/
rule = chain->reap;
- chain->reap = NULL;
IPFW_WUNLOCK(chain);
- if (rule)
- reap_rules(rule);
+ reap_rules(rule);
return 0;
}
int i;
time_t boot_seconds;
- boot_seconds = boottime.tv_sec;
+ boot_seconds = boottime.tv_sec;
/* XXX this can take a long time and locking will block packet flow */
IPFW_RLOCK(chain);
for (rule = chain->rules; rule ; rule = rule->next) {
if (last != NULL) /* mark last dynamic rule */
bzero(&last->next, sizeof(last));
}
-
return (bp - (char *)buf);
}
*/
IPFW_WLOCK(&V_layer3_chain);
- V_layer3_chain.reap = NULL;
free_chain(&V_layer3_chain, 0 /* keep default rule */);
rule = V_layer3_chain.reap;
- V_layer3_chain.reap = NULL;
IPFW_WUNLOCK(&V_layer3_chain);
- if (rule != NULL)
- reap_rules(rule);
+ reap_rules(rule);
break;
case IP_FW_ADD:
#undef RULE_MAXSIZE
}
-/**
- * dummynet needs a reference to the default rule, because rules can be
- * deleted while packets hold a reference to them. When this happens,
- * dummynet changes the reference to the default rule (it could well be a
- * 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;
/*
* This procedure is only used to handle keepalives. It is invoked
#endif
done:
callout_reset(&V_ipfw_timeout, V_dyn_keepalive_period*hz,
- ipfw_tick, NULL);
+ ipfw_tick, vnetx);
CURVNET_RESTORE();
}
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
IPFW_LOCK_INIT(&V_layer3_chain);
callout_init(&V_ipfw_timeout, CALLOUT_MPSAFE);
+ set_skipto_table(&V_layer3_chain);
+
bzero(&default_rule, sizeof default_rule);
default_rule.act_ofs = 0;
default_rule.rulenum = IPFW_DEFAULT_RULE;
return (error);
}
- ip_fw_default_rule = V_layer3_chain.rules;
+ V_layer3_chain.default_rule = V_layer3_chain.rules;
/* curvnet is NULL in the !VIMAGE case */
callout_reset(&V_ipfw_timeout, hz, ipfw_tick, curvnet);
args.m = *m0;
args.inp = inp;
- ipfw = ipfw_chk(&args);
- *m0 = args.m;
tee = 0;
+ if (V_fw_one_pass == 0 || args.rule == NULL) {
+ ipfw = ipfw_chk(&args);
+ *m0 = args.m;
+ } else
+ ipfw = IP_FW_PASS;
+
KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
__func__));
args.m = *m0;
args.oif = ifp;
args.inp = inp;
- ipfw = ipfw_chk(&args);
- *m0 = args.m;
tee = 0;
+ if (V_fw_one_pass == 0 || args.rule == NULL) {
+ ipfw = ipfw_chk(&args);
+ *m0 = args.m;
+ } else
+ ipfw = IP_FW_PASS;
+
KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
__func__));
int
ipfw_chg_hook(SYSCTL_HANDLER_ARGS)
{
- int enable = *(int *)arg1;
+ int enable;
+ int oldenable;
int error;
+ if (arg1 == &VNET_NAME(fw_enable)) {
+ enable = V_fw_enable;
+ }
+#ifdef INET6
+ else if (arg1 == &VNET_NAME(fw6_enable)) {
+ enable = V_fw6_enable;
+ }
+#endif
+ else
+ return (EINVAL);
+
+ oldenable = enable;
+
error = sysctl_handle_int(oidp, &enable, 0, req);
+
if (error)
return (error);
enable = (enable) ? 1 : 0;
- if (enable == *(int *)arg1)
+ if (enable == oldenable)
return (0);
- if (arg1 == &fw_enable) {
+ if (arg1 == &VNET_NAME(fw_enable)) {
if (enable)
error = ipfw_hook();
else
error = ipfw_unhook();
+ if (error)
+ return (error);
+ V_fw_enable = enable;
}
#ifdef INET6
- if (arg1 == &fw6_enable) {
+ else if (arg1 == &VNET_NAME(fw6_enable)) {
if (enable)
error = ipfw6_hook();
else
error = ipfw6_unhook();
+ if (error)
+ return (error);
+ V_fw6_enable = enable;
}
#endif
- if (error)
- return (error);
-
- *(int *)arg1 = enable;
-
return (0);
}
#include <netinet/ip_fw.h> /* ip_fw_ctl_t, ip_fw_chk_t */
#include <netinet/ip_dummynet.h> /* ip_dn_ctl_t, ip_dn_io_t */
#include <net/pfil.h> /* PFIL_IN, PFIL_OUT */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#warning --- inet_hashtables not present on 2.4
+#include <linux/tcp.h>
+#include <net/route.h>
+#include <net/sock.h>
+static inline int inet_iif(const struct sk_buff *skb)
+{
+ return ((struct rtable *)skb->dst)->rt_iif;
+}
+
+#else
#include <net/inet_hashtables.h> /* inet_lookup */
+#endif
#include <net/route.h> /* inet_iif */
/*
static unsigned int mod_idx;
static struct mod_args mods[10]; /* hard limit to 10 modules */
-/*
- * Data structure to cache our ucred related
- * information. This structure only gets used if
- * the user specified UID/GID based constraints in
- * a firewall rule.
- */
-struct ip_fw_ugid {
- gid_t fw_groups[NGROUPS];
- int fw_ngroups;
- uid_t fw_uid;
- int fw_prid;
-};
-
/*
* my_mod_register should be called automatically as the init
* functions in the submodules. Unfortunately this compiler/linker
int
linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
const __be32 daddr, const __be16 dport,
- struct sk_buff *skb, int dir, struct ip_fw_ugid *ugp)
+ struct sk_buff *skb, int dir, struct bsd_ucred *u)
{
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0)
+ return -1;
+#else
struct sock *sk;
int ret = -1; /* default return value */
int st = -1; /* state */
+
if (proto != IPPROTO_TCP) /* XXX extend for UDP */
return -1;
ret = 1; /* retrying won't make things better */
st = sk->sk_state;
#ifdef CONFIG_VSERVER
- ugp->fw_groups[1] = sk->sk_xid;
- ugp->fw_groups[2] = sk->sk_nid;
+ u->xid = sk->sk_xid;
+ u->nid = sk->sk_nid;
#else
- ugp->fw_groups[1] = ugp->fw_groups[2] = 0;
+ u->xid = u->nid = 0;
#endif
/*
* Exclude tcp states where sk points to a inet_timewait_sock which
#define _CURR_GID f_cred->fsgid
#endif
-#ifdef CONFIG_VSERVER
- ugp->fw_groups[1] = sk->sk_xid;
- ugp->fw_groups[2] = sk->sk_nid;
-#else
- ugp->fw_groups[1] =
- ugp->fw_groups[2] = 0;
-#endif
- ret = 1;
-
#define GOOD_STATES ( \
(1<<TCP_LISTEN) | (1<<TCP_SYN_RECV) | (1<<TCP_SYN_SENT) | \
(1<<TCP_ESTABLISHED) | (1<<TCP_FIN_WAIT1) | (1<<TCP_FIN_WAIT2) )
if ((1<<st) & GOOD_STATES) {
read_lock_bh(&sk->sk_callback_lock);
- if (sk->sk_socket && sk->sk_socket->file) {
- ugp->fw_uid = sk->sk_socket->file->_CURR_UID;
- ugp->fw_groups[0] = sk->sk_socket->file->_CURR_GID;
- }
+ if (sk->sk_socket && sk->sk_socket->file) {
+ u->uid = sk->sk_socket->file->_CURR_UID;
+ u->gid = sk->sk_socket->file->_CURR_GID;
+ }
read_unlock_bh(&sk->sk_callback_lock);
} else {
- ugp->fw_uid = ugp->fw_groups[0] = 0;
+ u->uid = u->gid = 0;
}
if (!skb->sk) /* return the reference that came from the lookup */
sock_put(sk);
#undef _CURR_UID
#undef _CURR_GID
return ret;
+
+#endif /* LINUX > 2.4 */
}
/*
extern moduledata_t *moddesc_ipfw;
extern moduledata_t *moddesc_dummynet;
+extern void rn_init(void);
/*
* Module glue - init and exit function.
*/
printf("%s in-hook %d svn id %s\n", __FUNCTION__, IPFW_HOOK_IN, "$Id$");
+ rn_init();
+
my_mod_register(moddesc_ipfw, "ipfw", 1);
my_mod_register(moddesc_dummynet, "dummynet", 2);
init_children();
#define rw_runlock(_l) spin_unlock_bh(_l)
#define rw_wlock(_l) spin_lock_bh(_l)
#define rw_wunlock(_l) spin_unlock_bh(_l)
+#define rw_init_flags(_l, s, v)
#define mtx_assert(a, b)
#define mtx_destroy(m)
/* defined in session.c */
int priv_check(struct thread *td, int priv);
+/* struct ucred is in linux/socket.h and has pid, uid, gid.
+ * We need a 'bsd_ucred' to store also the extra info
+ */
+
+struct bsd_ucred {
+ uid_t uid;
+ gid_t gid;
+ uint32_t xid;
+ uint32_t nid;
+};
+
int securelevel_ge(struct ucred *cr, int level);
struct sysctl_oid;
#ifdef _WIN32
#define module_param_named(_name, _var, _ty, _perm)
#else
+
+/* Linux 2.4 is mostly for openwrt */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#include <linux/bitops.h> /* generic_ffs() used in ip_fw2.c */
+typedef uint32_t __be32;
+typedef uint16_t __be16;
+struct sock;
+struct net;
+struct inet_hashinfo;
+struct sock *inet_lookup(
+ struct inet_hashinfo *hashinfo,
+ const __be32 saddr, const __be16 sport,
+ const __be32 daddr, const __be16 dport,
+ const int dif);
+static int inet_iif(const struct sk_buff *skb);
+struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif);
+#endif /* Linux < 2.6 */
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
#define module_param_named(_name, _var, _ty, _perm) \
//module_param(_name, _ty, 0644)
_SYSCTL_BASE(_name, _var, ulong, _mode)
#define SYSCTL_UINT(_base, _oid, _name, _mode, _var, _val, _desc) \
- // _SYSCTL_BASE(_name, _var, uint, _mode)
+ _SYSCTL_BASE(_name, _var, uint, _mode)
#define SYSCTL_HANDLER_ARGS \
struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req
#define INP_LOCK_ASSERT(a)
#endif
-int rn_inithead(void **head, int off);
-
int jailed(struct ucred *cred);
/*
int fnmatch(const char *pattern, const char *string, int flags);
-struct ip_fw_ugid;
int
linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
const __be32 daddr, const __be16 dport,
- struct sk_buff *skb, int dir, struct ip_fw_ugid *ugp);
+ struct sk_buff *skb, int dir, struct bsd_ucred *u);
/* vnet wrappers, in vnet.h and ip_var.h */
int ipfw_init(void);
simple_hash32(const void *key, uint32_t size)
{
uint32_t ret = *(const uint32_t *)key % size;
- printf("%s called\n", __FUNCTION__);
- printf("Hash returns %d\n", ret);
return ret;
}
static int
-cmp_func32(const void *key1, const void *key2)
+cmp_func32(const void *key1, const void *key2, int sz)
{
int k1 = *(const int *)key1;
int k2 = *(const int *)key2;
int ret;
- printf("(%s) k1=%d, k2=%d\n", __FUNCTION__, k1, k2);
+
if (k1 < k2)
ret = -1;
else if (k1 > k2)
else
ret = 0;
- printf("compare returns %d\n", ret);
-
return ret;
}
int size = 128;
int obj_size = sizeof(struct t_o);
- printf("%s called\n", __FUNCTION__);
if (i < 0 || i > size-1) /* wrong table number */
return 1;
if (ch->global_tables[i] == NULL) {
- printf("Creating table n %d\n", tbl);
ch->global_tables[i] = new_table_init(size, obj_size,
simple_hash32, cmp_func32, M_IPFW_HTBL);
}
int ret;
int nr = tbl - IPFW_TABLES_MAX;
- printf("%s called\n", __FUNCTION__);
-
ret = new_table_delete_obj(ch->global_tables[nr], &addr);
return ret;
del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
uint8_t mlen)
{
- printf("%s called\n", __FUNCTION__);
if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX) {
new_del_table_entry(ch, tbl, addr);
return 0;
int
new_flush_table(struct ip_fw_chain *ch, uint16_t tbl)
{
- printf("%s called\n", __FUNCTION__);
new_table_destroy(ch->global_tables[tbl - IPFW_TABLES_MAX]);
return 0;
}
int
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(ch, tbl);
lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
uint32_t *val)
{
- printf("%s called\n", __FUNCTION__);
if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX) {
struct new_hash_table *h;
const struct t_o *obj;
h = ch->global_tables[tbl - IPFW_TABLES_MAX];
- printf("Search %d in table number %d\n", addr, tbl);
obj = new_table_extract_obj(h, (void *)&addr);
if (obj == NULL)
return 0; /* no match */
*val = obj->value;
- printf("obj->addr=%d,obj->value=%d\n",obj->addr, obj->value);
return 1; /* match */
}
return 0;
int
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(ch->global_tables[tbl - IPFW_TABLES_MAX]);
return 0;
}
int
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(ch, tbl, cnt);
return (0);
int nr = tbl->tbl - IPFW_TABLES_MAX;
struct new_hash_table *t = ch->global_tables[nr];
- printf("%s called\n", __FUNCTION__);
-
i = 0;
tbl->cnt = 0;
obj = table_next(t, obj);
if (obj == NULL)
break;
- printf("Found \n");
ent = &tbl->ent[tbl->cnt];
ent->addr = obj->addr;
ent->masklen = obj->mask;
tbl->cnt++;
}
- printf("\n");
return 0;
}
int
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(ch, tbl);
return (0);
{
int i;
- printf("%s called\n", __FUNCTION__);
/* Initialize new tables XXXMPD */
for (i = 0; i < IPFW_NEWTABLES_MAX - IPFW_TABLES_MAX; i++) {
memset(&ch->global_tables[i], sizeof(struct new_hash_table*), 0);
* SUCH DAMAGE.
*
* @(#)radix.c 8.5 (Berkeley) 5/19/95
- * $FreeBSD: head/sys/net/radix.c 186176 2008-12-16 11:01:36Z kmacy $
+ * $FreeBSD: head/sys/net/radix.c 200354 2009-12-10 10:34:30Z luigi $
*/
-#include "missing.h"
/*
* Routines to build and maintain radix trees for routing lookups.
*/
-#ifndef _RADIX_H_
#include <sys/param.h>
#ifdef _KERNEL
+#include <sys/cdefs.h>
+#include "missing.h"
#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"
-
+#include "opt_mpath.h"
#ifdef RADIX_MPATH
#include <net/radix_mpath.h>
#endif
-
+#else /* !_KERNEL */
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#define log(x, arg...) fprintf(stderr, ## arg)
+#define panic(x) fprintf(stderr, "PANIC: %s", x), exit(1)
+#define min(a, b) ((a) < (b) ? (a) : (b) )
+#include "include/net/radix.h"
+#endif /* !_KERNEL */
static int rn_walktree_from(struct radix_node_head *h, void *a, void *m,
walktree_f_t *f, void *w);
/*
* 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.
+ * rn_zeros, rn_ones are set in rn_init and used in readonly afterwards.
+ * addmask_key is used in rn_addmask in rw mode and not thread-safe.
*/
static char *rn_zeros, *rn_ones, *addmask_key;
* 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.
+ * We cast the result to int as this is the dominant usage.
*/
-#define LEN(x) (*(const u_char *)(x))
+#define LEN(x) ( (int) (*(const u_char *)(x)) )
/*
* XXX THIS NEEDS TO BE FIXED
{
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 longer = LEN(n++) - LEN(m++);
int masks_are_equal = 1;
if (longer > 0)
char *cplim;
int length = min(LEN(cp), LEN(cp2));
- if (cp3 == 0)
+ if (cp3 == NULL)
cp3 = rn_ones;
else
- length = min(length, (int)(*(u_char *)cp3));
+ length = min(length, LEN(cp3));
cplim = cp + length; cp3 += skip; cp2 += skip;
for (cp += skip; cp < cplim; cp++, cp2++, cp3++)
if ((*cp ^ *cp2) & *cp3)
{
caddr_t v = v_arg;
struct radix_node *top = head->rnh_treetop;
- int head_off = top->rn_offset, vlen = (int)LEN(v);
+ int head_off = top->rn_offset, vlen = LEN(v);
register struct radix_node *t = rn_search(v_arg, top);
register caddr_t cp = v + head_off;
register int b;
}
void
-rn_init()
+rn_init(int maxk)
{
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
+ max_keylen = maxk;
if (max_keylen == 0) {
log(LOG_ERR,
"rn_init: radix functions require max_keylen be set\n");
--- /dev/null
+/*
+ * Test the radix tree net
+ */
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <netinet/in.h> /* htonl */
+#include "include/net/radix.h"
+
+struct d {
+ uint8_t len[4];
+ uint32_t data;
+};
+
+struct table_entry {
+ struct radix_node rn[2];
+ struct d x, mask;
+ int value;
+};
+
+static int
+del(struct radix_node *rn, void *arg)
+{
+ struct radix_node_head * const rnh = arg;
+ struct table_entry *ent;
+
+ ent = (struct table_entry *)
+ rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh);
+ fprintf(stderr, "del returns %p\n", ent);
+ if (0 && ent != NULL)
+ free(ent);
+ return (0);
+}
+
+int
+list(struct radix_node *rn, void *arg)
+{
+ struct table_entry *ent = (struct table_entry *)rn;
+
+ fprintf(stderr, "walking on node %d\n", ent->value);
+ return (0);
+}
+
+static void
+print_dt(struct timeval *start, struct timeval *end, int n, const char *msg)
+{
+ int ds = 0, du, l;
+ du = end->tv_usec - start->tv_usec;
+ if (du < 0) {
+ ds = -1;
+ du += 1000000;
+ }
+ ds += end->tv_sec - start->tv_sec;
+ if (n <= 1)
+ n = 1;
+ l = (ds * 1000000+ du)/n;
+ fprintf(stderr, "%d tries in %d.%06ds, %dus each\n",
+ n, ds, du, l);
+}
+
+static void
+test1(struct radix_node_head *h, int n)
+{
+ struct table_entry *p;
+ struct timeval start, end;
+ int i;
+
+ p = calloc(n, sizeof(*p));
+ if (!p)
+ return;
+ for (i=0; i < n; i++) {
+ p->value = i;
+ p->x.len[0] = p->mask.len[0] = 8;
+ p->mask.data = 0xffffffff;
+ p->x.data = htonl(i);
+ }
+ gettimeofday(&start, NULL);
+ for (i=0; i < n; i++) {
+ h->rnh_addaddr(&(p->x), &(p->mask), h, (void *)p);
+ }
+ gettimeofday(&end, NULL);
+ print_dt(&start, &end, n, NULL);
+ h->rnh_walktree(h, del, h);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct radix_node_head *h = NULL;
+
+ rn_init(64); // XXX bits or bytes ?
+ rn_inithead((void **)&h, 32); /* data offset in bits */
+ test1(h, 1000000);
+ return 0;
+}
* SUCH DAMAGE.
*/
/*
- * $Id: glue.h 4413 2009-12-10 08:57:02Z luigi $
+ * $Id: glue.h 4436 2009-12-10 18:31:49Z luigi $
*
* glue code to adapt the FreeBSD version to linux and windows,
* userland and kernel.
#ifdef linux
/* linux does not have sin_len in sockaddr */
-#define sin_len __pad[0]
+#define sin_len sin_zero[0]
#endif /* linux */
/*
*/
/*
- * $Id: glue.c 4051 2009-11-16 11:30:05Z luigi $
+ * $Id: glue.c 4469 2009-12-11 20:23:11Z marta $
*
* Userland functions missing in linux
*/
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#ifndef HAVE_NAT
/* dummy nat functions */
return strtoll(nptr, (char **)errstr, 0);
}
+/*
+ * set or get system information
+ * XXX lock acquisition/serialize calls
+ *
+ * we export this as sys/module/ipfw_mod/parameters/___
+ * This function get or/and set the value of the sysctl passed by
+ * the name parameter. If the old value is not desired,
+ * oldp and oldlenp should be set to NULL.
+ *
+ * XXX
+ * I do not know how this works in FreeBSD in the case
+ * where there are no write permission on the sysctl var.
+ * We read the value and set return variables in any way
+ * but returns -1 on write failures, regardless the
+ * read success.
+ *
+ * Since there is no information on types, in the following
+ * code we assume a lenght of 4 is a int.
+ *
+ * Returns 0 on success, -1 on errors.
+ */
int
sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
size_t newlen)
{
- return -1;
+ FILE *fp;
+ char *basename = "/sys/module/ipfw_mod/parameters/";
+ char filename[256]; /* full filename */
+ char *varp;
+ int ret = 0; /* return value */
+ int d;
+
+ /* debug message */
+ if (0) fprintf(stderr, "%s name %s oldp %p oldlenp %p %d newp %p newlen %d\n", __FUNCTION__, name, \
+ oldp, oldlenp, oldlenp ? *oldlenp : -1 , newp, (int) newlen);
+
+ if (name == NULL) /* XXX set errno */
+ return -1;
+
+ /* locate the filename */
+ varp = strrchr(name, '.');
+ if (varp == NULL) /* XXX set errno */
+ return -1;
+
+ snprintf(filename, sizeof(filename), "%s%s", basename, varp+1);
+
+ /*
+ * XXX we could open the file here, in rw mode
+ * but need to check if a file have write
+ * permissions.
+ */
+
+ /* check parameters */
+ if (oldp && oldlenp) { /* read mode */
+ fp = fopen(filename, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "%s fopen error reading filename %s\n", __FUNCTION__, filename);
+ return -1;
+ }
+ if (*oldlenp == 4) {
+ if (fscanf(fp, "%d", &d) == 1)
+ memcpy(oldp, &d, *oldlenp);
+ else
+ ret = -1;
+ }
+ fclose(fp);
+ }
+
+ if (newp && newlen) { /* write */
+ fp = fopen(filename, "w");
+ if (fp == NULL) {
+ fprintf(stderr, "%s fopen error writing filename %s\n", __FUNCTION__, filename);
+ return -1;
+ }
+ if (newlen == 4) {
+ if (fprintf(fp, "%d", *(int*)newp) < 1)
+ ret = -1;
+ }
+
+ fclose(fp);
+ }
+
+ return ret;
}
#endif /* __linux__ || _WIN32 */
if (s < 0)
err(EX_UNAVAILABLE, "socket");
- if (optname == IP_FW_GET || optname == IP_FW_DYN_GET ||
- optname == IP_DUMMYNET_GET ||
+ if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET ||
+ optname == IP_FW_DYN_GET ||
optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST ||
optname == IP_FW_TABLE_GETSIZE ||
optname == IP_FW_NAT_GET_CONFIG ||
* 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_len = sizeof(struct sockaddr_in);
p->sa.sin_port = 0;
/*
* locate the address-port separator (':' or ',')
LOADED=`cat /proc/modules | grep ^ipfw_mod`; if [ -n "$LOADED" ] ; then rmmod ipfw_mod; fi
%changelog
+* Tue Dec 15 2009 Marta Carbone <marta.carbone@iet.unipi.it>
+- more work on the radix code, added sysctl read/write support
+
* Sun Nov 29 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-7
- added missing qsort.c - tag 0.9-6 was broken
%{_mandir}/man8/ipfw.8*
%changelog
+* Tue Dec 15 2009 Marta Carbone <marta.carbone@iet.unipi.it>
+- more work on the radix code, added sysctl read/write support
+
* Sun Nov 29 2009 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - ipfw-0.9-7
- added missing qsort.c - tag 0.9-6 was broken
--- /dev/null
+# $Id: planetlab-tags.mk 4496 2009-12-14 12:01:38Z luigi $
+# These are good to build the ipfw modules from svn on kernels 2.6.22
+linux-2.6-SVNBRANCH := 22
+linux-2.6-SVNPATH := http://svn.planet-lab.org/svn/linux-2.6/tags/linux-2.6-22-39-1
+ipfwsrc-SVNPATH := svn+ssh://luigi%40onelab2.iet.unipi.it/home/svn/ports-luigi/dummynet-branches/ipfw_mod
--- /dev/null
+# $Id: planetlab.mk 4496 2009-12-14 12:01:38Z luigi $
+# .mk file to build a module
+kernel-MODULES := linux-2.6
+kernel-SPEC := kernel-2.6.spec
+kernel-BUILD-FROM-SRPM := yes
+ifeq "$(HOSTARCH)" "i386"
+kernel-RPMFLAGS:= --target i686
+else
+kernel-RPMFLAGS:= --target $(HOSTARCH)
+endif
+ALL += kernel
+
+ipfwroot-MODULES := ipfwsrc
+ipfwroot-SPEC := planetlab/ipfwroot.spec
+ipfwroot-DEPEND-DEVEL-RPMS := kernel-devel
+ipfwroot-SPECVARS = kernel_version=$(kernel.rpm-version) \
+ kernel_release=$(kernel.rpm-release) \
+ kernel_arch=$(kernel.rpm-arch)
+ALL += ipfwroot
+
+ipfwslice-MODULES := ipfwsrc
+ipfwslice-SPEC := planetlab/ipfwslice.spec
+ipfwslice-SPECVARS = kernel_version=$(kernel.rpm-version) \
+ kernel_release=$(kernel.rpm-release) \
+ kernel_arch=$(kernel.rpm-arch)
+ALL += ipfwslice