diff -ruN ./daq-2.2.2.orig/os-daq-modules/daq_netmap.c ./daq-2.2.2/os-daq-modules/daq_netmap.c --- ./daq-2.2.2.orig/os-daq-modules/daq_netmap.c 2017-02-08 17:04:18.000000000 -0500 +++ ./os-daq-modules/daq_netmap.c 2020-09-15 09:35:07.000000000 -0400 @@ -1,6 +1,7 @@ /* -** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. +** Copyright (C) 2021 Cisco and/or its affiliates. All rights reserved. ** Author: Michael R. Altizer +** Author: Bill Meeks ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as @@ -37,6 +38,9 @@ #include #include +#if NETMAP_API < 14 +#define NETMAP_WITH_LIBS +#endif #include #define DAQ_NETMAP_VERSION 3 @@ -44,12 +48,6 @@ /* Hi! I'm completely arbitrary! */ #define NETMAP_MAX_INTERFACES 32 -/* FreeBSD 10.0 uses an old version of netmap, so work around it accordingly. */ -#if NETMAP_API < 10 -#define nm_ring_next(r, i) NETMAP_RING_NEXT(r, i) -#define nm_ring_empty(r) ((r)->avail == 0) -#endif - typedef struct _netmap_instance { struct _netmap_instance *next; @@ -59,6 +57,10 @@ #define NMINST_TX_BLOCKED 0x2 uint32_t flags; int index; + int done_mmap; + unsigned long long fwd_tx_blocked; + /* Netmap port name with suffix */ + char nm_port_name[IFNAMSIZ + 1]; struct netmap_if *nifp; /* TX ring info */ uint16_t first_tx_ring; @@ -71,8 +73,15 @@ /* MMAP'd memory */ void *mem; uint32_t memsize; - struct nmreq req; - unsigned long long fwd_tx_blocked; + /* Use netmap API version-specific structures */ +#if NETMAP_API >= 14 + /* Newer netmap Header and Request structures */ + struct nmreq_header hdr; + struct nmreq_register reg; +#else + /* Netmap descriptor structure */ + struct nm_desc *ndesc; +#endif } NetmapInstance; typedef struct _netmap_context @@ -109,6 +118,7 @@ { if (instance) { +#if NETMAP_API >= 14 /* Unmap the packet memory region. If we had a peer, notify them that the shared mapping has been freed and that we no longer exist. */ if (instance->mem) @@ -124,6 +134,24 @@ instance->peer->peer = NULL; if (instance->fd != -1) close(instance->fd); +#else + /* Check for an active peer. */ + if (instance->peer) + { + /* Close our peer's netmap connection first. */ + if (instance->peer->ndesc != NULL) + { + nm_close(instance->peer->ndesc); + instance->peer->ndesc = NULL; + instance->peer->peer = NULL; + instance->peer->done_mmap = 0; + } + } + + /* Now close our netmap connection if open. */ + if (instance->ndesc != NULL) + nm_close(instance->ndesc); +#endif free(instance); } } @@ -142,7 +170,7 @@ if (nmc->debug) { printf("Netmap instance %s (%d) blocked %llu times on TX while forwarding.\n", - instance->req.nr_name, instance->index, instance->fwd_tx_blocked); + instance->nm_port_name, instance->index, instance->fwd_tx_blocked); } destroy_instance(instance); } @@ -157,14 +185,18 @@ static NetmapInstance *create_instance(const char *device, NetmapInstance *parent, char *errbuf, size_t errlen) { NetmapInstance *instance; - struct nmreq *req; +#if NETMAP_API >= 14 + char *suffix = NULL; + char intf[IFNAMSIZ + 1]; + uint32_t nr_mode = NR_REG_ALL_NIC; +#endif static int index = 0; instance = calloc(1, sizeof(NetmapInstance)); if (!instance) { snprintf(errbuf, errlen, "%s: Could not allocate a new instance structure.", __func__); - goto err; + return NULL; } /* Initialize the instance, including an arbitrary and unique device index. */ @@ -172,29 +204,45 @@ instance->index = index; index++; + /* Initialize the netmap port name. */ + strncpy(instance->nm_port_name, device, sizeof(instance->nm_port_name)); + +#if NETMAP_API >= 14 /* Open /dev/netmap for communications to the driver. */ instance->fd = open("/dev/netmap", O_RDWR); if (instance->fd < 0) { snprintf(errbuf, errlen, "%s: Could not open /dev/netmap: %s (%d)", __func__, strerror(errno), errno); - goto err; + destroy_instance(instance); + return NULL; } - /* Initialize the netmap request object. */ - req = &instance->req; - strncpy(req->nr_name, device, sizeof(req->nr_name)); - req->nr_version = NETMAP_API; - req->nr_ringid = 0; -#if NETMAP_API >= 11 - req->nr_flags = NR_REG_ALL_NIC; + /* Check for suffix to see if this is a Host Stack interface spec. */ + suffix = strchr(device, '^'); + if (suffix != NULL) + { + /* Omit the trailing '^' suffix from the interface name we send netmap. */ + snprintf(intf, strcspn(device, "^") + 1, "%s", device); + nr_mode = NR_REG_SW; + } + else + { + strncpy(intf, device, sizeof(intf)); + nr_mode = NR_REG_ALL_NIC; + } + + /* Initialize the netmap header object for the instance. */ + instance->hdr.nr_version = NETMAP_API; + instance->hdr.nr_reqtype = NETMAP_REQ_REGISTER; + strncpy(instance->hdr.nr_name, intf, sizeof(instance->hdr.nr_name)); + instance->hdr.nr_body = (uintptr_t)&instance->reg; + + /* Initialize the netmap register object for the instance. */ + instance->reg.nr_mode = nr_mode; #endif return instance; - -err: - destroy_instance(instance); - return NULL; } static int create_bridge(Netmap_Context_t *nmc, const char *device_name1, const char *device_name2) @@ -204,9 +252,9 @@ peer1 = peer2 = NULL; for (instance = nmc->instances; instance; instance = instance->next) { - if (!strcmp(instance->req.nr_name, device_name1)) + if (!strcmp(instance->nm_port_name, device_name1)) peer1 = instance; - else if (!strcmp(instance->req.nr_name, device_name2)) + else if (!strcmp(instance->nm_port_name, device_name2)) peer2 = instance; } @@ -221,10 +269,13 @@ static int start_instance(Netmap_Context_t *nmc, NetmapInstance *instance) { - if (ioctl(instance->fd, NIOCREGIF, &instance->req)) +#if NETMAP_API >= 14 + u_int i, num_tx, num_rx; + + if (ioctl(instance->fd, NIOCCTRL, &instance->hdr)) { DPE(nmc->errbuf, "%s: Netmap registration for %s failed: %s (%d)", - __func__, instance->req.nr_name, strerror(errno), errno); + __func__, instance->nm_port_name, strerror(errno), errno); return DAQ_ERROR; } @@ -236,32 +287,96 @@ } else { - instance->memsize = instance->req.nr_memsize; + instance->memsize = instance->reg.nr_memsize; instance->mem = mmap(0, instance->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, instance->fd, 0); if (instance->mem == MAP_FAILED) { DPE(nmc->errbuf, "%s: Could not MMAP the buffer memory region for %s: %s (%d)", - __func__, instance->req.nr_name, strerror(errno), errno); + __func__, instance->nm_port_name, strerror(errno), errno); return DAQ_ERROR; } } - instance->nifp = NETMAP_IF(instance->mem, instance->req.nr_offset); + /* Calculate and set first and last TX and RX rings for this instance. */ + instance->nifp = NETMAP_IF(instance->mem, instance->reg.nr_offset); + + num_tx = instance->nifp->ni_tx_rings + instance->nifp->ni_host_tx_rings; + for (i = 0; i < num_tx && !instance->nifp->ring_ofs[i]; i++) + ; + instance->first_tx_ring = i; + instance->cur_tx_ring = i; - instance->first_tx_ring = 0; - instance->first_rx_ring = 0; - instance->last_tx_ring = instance->req.nr_tx_rings - 1; - instance->last_rx_ring = instance->req.nr_rx_rings - 1; + for ( ; i < num_tx && instance->nifp->ring_ofs[i]; i++) + ; + instance->last_tx_ring = i - 1; + num_rx = instance->nifp->ni_rx_rings + instance->nifp->ni_host_rx_rings; + for (i = 0; i < num_rx && !instance->nifp->ring_ofs[i + num_tx]; i++) + ; + instance->first_rx_ring = i; + instance->cur_rx_ring = i; + + for ( ; i < num_rx && instance->nifp->ring_ofs[i + num_tx]; i++) + ; + instance->last_rx_ring = i - 1; + +#else + char nm_port[IFNAMSIZ + 9]; + + /* Create the proper netmap port name spec. */ + snprintf(nm_port, sizeof(nm_port), "netmap:%s", instance->nm_port_name); + + /* Only mmap the packet memory region for the first interface in a pair. */ + if (instance->peer && instance->peer->done_mmap) + { + if ((instance->ndesc = nm_open(nm_port, NULL, NM_OPEN_NO_MMAP, instance->peer->ndesc)) == NULL) + { + DPE(nmc->errbuf, "%s: Netmap registration for port %s failed: %s (%d)", + __func__, instance->nm_port_name, strerror(errno), errno); + return DAQ_ERROR; + } + } + else + { + if ((instance->ndesc = nm_open(nm_port, NULL, 0, NULL)) == NULL) + { + DPE(nmc->errbuf, "%s: Netmap registration for port %s failed: %s (%d)", + __func__, instance->nm_port_name, strerror(errno), errno); + return DAQ_ERROR; + } + instance->done_mmap = instance->ndesc->done_mmap; + } + + /* Copy important netmap parameters to our local instance variables. */ + instance->fd = instance->ndesc->fd; + instance->nifp = instance->ndesc->nifp; + instance->mem = instance->ndesc->mem; + instance->memsize = instance->ndesc->memsize; + instance->first_tx_ring = instance->ndesc->first_tx_ring; + instance->last_tx_ring = instance->ndesc->last_tx_ring; + instance->cur_tx_ring = instance->ndesc->cur_tx_ring; + instance->first_rx_ring = instance->ndesc->first_rx_ring; + instance->last_rx_ring = instance->ndesc->last_rx_ring; + instance->cur_rx_ring = instance->ndesc->cur_rx_ring; +#endif + if (nmc->debug) { struct netmap_ring *ring; int i; - printf("[%s]\n", instance->req.nr_name); - printf(" nr_tx_slots: %u\n", instance->req.nr_tx_slots); - printf(" nr_rx_slots: %u\n", instance->req.nr_rx_slots); - printf(" nr_tx_rings: %hu\n", instance->req.nr_tx_rings); + printf("[%s]\n", instance->nm_port_name); +#if NETMAP_API >= 14 + printf(" nr_tx_slots: %u\n", instance->reg.nr_tx_slots); + printf(" nr_rx_slots: %u\n", instance->reg.nr_rx_slots); + printf(" nr_tx_rings: %hu\n", instance->reg.nr_tx_rings); + printf(" nr_host_tx_rings: %hu\n", instance->reg.nr_host_tx_rings); +#else + printf(" nr_tx_slots: %u\n", instance->ndesc->req.nr_tx_slots); + printf(" nr_rx_slots: %u\n", instance->ndesc->req.nr_rx_slots); + printf(" nr_tx_rings: %hu\n", instance->ndesc->req.nr_tx_rings); +#endif + for (i = instance->first_tx_ring; i <= instance->last_tx_ring; i++) { ring = NETMAP_TXRING(instance->nifp, i); @@ -271,7 +386,13 @@ printf(" nr_buf_size = %u\n", ring->nr_buf_size); printf(" flags = 0x%x\n", ring->flags); } - printf(" nr_rx_rings: %hu\n", instance->req.nr_rx_rings); + +#if NETMAP_API >= 14 + printf(" nr_rx_rings: %hu\n", instance->reg.nr_rx_rings); + printf(" nr_host_rx_rings: %hu\n", instance->reg.nr_host_rx_rings); +#else + printf(" nr_rx_rings: %hu\n", instance->ndesc->req.nr_rx_rings); +#endif for (i = instance->first_rx_ring; i <= instance->last_rx_ring; i++) { ring = NETMAP_RXRING(instance->nifp, i); @@ -293,11 +414,17 @@ Netmap_Context_t *nmc; NetmapInstance *instance; DAQ_Dict *entry; - char intf[IFNAMSIZ]; + char intf[IFNAMSIZ + 1]; uint32_t num_intfs = 0; size_t len; char *name1, *name2, *dev; int rval = DAQ_ERROR; +#if NETMAP_API >= 14 + int fd; + NetmapInstance *host_peer; + struct nmreq_header hdr; + struct nmreq_port_info_get nm_info; +#endif nmc = calloc(1, sizeof(Netmap_Context_t)); if (!nmc) @@ -343,6 +470,7 @@ __func__, NETMAP_MAX_INTERFACES); goto err; } + snprintf(intf, len + 1, "%s", dev); instance = create_instance(intf, nmc->instances, errbuf, errlen); if (!instance) @@ -355,8 +483,8 @@ { if (num_intfs == 2) { - name1 = nmc->instances->next->req.nr_name; - name2 = nmc->instances->req.nr_name; + name1 = nmc->instances->next->nm_port_name; + name2 = nmc->instances->nm_port_name; if (create_bridge(nmc, name1, name2) != DAQ_SUCCESS) { @@ -364,6 +492,51 @@ __func__, name1, name2); goto err; } + +#if NETMAP_API >= 14 + /* Prepare netmap header object to query interface for number of HW rings. */ + memset(&hdr, 0, sizeof(hdr)); + memset(&nm_info, 0, sizeof(nm_info)); + host_peer = NULL; + hdr.nr_version = NETMAP_API; + hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET; + hdr.nr_body = (uintptr_t)&nm_info; + + /* Find the NIC side of the bridge pair and query it for number of HW rings. + Then set the requested number of Host Rings on the SW Host Stack peer + (if present) to match the available HW rings. */ + if (nmc->instances->reg.nr_mode == NR_REG_ALL_NIC && nmc->instances->next->reg.nr_mode == NR_REG_SW) + { + fd = nmc->instances->fd; + strncpy(hdr.nr_name, nmc->instances->hdr.nr_name, sizeof(hdr.nr_name)); + host_peer = nmc->instances->next; + } + + if (nmc->instances->next->reg.nr_mode == NR_REG_ALL_NIC && nmc->instances->reg.nr_mode == NR_REG_SW) + { + fd = nmc->instances->next->fd; + strncpy(hdr.nr_name, nmc->instances->next->hdr.nr_name, sizeof(hdr.nr_name)); + host_peer = nmc->instances; + } + + /* Did we find a HW NIC and SW Host Stack peer pair? + If not, skip requesting the SW Host Stack rings. */ + if(host_peer) + { + /* Query the HW NIC netmap device for the number of TX and RX rings. */ + if (ioctl(fd, NIOCCTRL, &hdr)) + { + DPE(nmc->errbuf, "%s: Netmap NETMAP_REQ_PORT_INFO_GET for %s failed: %s (%d). Will run with default single pair of Host Rings.", + __func__, hdr.nr_name, strerror(errno), errno); + } + else + { + /* Set the Host Stack peer to request a matching number of Host Tx,Rx rings. */ + host_peer->reg.nr_host_tx_rings = nm_info.nr_tx_rings; + host_peer->reg.nr_host_rx_rings = nm_info.nr_rx_rings; + } + } +#endif num_intfs = 0; } else if (num_intfs > 2) @@ -569,6 +742,7 @@ nminst_inc_tx_ring(peer); if (nm_ring_empty(tx_ring)) continue; + /* Swap the RX buffer we want to forward with the next unused buffer in the peer's TX ring. */ tx_cur = tx_ring->cur; @@ -577,16 +751,16 @@ tx_slot->len = len; tx_slot->buf_idx = rx_slot->buf_idx; rx_slot->buf_idx = tx_buf_idx; + /* Report the buffer change. */ tx_slot->flags |= NS_BUF_CHANGED; rx_slot->flags |= NS_BUF_CHANGED; + /* copy the NS_MOREFRAG */ + tx_slot->flags = (tx_slot->flags & ~NS_MOREFRAG) | (rx_slot->flags & NS_MOREFRAG); + tx_ring->cur = nm_ring_next(tx_ring, tx_cur); -#if NETMAP_API >= 10 tx_ring->head = tx_ring->cur; -#else - tx_ring->avail--; -#endif sent = 1; } while (peer->cur_tx_ring != start_tx_ring && !sent); @@ -604,11 +778,7 @@ } rx_ring->cur = nm_ring_next(rx_ring, rx_cur); -#if NETMAP_API >= 10 rx_ring->head = rx_ring->cur; -#else - rx_ring->avail--; -#endif /* Increment the current RX ring pointer on successfully completed processing. */ nminst_inc_rx_ring(instance); @@ -644,7 +814,7 @@ /* If the poll times out, return control to the caller. */ if (ret == 0) break; - /* If some number of of sockets have events returned, check them all for badness. */ + /* If some number of sockets have events returned, check them all for badness. */ if (ret > 0) { for (i = 0; i < nmc->intf_count; i++) @@ -715,18 +885,14 @@ memcpy(NETMAP_BUF(tx_ring, tx_buf_idx), packet_data, len); tx_ring->cur = nm_ring_next(tx_ring, tx_cur); -#if NETMAP_API >= 10 tx_ring->head = tx_ring->cur; -#else - tx_ring->avail--; -#endif nmc->stats.packets_injected++; return DAQ_SUCCESS; } while (instance->cur_tx_ring != start_tx_ring); /* If we got here, it means we couldn't find an available TX slot, so tell the user to try again. */ - DPE(nmc->errbuf, "%s: Could not find an available TX slot. Try again.", __func__); + DPE(nmc->errbuf, "%s: Could not find an available TX slot for interface %s. Try again.", __func__, instance->nm_port_name); return DAQ_ERROR_AGAIN; } @@ -826,7 +992,7 @@ for (instance = nmc->instances; instance; instance = instance->next) { - if (!strcmp(device, instance->req.nr_name)) + if (!strcmp(device, instance->nm_port_name)) return instance->index; }