Author: vmaffione
Date: Thu Dec 13 10:13:29 2018
New Revision: 342033
URL: https://svnweb.freebsd.org/changeset/base/342033

Log:
  MFC r341516, r341589
  
  netmap: align codebase to the current upstream (760279cfb2730a585)
  
  Changelist:
    - Replace netmap passthrough host support with a more general
      mechanism to call TXSYNC/RXSYNC from an in-kernel event-loop.
      No kernel threads are used to use this feature: the application
      is required to spawn a thread (or a process) and issue a
      SYNC_KLOOP_START (NIOCCTRL) command in the thread body. The
      kernel loop is executed by the ioctl implementation, which returns
      to userspace only when a different thread calls SYNC_KLOOP_STOP
      or the netmap file descriptor is closed.
    - Update the if_ptnet driver to cope with the new data structures,
      and prune all the obsolete ptnetmap code.
    - Add support for "null" netmap ports, useful to allocate netmap_if,
      netmap_ring and netmap buffers to be used by specialized applications
      (e.g. hypervisors). TXSYNC/RXSYNC on these ports have no effect.
    - Various fixes and code refactoring.
  
  Sponsored by:   Sunny Valley Networks
  Differential Revision:  https://reviews.freebsd.org/D18015

Added:
  stable/11/sys/dev/netmap/netmap_kloop.c
     - copied unchanged from r341815, stable/12/sys/dev/netmap/netmap_kloop.c
  stable/11/sys/dev/netmap/netmap_null.c
     - copied unchanged from r341815, stable/12/sys/dev/netmap/netmap_null.c
Modified:
  stable/11/sys/conf/files
  stable/11/sys/dev/netmap/if_ixl_netmap.h
  stable/11/sys/dev/netmap/if_vtnet_netmap.h
  stable/11/sys/dev/netmap/netmap.c
  stable/11/sys/dev/netmap/netmap_bdg.c
  stable/11/sys/dev/netmap/netmap_bdg.h
  stable/11/sys/dev/netmap/netmap_freebsd.c
  stable/11/sys/dev/netmap/netmap_generic.c
  stable/11/sys/dev/netmap/netmap_kern.h
  stable/11/sys/dev/netmap/netmap_legacy.c
  stable/11/sys/dev/netmap/netmap_mem2.c
  stable/11/sys/dev/netmap/netmap_mem2.h
  stable/11/sys/dev/netmap/netmap_pipe.c
  stable/11/sys/dev/netmap/netmap_vale.c
  stable/11/sys/modules/netmap/Makefile
  stable/11/sys/net/netmap.h
  stable/11/sys/net/netmap_user.h
  stable/11/sys/net/netmap_virt.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/conf/files
==============================================================================
--- stable/11/sys/conf/files    Thu Dec 13 09:40:06 2018        (r342032)
+++ stable/11/sys/conf/files    Thu Dec 13 10:13:29 2018        (r342033)
@@ -2469,17 +2469,19 @@ dev/ncr/ncr.c                   optional ncr pci
 dev/ncv/ncr53c500.c            optional ncv
 dev/ncv/ncr53c500_pccard.c     optional ncv pccard
 dev/netmap/netmap.c            optional netmap
+dev/netmap/netmap_bdg.c                optional netmap
 dev/netmap/netmap_freebsd.c    optional netmap
 dev/netmap/netmap_generic.c    optional netmap
+dev/netmap/netmap_kloop.c      optional netmap
+dev/netmap/netmap_legacy.c     optional netmap
 dev/netmap/netmap_mbq.c                optional netmap
 dev/netmap/netmap_mem2.c       optional netmap
 dev/netmap/netmap_monitor.c    optional netmap
+dev/netmap/netmap_null.c       optional netmap
 dev/netmap/netmap_offloadings.c        optional netmap
 dev/netmap/netmap_pipe.c       optional netmap
 dev/netmap/netmap_pt.c         optional netmap
 dev/netmap/netmap_vale.c       optional netmap
-dev/netmap/netmap_legacy.c     optional netmap
-dev/netmap/netmap_bdg.c                optional netmap
 # compile-with "${NORMAL_C} -Wconversion -Wextra"
 dev/nfsmb/nfsmb.c              optional nfsmb pci
 dev/nge/if_nge.c               optional nge

Modified: stable/11/sys/dev/netmap/if_ixl_netmap.h
==============================================================================
--- stable/11/sys/dev/netmap/if_ixl_netmap.h    Thu Dec 13 09:40:06 2018        
(r342032)
+++ stable/11/sys/dev/netmap/if_ixl_netmap.h    Thu Dec 13 10:13:29 2018        
(r342033)
@@ -130,7 +130,7 @@ ixl_netmap_attach(struct ixl_vsi *vsi)
        na.ifp = vsi->ifp;
        na.na_flags = NAF_BDG_MAYSLEEP;
        // XXX check that queues is set.
-       nm_prinf("queues is %p\n", vsi->queues);
+       nm_prinf("queues is %p", vsi->queues);
        if (vsi->queues) {
                na.num_tx_desc = vsi->queues[0].num_desc;
                na.num_rx_desc = vsi->queues[0].num_desc;

Modified: stable/11/sys/dev/netmap/if_vtnet_netmap.h
==============================================================================
--- stable/11/sys/dev/netmap/if_vtnet_netmap.h  Thu Dec 13 09:40:06 2018        
(r342032)
+++ stable/11/sys/dev/netmap/if_vtnet_netmap.h  Thu Dec 13 10:13:29 2018        
(r342033)
@@ -79,7 +79,7 @@ vtnet_free_used(struct virtqueue *vq, int netmap_bufs,
        }
 
        if (deq)
-               nm_prinf("%d sgs dequeued from %s-%d (netmap=%d)\n",
+               nm_prinf("%d sgs dequeued from %s-%d (netmap=%d)",
                         deq, nm_txrx2str(t), idx, netmap_bufs);
 }
 
@@ -230,7 +230,7 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int fl
                                                /*writeable=*/0);
                        if (unlikely(err)) {
                                if (err != ENOSPC)
-                                       nm_prerr("virtqueue_enqueue(%s) failed: 
%d\n",
+                                       nm_prerr("virtqueue_enqueue(%s) failed: 
%d",
                                                        kring->name, err);
                                break;
                        }
@@ -251,7 +251,7 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int fl
                if (token == NULL)
                        break;
                if (unlikely(token != (void *)txq))
-                       nm_prerr("BUG: TX token mismatch\n");
+                       nm_prerr("BUG: TX token mismatch");
                else
                        n++;
        }
@@ -307,7 +307,7 @@ vtnet_netmap_kring_refill(struct netmap_kring *kring, 
                                /*readable=*/0, /*writeable=*/sg.sg_nseg);
                if (unlikely(err)) {
                        if (err != ENOSPC)
-                               nm_prerr("virtqueue_enqueue(%s) failed: %d\n",
+                               nm_prerr("virtqueue_enqueue(%s) failed: %d",
                                        kring->name, err);
                        break;
                }
@@ -391,7 +391,7 @@ vtnet_netmap_rxsync(struct netmap_kring *kring, int fl
                                break;
                        }
                        if (unlikely(token != (void *)rxq)) {
-                               nm_prerr("BUG: RX token mismatch\n");
+                               nm_prerr("BUG: RX token mismatch");
                        } else {
                                /* Skip the virtio-net header. */
                                len -= sc->vtnet_hdr_size;
@@ -533,7 +533,7 @@ vtnet_netmap_attach(struct vtnet_softc *sc)
 
        netmap_attach(&na);
 
-       nm_prinf("vtnet attached txq=%d, txd=%d rxq=%d, rxd=%d\n",
+       nm_prinf("vtnet attached txq=%d, txd=%d rxq=%d, rxd=%d",
                        na.num_tx_rings, na.num_tx_desc,
                        na.num_tx_rings, na.num_rx_desc);
 }

Modified: stable/11/sys/dev/netmap/netmap.c
==============================================================================
--- stable/11/sys/dev/netmap/netmap.c   Thu Dec 13 09:40:06 2018        
(r342032)
+++ stable/11/sys/dev/netmap/netmap.c   Thu Dec 13 10:13:29 2018        
(r342033)
@@ -478,6 +478,9 @@ ports attached to the switch)
 
 /* user-controlled variables */
 int netmap_verbose;
+#ifdef CONFIG_NETMAP_DEBUG
+int netmap_debug;
+#endif /* CONFIG_NETMAP_DEBUG */
 
 static int netmap_no_timestamp; /* don't timestamp on rxsync */
 int netmap_mitigate = 1;
@@ -526,9 +529,6 @@ int netmap_generic_hwcsum = 0;
 /* Non-zero if ptnet devices are allowed to use virtio-net headers. */
 int ptnet_vnet_hdr = 1;
 
-/* 0 if ptnetmap should not use worker threads for TX processing */
-int ptnetmap_tx_workers = 1;
-
 /*
  * SYSCTL calls are grouped between SYSBEGIN and SYSEND to be emulated
  * in some other operating systems
@@ -539,6 +539,10 @@ SYSCTL_DECL(_dev_netmap);
 SYSCTL_NODE(_dev, OID_AUTO, netmap, CTLFLAG_RW, 0, "Netmap args");
 SYSCTL_INT(_dev_netmap, OID_AUTO, verbose,
                CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode");
+#ifdef CONFIG_NETMAP_DEBUG
+SYSCTL_INT(_dev_netmap, OID_AUTO, debug,
+               CTLFLAG_RW, &netmap_debug, 0, "Debug messages");
+#endif /* CONFIG_NETMAP_DEBUG */
 SYSCTL_INT(_dev_netmap, OID_AUTO, no_timestamp,
                CTLFLAG_RW, &netmap_no_timestamp, 0, "no_timestamp");
 SYSCTL_INT(_dev_netmap, OID_AUTO, no_pendintr, CTLFLAG_RW, &netmap_no_pendintr,
@@ -570,8 +574,6 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, generic_txqdisc, CTL
 #endif
 SYSCTL_INT(_dev_netmap, OID_AUTO, ptnet_vnet_hdr, CTLFLAG_RW, &ptnet_vnet_hdr,
                0, "Allow ptnet devices to use virtio-net headers");
-SYSCTL_INT(_dev_netmap, OID_AUTO, ptnetmap_tx_workers, CTLFLAG_RW,
-               &ptnetmap_tx_workers, 0, "Use worker threads for pnetmap TX 
processing");
 
 SYSEND;
 
@@ -693,7 +695,7 @@ nm_bound_var(u_int *v, u_int dflt, u_int lo, u_int hi,
                op = "Clamp";
        }
        if (op && msg)
-               nm_prinf("%s %s to %d (was %d)\n", op, msg, *v, oldv);
+               nm_prinf("%s %s to %d (was %d)", op, msg, *v, oldv);
        return *v;
 }
 
@@ -777,13 +779,14 @@ netmap_update_config(struct netmap_adapter *na)
                na->num_rx_rings = info.num_rx_rings;
                na->num_rx_desc = info.num_rx_descs;
                na->rx_buf_maxsize = info.rx_buf_maxsize;
-               D("configuration changed for %s: txring %d x %d, "
-                       "rxring %d x %d, rxbufsz %d",
-                       na->name, na->num_tx_rings, na->num_tx_desc,
-                       na->num_rx_rings, na->num_rx_desc, na->rx_buf_maxsize);
+               if (netmap_verbose)
+                       nm_prinf("configuration changed for %s: txring %d x %d, 
"
+                               "rxring %d x %d, rxbufsz %d",
+                               na->name, na->num_tx_rings, na->num_tx_desc,
+                               na->num_rx_rings, na->num_rx_desc, 
na->rx_buf_maxsize);
                return 0;
        }
-       D("WARNING: configuration changed for %s while active: "
+       nm_prerr("WARNING: configuration changed for %s while active: "
                "txring %d x %d, rxring %d x %d, rxbufsz %d",
                na->name, info.num_tx_rings, info.num_tx_descs,
                info.num_rx_rings, info.num_rx_descs,
@@ -829,7 +832,8 @@ netmap_krings_create(struct netmap_adapter *na, u_int 
        enum txrx t;
 
        if (na->tx_rings != NULL) {
-               D("warning: krings were already created");
+               if (netmap_debug & NM_DEBUG_ON)
+                       nm_prerr("warning: krings were already created");
                return 0;
        }
 
@@ -843,7 +847,7 @@ netmap_krings_create(struct netmap_adapter *na, u_int 
 
        na->tx_rings = nm_os_malloc((size_t)len);
        if (na->tx_rings == NULL) {
-               D("Cannot allocate krings");
+               nm_prerr("Cannot allocate krings");
                return ENOMEM;
        }
        na->rx_rings = na->tx_rings + n[NR_TX];
@@ -911,7 +915,8 @@ netmap_krings_delete(struct netmap_adapter *na)
        enum txrx t;
 
        if (na->tx_rings == NULL) {
-               D("warning: krings were already deleted");
+               if (netmap_debug & NM_DEBUG_ON)
+                       nm_prerr("warning: krings were already deleted");
                return;
        }
 
@@ -1013,11 +1018,11 @@ netmap_do_unregif(struct netmap_priv_d *priv)
                 * happens if the close() occurs while a concurrent
                 * syscall is running.
                 */
-               if (netmap_verbose)
-                       D("deleting last instance for %s", na->name);
+               if (netmap_debug & NM_DEBUG_ON)
+                       nm_prinf("deleting last instance for %s", na->name);
 
                if (nm_netmap_on(na)) {
-                       D("BUG: netmap on while going to delete the krings");
+                       nm_prerr("BUG: netmap on while going to delete the 
krings");
                }
 
                na->nm_krings_delete(na);
@@ -1034,14 +1039,6 @@ netmap_do_unregif(struct netmap_priv_d *priv)
        priv->np_nifp = NULL;
 }
 
-/* call with NMG_LOCK held */
-static __inline int
-nm_si_user(struct netmap_priv_d *priv, enum txrx t)
-{
-       return (priv->np_na != NULL &&
-               (priv->np_qlast[t] - priv->np_qfirst[t] > 1));
-}
-
 struct netmap_priv_d*
 netmap_priv_new(void)
 {
@@ -1137,8 +1134,8 @@ netmap_send_up(struct ifnet *dst, struct mbq *q)
        /* Send packets up, outside the lock; head/prev machinery
         * is only useful for Windows. */
        while ((m = mbq_dequeue(q)) != NULL) {
-               if (netmap_verbose & NM_VERB_HOST)
-                       D("sending up pkt %p size %d", m, MBUF_LEN(m));
+               if (netmap_debug & NM_DEBUG_HOST)
+                       nm_prinf("sending up pkt %p size %d", m, MBUF_LEN(m));
                prev = nm_os_send_up(dst, m, prev);
                if (head == NULL)
                        head = prev;
@@ -1333,8 +1330,8 @@ netmap_rxsync_from_host(struct netmap_kring *kring, in
 
                        m_copydata(m, 0, len, NMB(na, slot));
                        ND("nm %d len %d", nm_i, len);
-                       if (netmap_verbose)
-                               D("%s", nm_dump_buf(NMB(na, slot),len, 128, 
NULL));
+                       if (netmap_debug & NM_DEBUG_HOST)
+                               nm_prinf("%s", nm_dump_buf(NMB(na, slot),len, 
128, NULL));
 
                        slot->len = len;
                        slot->flags = 0;
@@ -1501,7 +1498,7 @@ netmap_get_na(struct nmreq_header *hdr,
        if (req->nr_mode == NR_REG_PIPE_MASTER ||
                        req->nr_mode == NR_REG_PIPE_SLAVE) {
                /* Do not accept deprecated pipe modes. */
-               D("Deprecated pipe nr_mode, use xx{yy or xx}yy syntax");
+               nm_prerr("Deprecated pipe nr_mode, use xx{yy or xx}yy syntax");
                return EINVAL;
        }
 
@@ -1528,9 +1525,7 @@ netmap_get_na(struct nmreq_header *hdr,
         *   0    !NULL         type matches and na created/found
         *  !0    !NULL         impossible
         */
-
-       /* try to see if this is a ptnetmap port */
-       error = netmap_get_pt_host_na(hdr, na, nmd, create);
+       error = netmap_get_null_na(hdr, na, nmd, create);
        if (error || *na != NULL)
                goto out;
 
@@ -1740,7 +1735,7 @@ nm_rxsync_prologue(struct netmap_kring *kring, struct 
 
 /*
  * Error routine called when txsync/rxsync detects an error.
- * Can't do much more than resetting head =cur = hwcur, tail = hwtail
+ * Can't do much more than resetting head = cur = hwcur, tail = hwtail
  * Return 1 on reinit.
  *
  * This routine is only called by the upper half of the kernel.
@@ -1811,12 +1806,6 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint3
        enum txrx t;
        u_int j;
 
-       if ((nr_flags & NR_PTNETMAP_HOST) && ((nr_mode != NR_REG_ALL_NIC) ||
-                       nr_flags & (NR_RX_RINGS_ONLY|NR_TX_RINGS_ONLY))) {
-               D("Error: only NR_REG_ALL_NIC supported with netmap 
passthrough");
-               return EINVAL;
-       }
-
        for_rx_tx(t) {
                if (nr_flags & excluded_direction[t]) {
                        priv->np_qfirst[t] = priv->np_qlast[t] = 0;
@@ -1824,6 +1813,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint3
                }
                switch (nr_mode) {
                case NR_REG_ALL_NIC:
+               case NR_REG_NULL:
                        priv->np_qfirst[t] = 0;
                        priv->np_qlast[t] = nma_get_nrings(na, t);
                        ND("ALL/PIPE: %s %d %d", nm_txrx2str(t),
@@ -1832,7 +1822,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint3
                case NR_REG_SW:
                case NR_REG_NIC_SW:
                        if (!(na->na_flags & NAF_HOST_RINGS)) {
-                               D("host rings not supported");
+                               nm_prerr("host rings not supported");
                                return EINVAL;
                        }
                        priv->np_qfirst[t] = (nr_mode == NR_REG_SW ?
@@ -1845,7 +1835,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint3
                case NR_REG_ONE_NIC:
                        if (nr_ringid >= na->num_tx_rings &&
                                        nr_ringid >= na->num_rx_rings) {
-                               D("invalid ring id %d", nr_ringid);
+                               nm_prerr("invalid ring id %d", nr_ringid);
                                return EINVAL;
                        }
                        /* if not enough rings, use the first one */
@@ -1858,11 +1848,11 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint3
                                priv->np_qfirst[t], priv->np_qlast[t]);
                        break;
                default:
-                       D("invalid regif type %d", nr_mode);
+                       nm_prerr("invalid regif type %d", nr_mode);
                        return EINVAL;
                }
        }
-       priv->np_flags = nr_flags | nr_mode; // TODO
+       priv->np_flags = nr_flags;
 
        /* Allow transparent forwarding mode in the host --> nic
         * direction only if all the TX hw rings have been opened. */
@@ -1872,7 +1862,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint3
        }
 
        if (netmap_verbose) {
-               D("%s: tx [%d,%d) rx [%d,%d) id %d",
+               nm_prinf("%s: tx [%d,%d) rx [%d,%d) id %d",
                        na->name,
                        priv->np_qfirst[NR_TX],
                        priv->np_qlast[NR_TX],
@@ -1928,6 +1918,7 @@ netmap_unset_ringid(struct netmap_priv_d *priv)
        }
        priv->np_flags = 0;
        priv->np_txpoll = 0;
+       priv->np_kloop_state = 0;
 }
 
 
@@ -1944,8 +1935,8 @@ netmap_krings_get(struct netmap_priv_d *priv)
        int excl = (priv->np_flags & NR_EXCLUSIVE);
        enum txrx t;
 
-       if (netmap_verbose)
-               D("%s: grabbing tx [%d, %d) rx [%d, %d)",
+       if (netmap_debug & NM_DEBUG_ON)
+               nm_prinf("%s: grabbing tx [%d, %d) rx [%d, %d)",
                        na->name,
                        priv->np_qfirst[NR_TX],
                        priv->np_qlast[NR_TX],
@@ -2022,6 +2013,110 @@ nm_priv_rx_enabled(struct netmap_priv_d *priv)
        return (priv->np_qfirst[NR_RX] != priv->np_qlast[NR_RX]);
 }
 
+/* Validate the CSB entries for both directions (atok and ktoa).
+ * To be called under NMG_LOCK(). */
+static int
+netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
+{
+       struct nm_csb_atok *csb_atok_base =
+               (struct nm_csb_atok *)(uintptr_t)csbo->csb_atok;
+       struct nm_csb_ktoa *csb_ktoa_base =
+               (struct nm_csb_ktoa *)(uintptr_t)csbo->csb_ktoa;
+       enum txrx t;
+       int num_rings[NR_TXRX], tot_rings;
+       size_t entry_size[2];
+       void *csb_start[2];
+       int i;
+
+       if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
+               nm_prerr("Cannot update CSB while kloop is running");
+               return EBUSY;
+       }
+
+       tot_rings = 0;
+       for_rx_tx(t) {
+               num_rings[t] = priv->np_qlast[t] - priv->np_qfirst[t];
+               tot_rings += num_rings[t];
+       }
+       if (tot_rings <= 0)
+               return 0;
+
+       if (!(priv->np_flags & NR_EXCLUSIVE)) {
+               nm_prerr("CSB mode requires NR_EXCLUSIVE");
+               return EINVAL;
+       }
+
+       entry_size[0] = sizeof(*csb_atok_base);
+       entry_size[1] = sizeof(*csb_ktoa_base);
+       csb_start[0] = (void *)csb_atok_base;
+       csb_start[1] = (void *)csb_ktoa_base;
+
+       for (i = 0; i < 2; i++) {
+               /* On Linux we could use access_ok() to simplify
+                * the validation. However, the advantage of
+                * this approach is that it works also on
+                * FreeBSD. */
+               size_t csb_size = tot_rings * entry_size[i];
+               void *tmp;
+               int err;
+
+               if ((uintptr_t)csb_start[i] & (entry_size[i]-1)) {
+                       nm_prerr("Unaligned CSB address");
+                       return EINVAL;
+               }
+
+               tmp = nm_os_malloc(csb_size);
+               if (!tmp)
+                       return ENOMEM;
+               if (i == 0) {
+                       /* Application --> kernel direction. */
+                       err = copyin(csb_start[i], tmp, csb_size);
+               } else {
+                       /* Kernel --> application direction. */
+                       memset(tmp, 0, csb_size);
+                       err = copyout(tmp, csb_start[i], csb_size);
+               }
+               nm_os_free(tmp);
+               if (err) {
+                       nm_prerr("Invalid CSB address");
+                       return err;
+               }
+       }
+
+       priv->np_csb_atok_base = csb_atok_base;
+       priv->np_csb_ktoa_base = csb_ktoa_base;
+
+       /* Initialize the CSB. */
+       for_rx_tx(t) {
+               for (i = 0; i < num_rings[t]; i++) {
+                       struct netmap_kring *kring =
+                               NMR(priv->np_na, t)[i + priv->np_qfirst[t]];
+                       struct nm_csb_atok *csb_atok = csb_atok_base + i;
+                       struct nm_csb_ktoa *csb_ktoa = csb_ktoa_base + i;
+
+                       if (t == NR_RX) {
+                               csb_atok += num_rings[NR_TX];
+                               csb_ktoa += num_rings[NR_TX];
+                       }
+
+                       CSB_WRITE(csb_atok, head, kring->rhead);
+                       CSB_WRITE(csb_atok, cur, kring->rcur);
+                       CSB_WRITE(csb_atok, appl_need_kick, 1);
+                       CSB_WRITE(csb_atok, sync_flags, 1);
+                       CSB_WRITE(csb_ktoa, hwcur, kring->nr_hwcur);
+                       CSB_WRITE(csb_ktoa, hwtail, kring->nr_hwtail);
+                       CSB_WRITE(csb_ktoa, kern_need_kick, 1);
+
+                       nm_prinf("csb_init for kring %s: head %u, cur %u, "
+                               "hwcur %u, hwtail %u", kring->name,
+                               kring->rhead, kring->rcur, kring->nr_hwcur,
+                               kring->nr_hwtail);
+               }
+       }
+
+       return 0;
+}
+
 /*
  * possibly move the interface to netmap-mode.
  * If success it returns a pointer to netmap_if, otherwise NULL.
@@ -2138,7 +2233,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct net
                                        na->name, mtu, na->rx_buf_maxsize, nbs);
 
                        if (na->rx_buf_maxsize == 0) {
-                               D("%s: error: rx_buf_maxsize == 0", na->name);
+                               nm_prerr("%s: error: rx_buf_maxsize == 0", 
na->name);
                                error = EIO;
                                goto err_drop_mem;
                        }
@@ -2150,7 +2245,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct net
                                 * cannot be used in this case. */
                                if (nbs < mtu) {
                                        nm_prerr("error: netmap buf size (%u) "
-                                               "< device MTU (%u)\n", nbs, 
mtu);
+                                               "< device MTU (%u)", nbs, mtu);
                                        error = EINVAL;
                                        goto err_drop_mem;
                                }
@@ -2163,14 +2258,14 @@ netmap_do_regif(struct netmap_priv_d *priv, struct net
                                if (!(na->na_flags & NAF_MOREFRAG)) {
                                        nm_prerr("error: large MTU (%d) needed "
                                                "but %s does not support "
-                                               "NS_MOREFRAG\n", mtu,
+                                               "NS_MOREFRAG", mtu,
                                                na->ifp->if_xname);
                                        error = EINVAL;
                                        goto err_drop_mem;
                                } else if (nbs < na->rx_buf_maxsize) {
                                        nm_prerr("error: using NS_MOREFRAG on "
                                                "%s requires netmap buf size "
-                                               ">= %u\n", na->ifp->if_xname,
+                                               ">= %u", na->ifp->if_xname,
                                                na->rx_buf_maxsize);
                                        error = EINVAL;
                                        goto err_drop_mem;
@@ -2178,7 +2273,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct net
                                        nm_prinf("info: netmap application on "
                                                "%s needs to support "
                                                "NS_MOREFRAG "
-                                               "(MTU=%u,netmap_buf_size=%u)\n",
+                                               "(MTU=%u,netmap_buf_size=%u)",
                                                na->ifp->if_xname, mtu, nbs);
                                }
                        }
@@ -2308,7 +2403,6 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
        struct ifnet *ifp = NULL;
        int error = 0;
        u_int i, qfirst, qlast;
-       struct netmap_if *nifp;
        struct netmap_kring **krings;
        int sync_flags;
        enum txrx t;
@@ -2317,14 +2411,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
        case NIOCCTRL: {
                struct nmreq_header *hdr = (struct nmreq_header *)data;
 
-               if (hdr->nr_version != NETMAP_API) {
-                       D("API mismatch for reqtype %d: got %d need %d",
-                               hdr->nr_version,
-                               hdr->nr_version, NETMAP_API);
-                       hdr->nr_version = NETMAP_API;
-               }
                if (hdr->nr_version < NETMAP_MIN_API ||
                    hdr->nr_version > NETMAP_MAX_API) {
+                       nm_prerr("API mismatch: got %d need %d",
+                               hdr->nr_version, NETMAP_API);
                        return EINVAL;
                }
 
@@ -2346,13 +2436,13 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
                case NETMAP_REQ_REGISTER: {
                        struct nmreq_register *req =
                                (struct nmreq_register 
*)(uintptr_t)hdr->nr_body;
+                       struct netmap_if *nifp;
+
                        /* Protect access to priv from concurrent requests. */
                        NMG_LOCK();
                        do {
-                               u_int memflags;
-#ifdef WITH_EXTMEM
                                struct nmreq_option *opt;
-#endif /* WITH_EXTMEM */
+                               u_int memflags;
 
                                if (priv->np_nifp != NULL) {    /* thread 
already registered */
                                        error = EBUSY;
@@ -2383,6 +2473,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
                                        /* find the allocator and get a 
reference */
                                        nmd = netmap_mem_find(req->nr_mem_id);
                                        if (nmd == NULL) {
+                                               if (netmap_verbose) {
+                                                       nm_prerr("%s: failed to 
find mem_id %u",
+                                                                       
hdr->nr_name, req->nr_mem_id);
+                                               }
                                                error = EINVAL;
                                                break;
                                        }
@@ -2398,6 +2492,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
                                }
 
                                if (na->virt_hdr_len && !(req->nr_flags & 
NR_ACCEPT_VNET_HDR)) {
+                                       nm_prerr("virt_hdr_len=%d, but 
application does "
+                                               "not accept it", 
na->virt_hdr_len);
                                        error = EIO;
                                        break;
                                }
@@ -2407,6 +2503,23 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
                                if (error) {    /* reg. failed, release priv 
and ref */
                                        break;
                                }
+
+                               opt = nmreq_findoption((struct nmreq_option 
*)(uintptr_t)hdr->nr_options,
+                                                       NETMAP_REQ_OPT_CSB);
+                               if (opt != NULL) {
+                                       struct nmreq_opt_csb *csbo =
+                                               (struct nmreq_opt_csb *)opt;
+                                       error = nmreq_checkduplicate(opt);
+                                       if (!error) {
+                                               error = 
netmap_csb_validate(priv, csbo);
+                                       }
+                                       opt->nro_status = error;
+                                       if (error) {
+                                               netmap_do_unregif(priv);
+                                               break;
+                                       }
+                               }
+
                                nifp = priv->np_nifp;
                                priv->np_td = td; /* for debugging purposes */
 
@@ -2431,12 +2544,12 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
 
                                if (req->nr_extra_bufs) {
                                        if (netmap_verbose)
-                                               D("requested %d extra buffers",
+                                               nm_prinf("requested %d extra 
buffers",
                                                        req->nr_extra_bufs);
                                        req->nr_extra_bufs = 
netmap_extra_alloc(na,
                                                &nifp->ni_bufs_head, 
req->nr_extra_bufs);
                                        if (netmap_verbose)
-                                               D("got %d extra buffers", 
req->nr_extra_bufs);
+                                               nm_prinf("got %d extra 
buffers", req->nr_extra_bufs);
                                }
                                req->nr_offset = 
netmap_mem_if_offset(na->nm_mem, nifp);
 
@@ -2474,6 +2587,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
                                         * so that we can call netmap_get_na(). 
*/
                                        struct nmreq_register regreq;
                                        bzero(&regreq, sizeof(regreq));
+                                       regreq.nr_mode = NR_REG_ALL_NIC;
                                        regreq.nr_tx_slots = req->nr_tx_slots;
                                        regreq.nr_rx_slots = req->nr_rx_slots;
                                        regreq.nr_tx_rings = req->nr_tx_rings;
@@ -2495,6 +2609,10 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
                                } else {
                                        nmd = netmap_mem_find(req->nr_mem_id ? 
req->nr_mem_id : 1);
                                        if (nmd == NULL) {
+                                               if (netmap_verbose)
+                                                       nm_prerr("%s: failed to 
find mem_id %u",
+                                                                       
hdr->nr_name,
+                                                                       
req->nr_mem_id ? req->nr_mem_id : 1);
                                                error = EINVAL;
                                                break;
                                        }
@@ -2506,8 +2624,6 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
                                        break;
                                if (na == NULL) /* only memory info */
                                        break;
-                               req->nr_offset = 0;
-                               req->nr_rx_slots = req->nr_tx_slots = 0;
                                netmap_update_config(na);
                                req->nr_rx_rings = na->num_rx_rings;
                                req->nr_tx_rings = na->num_tx_rings;
@@ -2520,17 +2636,17 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
                }
 #ifdef WITH_VALE
                case NETMAP_REQ_VALE_ATTACH: {
-                       error = nm_bdg_ctl_attach(hdr, NULL /* userspace 
request */);
+                       error = netmap_vale_attach(hdr, NULL /* userspace 
request */);
                        break;
                }
 
                case NETMAP_REQ_VALE_DETACH: {
-                       error = nm_bdg_ctl_detach(hdr, NULL /* userspace 
request */);
+                       error = netmap_vale_detach(hdr, NULL /* userspace 
request */);
                        break;
                }
 
                case NETMAP_REQ_VALE_LIST: {
-                       error = netmap_bdg_list(hdr);
+                       error = netmap_vale_list(hdr);
                        break;
                }
 
@@ -2541,12 +2657,16 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
                         * so that we can call netmap_get_bdg_na(). */
                        struct nmreq_register regreq;
                        bzero(&regreq, sizeof(regreq));
+                       regreq.nr_mode = NR_REG_ALL_NIC;
+
                        /* For now we only support virtio-net headers, and only 
for
                         * VALE ports, but this may change in future. Valid 
lengths
                         * for the virtio-net header are 0 (no header), 10 and 
12. */
                        if (req->nr_hdr_len != 0 &&
                                req->nr_hdr_len != sizeof(struct nm_vnet_hdr) &&
                                        req->nr_hdr_len != 12) {
+                               if (netmap_verbose)
+                                       nm_prerr("invalid hdr_len %u", 
req->nr_hdr_len);
                                error = EINVAL;
                                break;
                        }
@@ -2563,7 +2683,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
                                if (na->virt_hdr_len) {
                                        vpna->mfs = NETMAP_BUF_SIZE(na);
                                }
-                               D("Using vnet_hdr_len %d for %p", 
na->virt_hdr_len, na);
+                               if (netmap_verbose)
+                                       nm_prinf("Using vnet_hdr_len %d for 
%p", na->virt_hdr_len, na);
                                netmap_adapter_put(na);
                        } else if (!na) {
                                error = ENXIO;
@@ -2582,6 +2703,7 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
                        struct ifnet *ifp;
 
                        bzero(&regreq, sizeof(regreq));
+                       regreq.nr_mode = NR_REG_ALL_NIC;
                        NMG_LOCK();
                        hdr->nr_reqtype = NETMAP_REQ_REGISTER;
                        hdr->nr_body = (uintptr_t)&regreq;
@@ -2613,22 +2735,80 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
                }
 #endif  /* WITH_VALE */
                case NETMAP_REQ_POOLS_INFO_GET: {
+                       /* Get information from the memory allocator used for
+                        * hdr->nr_name. */
                        struct nmreq_pools_info *req =
                                (struct nmreq_pools_info 
*)(uintptr_t)hdr->nr_body;
-                       /* Get information from the memory allocator. This
-                        * netmap device must already be bound to a port.
-                        * Note that hdr->nr_name is ignored. */
                        NMG_LOCK();
-                       if (priv->np_na && priv->np_na->nm_mem) {
-                               struct netmap_mem_d *nmd = priv->np_na->nm_mem;
+                       do {
+                               /* Build a nmreq_register out of the 
nmreq_pools_info,
+                                * so that we can call netmap_get_na(). */
+                               struct nmreq_register regreq;
+                               bzero(&regreq, sizeof(regreq));
+                               regreq.nr_mem_id = req->nr_mem_id;
+                               regreq.nr_mode = NR_REG_ALL_NIC;
+
+                               hdr->nr_reqtype = NETMAP_REQ_REGISTER;
+                               hdr->nr_body = (uintptr_t)&regreq;
+                               error = netmap_get_na(hdr, &na, &ifp, NULL, 1 
/* create */);
+                               hdr->nr_reqtype = NETMAP_REQ_POOLS_INFO_GET; /* 
reset type */
+                               hdr->nr_body = (uintptr_t)req; /* reset nr_body 
*/
+                               if (error) {
+                                       na = NULL;
+                                       ifp = NULL;
+                                       break;
+                               }
+                               nmd = na->nm_mem; /* grab the memory allocator 
*/
+                               if (nmd == NULL) {
+                                       error = EINVAL;
+                                       break;
+                               }
+
+                               /* Finalize the memory allocator, get the pools
+                                * information and release the allocator. */
+                               error = netmap_mem_finalize(nmd, na);
+                               if (error) {
+                                       break;
+                               }
                                error = netmap_mem_pools_info_get(req, nmd);
-                       } else {
+                               netmap_mem_drop(na);
+                       } while (0);
+                       netmap_unget_na(na, ifp);
+                       NMG_UNLOCK();
+                       break;
+               }
+
+               case NETMAP_REQ_CSB_ENABLE: {
+                       struct nmreq_option *opt;
+
+                       opt = nmreq_findoption((struct nmreq_option 
*)(uintptr_t)hdr->nr_options,
+                                               NETMAP_REQ_OPT_CSB);
+                       if (opt == NULL) {
                                error = EINVAL;
+                       } else {
+                               struct nmreq_opt_csb *csbo =
+                                       (struct nmreq_opt_csb *)opt;
+                               error = nmreq_checkduplicate(opt);
+                               if (!error) {
+                                       NMG_LOCK();
+                                       error = netmap_csb_validate(priv, csbo);
+                                       NMG_UNLOCK();
+                               }
+                               opt->nro_status = error;
                        }
-                       NMG_UNLOCK();
                        break;
                }
 
+               case NETMAP_REQ_SYNC_KLOOP_START: {
+                       error = netmap_sync_kloop(priv, hdr);
+                       break;
+               }
+
+               case NETMAP_REQ_SYNC_KLOOP_STOP: {
+                       error = netmap_sync_kloop_stop(priv);
+                       break;
+               }
+
                default: {
                        error = EINVAL;
                        break;
@@ -2642,22 +2822,20 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
 
        case NIOCTXSYNC:
        case NIOCRXSYNC: {
-               nifp = priv->np_nifp;
-
-               if (nifp == NULL) {
+               if (unlikely(priv->np_nifp == NULL)) {
                        error = ENXIO;
                        break;
                }
                mb(); /* make sure following reads are not from cache */
 
-               na = priv->np_na;      /* we have a reference */
-
-               if (na == NULL) {
-                       D("Internal error: nifp != NULL && na == NULL");
-                       error = ENXIO;
+               if (unlikely(priv->np_csb_atok_base)) {
+                       nm_prerr("Invalid sync in CSB mode");
+                       error = EBUSY;
                        break;
                }
 
+               na = priv->np_na;      /* we have a reference */
+
                mbq_init(&q);
                t = (cmd == NIOCTXSYNC ? NR_TX : NR_RX);
                krings = NMR(na, t);
@@ -2675,8 +2853,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
                        }
 
                        if (cmd == NIOCTXSYNC) {
-                               if (netmap_verbose & NM_VERB_TXSYNC)
-                                       D("pre txsync ring %d cur %d hwcur %d",
+                               if (netmap_debug & NM_DEBUG_TXSYNC)
+                                       nm_prinf("pre txsync ring %d cur %d 
hwcur %d",
                                            i, ring->cur,
                                            kring->nr_hwcur);
                                if (nm_txsync_prologue(kring, ring) >= 
kring->nkr_num_slots) {
@@ -2684,8 +2862,8 @@ netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, c
                                } else if (kring->nm_sync(kring, sync_flags | 
NAF_FORCE_RECLAIM) == 0) {
                                        nm_sync_finalize(kring);
                                }
-                               if (netmap_verbose & NM_VERB_TXSYNC)
-                                       D("post txsync ring %d cur %d hwcur %d",
+                               if (netmap_debug & NM_DEBUG_TXSYNC)
+                                       nm_prinf("post txsync ring %d cur %d 
hwcur %d",
                                            i, ring->cur,
                                            kring->nr_hwcur);
                        } else {
@@ -2740,18 +2918,22 @@ nmreq_size_by_type(uint16_t nr_reqtype)
        case NETMAP_REQ_VALE_NEWIF:
                return sizeof(struct nmreq_vale_newif);
        case NETMAP_REQ_VALE_DELIF:
+       case NETMAP_REQ_SYNC_KLOOP_STOP:
+       case NETMAP_REQ_CSB_ENABLE:
                return 0;
        case NETMAP_REQ_VALE_POLLING_ENABLE:
        case NETMAP_REQ_VALE_POLLING_DISABLE:
                return sizeof(struct nmreq_vale_polling);
        case NETMAP_REQ_POOLS_INFO_GET:
                return sizeof(struct nmreq_pools_info);
+       case NETMAP_REQ_SYNC_KLOOP_START:
+               return sizeof(struct nmreq_sync_kloop_start);
        }
        return 0;
 }
 
 static size_t
-nmreq_opt_size_by_type(uint16_t nro_reqtype)
+nmreq_opt_size_by_type(uint32_t nro_reqtype, uint64_t nro_size)
 {
        size_t rv = sizeof(struct nmreq_option);
 #ifdef NETMAP_REQ_OPT_DEBUG
@@ -2764,6 +2946,13 @@ nmreq_opt_size_by_type(uint16_t nro_reqtype)
                rv = sizeof(struct nmreq_opt_extmem);
                break;
 #endif /* WITH_EXTMEM */
+       case NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS:
+               if (nro_size >= rv)
+                       rv = nro_size;
+               break;
+       case NETMAP_REQ_OPT_CSB:
+               rv = sizeof(struct nmreq_opt_csb);
+               break;
        }
        /* subtract the common header */
        return rv - sizeof(struct nmreq_option);
@@ -2779,8 +2968,11 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_
        struct nmreq_option buf;
        uint64_t *ptrs;
 
-       if (hdr->nr_reserved)
+       if (hdr->nr_reserved) {
+               if (netmap_verbose)
+                       nm_prerr("nr_reserved must be zero");
                return EINVAL;
+       }
 
        if (!nr_body_is_user)
                return 0;
@@ -2797,6 +2989,8 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_
                (!rqsz && hdr->nr_body != (uintptr_t)NULL)) {
                /* Request body expected, but not found; or
                 * request body found but unexpected. */
+               if (netmap_verbose)
+                       nm_prerr("nr_body expected but not found, or vice 
versa");
                error = EINVAL;
                goto out_err;
        }
@@ -2810,7 +3004,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_
                if (error)
                        goto out_err;
                optsz += sizeof(*src);
-               optsz += nmreq_opt_size_by_type(buf.nro_reqtype);
+               optsz += nmreq_opt_size_by_type(buf.nro_reqtype, buf.nro_size);
                if (rqsz + optsz > NETMAP_REQ_MAXSIZE) {
                        error = EMSGSIZE;
                        goto out_err;
@@ -2864,7 +3058,8 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_
                p = (char *)(opt + 1);
 
                /* copy the option body */
-               optsz = nmreq_opt_size_by_type(opt->nro_reqtype);
+               optsz = nmreq_opt_size_by_type(opt->nro_reqtype,
+                                               opt->nro_size);
                if (optsz) {
                        /* the option body follows the option header */
                        error = copyin(src + 1, p, optsz);
@@ -2938,7 +3133,8 @@ nmreq_copyout(struct nmreq_header *hdr, int rerror)
 
                /* copy the option body only if there was no error */
                if (!rerror && !src->nro_status) {
-                       optsz = nmreq_opt_size_by_type(src->nro_reqtype);
+                       optsz = nmreq_opt_size_by_type(src->nro_reqtype,
+                                                       src->nro_size);
                        if (optsz) {
                                error = copyout(src + 1, dst + 1, optsz);
                                if (error) {
@@ -3016,7 +3212,8 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM
        struct netmap_adapter *na;
        struct netmap_kring *kring;
        struct netmap_ring *ring;
-       u_int i, check_all_tx, check_all_rx, want[NR_TXRX], revents = 0;
+       u_int i, want[NR_TXRX], revents = 0;
+       NM_SELINFO_T *si[NR_TXRX];
 #define want_tx want[NR_TX]
 #define want_rx want[NR_RX]
        struct mbq q;   /* packets from RX hw queues to host stack */
@@ -3039,27 +3236,31 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM
 
        mbq_init(&q);
 
-       if (priv->np_nifp == NULL) {
-               D("No if registered");
+       if (unlikely(priv->np_nifp == NULL)) {
                return POLLERR;
        }
        mb(); /* make sure following reads are not from cache */
 
        na = priv->np_na;
 
-       if (!nm_netmap_on(na))
+       if (unlikely(!nm_netmap_on(na)))
                return POLLERR;
 
-       if (netmap_verbose & 0x8000)
-               D("device %s events 0x%x", na->name, events);
+       if (unlikely(priv->np_csb_atok_base)) {
+               nm_prerr("Invalid poll in CSB mode");
+               return POLLERR;
+       }
+
+       if (netmap_debug & NM_DEBUG_ON)
+               nm_prinf("device %s events 0x%x", na->name, events);
        want_tx = events & (POLLOUT | POLLWRNORM);
        want_rx = events & (POLLIN | POLLRDNORM);
 
        /*
-        * check_all_{tx|rx} are set if the card has more than one queue AND
-        * the file descriptor is bound to all of them. If so, we sleep on
-        * the "global" selinfo, otherwise we sleep on individual selinfo
-        * (FreeBSD only allows two selinfo's per file descriptor).
+        * If the card has more than one queue AND the file descriptor is
+        * bound to all of them, we sleep on the "global" selinfo, otherwise
+        * we sleep on individual selinfo (FreeBSD only allows two selinfo's
+        * per file descriptor).
         * The interrupt routine in the driver wake one or the other
         * (or both) depending on which clients are active.
         *
@@ -3068,8 +3269,10 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM
         * there are pending packets to send. The latter can be disabled
         * passing NETMAP_NO_TX_POLL in the NIOCREG call.
         */
-       check_all_tx = nm_si_user(priv, NR_TX);
-       check_all_rx = nm_si_user(priv, NR_RX);
+       si[NR_RX] = nm_si_user(priv, NR_RX) ? &na->si[NR_RX] :
+                               &na->rx_rings[priv->np_qfirst[NR_RX]]->si;
+       si[NR_TX] = nm_si_user(priv, NR_TX) ? &na->si[NR_TX] :
+                               &na->tx_rings[priv->np_qfirst[NR_TX]]->si;
 
 #ifdef __FreeBSD__
        /*
@@ -3106,10 +3309,8 @@ netmap_poll(struct netmap_priv_d *priv, int events, NM
 
 #ifdef linux
        /* The selrecord must be unconditional on linux. */
-       nm_os_selrecord(sr, check_all_tx ?
-           &na->si[NR_TX] : &na->tx_rings[priv->np_qfirst[NR_TX]]->si);
-       nm_os_selrecord(sr, check_all_rx ?
-               &na->si[NR_RX] : &na->rx_rings[priv->np_qfirst[NR_RX]]->si);
+       nm_os_selrecord(sr, si[NR_RX]);
+       nm_os_selrecord(sr, si[NR_TX]);
 #endif /* linux */
 
        /*
@@ -3174,8 +3375,7 @@ flush_tx:
                send_down = 0;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to