The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/netmap_user.h

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (C) 2011-2014 Universita` di Pisa. All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  *
    8  *   1. Redistributions of source code must retain the above copyright
    9  *      notice, this list of conditions and the following disclaimer.
   10  *   2. Redistributions in binary form must reproduce the above copyright
   11  *      notice, this list of conditions and the following disclaimer in the
   12  *      documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 /*
   28  * $FreeBSD$
   29  *
   30  * Functions and macros to manipulate netmap structures and packets
   31  * in userspace. See netmap(4) for more information.
   32  *
   33  * The address of the struct netmap_if, say nifp, is computed from the
   34  * value returned from ioctl(.., NIOCREG, ...) and the mmap region:
   35  *      ioctl(fd, NIOCREG, &req);
   36  *      mem = mmap(0, ... );
   37  *      nifp = NETMAP_IF(mem, req.nr_nifp);
   38  *              (so simple, we could just do it manually)
   39  *
   40  * From there:
   41  *      struct netmap_ring *NETMAP_TXRING(nifp, index)
   42  *      struct netmap_ring *NETMAP_RXRING(nifp, index)
   43  *              we can access ring->nr_cur, ring->nr_avail, ring->nr_flags
   44  *
   45  *      ring->slot[i] gives us the i-th slot (we can access
   46  *              directly len, flags, buf_idx)
   47  *
   48  *      char *buf = NETMAP_BUF(ring, x) returns a pointer to
   49  *              the buffer numbered x
   50  *
   51  * All ring indexes (head, cur, tail) should always move forward.
   52  * To compute the next index in a circular ring you can use
   53  *      i = nm_ring_next(ring, i);
   54  *
   55  * To ease porting apps from pcap to netmap we supply a few fuctions
   56  * that can be called to open, close, read and write on netmap in a way
   57  * similar to libpcap. Note that the read/write function depend on
   58  * an ioctl()/select()/poll() being issued to refill rings or push
   59  * packets out.
   60  *
   61  * In order to use these, include #define NETMAP_WITH_LIBS
   62  * in the source file that invokes these functions.
   63  */
   64 
   65 #ifndef _NET_NETMAP_USER_H_
   66 #define _NET_NETMAP_USER_H_
   67 
   68 #include <stdint.h>
   69 #include <sys/socket.h>         /* apple needs sockaddr */
   70 #include <net/if.h>             /* IFNAMSIZ */
   71 
   72 #ifndef likely
   73 #define likely(x)       __builtin_expect(!!(x), 1)
   74 #define unlikely(x)     __builtin_expect(!!(x), 0)
   75 #endif /* likely and unlikely */
   76 
   77 #include <net/netmap.h>
   78 
   79 /* helper macro */
   80 #define _NETMAP_OFFSET(type, ptr, offset) \
   81         ((type)(void *)((char *)(ptr) + (offset)))
   82 
   83 #define NETMAP_IF(_base, _ofs)  _NETMAP_OFFSET(struct netmap_if *, _base, _ofs)
   84 
   85 #define NETMAP_TXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \
   86         nifp, (nifp)->ring_ofs[index] )
   87 
   88 #define NETMAP_RXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \
   89         nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] )
   90 
   91 #define NETMAP_BUF(ring, index)                         \
   92         ((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size))
   93 
   94 #define NETMAP_BUF_IDX(ring, buf)                       \
   95         ( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \
   96                 (ring)->nr_buf_size )
   97 
   98 
   99 static inline uint32_t
  100 nm_ring_next(struct netmap_ring *r, uint32_t i)
  101 {
  102         return ( unlikely(i + 1 == r->num_slots) ? 0 : i + 1);
  103 }
  104 
  105 
  106 /*
  107  * Return 1 if we have pending transmissions in the tx ring.
  108  * When everything is complete ring->head = ring->tail + 1 (modulo ring size)
  109  */
  110 static inline int
  111 nm_tx_pending(struct netmap_ring *r)
  112 {
  113         return nm_ring_next(r, r->tail) != r->head;
  114 }
  115 
  116 
  117 static inline uint32_t
  118 nm_ring_space(struct netmap_ring *ring)
  119 {
  120         int ret = ring->tail - ring->cur;
  121         if (ret < 0)
  122                 ret += ring->num_slots;
  123         return ret;
  124 }
  125 
  126 
  127 #ifdef NETMAP_WITH_LIBS
  128 /*
  129  * Support for simple I/O libraries.
  130  * Include other system headers required for compiling this.
  131  */
  132 
  133 #ifndef HAVE_NETMAP_WITH_LIBS
  134 #define HAVE_NETMAP_WITH_LIBS
  135 
  136 #include <sys/time.h>
  137 #include <sys/mman.h>
  138 #include <string.h>     /* memset */
  139 #include <sys/ioctl.h>
  140 #include <sys/errno.h>  /* EINVAL */
  141 #include <fcntl.h>      /* O_RDWR */
  142 #include <unistd.h>     /* close() */
  143 #include <signal.h>
  144 #include <stdlib.h>
  145 
  146 #ifndef ND /* debug macros */
  147 /* debug support */
  148 #define ND(_fmt, ...) do {} while(0)
  149 #define D(_fmt, ...)                                            \
  150         do {                                                    \
  151                 struct timeval t0;                              \
  152                 gettimeofday(&t0, NULL);                        \
  153                 fprintf(stderr, "%03d.%06d %s [%d] " _fmt "\n", \
  154                     (int)(t0.tv_sec % 1000), (int)t0.tv_usec,   \
  155                     __FUNCTION__, __LINE__, ##__VA_ARGS__);     \
  156         } while (0)
  157 
  158 /* Rate limited version of "D", lps indicates how many per second */
  159 #define RD(lps, format, ...)                                    \
  160     do {                                                        \
  161         static int t0, __cnt;                                   \
  162         struct timeval __xxts;                                  \
  163         gettimeofday(&__xxts, NULL);                            \
  164         if (t0 != __xxts.tv_sec) {                              \
  165             t0 = __xxts.tv_sec;                                 \
  166             __cnt = 0;                                          \
  167         }                                                       \
  168         if (__cnt++ < lps) {                                    \
  169             D(format, ##__VA_ARGS__);                           \
  170         }                                                       \
  171     } while (0)
  172 #endif
  173 
  174 struct nm_pkthdr {      /* same as pcap_pkthdr */
  175         struct timeval  ts;
  176         uint32_t        caplen;
  177         uint32_t        len;
  178 };
  179 
  180 struct nm_stat {        /* same as pcap_stat    */
  181         u_int   ps_recv;
  182         u_int   ps_drop;
  183         u_int   ps_ifdrop;
  184 #ifdef WIN32
  185         u_int   bs_capt;
  186 #endif /* WIN32 */
  187 };
  188 
  189 #define NM_ERRBUF_SIZE  512
  190 
  191 struct nm_desc {
  192         struct nm_desc *self; /* point to self if netmap. */
  193         int fd;
  194         void *mem;
  195         int memsize;
  196         int done_mmap;  /* set if mem is the result of mmap */
  197         struct netmap_if * const nifp;
  198         uint16_t first_tx_ring, last_tx_ring, cur_tx_ring;
  199         uint16_t first_rx_ring, last_rx_ring, cur_rx_ring;
  200         struct nmreq req;       /* also contains the nr_name = ifname */
  201         struct nm_pkthdr hdr;
  202 
  203         /*
  204          * The memory contains netmap_if, rings and then buffers.
  205          * Given a pointer (e.g. to nm_inject) we can compare with
  206          * mem/buf_start/buf_end to tell if it is a buffer or
  207          * some other descriptor in our region.
  208          * We also store a pointer to some ring as it helps in the
  209          * translation from buffer indexes to addresses.
  210          */
  211         struct netmap_ring * const some_ring;
  212         void * const buf_start;
  213         void * const buf_end;
  214         /* parameters from pcap_open_live */
  215         int snaplen;
  216         int promisc;
  217         int to_ms;
  218         char *errbuf;
  219 
  220         /* save flags so we can restore them on close */
  221         uint32_t if_flags;
  222         uint32_t if_reqcap;
  223         uint32_t if_curcap;
  224 
  225         struct nm_stat st;
  226         char msg[NM_ERRBUF_SIZE];
  227 };
  228 
  229 /*
  230  * when the descriptor is open correctly, d->self == d
  231  * Eventually we should also use some magic number.
  232  */
  233 #define P2NMD(p)                ((struct nm_desc *)(p))
  234 #define IS_NETMAP_DESC(d)       ((d) && P2NMD(d)->self == P2NMD(d))
  235 #define NETMAP_FD(d)            (P2NMD(d)->fd)
  236 
  237 
  238 /*
  239  * this is a slightly optimized copy routine which rounds
  240  * to multiple of 64 bytes and is often faster than dealing
  241  * with other odd sizes. We assume there is enough room
  242  * in the source and destination buffers.
  243  *
  244  * XXX only for multiples of 64 bytes, non overlapped.
  245  */
  246 static inline void
  247 nm_pkt_copy(const void *_src, void *_dst, int l)
  248 {
  249         const uint64_t *src = (const uint64_t *)_src;
  250         uint64_t *dst = (uint64_t *)_dst;
  251 
  252         if (unlikely(l >= 1024)) {
  253                 memcpy(dst, src, l);
  254                 return;
  255         }
  256         for (; likely(l > 0); l-=64) {
  257                 *dst++ = *src++;
  258                 *dst++ = *src++;
  259                 *dst++ = *src++;
  260                 *dst++ = *src++;
  261                 *dst++ = *src++;
  262                 *dst++ = *src++;
  263                 *dst++ = *src++;
  264                 *dst++ = *src++;
  265         }
  266 }
  267 
  268 
  269 /*
  270  * The callback, invoked on each received packet. Same as libpcap
  271  */
  272 typedef void (*nm_cb_t)(u_char *, const struct nm_pkthdr *, const u_char *d);
  273 
  274 /*
  275  *--- the pcap-like API ---
  276  *
  277  * nm_open() opens a file descriptor, binds to a port and maps memory.
  278  *
  279  * ifname       (netmap:foo or vale:foo) is the port name
  280  *              a suffix can indicate the follwing:
  281  *              ^               bind the host (sw) ring pair
  282  *              *               bind host and NIC ring pairs (transparent)
  283  *              -NN             bind individual NIC ring pair
  284  *              {NN             bind master side of pipe NN
  285  *              }NN             bind slave side of pipe NN
  286  *
  287  * req          provides the initial values of nmreq before parsing ifname.
  288  *              Remember that the ifname parsing will override the ring
  289  *              number in nm_ringid, and part of nm_flags;
  290  * flags        special functions, normally 0
  291  *              indicates which fields of *arg are significant
  292  * arg          special functions, normally NULL
  293  *              if passed a netmap_desc with mem != NULL,
  294  *              use that memory instead of mmap.
  295  */
  296  
  297 static struct nm_desc *nm_open(const char *ifname, const struct nmreq *req,
  298         uint64_t flags, const struct nm_desc *arg);
  299 
  300 /*
  301  * nm_open can import some fields from the parent descriptor.
  302  * These flags control which ones.
  303  * Also in flags you can specify NETMAP_NO_TX_POLL and NETMAP_DO_RX_POLL,
  304  * which set the initial value for these flags.
  305  * Note that the 16 low bits of the flags are reserved for data
  306  * that may go into the nmreq.
  307  */
  308 enum {
  309         NM_OPEN_NO_MMAP =       0x040000, /* reuse mmap from parent */
  310         NM_OPEN_IFNAME =        0x080000, /* nr_name, nr_ringid, nr_flags */
  311         NM_OPEN_ARG1 =          0x100000,
  312         NM_OPEN_ARG2 =          0x200000,
  313         NM_OPEN_ARG3 =          0x400000,
  314         NM_OPEN_RING_CFG =      0x800000, /* tx|rx rings|slots */
  315 };
  316 
  317 
  318 /*
  319  * nm_close()   closes and restores the port to its previous state
  320  */
  321 
  322 static int nm_close(struct nm_desc *);
  323 
  324 /*
  325  * nm_inject() is the same as pcap_inject()
  326  * nm_dispatch() is the same as pcap_dispatch()
  327  * nm_nextpkt() is the same as pcap_next()
  328  */
  329 
  330 static int nm_inject(struct nm_desc *, const void *, size_t);
  331 static int nm_dispatch(struct nm_desc *, int, nm_cb_t, u_char *);
  332 static u_char *nm_nextpkt(struct nm_desc *, struct nm_pkthdr *);
  333 
  334 
  335 /*
  336  * Try to open, return descriptor if successful, NULL otherwise.
  337  * An invalid netmap name will return errno = 0;
  338  * You can pass a pointer to a pre-filled nm_desc to add special
  339  * parameters. Flags is used as follows
  340  * NM_OPEN_NO_MMAP      use the memory from arg, only
  341  *                      if the nr_arg2 (memory block) matches.
  342  * NM_OPEN_ARG1         use req.nr_arg1 from arg
  343  * NM_OPEN_ARG2         use req.nr_arg2 from arg
  344  * NM_OPEN_RING_CFG     user ring config from arg
  345  */
  346 static struct nm_desc *
  347 nm_open(const char *ifname, const struct nmreq *req,
  348         uint64_t new_flags, const struct nm_desc *arg)
  349 {
  350         struct nm_desc *d = NULL;
  351         const struct nm_desc *parent = arg;
  352         u_int namelen;
  353         uint32_t nr_ringid = 0, nr_flags;
  354         const char *port = NULL;
  355         const char *errmsg = NULL;
  356 
  357         if (strncmp(ifname, "netmap:", 7) && strncmp(ifname, "vale", 4)) {
  358                 errno = 0; /* name not recognised, not an error */
  359                 return NULL;
  360         }
  361         if (ifname[0] == 'n')
  362                 ifname += 7;
  363         /* scan for a separator */
  364         for (port = ifname; *port && !index("-*^{}", *port); port++)
  365                 ;
  366         namelen = port - ifname;
  367         if (namelen >= sizeof(d->req.nr_name)) {
  368                 errmsg = "name too long";
  369                 goto fail;
  370         }
  371         switch (*port) {
  372         default:  /* '\0', no suffix */
  373                 nr_flags = NR_REG_ALL_NIC;
  374                 break;
  375         case '-': /* one NIC */
  376                 nr_flags = NR_REG_ONE_NIC;
  377                 nr_ringid = atoi(port + 1);
  378                 break;
  379         case '*': /* NIC and SW, ignore port */
  380                 nr_flags = NR_REG_NIC_SW;
  381                 if (port[1]) {
  382                         errmsg = "invalid port for nic+sw";
  383                         goto fail;
  384                 }
  385                 break;
  386         case '^': /* only sw ring */
  387                 nr_flags = NR_REG_SW;
  388                 if (port[1]) {
  389                         errmsg = "invalid port for sw ring";
  390                         goto fail;
  391                 }
  392                 break;
  393         case '{':
  394                 nr_flags = NR_REG_PIPE_MASTER;
  395                 nr_ringid = atoi(port + 1);
  396                 break;
  397         case '}':
  398                 nr_flags = NR_REG_PIPE_SLAVE;
  399                 nr_ringid = atoi(port + 1);
  400                 break;
  401         }
  402 
  403         if (nr_ringid >= NETMAP_RING_MASK) {
  404                 errmsg = "invalid ringid";
  405                 goto fail;
  406         }
  407         /* add the *XPOLL flags */
  408         nr_ringid |= new_flags & (NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL);
  409 
  410         d = (struct nm_desc *)calloc(1, sizeof(*d));
  411         if (d == NULL) {
  412                 errmsg = "nm_desc alloc failure";
  413                 errno = ENOMEM;
  414                 return NULL;
  415         }
  416         d->self = d;    /* set this early so nm_close() works */
  417         d->fd = open("/dev/netmap", O_RDWR);
  418         if (d->fd < 0) {
  419                 errmsg = "cannot open /dev/netmap";
  420                 goto fail;
  421         }
  422 
  423         if (req)
  424                 d->req = *req;
  425         d->req.nr_version = NETMAP_API;
  426         d->req.nr_ringid &= ~NETMAP_RING_MASK;
  427 
  428         /* these fields are overridden by ifname and flags processing */
  429         d->req.nr_ringid |= nr_ringid;
  430         d->req.nr_flags = nr_flags;
  431         memcpy(d->req.nr_name, ifname, namelen);
  432         d->req.nr_name[namelen] = '\0';
  433         /* optionally import info from parent */
  434         if (IS_NETMAP_DESC(parent) && new_flags) {
  435                 if (new_flags & NM_OPEN_ARG1)
  436                         D("overriding ARG1 %d", parent->req.nr_arg1);
  437                 d->req.nr_arg1 = new_flags & NM_OPEN_ARG1 ?
  438                         parent->req.nr_arg1 : 4;
  439                 if (new_flags & NM_OPEN_ARG2)
  440                         D("overriding ARG2 %d", parent->req.nr_arg2);
  441                 d->req.nr_arg2 = new_flags & NM_OPEN_ARG2 ?
  442                         parent->req.nr_arg2 : 0;
  443                 if (new_flags & NM_OPEN_ARG3)
  444                         D("overriding ARG3 %d", parent->req.nr_arg3);
  445                 d->req.nr_arg3 = new_flags & NM_OPEN_ARG3 ?
  446                         parent->req.nr_arg3 : 0;
  447                 if (new_flags & NM_OPEN_RING_CFG) {
  448                         D("overriding RING_CFG");
  449                         d->req.nr_tx_slots = parent->req.nr_tx_slots;
  450                         d->req.nr_rx_slots = parent->req.nr_rx_slots;
  451                         d->req.nr_tx_rings = parent->req.nr_tx_rings;
  452                         d->req.nr_rx_rings = parent->req.nr_rx_rings;
  453                 }
  454                 if (new_flags & NM_OPEN_IFNAME) {
  455                         D("overriding ifname %s ringid 0x%x flags 0x%x",
  456                                 parent->req.nr_name, parent->req.nr_ringid,
  457                                 parent->req.nr_flags);
  458                         memcpy(d->req.nr_name, parent->req.nr_name,
  459                                 sizeof(d->req.nr_name));
  460                         d->req.nr_ringid = parent->req.nr_ringid;
  461                         d->req.nr_flags = parent->req.nr_flags;
  462                 }
  463         }
  464         if (ioctl(d->fd, NIOCREGIF, &d->req)) {
  465                 errmsg = "NIOCREGIF failed";
  466                 goto fail;
  467         }
  468 
  469         if (IS_NETMAP_DESC(parent) && parent->mem &&
  470             parent->req.nr_arg2 == d->req.nr_arg2) {
  471                 /* do not mmap, inherit from parent */
  472                 d->memsize = parent->memsize;
  473                 d->mem = parent->mem;
  474         } else {
  475                 d->memsize = d->req.nr_memsize;
  476                 d->mem = mmap(0, d->memsize, PROT_WRITE | PROT_READ, MAP_SHARED,
  477                                 d->fd, 0);
  478                 if (d->mem == NULL) {
  479                         errmsg = "mmap failed";
  480                         goto fail;
  481                 }
  482                 d->done_mmap = 1;
  483         }
  484         {
  485                 struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset);
  486                 struct netmap_ring *r = NETMAP_RXRING(nifp, );
  487 
  488                 *(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp;
  489                 *(struct netmap_ring **)(uintptr_t)&d->some_ring = r;
  490                 *(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0);
  491                 *(void **)(uintptr_t)&d->buf_end =
  492                         (char *)d->mem + d->memsize;
  493         }
  494 
  495         if (nr_flags ==  NR_REG_SW) { /* host stack */
  496                 d->first_tx_ring = d->last_tx_ring = d->req.nr_tx_rings;
  497                 d->first_rx_ring = d->last_rx_ring = d->req.nr_rx_rings;
  498         } else if (nr_flags ==  NR_REG_ALL_NIC) { /* only nic */
  499                 d->first_tx_ring = 0;
  500                 d->first_rx_ring = 0;
  501                 d->last_tx_ring = d->req.nr_tx_rings - 1;
  502                 d->last_rx_ring = d->req.nr_rx_rings - 1;
  503         } else if (nr_flags ==  NR_REG_NIC_SW) {
  504                 d->first_tx_ring = 0;
  505                 d->first_rx_ring = 0;
  506                 d->last_tx_ring = d->req.nr_tx_rings;
  507                 d->last_rx_ring = d->req.nr_rx_rings;
  508         } else if (nr_flags == NR_REG_ONE_NIC) {
  509                 /* XXX check validity */
  510                 d->first_tx_ring = d->last_tx_ring =
  511                 d->first_rx_ring = d->last_rx_ring = nr_ringid;
  512         } else { /* pipes */
  513                 d->first_tx_ring = d->last_tx_ring = 0;
  514                 d->first_rx_ring = d->last_rx_ring = 0;
  515         }
  516 
  517 #ifdef DEBUG_NETMAP_USER
  518     { /* debugging code */
  519         int i;
  520 
  521         D("%s tx %d .. %d %d rx %d .. %d %d", ifname,
  522                 d->first_tx_ring, d->last_tx_ring, d->req.nr_tx_rings,
  523                 d->first_rx_ring, d->last_rx_ring, d->req.nr_rx_rings);
  524         for (i = 0; i <= d->req.nr_tx_rings; i++) {
  525                 struct netmap_ring *r = NETMAP_TXRING(d->nifp, i);
  526                 D("TX%d %p h %d c %d t %d", i, r, r->head, r->cur, r->tail);
  527         }
  528         for (i = 0; i <= d->req.nr_rx_rings; i++) {
  529                 struct netmap_ring *r = NETMAP_RXRING(d->nifp, i);
  530                 D("RX%d %p h %d c %d t %d", i, r, r->head, r->cur, r->tail);
  531         }
  532     }
  533 #endif /* debugging */
  534                 
  535         d->cur_tx_ring = d->first_tx_ring;
  536         d->cur_rx_ring = d->first_rx_ring;
  537         return d;
  538 
  539 fail:
  540         nm_close(d);
  541         if (errmsg)
  542                 D("%s %s", errmsg, ifname);
  543         errno = EINVAL;
  544         return NULL;
  545 }
  546 
  547 
  548 static int
  549 nm_close(struct nm_desc *d)
  550 {
  551         /*
  552          * ugly trick to avoid unused warnings
  553          */
  554         static void *__xxzt[] __attribute__ ((unused))  =
  555                 { (void *)nm_open, (void *)nm_inject,
  556                   (void *)nm_dispatch, (void *)nm_nextpkt } ;
  557 
  558         if (d == NULL || d->self != d)
  559                 return EINVAL;
  560         if (d->done_mmap && d->mem)
  561                 munmap(d->mem, d->memsize);
  562         if (d->fd != -1)
  563                 close(d->fd);
  564         bzero(d, sizeof(*d));
  565         free(d);
  566         return 0;
  567 }
  568 
  569 
  570 /*
  571  * Same prototype as pcap_inject(), only need to cast.
  572  */
  573 static int
  574 nm_inject(struct nm_desc *d, const void *buf, size_t size)
  575 {
  576         u_int c, n = d->last_tx_ring - d->first_tx_ring + 1;
  577 
  578         for (c = 0; c < n ; c++) {
  579                 /* compute current ring to use */
  580                 struct netmap_ring *ring;
  581                 uint32_t i, idx;
  582                 uint32_t ri = d->cur_tx_ring + c;
  583 
  584                 if (ri > d->last_tx_ring)
  585                         ri = d->first_tx_ring;
  586                 ring = NETMAP_TXRING(d->nifp, ri);
  587                 if (nm_ring_empty(ring)) {
  588                         continue;
  589                 }
  590                 i = ring->cur;
  591                 idx = ring->slot[i].buf_idx;
  592                 ring->slot[i].len = size;
  593                 nm_pkt_copy(buf, NETMAP_BUF(ring, idx), size);
  594                 d->cur_tx_ring = ri;
  595                 ring->head = ring->cur = nm_ring_next(ring, i);
  596                 return size;
  597         }
  598         return 0; /* fail */
  599 }
  600 
  601 
  602 /*
  603  * Same prototype as pcap_dispatch(), only need to cast.
  604  */
  605 static int
  606 nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg)
  607 {
  608         int n = d->last_rx_ring - d->first_rx_ring + 1;
  609         int c, got = 0, ri = d->cur_rx_ring;
  610 
  611         if (cnt == 0)
  612                 cnt = -1;
  613         /* cnt == -1 means infinite, but rings have a finite amount
  614          * of buffers and the int is large enough that we never wrap,
  615          * so we can omit checking for -1
  616          */
  617         for (c=0; c < n && cnt != got; c++) {
  618                 /* compute current ring to use */
  619                 struct netmap_ring *ring;
  620 
  621                 ri = d->cur_rx_ring + c;
  622                 if (ri > d->last_rx_ring)
  623                         ri = d->first_rx_ring;
  624                 ring = NETMAP_RXRING(d->nifp, ri);
  625                 for ( ; !nm_ring_empty(ring) && cnt != got; got++) {
  626                         u_int i = ring->cur;
  627                         u_int idx = ring->slot[i].buf_idx;
  628                         u_char *buf = (u_char *)NETMAP_BUF(ring, idx);
  629 
  630                         // __builtin_prefetch(buf);
  631                         d->hdr.len = d->hdr.caplen = ring->slot[i].len;
  632                         d->hdr.ts = ring->ts;
  633                         cb(arg, &d->hdr, buf);
  634                         ring->head = ring->cur = nm_ring_next(ring, i);
  635                 }
  636         }
  637         d->cur_rx_ring = ri;
  638         return got;
  639 }
  640 
  641 static u_char *
  642 nm_nextpkt(struct nm_desc *d, struct nm_pkthdr *hdr)
  643 {
  644         int ri = d->cur_rx_ring;
  645 
  646         do {
  647                 /* compute current ring to use */
  648                 struct netmap_ring *ring = NETMAP_RXRING(d->nifp, ri);
  649                 if (!nm_ring_empty(ring)) {
  650                         u_int i = ring->cur;
  651                         u_int idx = ring->slot[i].buf_idx;
  652                         u_char *buf = (u_char *)NETMAP_BUF(ring, idx);
  653 
  654                         // __builtin_prefetch(buf);
  655                         hdr->ts = ring->ts;
  656                         hdr->len = hdr->caplen = ring->slot[i].len;
  657                         ring->cur = nm_ring_next(ring, i);
  658                         /* we could postpone advancing head if we want
  659                          * to hold the buffer. This can be supported in
  660                          * the future.
  661                          */
  662                         ring->head = ring->cur;
  663                         d->cur_rx_ring = ri;
  664                         return buf;
  665                 }
  666                 ri++;
  667                 if (ri > d->last_rx_ring)
  668                         ri = d->first_rx_ring;
  669         } while (ri != d->cur_rx_ring);
  670         return NULL; /* nothing found */
  671 }
  672 
  673 #endif /* !HAVE_NETMAP_WITH_LIBS */
  674 
  675 #endif /* NETMAP_WITH_LIBS */
  676 
  677 #endif /* _NET_NETMAP_USER_H_ */

Cache object: 912ef72b0a449bc0961f506fd30618f1


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.