6 * A simple library that maps some pcap functions onto netmap
7 * This is not 100% complete but enough to let tcpdump, trafshow
14 #include <signal.h> /* signal */
17 #include <string.h> /* strcmp */
18 #include <fcntl.h> /* open */
19 #include <unistd.h> /* close */
21 #include <sys/endian.h> /* le64toh */
22 #include <sys/mman.h> /* PROT_* */
23 #include <sys/ioctl.h> /* ioctl */
24 #include <machine/param.h>
26 #include <sys/socket.h> /* sockaddr.. */
27 #include <arpa/inet.h> /* ntohs */
29 #include <net/if.h> /* ifreq */
30 #include <net/ethernet.h>
31 #include <net/netmap.h>
32 #include <net/netmap_user.h>
34 #include <netinet/in.h> /* sockaddr_in */
36 #include <sys/socket.h>
39 #define MIN(a, b) ((a) < (b) ? (a) : (b))
41 char *version = "$Id$";
45 #define ND(format, ...) do {} while (0)
46 #define D(format, ...) do { \
48 fprintf(stderr, "--- %s [%d] " format "\n", \
49 __FUNCTION__, __LINE__, ##__VA_ARGS__); \
52 inline void prefetch (const void *x)
54 __asm volatile("prefetcht0 %0" :: "m" (*(const unsigned long *)x));
57 // XXX only for multiples of 64 bytes, non overlapped.
59 pkt_copy(const void *_src, void *_dst, int l)
61 const uint64_t *src = _src;
63 #define likely(x) __builtin_expect(!!(x), 1)
64 #define unlikely(x) __builtin_expect(!!(x), 0)
65 if (unlikely(l >= 1024)) {
69 for (; l > 0; l-=64) {
82 * We redefine here a number of structures that are in pcap.h
83 * so we can compile this file without the system header.
85 #ifndef PCAP_ERRBUF_SIZE
86 #define PCAP_ERRBUF_SIZE 128
89 * Each packet is accompanied by a header including the timestamp,
90 * captured size and actual size.
93 struct timeval ts; /* time stamp */
94 uint32_t caplen; /* length of portion present */
95 uint32_t len; /* length this packet (off wire) */
98 typedef struct pcap_if pcap_if_t;
101 * Representation of an interface address.
104 struct pcap_addr *next;
105 struct sockaddr *addr; /* address */
106 struct sockaddr *netmask; /* netmask for the above */
107 struct sockaddr *broadaddr; /* broadcast addr for the above */
108 struct sockaddr *dstaddr; /* P2P dest. address for the above */
112 struct pcap_if *next;
113 char *name; /* name to hand to "pcap_open_live()" */
114 char *description; /* textual description of interface, or NULL */
115 struct pcap_addr *addresses;
116 uint32_t flags; /* PCAP_IF_ interface flags */
120 * We do not support stats (yet)
123 u_int ps_recv; /* number of packets received */
124 u_int ps_drop; /* number of packets dropped */
125 u_int ps_ifdrop; /* drops by interface XXX not yet supported */
127 u_int bs_capt; /* number of packets that reach the app. */
140 typedef void (*pcap_handler)(u_char *user,
141 const struct pcap_pkthdr *h, const u_char *bytes);
143 char errbuf[PCAP_ERRBUF_SIZE];
145 pcap_t *pcap_open_live(const char *device, int snaplen,
146 int promisc, int to_ms, char *errbuf);
148 int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf);
149 void pcap_close(pcap_t *p);
150 int pcap_get_selectable_fd(pcap_t *p);
151 int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
152 int pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf);
153 int pcap_setdirection(pcap_t *p, pcap_direction_t d);
154 char *pcap_lookupdev(char *errbuf);
155 int pcap_inject(pcap_t *p, const void *buf, size_t size);
156 int pcap_fileno(pcap_t *p);
157 const char *pcap_lib_version(void);
164 #endif /* !PCAP_ERRBUF_SIZE */
168 * build as a shared library
171 char pcap_version[] = "libnetmap version 0.3";
174 * Our equivalent of pcap_t
180 char *mem; /* userspace mmap address */
183 u_int begin, end; /* first..last+1 rings to check */
184 struct netmap_if *nifp;
191 struct pcap_pkthdr hdr;
199 char msg[PCAP_ERRBUF_SIZE];
204 do_ioctl(struct my_ring *me, int what)
209 bzero(&ifr, sizeof(ifr));
210 strncpy(ifr.ifr_name, me->nmr.nr_name, sizeof(ifr.ifr_name));
213 D("call SIOCSIFFLAGS 0x%x", me->if_flags);
214 ifr.ifr_flagshigh = (me->if_flags >> 16) & 0xffff;
215 ifr.ifr_flags = me->if_flags & 0xffff;
218 ifr.ifr_reqcap = me->if_reqcap;
219 ifr.ifr_curcap = me->if_curcap;
222 error = ioctl(me->fd, what, &ifr);
224 D("ioctl 0x%x error %d", what, error);
230 me->if_flags = (ifr.ifr_flagshigh << 16) |
231 (0xffff & ifr.ifr_flags);
232 D("flags are L 0x%x H 0x%x 0x%x",
233 (uint16_t)ifr.ifr_flags,
234 (uint16_t)ifr.ifr_flagshigh, me->if_flags);
238 me->if_reqcap = ifr.ifr_reqcap;
239 me->if_curcap = ifr.ifr_curcap;
240 D("curcap are 0x%x", me->if_curcap);
248 * open a device. if me->mem is null then do an mmap.
251 netmap_open(struct my_ring *me, int ringid)
257 me->fd = fd = open("/dev/netmap", O_RDWR);
259 D("Unable to open /dev/netmap");
262 bzero(&req, sizeof(req));
263 strncpy(req.nr_name, me->nmr.nr_name, sizeof(req.nr_name));
264 req.nr_ringid = ringid;
265 req.nr_version = NETMAP_API;
266 err = ioctl(fd, NIOCGINFO, &req);
268 D("cannot get info on %s", me->nmr.nr_name);
271 me->memsize = l = req.nr_memsize;
272 ND("memsize is %d MB", l>>20);
273 err = ioctl(fd, NIOCREGIF, &req);
275 D("Unable to register %s", me->nmr.nr_name);
279 if (me->mem == NULL) {
280 me->mem = mmap(0, l, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
281 if (me->mem == MAP_FAILED) {
288 me->nifp = NETMAP_IF(me->mem, req.nr_offset);
289 me->queueid = ringid;
290 if (ringid & NETMAP_SW_RING) {
291 me->begin = req.nr_rx_rings;
292 me->end = me->begin + 1;
293 } else if (ringid & NETMAP_HW_RING) {
294 me->begin = ringid & NETMAP_RING_MASK;
295 me->end = me->begin + 1;
298 me->end = req.nr_rx_rings;
300 /* request timestamps for packets */
301 for (i = me->begin; i < me->end; i++) {
302 struct netmap_ring *ring = NETMAP_RXRING(me->nifp, i);
303 ring->flags = NR_TIMESTAMP;
305 //me->tx = NETMAP_TXRING(me->nifp, 0);
313 * There is a set of functions that tcpdump expects even if probably
316 struct eproto eproto_db[] = {
317 { "ip", ETHERTYPE_IP },
318 { "arp", ETHERTYPE_ARP },
323 const char *pcap_lib_version(void)
329 pcap_findalldevs(pcap_if_t **alldevsp, __unused char *errbuf)
331 struct ifaddrs *i_head, *i;
332 pcap_if_t *top = NULL, *cur;
333 struct pcap_addr *tail = NULL;
336 D("listing all devs");
340 if (getifaddrs(&i_head)) {
341 D("cannot get if addresses");
344 for (i = i_head; i; i = i->ifa_next) {
345 //struct ifaddrs *ifa;
346 struct pcap_addr *pca;
347 //struct sockaddr *sa;
349 D("got interface %s", i->ifa_name);
350 if (!top || strcmp(top->name, i->ifa_name)) {
352 l = sizeof(*top) + strlen(i->ifa_name) + 1;
355 D("no space for if descriptor");
358 cur->name = (char *)(cur + 1);
359 //cur->flags = i->ifa_flags;
360 strcpy(cur->name, i->ifa_name);
361 cur->description = NULL;
366 /* now deal with addresses */
367 D("%s addr family %d len %d %s %s",
369 i->ifa_addr->sa_family, i->ifa_addr->sa_len,
370 i->ifa_netmask ? "Netmask" : "",
371 i->ifa_broadaddr ? "Broadcast" : "");
372 l = sizeof(struct pcap_addr) +
373 (i->ifa_addr ? i->ifa_addr->sa_len:0) +
374 (i->ifa_netmask ? i->ifa_netmask->sa_len:0) +
375 (i->ifa_broadaddr? i->ifa_broadaddr->sa_len:0);
378 D("no space for if addr");
381 #define SA_NEXT(x) ((struct sockaddr *)((char *)(x) + (x)->sa_len))
382 pca->addr = (struct sockaddr *)(pca + 1);
383 bcopy(i->ifa_addr, pca->addr, i->ifa_addr->sa_len);
384 if (i->ifa_netmask) {
385 pca->netmask = SA_NEXT(pca->addr);
386 bcopy(i->ifa_netmask, pca->netmask, i->ifa_netmask->sa_len);
387 if (i->ifa_broadaddr) {
388 pca->broadaddr = SA_NEXT(pca->netmask);
389 bcopy(i->ifa_broadaddr, pca->broadaddr, i->ifa_broadaddr->sa_len);
393 top->addresses = pca;
405 void pcap_freealldevs(__unused pcap_if_t *alldevs)
411 pcap_lookupdev(char *buf)
414 strcpy(buf, "/dev/netmap");
419 pcap_create(const char *source, char *errbuf)
421 D("src %s (call open liveted)", source);
422 return pcap_open_live(source, 0, 1, 100, errbuf);
426 pcap_activate(pcap_t *p)
428 D("pcap %p running", p);
433 pcap_can_set_rfmon(__unused pcap_t *p)
436 return 0; /* no we can't */
440 pcap_set_snaplen(pcap_t *p, int snaplen)
442 struct my_ring *me = p;
444 D("len %d", snaplen);
445 me->snaplen = snaplen;
450 pcap_snapshot(pcap_t *p)
452 struct my_ring *me = p;
454 D("len %d", me->snaplen);
459 pcap_lookupnet(const char *device, uint32_t *netp,
460 uint32_t *maskp, __unused char *errbuf)
463 D("device %s", device);
464 inet_aton("10.0.0.255", (struct in_addr *)netp);
465 inet_aton("255.255.255.0",(struct in_addr *) maskp);
470 pcap_set_promisc(pcap_t *p, int promisc)
472 struct my_ring *me = p;
474 D("promisc %d", promisc);
475 if (do_ioctl(me, SIOCGIFFLAGS))
476 D("SIOCGIFFLAGS failed");
478 me->if_flags |= IFF_PPROMISC;
480 me->if_flags &= ~IFF_PPROMISC;
482 if (do_ioctl(me, SIOCSIFFLAGS))
483 D("SIOCSIFFLAGS failed");
488 pcap_set_timeout(pcap_t *p, int to_ms)
490 struct my_ring *me = p;
500 pcap_compile(__unused pcap_t *p, __unused struct bpf_program *fp,
501 const char *str, __unused int optimize, __unused uint32_t netmask)
508 pcap_setfilter(__unused pcap_t *p, __unused struct bpf_program *fp)
515 pcap_datalink(__unused pcap_t *p)
518 return 1; // ethernet
522 pcap_datalink_val_to_name(int dlt)
524 D("%d returns DLT_EN10MB", dlt);
529 pcap_datalink_val_to_description(int dlt)
531 D("%d returns Ethernet link", dlt);
532 return "Ethernet link";
537 pcap_stats(pcap_t *p, struct pcap_stat *ps)
539 struct my_ring *me = p;
543 return 0; /* accumulate from pcap_dispatch() */
547 pcap_geterr(pcap_t *p)
549 struct my_ring *me = p;
556 pcap_open_live(const char *device, __unused int snaplen,
557 int promisc, int to_ms, __unused char *errbuf)
561 D("request to open %s snaplen %d promisc %d timeout %dms",
562 device, snaplen, promisc, to_ms);
563 me = calloc(1, sizeof(*me));
565 D("failed to allocate struct for %s", device);
568 strncpy(me->nmr.nr_name, device, sizeof(me->nmr.nr_name));
569 if (netmap_open(me, 0)) {
570 D("error opening %s", device);
575 if (do_ioctl(me, SIOCGIFFLAGS))
576 D("SIOCGIFFLAGS failed");
578 me->if_flags |= IFF_PPROMISC;
579 if (do_ioctl(me, SIOCSIFFLAGS))
580 D("SIOCSIFFLAGS failed");
582 if (do_ioctl(me, SIOCGIFCAP))
583 D("SIOCGIFCAP failed");
584 me->if_reqcap &= ~(IFCAP_HWCSUM | IFCAP_TSO | IFCAP_TOE);
585 if (do_ioctl(me, SIOCSIFCAP))
586 D("SIOCSIFCAP failed");
592 pcap_close(pcap_t *p)
594 struct my_ring *me = p;
600 munmap(me->mem, me->memsize);
601 /* restore original flags ? */
602 ioctl(me->fd, NIOCUNREGIF, NULL);
604 bzero(me, sizeof(*me));
609 pcap_fileno(pcap_t *p)
611 struct my_ring *me = p;
612 D("returns %d", me->fd);
617 pcap_get_selectable_fd(pcap_t *p)
619 struct my_ring *me = p;
626 pcap_setnonblock(__unused pcap_t *p, int nonblock, __unused char *errbuf)
628 D("mode is %d", nonblock);
629 return 0; /* ignore */
633 pcap_setdirection(__unused pcap_t *p, __unused pcap_direction_t d)
636 return 0; /* ignore */
640 pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
642 struct my_ring *me = p;
650 for (si = me->begin; si < me->end; si++) {
651 struct netmap_ring *ring = NETMAP_RXRING(me->nifp, si);
652 ND("ring has %d pkts", ring->avail);
653 if (ring->avail == 0)
655 me->hdr.ts = ring->ts;
657 * XXX a proper prefetch should be done as
658 * prefetch(i); callback(i-1); ...
660 while ((cnt == -1 || cnt != got) && ring->avail > 0) {
662 u_int idx = ring->slot[i].buf_idx;
664 D("%s bogus RX index %d at offset %d",
665 me->nifp->ni_name, idx, i);
668 u_char *buf = (u_char *)NETMAP_BUF(ring, idx);
670 me->hdr.len = me->hdr.caplen = ring->slot[i].len;
671 // D("call %p len %d", p, me->hdr.len);
672 callback(user, &me->hdr, buf);
673 ring->cur = NETMAP_RING_NEXT(ring, i);
678 me->st.ps_recv += got;
683 pcap_inject(pcap_t *p, const void *buf, size_t size)
685 struct my_ring *me = p;
690 for (si = me->begin; si < me->end; si++) {
691 struct netmap_ring *ring = NETMAP_TXRING(me->nifp, si);
693 ND("ring has %d pkts", ring->avail);
694 if (ring->avail == 0)
697 u_int idx = ring->slot[i].buf_idx;
699 D("%s bogus TX index %d at offset %d",
700 me->nifp->ni_name, idx, i);
703 u_char *dst = (u_char *)NETMAP_BUF(ring, idx);
704 ring->slot[i].len = size;
705 pkt_copy(buf, dst, size);
706 ring->cur = NETMAP_RING_NEXT(ring, i);
708 // if (ring->avail == 0) ioctl(me->fd, NIOCTXSYNC, NULL);
716 pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
718 struct my_ring *me = p;
719 struct pollfd fds[1];
723 memset(fds, 0, sizeof(fds));
725 fds[0].events = (POLLIN);
727 while (cnt == -1 || cnt > 0) {
728 if (poll(fds, 1, me->to_ms) <= 0) {
729 D("poll error/timeout");
732 i = pcap_dispatch(p, cnt, callback, user);
742 void do_send(u_char *user, const struct pcap_pkthdr *h, const u_char *buf)
744 pcap_inject((pcap_t *)user, buf, h->caplen);
748 * a simple pcap test program, bridge between two interfaces.
751 main(int argc, char **argv)
755 struct pollfd pollfd[2];
757 fprintf(stderr, "%s %s built %s %s\n",
758 argv[0], version, __DATE__, __TIME__);
760 while (argc > 1 && !strcmp(argv[1], "-v")) {
766 if (argc < 3 || argc > 4 || !strcmp(argv[1], argv[2])) {
767 D("Usage: %s IFNAME1 IFNAME2 [BURST]", argv[0]);
771 burst = atoi(argv[3]);
773 p0 = pcap_open_live(argv[1], 0, 1, 100, NULL);
774 p1 = pcap_open_live(argv[2], 0, 1, 100, NULL);
776 D("open returns %p %p", p0, p1);
779 bzero(pollfd, sizeof(pollfd));
780 pollfd[0].fd = pcap_fileno(p0);
781 pollfd[1].fd = pcap_fileno(p1);
782 pollfd[0].events = pollfd[1].events = POLLIN;
784 /* do i need to reset ? */
785 pollfd[0].revents = pollfd[1].revents = 0;
786 int ret = poll(pollfd, 2, 1000);
787 if (ret <= 0 || verbose)
788 D("poll %s [0] ev %x %x [1] ev %x %x",
789 ret <= 0 ? "timeout" : "ok",
796 if (pollfd[0].revents & POLLIN)
797 pcap_dispatch(p0, burst, do_send, p1);
798 if (pollfd[1].revents & POLLIN)
799 pcap_dispatch(p1, burst, do_send, p0);
804 #endif /* !__PIC__ */