git: c30251c44fb3 - main - net/daq: improve netmap support

Brad Davis brd at FreeBSD.org
Thu Jun 10 22:22:26 UTC 2021


The branch main has been updated by brd (doc, src committer):

URL: https://cgit.FreeBSD.org/ports/commit/?id=c30251c44fb345a54b56ebdd9c482071306e5eff

commit c30251c44fb345a54b56ebdd9c482071306e5eff
Author:     Bill Meeks <bmeeks8 at bellsouth.net>
AuthorDate: 2019-05-29 21:04:41 +0000
Commit:     Brad Davis <brd at FreeBSD.org>
CommitDate: 2021-06-10 21:41:44 +0000

    net/daq: improve netmap support
    
    Cherry-pick c0c4b55 from pfsense/FreeBSD-ports:
       Add host stack OS endpoint support for netmap module.
    
    Cherry-pick 52b6dea from pfsense/FreeBSD-ports:
       Support host stack interfaces with netmap and NETMAP_API versions 13 and 14.
    
    Cherry-pick 6914d3a from pfsense/FreeBSD-ports:
       Backport NS_MOREFRAG bug fix from netmap upstream demo app code.
    
    Approved by:    zi (maintainer)
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
---
 net/daq/Makefile                      |   2 +-
 net/daq/files/patch-daq22-netmap.diff | 505 ++++++++++++++++++++++++++++++++++
 2 files changed, 506 insertions(+), 1 deletion(-)

diff --git a/net/daq/Makefile b/net/daq/Makefile
index 28d8429e0e7d..81fe1f408578 100644
--- a/net/daq/Makefile
+++ b/net/daq/Makefile
@@ -2,7 +2,7 @@
 
 PORTNAME=	daq
 PORTVERSION=	2.2.2
-PORTREVISION=	0
+PORTREVISION=	3
 CATEGORIES=	net
 MASTER_SITES=	https://snort.org/downloads/snortplus/ \
 		ZI
diff --git a/net/daq/files/patch-daq22-netmap.diff b/net/daq/files/patch-daq22-netmap.diff
new file mode 100644
index 000000000000..36e0e2c59f9a
--- /dev/null
+++ b/net/daq/files/patch-daq22-netmap.diff
@@ -0,0 +1,505 @@
+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 <mialtize at cisco.com>
++** Author: Bill Meeks <billmeeks8 at gmail.com>
+ **
+ ** 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 <sfbpf_dlt.h>
+ 
+ #include <net/netmap.h>
++#if NETMAP_API < 14
++#define NETMAP_WITH_LIBS
++#endif 
+ #include <net/netmap_user.h>
+ 
+ #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;
+     }
+ 


More information about the dev-commits-ports-main mailing list