Date: Fri, 3 Sep 2010 12:02:50 GMT From: Alexandre Fiveg <afiveg@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 183300 for review Message-ID: <201009031202.o83C2otg029243@skunkworks.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@183300?ac=10 Change 183300 by afiveg@cottonmouth on 2010/09/03 12:01:58 Added filtering using kernel BPF: ringmap.c ringmap_filter(). It needs to be reviewed! It works in my testbed but I guess it is not properly implemented so it works in all possible cases. ringmap_filter sets BPFIF_LOCK then tries to find bpf_d belonging to the process that capture from current ring. Then sets BPFD_LOCK and call bpf_filter(). If bpf_filter returns > 0, then set ring->slot->filtered=1. User-space process cheks "filtered" value to know whether the packet was accepted by BPF. Affected files ... .. //depot/projects/soc2010/ringmap/current/contrib/libpcap/pcap-bpf.c#18 edit .. //depot/projects/soc2010/ringmap/current/contrib/libpcap/pcap-int.h#18 edit .. //depot/projects/soc2010/ringmap/current/contrib/libpcap/pcap.c#21 edit .. //depot/projects/soc2010/ringmap/current/contrib/libpcap/ringmap_pcap.c#33 edit .. //depot/projects/soc2010/ringmap/current/sys/dev/e1000/if_lem.c#34 edit .. //depot/projects/soc2010/ringmap/current/sys/dev/e1000/if_lem.h#22 edit .. //depot/projects/soc2010/ringmap/current/sys/dev/e1000/ringmap_8254.c#33 edit .. //depot/projects/soc2010/ringmap/current/sys/dev/e1000/ringmap_8254.h#31 edit .. //depot/projects/soc2010/ringmap/current/sys/dev/e1000/ringmap_e1000.h#23 edit .. //depot/projects/soc2010/ringmap/current/sys/dev/ixgbe/ringmap_8259.h#16 edit .. //depot/projects/soc2010/ringmap/current/sys/dev/ixgbe/ringmap_ixgbe.c#17 edit .. //depot/projects/soc2010/ringmap/current/sys/net/ringmap.c#47 edit .. //depot/projects/soc2010/ringmap/current/sys/net/ringmap.h#47 edit .. //depot/projects/soc2010/ringmap/current/sys/net/ringmap_kernel.h#17 edit .. //depot/projects/soc2010/ringmap/scripts/build_ringmap.sh#29 edit .. //depot/projects/soc2010/ringmap/scripts/set_ringmap.sh#30 edit .. //depot/projects/soc2010/ringmap/scripts/tailf_ringmap_msgs.sh#24 edit .. //depot/projects/soc2010/ringmap/tests/libpcap/easy_pcap.c#15 edit Differences ... ==== //depot/projects/soc2010/ringmap/current/contrib/libpcap/pcap-bpf.c#18 (text+ko) ==== ==== //depot/projects/soc2010/ringmap/current/contrib/libpcap/pcap-int.h#18 (text+ko) ==== ==== //depot/projects/soc2010/ringmap/current/contrib/libpcap/pcap.c#21 (text+ko) ==== ==== //depot/projects/soc2010/ringmap/current/contrib/libpcap/ringmap_pcap.c#33 (text+ko) ==== @@ -227,36 +227,47 @@ { unsigned int ws, wait_flag = 1, tmp_dist; unsigned int curr_slot; + int err_sleep, slen; struct mbuf *mb; caddr_t datap; struct pcap_pkthdr pkthdr; struct ring *ring; + RINGMAP_FUNC_DEBUG(start); + if (p->break_loop) { + p->break_loop = 0; + return (-2); + } + if (p->ring == NULL){ RINGMAP_ERROR(Ring is not allocated); - exit (1); } ring = p->ring; - if (p->break_loop) { - p->break_loop = 0; - return (-2); - } - - while ( RING_IS_EMPTY(ring) ) { + /* stay here as long as the ring is empty */ + while (RING_IS_EMPTY(ring)) { #if (__RINGMAP_DEB) PRINT_RING_PTRS(ring); RINGMAP_FUNC_DEBUG(Ring is empty. Sleep...); #endif /* Sleep and wait for new incoming packets */ - ioctl(ringmap_cdev_fd, IOCTL_SLEEP_WAIT); + err_sleep = ioctl(ringmap_cdev_fd, IOCTL_SLEEP_WAIT); + + /* catching signals */ + if (err_sleep) { + if (errno == EINTR) { + pcap_close(p); + exit(0); + } + } } + /* Ok, if we are here the ring shouldn't be empty, let's capture */ #if (__RINGMAP_DEB) RINGMAP_FUNC_DEBUG(Ring is NOT empty:); PRINT_RING_PTRS(ring); @@ -275,7 +286,18 @@ return (cnt - ws); } + /* Slot we want to check */ curr_slot = R_MODULO( SW_TAIL(ring) + 1 ); + + mb = (struct mbuf *)U_MBUF(ring, curr_slot); + datap = (caddr_t)U_PACKET(ring, curr_slot); + pkthdr.caplen = pkthdr.len = mb->m_len; + pkthdr.ts = ring->slot[curr_slot].ts; + + /* + * ringmap-Driver tell us whether the slot contains + * a good packet + */ if (ring->slot[curr_slot].is_ok == 0) { #if (__RINGMAP_DEB) printf("Slot %d was not accepted by driver!\n", curr_slot); @@ -283,16 +305,30 @@ goto out; } - mb = (struct mbuf *)U_MBUF(ring, curr_slot); + /* Packet filtering */ + if (p->md.use_bpf) { + /* Filtered in Kernel */ + if (ring->slot[curr_slot].filtered == 0) { +#if (__RINGMAP_DEB) + printf("Slot %d was not filtered by kernel bpf!\n", curr_slot); +#endif + goto out; + } + } else { + /* Filtering in user-space */ + slen = bpf_filter(p->fcode.bf_insns, datap, mb->m_len, mb->m_len); + if (!slen) + goto out; + } - pkthdr.ts = ring->slot[curr_slot].ts; - pkthdr.caplen = pkthdr.len = mb->m_len; - datap = (caddr_t)U_PACKET(ring, curr_slot); - ring->pkt_counter++; --ws; +#if (__RINGMAP_DEB) PRINT_PKT_BYTES(datap, curr_slot); +#endif + + /* callback function */ (*callback)(user, &pkthdr, datap); #if (__RINGMAP_DEB) ==== //depot/projects/soc2010/ringmap/current/sys/dev/e1000/if_lem.c#34 (text+ko) ==== ==== //depot/projects/soc2010/ringmap/current/sys/dev/e1000/if_lem.h#22 (text+ko) ==== ==== //depot/projects/soc2010/ringmap/current/sys/dev/e1000/ringmap_8254.c#33 (text+ko) ==== @@ -31,6 +31,7 @@ extern devclass_t em_devclass; extern void ringmap_print_slot(struct ring *, unsigned int); extern void print_capt_obj(struct capt_object *); +extern int ringmap_filter(struct ifnet *, struct capt_object *, int); struct ringmap_functions ringmap_8254_f = { @@ -116,27 +117,6 @@ RINGMAP_INTR(end); } -/* Returns the ring which TAIL pointer is mostly near to to the HEAD(RDH) */ -struct capt_object * -rm_8254_find_next(struct adapter *adapter) -{ - unsigned int rdh, rdt, dist, min_dist = SLOTS_NUMBER; - struct ringmap *rm = adapter->rm; - struct capt_object *co = NULL, *min_co = NULL; - - rdh = RINGMAP_HW_READ_HEAD(adapter); - - SLIST_FOREACH(co, &rm->object_list, objects) { - rdt = co->ring->userrp; - dist = R_DISTANCE(rdh, rdt); - if (dist <= min_dist) { - min_dist = dist; - min_co = co; - } - } - - return (min_co); -} void rm_8254_delayed_interrupt_per_packet(void *context, int slot_num) @@ -155,12 +135,13 @@ if (co->ring != NULL) { co->ring->slot[slot_num].is_ok = 1; co->ring->slot[slot_num].intr_num = co->ring->intr_num;; + + ringmap_filter(adapter->ifp, co, slot_num); #ifdef RINGMAP_TIMESTAMP co->ring->slot[slot_num].ts = co->ring->last_ts; #endif - -#if (__RINGMAP_DEB) +#if (RINGMAP_INTR_DEB) PRINT_SLOT((co->ring), (slot_num)); #endif } @@ -170,6 +151,30 @@ } +/* Returns the ring which TAIL pointer is mostly near to to the HEAD(RDH) */ +struct capt_object * +rm_8254_find_next(struct adapter *adapter) +{ + unsigned int rdh, rdt, dist, min_dist = SLOTS_NUMBER; + struct ringmap *rm = adapter->rm; + struct capt_object *co = NULL, *min_co = NULL; + + rdh = RINGMAP_HW_READ_HEAD(adapter); + + SLIST_FOREACH(co, &rm->object_list, objects) { + rdt = co->ring->userrp; + dist = R_DISTANCE(rdh, rdt); + if (dist <= min_dist) { + min_dist = dist; + min_co = co; + } + } + + return (min_co); +} + + + int rm_8254_set_slot(struct capt_object *co, unsigned int slot_num) { ==== //depot/projects/soc2010/ringmap/current/sys/dev/e1000/ringmap_8254.h#31 (text+ko) ==== ==== //depot/projects/soc2010/ringmap/current/sys/dev/e1000/ringmap_e1000.h#23 (text+ko) ==== ==== //depot/projects/soc2010/ringmap/current/sys/dev/ixgbe/ringmap_8259.h#16 (text+ko) ==== ==== //depot/projects/soc2010/ringmap/current/sys/dev/ixgbe/ringmap_ixgbe.c#17 (text+ko) ==== ==== //depot/projects/soc2010/ringmap/current/sys/net/ringmap.c#47 (text+ko) ==== @@ -21,6 +21,8 @@ #include <net/if_var.h> #include <net/if_types.h> #include <net/if_media.h> +#include <net/bpf.h> +#include <net/bpfdesc.h> #include <vm/vm.h> #include <vm/pmap.h> @@ -43,6 +45,7 @@ void print_capt_obj(struct capt_object *); struct ringmap * cdev2ringmap(struct cdev *); struct ringmap * dev2ringmap(device_t); +int ringmap_filter(struct ifnet *, struct capt_object *, int); d_open_t ringmap_open; d_close_t ringmap_close; @@ -74,8 +77,9 @@ RINGMAP_FUNC_DEBUG(begin); - rm = (struct ringmap *) contigmalloc (sizeof(struct ringmap), - M_DEVBUF, M_ZERO, 0, -1L, PAGE_SIZE, 0); + MALLOC(rm, struct ringmap *, sizeof(struct ringmap), + M_DEVBUF, (M_ZERO | M_WAITOK)); + if (rm == NULL) { RINGMAP_ERROR(Can not allocate space for ringmap structure); return (NULL); @@ -119,6 +123,10 @@ RINGMAP_FUNC_DEBUG(end); + /* + * Return ringmap pointer to the generic driver. Generic driver should + * store the pointer in the adapter structure + */ return (rm); } @@ -144,7 +152,6 @@ /* Remove all capturing objects associated with ringmap */ while (!SLIST_EMPTY(&rm->object_list)) { co = SLIST_FIRST(&rm->object_list); - SLIST_REMOVE_HEAD(&rm->object_list, objects); clear_capt_object((void *)co); } @@ -157,7 +164,7 @@ /* And remove ringmap from global list */ SLIST_REMOVE(&ringmap_list_head, rm, ringmap, entries); - contigfree(rm, sizeof(struct ringmap), M_DEVBUF); + FREE(rm, M_DEVBUF); RINGMAP_FUNC_DEBUG(end); @@ -193,7 +200,7 @@ RINGMAP_LOCK(rm); - /* TODO: set max number of threads in the ringmap struct as a variable */ + /* TODO: set max number of threads in the ringmap struct as a member */ if (rm->open_cnt == RINGMAP_MAX_THREADS) { RINGMAP_ERROR(Can not open device!); err = EIO; goto out; @@ -222,7 +229,7 @@ * create the capturing object wich will represent * current thread and packets ring */ - MALLOC( co, struct capt_object *, + MALLOC(co, struct capt_object *, sizeof(struct capt_object), M_DEVBUF, (M_ZERO | M_WAITOK)); if ( co == NULL ){ contigfree(ring, sizeof(struct ring), M_DEVBUF); @@ -249,7 +256,7 @@ } #endif - /* Init ring-slots with mbufs and packets adrresses */ + /* Init ring-slots with mbufs and packets adrresses */ for (i = 0 ; i < SLOTS_NUMBER ; i++) { if (rm->funcs->set_slot(co, i) == -1){ RINGMAP_ERROR(Ring initialization failed!); @@ -274,7 +281,7 @@ * Store capturing object as private data. So we can access our capturing * object in other syscalls, e.g. read, close, etc... */ - if ( devfs_set_cdevpriv((void *)co, clear_capt_object) ) { + if (devfs_set_cdevpriv((void *)co, clear_capt_object)) { RINGMAP_ERROR(Can not set private data!); contigfree(ring, sizeof(struct ring), M_DEVBUF); @@ -283,7 +290,7 @@ err = EIO; goto out; } - rm->open_cnt++; + ++rm->open_cnt; #if (__RINGMAP_DEB) print_capt_obj(co); @@ -299,6 +306,12 @@ } +/* + * Do nothing here. This func will called when the last thread calls close(2). + * But the callback: clear_capt_object() will be called every time by + * close(2). Attention!!! - If the last thread call close(2) first will be + * ringmap_close() called and then clear_capt_object() !!! + */ int ringmap_close(struct cdev *cdev, int flag, int otyp, struct thread *td) { @@ -325,9 +338,14 @@ if (data != NULL) { co = (struct capt_object *)data; + + RINGMAP_LOCK(co->rm); + + /* to be completely sure */ + if (co == NULL) + goto out; + rm = co->rm; - - RINGMAP_LOCK(rm); #if (__RINGMAP_DEB) printf("[%s] Object to delete:\n", __func__); print_capt_obj(co); @@ -337,9 +355,14 @@ SLIST_REMOVE(&rm->object_list, co, capt_object, objects); FREE(co, M_DEVBUF); - data = NULL; + data = co = NULL; - rm->open_cnt--; + if (rm->open_cnt) { + --rm->open_cnt; + } else { + RINGMAP_WARN(Incorrect value of rm->open_cnt); + } +out: RINGMAP_UNLOCK(rm); } else { @@ -485,8 +508,12 @@ while (RING_IS_EMPTY(co->ring)) { RINGMAP_IOCTL(Sleep and wait for new packets); - err_sleep = tsleep(co->ring, + err = tsleep(co->ring, (PRI_MAX_ITHD) | PCATCH, "ioctl", 0); + + /* go in user-space by catching signal */ + if (err) + goto out; } break; @@ -502,12 +529,49 @@ return (ENODEV); } +out: + RINGMAP_IOCTL(end); return (err); } +/* Paket filtering */ +int +ringmap_filter(struct ifnet *rcvif, struct capt_object *co, int slot_num) +{ + struct bpf_if *bp = rcvif->if_bpf; + struct bpf_d *d = NULL; + struct mbuf *mb = (struct mbuf *)K_MBUF(co->ring, slot_num); + u_int pktlen = mb->m_len, slen; + + BPFIF_LOCK(bp); + + LIST_FOREACH(d, &bp->bif_dlist, bd_next) { + if (d->bd_pid == co->td->td_proc->p_pid) + break; + } + if (d != NULL) { + BPFD_LOCK(d); + + printf("ifdname: %s\n", rcvif->if_dname); + ++d->bd_rcount; + slen = bpf_filter(d->bd_rfilter, (u_char *)mb, pktlen, 0); + if (slen) + co->ring->slot[slot_num].filtered = 1; + else + co->ring->slot[slot_num].filtered = 0; + + BPFD_UNLOCK(d); + } + + BPFIF_UNLOCK(bp); + + return (0); +} + + void print_capt_obj(struct capt_object *co) { ==== //depot/projects/soc2010/ringmap/current/sys/net/ringmap.h#47 (text+ko) ==== ==== //depot/projects/soc2010/ringmap/current/sys/net/ringmap_kernel.h#17 (text+ko) ==== ==== //depot/projects/soc2010/ringmap/scripts/build_ringmap.sh#29 (text+ko) ==== @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/local/bin/bash RINGMAP_BUILD_DIR=../current/sys/modules/ringmap/ LIBPCAP_BUILD_DIR=../current/lib/libpcap/ @@ -6,7 +6,7 @@ make_ringmap() { cd ${RINGMAP_BUILD_DIR} make clean - make || { echo "Error while compiling driver" ; return 1 ; } + make DEBUG_FLAGS=-g || { echo "Error while compiling driver" ; return 1 ; } cd - } @@ -37,22 +37,24 @@ echo "==================================================================" echo +[ ${1} == "ringmap" ] && exit 0 + # Build libpcap echo -echo "MAKE libpcap FOR ringmap DRIVER:" +echo "MAKE LIBPCAP FOR RINGMAP DRIVER:" echo "==================================================================" sleep 1 make_libpcap if [ $? -eq 1 ] -then +then echo echo "Stop building! Exit!" exit 1; fi echo -echo Everything seems to be Ok. -echo Now, for loading ringmap driver and for installing libpcap: +echo Everything seems to be Ok. +echo For loading ringmap driver and for installing libpcap do: echo sudo ./set_ringmap.sh echo ==== //depot/projects/soc2010/ringmap/scripts/set_ringmap.sh#30 (text+ko) ==== ==== //depot/projects/soc2010/ringmap/scripts/tailf_ringmap_msgs.sh#24 (text+ko) ==== ==== //depot/projects/soc2010/ringmap/tests/libpcap/easy_pcap.c#15 (text+ko) ====
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201009031202.o83C2otg029243>