Wednesday, March 29, 2017

A sample netmap application

There and back again. After a seven year pause in hardcore tech stuff,  I've again started to code.

After cleaning the rust and dust off, I'm happy to see my tech skills remain intact.

It still feels good :)

Nowadays, I'm working on a novel network threat detection engine for my new startup. I'll be sharing some stuff that I think would be of value to people out there.

Here's the first one:

We've decided to utilize FreeBSD's netmap fast packet I/O API for managing packet input/output at high speeds. Since the documentation is quite limited, it's hard to find a minimal working sample code demonstrating netmap functionality.

Below is a simple packet receiver code which just counts the number of packet received off the wire:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <poll.h>
#include <fcntl.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>

#include <net/netmap_user.h>

int
main(int argc, char **argv)
{
        struct  netmap_if *nifp;
        struct  netmap_ring *ring;
        struct  nmreq nmr;
        struct  pollfd fds;
        int fd = 0;
        void *p = NULL;
        int i = 0;
        void *buf = NULL;
        int tot = 0;
        int nret = 0;

        if (argc < 2) {
                printf("%s int\n", argv[0]);
                return(1);
        }

        if ((fd = open("/dev/netmap", O_RDWR)) < 0) {
                perror("open");
                return(1);

        }
       
        bzero(&nmr, sizeof(nmr));
        strcpy(nmr.nr_name, argv[1]);
        nmr.nr_version  = NETMAP_API;

        /* Register interface for Netmap mode, bypass OS stack */
        if (ioctl(fd, NIOCREGIF, &nmr) != 0) {
                perror("ioctl");
                return(1);
        }
        /* MAP kernerl ring buffers to userspace */
        if ((p = mmap(0, nmr.nr_memsize, PROT_READ | PROT_WRITE, MAP_SHARED , fd, 0)) == NULL) {
                perror("mmap");
                return(1);
        }
        nifp =  NETMAP_IF(p, nmr.nr_offset);
        ring =  NETMAP_RXRING(nifp, 0);
        fds.fd  = fd;
        fds.events = POLLIN;
        for (;;) {
                poll(&fds, 1, 1000);
                while (!nm_ring_empty(ring)) {
                        i = ring->cur;
                        buf = NETMAP_BUF(ring,  ring->slot[i].buf_idx);
                        /* Insert your cool stuff here */
                        ring->head = ring->cur  = nm_ring_next(ring, i);
                        nret++;
                }
                if (ioctl(fd, NIOCRXSYNC, NULL) != 0)
                        perror("sync ioctl");
                tot += nret;
                printf("recv'd %d packets, total: %d\n", nret, tot);
                nret = 0;
        }
        return 0;
}