netmap: align codebase to the current upstream (commit id 3fb001303718146)

Changelist:
    - Turn tx_rings and rx_rings arrays into arrays of pointers to kring
      structs. This patch includes fixes for ixv, ixl, ix, re, cxgbe, iflib,
      vtnet and ptnet drivers to cope with the change.
    - Generalize the nm_config() callback to accept a struct containing many
      parameters.
    - Introduce NKR_FAKERING to support buffers sharing (used for netmap
      pipes)
    - Improved API for external VALE modules.
    - Various bug fixes and improvements to the netmap memory allocator,
      including support for externally (userspace) allocated memory.
    - Refactoring of netmap pipes: now linked rings share the same netmap
      buffers, with a separate set of kring pointers (rhead, rcur, rtail).
      Buffer swapping does not need to happen anymore.
    - Large refactoring of the control API towards an extensible solution;
      the goal is to allow the addition of more commands and extension of
      existing ones (with new options) without the need of hacks or the
      risk of running out of configuration space.
      A new NIOCCTRL ioctl has been added to handle all the requests of the
      new control API, which cover all the functionalities so far supported.
      The netmap API bumps from 11 to 12 with this patch. Full backward
      compatibility is provided for the old control command (NIOCREGIF), by
      means of a new netmap_legacy module. Many parts of the old netmap.h
      header has now been moved to netmap_legacy.h (included by netmap.h).

Approved by:	hrs (mentor)
This commit is contained in:
Vincenzo Maffione 2018-04-12 07:20:50 +00:00
parent 66def52613
commit 2ff91c175e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=332423
27 changed files with 3192 additions and 1865 deletions

View file

@ -2535,6 +2535,7 @@ 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
# compile-with "${NORMAL_C} -Wconversion -Wextra"
dev/nfsmb/nfsmb.c optional nfsmb pci
dev/nge/if_nge.c optional nge

View file

@ -344,7 +344,7 @@ cxgbe_netmap_on(struct adapter *sc, struct vi_info *vi, struct ifnet *ifp,
for_each_nm_rxq(vi, i, nm_rxq) {
struct irq *irq = &sc->irq[vi->first_intr + i];
kring = &na->rx_rings[nm_rxq->nid];
kring = na->rx_rings[nm_rxq->nid];
if (!nm_kring_pending_on(kring) ||
nm_rxq->iq_cntxt_id != INVALID_NM_RXQ_CNTXT_ID)
continue;
@ -375,7 +375,7 @@ cxgbe_netmap_on(struct adapter *sc, struct vi_info *vi, struct ifnet *ifp,
}
for_each_nm_txq(vi, i, nm_txq) {
kring = &na->tx_rings[nm_txq->nid];
kring = na->tx_rings[nm_txq->nid];
if (!nm_kring_pending_on(kring) ||
nm_txq->cntxt_id != INVALID_NM_TXQ_CNTXT_ID)
continue;
@ -427,7 +427,7 @@ cxgbe_netmap_off(struct adapter *sc, struct vi_info *vi, struct ifnet *ifp,
for_each_nm_txq(vi, i, nm_txq) {
struct sge_qstat *spg = (void *)&nm_txq->desc[nm_txq->sidx];
kring = &na->tx_rings[nm_txq->nid];
kring = na->tx_rings[nm_txq->nid];
if (!nm_kring_pending_off(kring) ||
nm_txq->cntxt_id == INVALID_NM_TXQ_CNTXT_ID)
continue;
@ -445,7 +445,7 @@ cxgbe_netmap_off(struct adapter *sc, struct vi_info *vi, struct ifnet *ifp,
for_each_nm_rxq(vi, i, nm_rxq) {
struct irq *irq = &sc->irq[vi->first_intr + i];
kring = &na->rx_rings[nm_rxq->nid];
kring = na->rx_rings[nm_rxq->nid];
if (!nm_kring_pending_off(kring) ||
nm_rxq->iq_cntxt_id == INVALID_NM_RXQ_CNTXT_ID)
continue;
@ -933,7 +933,7 @@ t4_nm_intr(void *arg)
struct adapter *sc = vi->pi->adapter;
struct ifnet *ifp = vi->ifp;
struct netmap_adapter *na = NA(ifp);
struct netmap_kring *kring = &na->rx_rings[nm_rxq->nid];
struct netmap_kring *kring = na->rx_rings[nm_rxq->nid];
struct netmap_ring *ring = kring->ring;
struct iq_desc *d = &nm_rxq->iq_desc[nm_rxq->iq_cidx];
const void *cpl;

View file

@ -1450,7 +1450,7 @@ ixv_initialize_receive_units(if_ctx_t ctx)
*/
if (ifp->if_capenable & IFCAP_NETMAP) {
struct netmap_adapter *na = NA(ifp);
struct netmap_kring *kring = &na->rx_rings[j];
struct netmap_kring *kring = na->rx_rings[j];
int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rxr->me), t);

View file

@ -2240,7 +2240,7 @@ ixl_initialize_vsi(struct ixl_vsi *vsi)
/* preserve queue */
if (vsi->ifp->if_capenable & IFCAP_NETMAP) {
struct netmap_adapter *na = NA(vsi->ifp);
struct netmap_kring *kring = &na->rx_rings[i];
struct netmap_kring *kring = na->rx_rings[i];
int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring);
wr32(vsi->hw, I40E_QRX_TAIL(que->me), t);
} else

View file

@ -547,7 +547,7 @@ ixl_init_tx_ring(struct ixl_queue *que)
* netmap slot index, si
*/
if (slot) {
int si = netmap_idx_n2k(&na->tx_rings[que->me], i);
int si = netmap_idx_n2k(na->tx_rings[que->me], i);
netmap_load_map(na, buf->tag, buf->map, NMB(na, slot + si));
}
#endif /* DEV_NETMAP */
@ -1214,7 +1214,7 @@ ixl_init_rx_ring(struct ixl_queue *que)
* an mbuf, so end the block with a continue;
*/
if (slot) {
int sj = netmap_idx_n2k(&na->rx_rings[que->me], j);
int sj = netmap_idx_n2k(na->rx_rings[que->me], j);
uint64_t paddr;
void *addr;

View file

@ -210,8 +210,8 @@ static int ptnet_irqs_init(struct ptnet_softc *sc);
static void ptnet_irqs_fini(struct ptnet_softc *sc);
static uint32_t ptnet_nm_ptctl(if_t ifp, uint32_t cmd);
static int ptnet_nm_config(struct netmap_adapter *na, unsigned *txr,
unsigned *txd, unsigned *rxr, unsigned *rxd);
static int ptnet_nm_config(struct netmap_adapter *na,
struct nm_config_info *info);
static void ptnet_update_vnet_hdr(struct ptnet_softc *sc);
static int ptnet_nm_register(struct netmap_adapter *na, int onoff);
static int ptnet_nm_txsync(struct netmap_kring *kring, int flags);
@ -1104,18 +1104,20 @@ ptnet_nm_ptctl(if_t ifp, uint32_t cmd)
}
static int
ptnet_nm_config(struct netmap_adapter *na, unsigned *txr, unsigned *txd,
unsigned *rxr, unsigned *rxd)
ptnet_nm_config(struct netmap_adapter *na, struct nm_config_info *info)
{
struct ptnet_softc *sc = if_getsoftc(na->ifp);
*txr = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_RINGS);
*rxr = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_RINGS);
*txd = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_SLOTS);
*rxd = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_SLOTS);
info->num_tx_rings = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_RINGS);
info->num_rx_rings = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_RINGS);
info->num_tx_descs = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_SLOTS);
info->num_rx_descs = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_SLOTS);
info->rx_buf_maxsize = NETMAP_BUF_SIZE(na);
device_printf(sc->dev, "txr %u, rxr %u, txd %u, rxd %u\n",
*txr, *rxr, *txd, *rxd);
device_printf(sc->dev, "txr %u, rxr %u, txd %u, rxd %u, rxbufsz %u\n",
info->num_tx_rings, info->num_rx_rings,
info->num_tx_descs, info->num_rx_descs,
info->rx_buf_maxsize);
return 0;
}
@ -1133,9 +1135,9 @@ ptnet_sync_from_csb(struct ptnet_softc *sc, struct netmap_adapter *na)
struct netmap_kring *kring;
if (i < na->num_tx_rings) {
kring = na->tx_rings + i;
kring = na->tx_rings[i];
} else {
kring = na->rx_rings + i - na->num_tx_rings;
kring = na->rx_rings[i - na->num_tx_rings];
}
kring->rhead = kring->ring->head = ptgh->head;
kring->rcur = kring->ring->cur = ptgh->cur;
@ -1228,7 +1230,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
if (native) {
for_rx_tx(t) {
for (i = 0; i <= nma_get_nrings(na, t); i++) {
struct netmap_kring *kring = &NMR(na, t)[i];
struct netmap_kring *kring = NMR(na, t)[i];
if (nm_kring_pending_on(kring)) {
kring->nr_mode = NKR_NETMAP_ON;
@ -1243,7 +1245,7 @@ ptnet_nm_register(struct netmap_adapter *na, int onoff)
nm_clear_native_flags(na);
for_rx_tx(t) {
for (i = 0; i <= nma_get_nrings(na, t); i++) {
struct netmap_kring *kring = &NMR(na, t)[i];
struct netmap_kring *kring = NMR(na, t)[i];
if (nm_kring_pending_off(kring)) {
kring->nr_mode = NKR_NETMAP_OFF;
@ -1758,7 +1760,7 @@ ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget,
ptgh = pq->ptgh;
pthg = pq->pthg;
kring = na->tx_rings + pq->kring_id;
kring = na->tx_rings[pq->kring_id];
ring = kring->ring;
lim = kring->nkr_num_slots - 1;
head = ring->head;
@ -2021,7 +2023,7 @@ ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched)
struct ptnet_csb_gh *ptgh = pq->ptgh;
struct ptnet_csb_hg *pthg = pq->pthg;
struct netmap_adapter *na = &sc->ptna->dr.up;
struct netmap_kring *kring = na->rx_rings + pq->kring_id;
struct netmap_kring *kring = na->rx_rings[pq->kring_id];
struct netmap_ring *ring = kring->ring;
unsigned int const lim = kring->nkr_num_slots - 1;
unsigned int batch_count = 0;

View file

@ -304,7 +304,7 @@ re_netmap_tx_init(struct rl_softc *sc)
/* l points in the netmap ring, i points in the NIC ring */
for (i = 0; i < n; i++) {
uint64_t paddr;
int l = netmap_idx_n2k(&na->tx_rings[0], i);
int l = netmap_idx_n2k(na->tx_rings[0], i);
void *addr = PNMB(na, slot + l, &paddr);
desc[i].rl_bufaddr_lo = htole32(RL_ADDR_LO(paddr));
@ -330,11 +330,11 @@ re_netmap_rx_init(struct rl_softc *sc)
* Do not release the slots owned by userspace,
* and also keep one empty.
*/
max_avail = n - 1 - nm_kr_rxspace(&na->rx_rings[0]);
max_avail = n - 1 - nm_kr_rxspace(na->rx_rings[0]);
for (nic_i = 0; nic_i < n; nic_i++) {
void *addr;
uint64_t paddr;
uint32_t nm_i = netmap_idx_n2k(&na->rx_rings[0], nic_i);
uint32_t nm_i = netmap_idx_n2k(na->rx_rings[0], nic_i);
addr = PNMB(na, slot + nm_i, &paddr);

View file

@ -383,7 +383,7 @@ vtnet_netmap_init_rx_buffers(struct SOFTC_T *sc)
if (!nm_native_on(na))
return 0;
for (r = 0; r < na->num_rx_rings; r++) {
struct netmap_kring *kring = &na->rx_rings[r];
struct netmap_kring *kring = na->rx_rings[r];
struct vtnet_rxq *rxq = &sc->vtnet_rxqs[r];
struct virtqueue *vq = rxq->vtnrx_vq;
struct netmap_slot* slot;
@ -407,29 +407,6 @@ vtnet_netmap_init_rx_buffers(struct SOFTC_T *sc)
return 1;
}
/* Update the virtio-net device configurations. Number of queues can
* change dinamically, by 'ethtool --set-channels $IFNAME combined $N'.
* This is actually the only way virtio-net can currently enable
* the multiqueue mode.
* XXX note that we seem to lose packets if the netmap ring has more
* slots than the queue
*/
static int
vtnet_netmap_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
u_int *rxr, u_int *rxd)
{
struct ifnet *ifp = na->ifp;
struct SOFTC_T *sc = ifp->if_softc;
*txr = *rxr = sc->vtnet_max_vq_pairs;
*rxd = 512; // sc->vtnet_rx_nmbufs;
*txd = *rxd; // XXX
D("vtnet config txq=%d, txd=%d rxq=%d, rxd=%d",
*txr, *txd, *rxr, *rxd);
return 0;
}
static void
vtnet_netmap_attach(struct SOFTC_T *sc)
{
@ -443,7 +420,6 @@ vtnet_netmap_attach(struct SOFTC_T *sc)
na.nm_register = vtnet_netmap_reg;
na.nm_txsync = vtnet_netmap_txsync;
na.nm_rxsync = vtnet_netmap_rxsync;
na.nm_config = vtnet_netmap_config;
na.nm_intr = vtnet_netmap_intr;
na.num_tx_rings = na.num_rx_rings = sc->vtnet_max_vq_pairs;
D("max rings %d", sc->vtnet_max_vq_pairs);

File diff suppressed because it is too large Load diff

View file

@ -619,6 +619,116 @@ nm_os_vi_detach(struct ifnet *ifp)
if_free(ifp);
}
#ifdef WITH_EXTMEM
#include <vm/vm_map.h>
#include <vm/vm_kern.h>
struct nm_os_extmem {
vm_object_t obj;
vm_offset_t kva;
vm_offset_t size;
vm_pindex_t scan;
};
void
nm_os_extmem_delete(struct nm_os_extmem *e)
{
D("freeing %lx bytes", e->size);
vm_map_remove(kernel_map, e->kva, e->kva + e->size);
nm_os_free(e);
}
char *
nm_os_extmem_nextpage(struct nm_os_extmem *e)
{
char *rv = NULL;
if (e->scan < e->kva + e->size) {
rv = (char *)e->scan;
e->scan += PAGE_SIZE;
}
return rv;
}
int
nm_os_extmem_isequal(struct nm_os_extmem *e1, struct nm_os_extmem *e2)
{
return (e1->obj == e1->obj);
}
int
nm_os_extmem_nr_pages(struct nm_os_extmem *e)
{
return e->size >> PAGE_SHIFT;
}
struct nm_os_extmem *
nm_os_extmem_create(unsigned long p, struct nmreq_pools_info *pi, int *perror)
{
vm_map_t map;
vm_map_entry_t entry;
vm_object_t obj;
vm_prot_t prot;
vm_pindex_t index;
boolean_t wired;
struct nm_os_extmem *e = NULL;
int rv, error = 0;
e = nm_os_malloc(sizeof(*e));
if (e == NULL) {
error = ENOMEM;
goto out;
}
map = &curthread->td_proc->p_vmspace->vm_map;
rv = vm_map_lookup(&map, p, VM_PROT_RW, &entry,
&obj, &index, &prot, &wired);
if (rv != KERN_SUCCESS) {
D("address %lx not found", p);
goto out_free;
}
/* check that we are given the whole vm_object ? */
vm_map_lookup_done(map, entry);
// XXX can we really use obj after releasing the map lock?
e->obj = obj;
vm_object_reference(obj);
/* wire the memory and add the vm_object to the kernel map,
* to make sure that it is not fred even if the processes that
* are mmap()ing it all exit
*/
e->kva = vm_map_min(kernel_map);
e->size = obj->size << PAGE_SHIFT;
rv = vm_map_find(kernel_map, obj, 0, &e->kva, e->size, 0,
VMFS_OPTIMAL_SPACE, VM_PROT_READ | VM_PROT_WRITE,
VM_PROT_READ | VM_PROT_WRITE, 0);
if (rv != KERN_SUCCESS) {
D("vm_map_find(%lx) failed", e->size);
goto out_rel;
}
rv = vm_map_wire(kernel_map, e->kva, e->kva + e->size,
VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES);
if (rv != KERN_SUCCESS) {
D("vm_map_wire failed");
goto out_rem;
}
e->scan = e->kva;
return e;
out_rem:
vm_map_remove(kernel_map, e->kva, e->kva + e->size);
e->obj = NULL;
out_rel:
vm_object_deallocate(e->obj);
out_free:
nm_os_free(e);
out:
if (perror)
*perror = error;
return NULL;
}
#endif /* WITH_EXTMEM */
/* ======================== PTNETMAP SUPPORT ========================== */
#ifdef WITH_PTNETMAP_GUEST
@ -1151,16 +1261,10 @@ nm_os_kctx_worker_setaff(struct nm_kctx *nmk, int affinity)
}
struct nm_kctx *
nm_os_kctx_create(struct nm_kctx_cfg *cfg, unsigned int cfgtype,
void *opaque)
nm_os_kctx_create(struct nm_kctx_cfg *cfg, void *opaque)
{
struct nm_kctx *nmk = NULL;
if (cfgtype != PTNETMAP_CFGTYPE_BHYVE) {
D("Unsupported cfgtype %u", cfgtype);
return NULL;
}
nmk = malloc(sizeof(*nmk), M_DEVBUF, M_NOWAIT | M_ZERO);
if (!nmk)
return NULL;
@ -1429,7 +1533,7 @@ freebsd_netmap_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
error = ENXIO;
goto out;
}
error = netmap_ioctl(priv, cmd, data, td);
error = netmap_ioctl(priv, cmd, data, td, /*nr_body_is_user=*/1);
out:
CURVNET_RESTORE();

View file

@ -232,7 +232,7 @@ nm_os_get_mbuf(struct ifnet *ifp, int len)
#define for_each_kring_n(_i, _k, _karr, _n) \
for (_k=_karr, _i = 0; _i < _n; (_k)++, (_i)++)
for ((_k)=*(_karr), (_i) = 0; (_i) < (_n); (_i)++, (_k) = (_karr)[(_i)])
#define for_each_tx_kring(_i, _k, _na) \
for_each_kring_n(_i, _k, (_na)->tx_rings, (_na)->num_tx_rings)
@ -589,7 +589,7 @@ generic_mbuf_destructor(struct mbuf *m)
for (;;) {
bool match = false;
kring = &na->tx_rings[r];
kring = na->tx_rings[r];
mtx_lock_spin(&kring->tx_event_lock);
if (kring->tx_event == m) {
kring->tx_event = NULL;
@ -953,7 +953,7 @@ generic_rx_handler(struct ifnet *ifp, struct mbuf *m)
r = r % na->num_rx_rings;
}
kring = &na->rx_rings[r];
kring = na->rx_rings[r];
if (kring->nr_mode == NKR_NETMAP_OFF) {
/* We must not intercept this mbuf. */

View file

@ -77,7 +77,7 @@
#define WITH_GENERIC
#define WITH_PTNETMAP_HOST /* ptnetmap host support */
#define WITH_PTNETMAP_GUEST /* ptnetmap guest support */
#define WITH_EXTMEM
#endif
#if defined(__FreeBSD__)
@ -367,9 +367,6 @@ struct netmap_zmon_list {
* the next empty buffer as known by the hardware (next_to_check or so).
* TX rings: hwcur + hwofs coincides with next_to_send
*
* For received packets, slot->flags is set to nkr_slot_flags
* so we can provide a proper initial value.
*
* The following fields are used to implement lock-free copy of packets
* from input to output ports in VALE switch:
* nkr_hwlease buffer after the last one being copied.
@ -401,7 +398,7 @@ struct netmap_zmon_list {
struct netmap_kring {
struct netmap_ring *ring;
uint32_t nr_hwcur;
uint32_t nr_hwcur; /* should be nr_hwhead */
uint32_t nr_hwtail;
/*
@ -424,6 +421,7 @@ struct netmap_kring {
* by ptnetmap host ports)
*/
#define NKR_NOINTR 0x10 /* don't use interrupts on this ring */
#define NKR_FAKERING 0x20 /* don't allocate/free buffers */
uint32_t nr_mode;
uint32_t nr_pending_mode;
@ -450,7 +448,14 @@ struct netmap_kring {
NM_LOCK_T q_lock; /* protects kring and ring. */
NM_ATOMIC_T nr_busy; /* prevent concurrent syscalls */
/* the adapter the owns this kring */
struct netmap_adapter *na;
/* the adapter that wants to be notified when this kring has
* new slots avaialable. This is usually the same as the above,
* but wrappers may let it point to themselves
*/
struct netmap_adapter *notify_na;
/* The following fields are for VALE switch support */
struct nm_bdg_fwd *nkr_ft;
@ -630,6 +635,15 @@ struct netmap_lut {
struct netmap_vp_adapter; // forward
/* Struct to be filled by nm_config callbacks. */
struct nm_config_info {
unsigned num_tx_rings;
unsigned num_rx_rings;
unsigned num_tx_descs;
unsigned num_rx_descs;
unsigned rx_buf_maxsize;
};
/*
* The "struct netmap_adapter" extends the "struct adapter"
* (or equivalent) device descriptor.
@ -690,8 +704,8 @@ struct netmap_adapter {
* as a contiguous chunk of memory. Each array has
* N+1 entries, for the adapter queues and for the host queue.
*/
struct netmap_kring *tx_rings; /* array of TX rings. */
struct netmap_kring *rx_rings; /* array of RX rings. */
struct netmap_kring **tx_rings; /* array of TX rings. */
struct netmap_kring **rx_rings; /* array of RX rings. */
void *tailroom; /* space below the rings array */
/* (used for leases) */
@ -766,8 +780,7 @@ struct netmap_adapter {
#define NAF_FORCE_RECLAIM 2
#define NAF_CAN_FORWARD_DOWN 4
/* return configuration information */
int (*nm_config)(struct netmap_adapter *,
u_int *txr, u_int *txd, u_int *rxr, u_int *rxd);
int (*nm_config)(struct netmap_adapter *, struct nm_config_info *info);
int (*nm_krings_create)(struct netmap_adapter *);
void (*nm_krings_delete)(struct netmap_adapter *);
#ifdef WITH_VALE
@ -787,7 +800,7 @@ struct netmap_adapter {
* Called with NMG_LOCK held.
*/
int (*nm_bdg_attach)(const char *bdg_name, struct netmap_adapter *);
int (*nm_bdg_ctl)(struct netmap_adapter *, struct nmreq *, int);
int (*nm_bdg_ctl)(struct nmreq_header *, struct netmap_adapter *);
/* adapter used to attach this adapter to a VALE switch (if any) */
struct netmap_vp_adapter *na_vp;
@ -823,7 +836,13 @@ struct netmap_adapter {
/* Offset of ethernet header for each packet. */
u_int virt_hdr_len;
char name[64];
/* Max number of bytes that the NIC can store in the buffer
* referenced by each RX descriptor. This translates to the maximum
* bytes that a single netmap slot can reference. Larger packets
* require NS_MOREFRAG support. */
unsigned rx_buf_maxsize;
char name[NETMAP_REQ_IFNAMSIZ]; /* used at least by pipes */
};
static __inline u_int
@ -856,7 +875,7 @@ nma_set_nrings(struct netmap_adapter *na, enum txrx t, u_int v)
na->num_rx_rings = v;
}
static __inline struct netmap_kring*
static __inline struct netmap_kring**
NMR(struct netmap_adapter *na, enum txrx t)
{
return (t == NR_TX ? na->tx_rings : na->rx_rings);
@ -1011,12 +1030,22 @@ struct netmap_bwrap_adapter {
*/
struct netmap_priv_d *na_kpriv;
struct nm_bdg_polling_state *na_polling_state;
/* we overwrite the hwna->na_vp pointer, so we save
* here its original value, to be restored at detach
*/
struct netmap_vp_adapter *saved_na_vp;
};
int nm_bdg_ctl_attach(struct nmreq_header *hdr, void *auth_token);
int nm_bdg_ctl_detach(struct nmreq_header *hdr, void *auth_token);
int nm_bdg_polling(struct nmreq_header *hdr);
int netmap_bwrap_attach(const char *name, struct netmap_adapter *);
int netmap_vi_create(struct nmreq *, int);
int netmap_vi_create(struct nmreq_header *hdr, int);
int nm_vi_create(struct nmreq_header *);
int nm_vi_destroy(const char *name);
int netmap_bdg_list(struct nmreq_header *hdr);
#else /* !WITH_VALE */
#define netmap_vi_create(nmr, a) (EOPNOTSUPP)
#define netmap_vi_create(hdr, a) (EOPNOTSUPP)
#endif /* WITH_VALE */
#ifdef WITH_PIPES
@ -1024,10 +1053,12 @@ int netmap_vi_create(struct nmreq *, int);
#define NM_MAXPIPES 64 /* max number of pipes per adapter */
struct netmap_pipe_adapter {
/* pipe identifier is up.name */
struct netmap_adapter up;
u_int id; /* pipe identifier */
int role; /* either NR_REG_PIPE_MASTER or NR_REG_PIPE_SLAVE */
#define NM_PIPE_ROLE_MASTER 0x1
#define NM_PIPE_ROLE_SLAVE 0x2
int role; /* either NM_PIPE_ROLE_MASTER or NM_PIPE_ROLE_SLAVE */
struct netmap_adapter *parent; /* adapter that owns the memory */
struct netmap_pipe_adapter *peer; /* the other end of the pipe */
@ -1195,6 +1226,7 @@ int netmap_transmit(struct ifnet *, struct mbuf *);
struct netmap_slot *netmap_reset(struct netmap_adapter *na,
enum txrx tx, u_int n, u_int new_cur);
int netmap_ring_reinit(struct netmap_kring *);
int netmap_rings_config_get(struct netmap_adapter *, struct nm_config_info *);
/* Return codes for netmap_*x_irq. */
enum {
@ -1255,10 +1287,10 @@ static inline void
nm_update_hostrings_mode(struct netmap_adapter *na)
{
/* Process nr_mode and nr_pending_mode for host rings. */
na->tx_rings[na->num_tx_rings].nr_mode =
na->tx_rings[na->num_tx_rings].nr_pending_mode;
na->rx_rings[na->num_rx_rings].nr_mode =
na->rx_rings[na->num_rx_rings].nr_pending_mode;
na->tx_rings[na->num_tx_rings]->nr_mode =
na->tx_rings[na->num_tx_rings]->nr_pending_mode;
na->rx_rings[na->num_rx_rings]->nr_mode =
na->rx_rings[na->num_rx_rings]->nr_pending_mode;
}
/* set/clear native flags and if_transmit/netdev_ops */
@ -1318,6 +1350,11 @@ nm_clear_native_flags(struct netmap_adapter *na)
#endif
}
#ifdef linux
int netmap_linux_config(struct netmap_adapter *na,
struct nm_config_info *info);
#endif /* linux */
/*
* nm_*sync_prologue() functions are used in ioctl/poll and ptnetmap
* kthreads.
@ -1373,9 +1410,10 @@ uint32_t nm_rxsync_prologue(struct netmap_kring *, struct netmap_ring *);
*/
int netmap_attach_common(struct netmap_adapter *);
/* fill priv->np_[tr]xq{first,last} using the ringid and flags information
* coming from a struct nmreq
* coming from a struct nmreq_register
*/
int netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags);
int netmap_interp_ringid(struct netmap_priv_d *priv, uint32_t nr_mode,
uint16_t nr_ringid, uint64_t nr_flags);
/* update the ring parameters (number and size of tx and rx rings).
* It calls the nm_config callback, if available.
*/
@ -1409,12 +1447,12 @@ void netmap_disable_all_rings(struct ifnet *);
void netmap_enable_all_rings(struct ifnet *);
int netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
uint16_t ringid, uint32_t flags);
uint32_t nr_mode, uint16_t nr_ringid, uint64_t nr_flags);
void netmap_do_unregif(struct netmap_priv_d *priv);
u_int nm_bound_var(u_int *v, u_int dflt, u_int lo, u_int hi, const char *msg);
int netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na,
struct ifnet **ifp, struct netmap_mem_d *nmd, int create);
int netmap_get_na(struct nmreq_header *hdr, struct netmap_adapter **na,
struct ifnet **ifp, struct netmap_mem_d *nmd, int create);
void netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp);
int netmap_get_hw_na(struct ifnet *ifp,
struct netmap_mem_d *nmd, struct netmap_adapter **na);
@ -1430,18 +1468,19 @@ int netmap_get_hw_na(struct ifnet *ifp,
* NM_BDG_MAXPORTS for broadcast, NM_BDG_MAXPORTS+1 to indicate
* drop.
*/
typedef u_int (*bdg_lookup_fn_t)(struct nm_bdg_fwd *ft, uint8_t *ring_nr,
struct netmap_vp_adapter *);
typedef uint32_t (*bdg_lookup_fn_t)(struct nm_bdg_fwd *ft, uint8_t *ring_nr,
struct netmap_vp_adapter *, void *private_data);
typedef int (*bdg_config_fn_t)(struct nm_ifreq *);
typedef void (*bdg_dtor_fn_t)(const struct netmap_vp_adapter *);
typedef void *(*bdg_update_private_data_fn_t)(void *private_data, void *callback_data, int *error);
struct netmap_bdg_ops {
bdg_lookup_fn_t lookup;
bdg_config_fn_t config;
bdg_dtor_fn_t dtor;
};
u_int netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
struct netmap_vp_adapter *);
uint32_t netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
struct netmap_vp_adapter *, void *private_data);
#define NM_BRIDGES 8 /* number of bridges */
#define NM_BDG_MAXPORTS 254 /* up to 254 */
@ -1449,45 +1488,47 @@ u_int netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
#define NM_BDG_NOPORT (NM_BDG_MAXPORTS+1)
/* these are redefined in case of no VALE support */
int netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na,
int netmap_get_bdg_na(struct nmreq_header *hdr, struct netmap_adapter **na,
struct netmap_mem_d *nmd, int create);
struct nm_bridge *netmap_init_bridges2(u_int);
void netmap_uninit_bridges2(struct nm_bridge *, u_int);
int netmap_init_bridges(void);
void netmap_uninit_bridges(void);
int netmap_bdg_ctl(struct nmreq *nmr, struct netmap_bdg_ops *bdg_ops);
int netmap_bdg_config(struct nmreq *nmr);
int netmap_bdg_regops(const char *name, struct netmap_bdg_ops *bdg_ops, void *private_data, void *auth_token);
int nm_bdg_update_private_data(const char *name, bdg_update_private_data_fn_t callback,
void *callback_data, void *auth_token);
int netmap_bdg_config(struct nm_ifreq *nifr);
void *netmap_bdg_create(const char *bdg_name, int *return_status);
int netmap_bdg_destroy(const char *bdg_name, void *auth_token);
#else /* !WITH_VALE */
#define netmap_get_bdg_na(_1, _2, _3, _4) 0
#define netmap_init_bridges(_1) 0
#define netmap_uninit_bridges()
#define netmap_bdg_ctl(_1, _2) EINVAL
#define netmap_bdg_regops(_1, _2) EINVAL
#endif /* !WITH_VALE */
#ifdef WITH_PIPES
/* max number of pipes per device */
#define NM_MAXPIPES 64 /* XXX this should probably be a sysctl */
void netmap_pipe_dealloc(struct netmap_adapter *);
int netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
struct netmap_mem_d *nmd, int create);
int netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
struct netmap_mem_d *nmd, int create);
#else /* !WITH_PIPES */
#define NM_MAXPIPES 0
#define netmap_pipe_alloc(_1, _2) 0
#define netmap_pipe_dealloc(_1)
#define netmap_get_pipe_na(nmr, _2, _3, _4) \
({ int role__ = (nmr)->nr_flags & NR_REG_MASK; \
(role__ == NR_REG_PIPE_MASTER || \
role__ == NR_REG_PIPE_SLAVE) ? EOPNOTSUPP : 0; })
#define netmap_get_pipe_na(hdr, _2, _3, _4) \
((strchr(hdr->nr_name, '{') != NULL || strchr(hdr->nr_name, '}') != NULL) ? EOPNOTSUPP : 0)
#endif
#ifdef WITH_MONITOR
int netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
int netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
struct netmap_mem_d *nmd, int create);
void netmap_monitor_stop(struct netmap_adapter *na);
#else
#define netmap_get_monitor_na(nmr, _2, _3, _4) \
((nmr)->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX) ? EOPNOTSUPP : 0)
#define netmap_get_monitor_na(hdr, _2, _3, _4) \
(((struct nmreq_register *)hdr->nr_body)->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX) ? EOPNOTSUPP : 0)
#endif
#ifdef CONFIG_NET_NS
@ -1508,7 +1549,11 @@ void netmap_fini(void);
int netmap_get_memory(struct netmap_priv_d* p);
void netmap_dtor(void *data);
int netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *);
int netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
struct thread *, int nr_body_is_user);
int netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
struct thread *td);
size_t nmreq_size_by_type(uint16_t nr_reqtype);
/* netmap_adapter creation/destruction */
@ -1871,7 +1916,7 @@ static inline int nm_kring_pending(struct netmap_priv_d *np)
for_rx_tx(t) {
for (i = np->np_qfirst[t]; i < np->np_qlast[t]; i++) {
struct netmap_kring *kring = &NMR(na, t)[i];
struct netmap_kring *kring = NMR(na, t)[i];
if (kring->nr_mode != kring->nr_pending_mode) {
return 1;
}
@ -1980,7 +2025,7 @@ void nm_os_mitigation_cleanup(struct nm_generic_mit *mit);
struct nm_bdg_fwd { /* forwarding entry for a bridge */
void *ft_buf; /* netmap or indirect buffer */
uint8_t ft_frags; /* how many fragments (only on 1st frag) */
uint8_t _ft_port; /* dst port (unused) */
uint16_t ft_offset; /* dst port (unused) */
uint16_t ft_flags; /* flags, e.g. indirect */
uint16_t ft_len; /* src fragment len */
uint16_t ft_next; /* next packet to same destination */
@ -2094,7 +2139,6 @@ struct nm_kctx_cfg {
};
/* kthread configuration */
struct nm_kctx *nm_os_kctx_create(struct nm_kctx_cfg *cfg,
unsigned int cfgtype,
void *opaque);
int nm_os_kctx_worker_start(struct nm_kctx *);
void nm_os_kctx_worker_stop(struct nm_kctx *);
@ -2120,19 +2164,21 @@ struct netmap_pt_host_adapter {
int (*parent_nm_notify)(struct netmap_kring *kring, int flags);
void *ptns;
};
/* ptnetmap HOST routines */
int netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na,
struct netmap_mem_d * nmd, int create);
int ptnetmap_ctl(struct nmreq *nmr, struct netmap_adapter *na);
/* ptnetmap host-side routines */
int netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
struct netmap_mem_d * nmd, int create);
int ptnetmap_ctl(const char *nr_name, int create, struct netmap_adapter *na);
static inline int
nm_ptnetmap_host_on(struct netmap_adapter *na)
{
return na && na->na_flags & NAF_PTNETMAP_HOST;
}
#else /* !WITH_PTNETMAP_HOST */
#define netmap_get_pt_host_na(nmr, _2, _3, _4) \
((nmr)->nr_flags & (NR_PTNETMAP_HOST) ? EOPNOTSUPP : 0)
#define ptnetmap_ctl(_1, _2) EINVAL
#define netmap_get_pt_host_na(hdr, _2, _3, _4) \
(((struct nmreq_register *)hdr->nr_body)->nr_flags & (NR_PTNETMAP_HOST) ? EOPNOTSUPP : 0)
#define ptnetmap_ctl(_1, _2, _3) EINVAL
#define nm_ptnetmap_host_on(_1) EINVAL
#endif /* !WITH_PTNETMAP_HOST */
@ -2175,4 +2221,7 @@ void ptnet_nm_krings_delete(struct netmap_adapter *na);
void ptnet_nm_dtor(struct netmap_adapter *na);
#endif /* WITH_PTNETMAP_GUEST */
struct nmreq_option * nmreq_findoption(struct nmreq_option *, uint16_t);
int nmreq_checkduplicate(struct nmreq_option *);
#endif /* _NET_NETMAP_KERN_H_ */

View file

@ -0,0 +1,428 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (C) 2018 Vincenzo Maffione
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* $FreeBSD$ */
#if defined(__FreeBSD__)
#include <sys/cdefs.h> /* prerequisite */
#include <sys/types.h>
#include <sys/param.h> /* defines used in kernel.h */
#include <sys/filio.h> /* FIONBIO */
#include <sys/malloc.h>
#include <sys/socketvar.h> /* struct socket */
#include <sys/socket.h> /* sockaddrs */
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/bpf.h> /* BIOCIMMEDIATE */
#include <machine/bus.h> /* bus_dmamap_* */
#include <sys/endian.h>
#elif defined(linux)
#include "bsd_glue.h"
#elif defined(__APPLE__)
#warning OSX support is only partial
#include "osx_glue.h"
#elif defined (_WIN32)
#include "win_glue.h"
#endif
/*
* common headers
*/
#include <net/netmap.h>
#include <dev/netmap/netmap_kern.h>
static int
nmreq_register_from_legacy(struct nmreq *nmr, struct nmreq_header *hdr,
struct nmreq_register *req)
{
req->nr_offset = nmr->nr_offset;
req->nr_memsize = nmr->nr_memsize;
req->nr_tx_slots = nmr->nr_tx_slots;
req->nr_rx_slots = nmr->nr_rx_slots;
req->nr_tx_rings = nmr->nr_tx_rings;
req->nr_rx_rings = nmr->nr_rx_rings;
req->nr_mem_id = nmr->nr_arg2;
req->nr_ringid = nmr->nr_ringid & NETMAP_RING_MASK;
if ((nmr->nr_flags & NR_REG_MASK) == NR_REG_DEFAULT) {
/* Convert the older nmr->nr_ringid (original
* netmap control API) to nmr->nr_flags. */
u_int regmode = NR_REG_DEFAULT;
if (req->nr_ringid & NETMAP_SW_RING) {
regmode = NR_REG_SW;
} else if (req->nr_ringid & NETMAP_HW_RING) {
regmode = NR_REG_ONE_NIC;
} else {
regmode = NR_REG_ALL_NIC;
}
nmr->nr_flags = regmode |
(nmr->nr_flags & (~NR_REG_MASK));
}
req->nr_mode = nmr->nr_flags & NR_REG_MASK;
/* Fix nr_name, nr_mode and nr_ringid to handle pipe requests. */
if (req->nr_mode == NR_REG_PIPE_MASTER ||
req->nr_mode == NR_REG_PIPE_SLAVE) {
char suffix[10];
snprintf(suffix, sizeof(suffix), "%c%d",
(req->nr_mode == NR_REG_PIPE_MASTER ? '{' : '}'),
req->nr_ringid);
if (strlen(hdr->nr_name) + strlen(suffix)
>= sizeof(hdr->nr_name)) {
/* No space for the pipe suffix. */
return ENOBUFS;
}
strncat(hdr->nr_name, suffix, strlen(suffix));
req->nr_mode = NR_REG_ALL_NIC;
req->nr_ringid = 0;
}
req->nr_flags = nmr->nr_flags & (~NR_REG_MASK);
if (nmr->nr_ringid & NETMAP_NO_TX_POLL) {
req->nr_flags |= NR_NO_TX_POLL;
}
if (nmr->nr_ringid & NETMAP_DO_RX_POLL) {
req->nr_flags |= NR_DO_RX_POLL;
}
/* nmr->nr_arg1 (nr_pipes) ignored */
req->nr_extra_bufs = nmr->nr_arg3;
return 0;
}
/* Convert the legacy 'nmr' struct into one of the nmreq_xyz structs
* (new API). The new struct is dynamically allocated. */
static struct nmreq_header *
nmreq_from_legacy(struct nmreq *nmr, u_long ioctl_cmd)
{
struct nmreq_header *hdr = nm_os_malloc(sizeof(*hdr));
if (hdr == NULL) {
goto oom;
}
/* Sanitize nmr->nr_name by adding the string terminator. */
if (ioctl_cmd == NIOCGINFO || ioctl_cmd == NIOCREGIF) {
nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0';
}
/* First prepare the request header. */
hdr->nr_version = NETMAP_API; /* new API */
strncpy(hdr->nr_name, nmr->nr_name, sizeof(nmr->nr_name));
hdr->nr_options = (uint64_t)NULL;
hdr->nr_body = (uint64_t)NULL;
switch (ioctl_cmd) {
case NIOCREGIF: {
switch (nmr->nr_cmd) {
case 0: {
/* Regular NIOCREGIF operation. */
struct nmreq_register *req = nm_os_malloc(sizeof(*req));
if (!req) { goto oom; }
hdr->nr_body = (uint64_t)req;
hdr->nr_reqtype = NETMAP_REQ_REGISTER;
if (nmreq_register_from_legacy(nmr, hdr, req)) {
goto oom;
}
break;
}
case NETMAP_BDG_ATTACH: {
struct nmreq_vale_attach *req = nm_os_malloc(sizeof(*req));
if (!req) { goto oom; }
hdr->nr_body = (uint64_t)req;
hdr->nr_reqtype = NETMAP_REQ_VALE_ATTACH;
if (nmreq_register_from_legacy(nmr, hdr, &req->reg)) {
goto oom;
}
/* Fix nr_mode, starting from nr_arg1. */
if (nmr->nr_arg1 & NETMAP_BDG_HOST) {
req->reg.nr_mode = NR_REG_NIC_SW;
} else {
req->reg.nr_mode = NR_REG_ALL_NIC;
}
break;
}
case NETMAP_BDG_DETACH: {
hdr->nr_reqtype = NETMAP_REQ_VALE_DETACH;
hdr->nr_body = (uint64_t)nm_os_malloc(sizeof(struct nmreq_vale_detach));
break;
}
case NETMAP_BDG_VNET_HDR:
case NETMAP_VNET_HDR_GET: {
struct nmreq_port_hdr *req = nm_os_malloc(sizeof(*req));
if (!req) { goto oom; }
hdr->nr_body = (uint64_t)req;
hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_VNET_HDR) ?
NETMAP_REQ_PORT_HDR_SET : NETMAP_REQ_PORT_HDR_GET;
req->nr_hdr_len = nmr->nr_arg1;
break;
}
case NETMAP_BDG_NEWIF : {
struct nmreq_vale_newif *req = nm_os_malloc(sizeof(*req));
if (!req) { goto oom; }
hdr->nr_body = (uint64_t)req;
hdr->nr_reqtype = NETMAP_REQ_VALE_NEWIF;
req->nr_tx_slots = nmr->nr_tx_slots;
req->nr_rx_slots = nmr->nr_rx_slots;
req->nr_tx_rings = nmr->nr_tx_rings;
req->nr_rx_rings = nmr->nr_rx_rings;
req->nr_mem_id = nmr->nr_arg2;
break;
}
case NETMAP_BDG_DELIF: {
hdr->nr_reqtype = NETMAP_REQ_VALE_DELIF;
break;
}
case NETMAP_BDG_POLLING_ON:
case NETMAP_BDG_POLLING_OFF: {
struct nmreq_vale_polling *req = nm_os_malloc(sizeof(*req));
if (!req) { goto oom; }
hdr->nr_body = (uint64_t)req;
hdr->nr_reqtype = (nmr->nr_cmd == NETMAP_BDG_POLLING_ON) ?
NETMAP_REQ_VALE_POLLING_ENABLE :
NETMAP_REQ_VALE_POLLING_DISABLE;
switch (nmr->nr_flags & NR_REG_MASK) {
default:
req->nr_mode = 0; /* invalid */
break;
case NR_REG_ONE_NIC:
req->nr_mode = NETMAP_POLLING_MODE_MULTI_CPU;
break;
case NR_REG_ALL_NIC:
req->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
break;
}
req->nr_first_cpu_id = nmr->nr_ringid & NETMAP_RING_MASK;
req->nr_num_polling_cpus = nmr->nr_arg1;
break;
}
case NETMAP_PT_HOST_CREATE:
case NETMAP_PT_HOST_DELETE: {
D("Netmap passthrough not supported yet");
return NULL;
break;
}
}
break;
}
case NIOCGINFO: {
if (nmr->nr_cmd == NETMAP_BDG_LIST) {
struct nmreq_vale_list *req = nm_os_malloc(sizeof(*req));
if (!req) { goto oom; }
hdr->nr_body = (uint64_t)req;
hdr->nr_reqtype = NETMAP_REQ_VALE_LIST;
req->nr_bridge_idx = nmr->nr_arg1;
req->nr_port_idx = nmr->nr_arg2;
} else {
/* Regular NIOCGINFO. */
struct nmreq_port_info_get *req = nm_os_malloc(sizeof(*req));
if (!req) { goto oom; }
hdr->nr_body = (uint64_t)req;
hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
req->nr_offset = nmr->nr_offset;
req->nr_memsize = nmr->nr_memsize;
req->nr_tx_slots = nmr->nr_tx_slots;
req->nr_rx_slots = nmr->nr_rx_slots;
req->nr_tx_rings = nmr->nr_tx_rings;
req->nr_rx_rings = nmr->nr_rx_rings;
req->nr_mem_id = nmr->nr_arg2;
}
break;
}
}
return hdr;
oom:
if (hdr) {
if (hdr->nr_body) {
nm_os_free((void *)hdr->nr_body);
}
nm_os_free(hdr);
}
D("Failed to allocate memory for nmreq_xyz struct");
return NULL;
}
static void
nmreq_register_to_legacy(const struct nmreq_register *req, struct nmreq *nmr)
{
nmr->nr_offset = req->nr_offset;
nmr->nr_memsize = req->nr_memsize;
nmr->nr_tx_slots = req->nr_tx_slots;
nmr->nr_rx_slots = req->nr_rx_slots;
nmr->nr_tx_rings = req->nr_tx_rings;
nmr->nr_rx_rings = req->nr_rx_rings;
nmr->nr_arg2 = req->nr_mem_id;
nmr->nr_arg3 = req->nr_extra_bufs;
}
/* Convert a nmreq_xyz struct (new API) to the legacy 'nmr' struct.
* It also frees the nmreq_xyz struct, as it was allocated by
* nmreq_from_legacy(). */
static int
nmreq_to_legacy(struct nmreq_header *hdr, struct nmreq *nmr)
{
int ret = 0;
/* We only write-back the fields that the user expects to be
* written back. */
switch (hdr->nr_reqtype) {
case NETMAP_REQ_REGISTER: {
struct nmreq_register *req =
(struct nmreq_register *)hdr->nr_body;
nmreq_register_to_legacy(req, nmr);
break;
}
case NETMAP_REQ_PORT_INFO_GET: {
struct nmreq_port_info_get *req =
(struct nmreq_port_info_get *)hdr->nr_body;
nmr->nr_offset = req->nr_offset;
nmr->nr_memsize = req->nr_memsize;
nmr->nr_tx_slots = req->nr_tx_slots;
nmr->nr_rx_slots = req->nr_rx_slots;
nmr->nr_tx_rings = req->nr_tx_rings;
nmr->nr_rx_rings = req->nr_rx_rings;
nmr->nr_arg2 = req->nr_mem_id;
break;
}
case NETMAP_REQ_VALE_ATTACH: {
struct nmreq_vale_attach *req =
(struct nmreq_vale_attach *)hdr->nr_body;
nmreq_register_to_legacy(&req->reg, nmr);
break;
}
case NETMAP_REQ_VALE_DETACH: {
break;
}
case NETMAP_REQ_VALE_LIST: {
struct nmreq_vale_list *req =
(struct nmreq_vale_list *)hdr->nr_body;
strncpy(nmr->nr_name, hdr->nr_name, sizeof(nmr->nr_name));
nmr->nr_arg1 = req->nr_bridge_idx;
nmr->nr_arg2 = req->nr_port_idx;
break;
}
case NETMAP_REQ_PORT_HDR_SET:
case NETMAP_REQ_PORT_HDR_GET: {
struct nmreq_port_hdr *req =
(struct nmreq_port_hdr *)hdr->nr_body;
nmr->nr_arg1 = req->nr_hdr_len;
break;
}
case NETMAP_REQ_VALE_NEWIF: {
struct nmreq_vale_newif *req =
(struct nmreq_vale_newif *)hdr->nr_body;
nmr->nr_tx_slots = req->nr_tx_slots;
nmr->nr_rx_slots = req->nr_rx_slots;
nmr->nr_tx_rings = req->nr_tx_rings;
nmr->nr_rx_rings = req->nr_rx_rings;
nmr->nr_arg2 = req->nr_mem_id;
break;
}
case NETMAP_REQ_VALE_DELIF:
case NETMAP_REQ_VALE_POLLING_ENABLE:
case NETMAP_REQ_VALE_POLLING_DISABLE: {
break;
}
}
return ret;
}
int
netmap_ioctl_legacy(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
struct thread *td)
{
int error = 0;
switch (cmd) {
case NIOCGINFO:
case NIOCREGIF: {
/* Request for the legacy control API. Convert it to a
* NIOCCTRL request. */
struct nmreq *nmr = (struct nmreq *) data;
struct nmreq_header *hdr = nmreq_from_legacy(nmr, cmd);
if (hdr == NULL) { /* out of memory */
return ENOMEM;
}
error = netmap_ioctl(priv, NIOCCTRL, (caddr_t)hdr, td,
/*nr_body_is_user=*/0);
if (error == 0) {
nmreq_to_legacy(hdr, nmr);
}
if (hdr->nr_body) {
nm_os_free((void *)hdr->nr_body);
}
nm_os_free(hdr);
break;
}
#ifdef WITH_VALE
case NIOCCONFIG: {
struct nm_ifreq *nr = (struct nm_ifreq *)data;
error = netmap_bdg_config(nr);
break;
}
#endif
#ifdef __FreeBSD__
case FIONBIO:
case FIOASYNC:
ND("FIONBIO/FIOASYNC are no-ops");
break;
case BIOCIMMEDIATE:
case BIOCGHDRCMPLT:
case BIOCSHDRCMPLT:
case BIOCSSEESENT:
D("ignore BIOCIMMEDIATE/BIOCSHDRCMPLT/BIOCSHDRCMPLT/BIOCSSEESENT");
break;
default: /* allow device-specific ioctls */
{
struct nmreq *nmr = (struct nmreq *)data;
struct ifnet *ifp = ifunit_ref(nmr->nr_name);
if (ifp == NULL) {
error = ENXIO;
} else {
struct socket so;
bzero(&so, sizeof(so));
so.so_vnet = ifp->if_vnet;
// so->so_proto not null.
error = ifioctl(&so, cmd, data, td);
if_rele(ifp);
}
break;
}
#else /* linux */
default:
error = EOPNOTSUPP;
#endif /* linux */
}
return error;
}

File diff suppressed because it is too large Load diff

View file

@ -137,12 +137,12 @@ void netmap_mem_if_delete(struct netmap_adapter *, struct netmap_if *);
int netmap_mem_rings_create(struct netmap_adapter *);
void netmap_mem_rings_delete(struct netmap_adapter *);
int netmap_mem_deref(struct netmap_mem_d *, struct netmap_adapter *);
int netmap_mem2_get_pool_info(struct netmap_mem_d *, u_int, u_int *, u_int *);
int netmap_mem_get_info(struct netmap_mem_d *, uint64_t *size, u_int *memflags, uint16_t *id);
int netmap_mem2_get_pool_info(struct netmap_mem_d *, u_int, u_int *, u_int *);
int netmap_mem_get_info(struct netmap_mem_d *, uint64_t *size,
u_int *memflags, nm_memid_t *id);
ssize_t netmap_mem_if_offset(struct netmap_mem_d *, const void *vaddr);
struct netmap_mem_d* netmap_mem_private_new( u_int txr, u_int txd, u_int rxr, u_int rxd,
u_int extra_bufs, u_int npipes, int* error);
void netmap_mem_delete(struct netmap_mem_d *);
#define netmap_mem_get(d) __netmap_mem_get(d, __FUNCTION__, __LINE__)
#define netmap_mem_put(d) __netmap_mem_put(d, __FUNCTION__, __LINE__)
@ -152,7 +152,7 @@ struct netmap_mem_d* netmap_mem_find(nm_memid_t);
unsigned netmap_mem_bufsize(struct netmap_mem_d *nmd);
#ifdef WITH_EXTMEM
struct netmap_mem_d* netmap_mem_ext_create(struct nmreq *, int *);
struct netmap_mem_d* netmap_mem_ext_create(uint64_t, struct nmreq_pools_info *, int *);
#else /* !WITH_EXTMEM */
#define netmap_mem_ext_create(nmr, _perr) \
({ int *perr = _perr; if (perr) *(perr) = EOPNOTSUPP; NULL; })
@ -167,7 +167,8 @@ struct netmap_mem_d* netmap_mem_pt_guest_attach(struct ptnetmap_memdev *, uint16
int netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *, struct ifnet *);
#endif /* WITH_PTNETMAP_GUEST */
int netmap_mem_pools_info_get(struct nmreq *, struct netmap_mem_d *);
int netmap_mem_pools_info_get(struct nmreq_pools_info *,
struct netmap_mem_d *);
#define NETMAP_MEM_PRIVATE 0x2 /* allocator uses private address space */
#define NETMAP_MEM_IO 0x4 /* the underlying memory is mmapped I/O */
@ -175,4 +176,14 @@ int netmap_mem_pools_info_get(struct nmreq *, struct netmap_mem_d *);
uint32_t netmap_extra_alloc(struct netmap_adapter *, uint32_t *, uint32_t n);
#ifdef WITH_EXTMEM
#include <net/netmap_virt.h>
struct nm_os_extmem; /* opaque */
struct nm_os_extmem *nm_os_extmem_create(unsigned long, struct nmreq_pools_info *, int *perror);
char *nm_os_extmem_nextpage(struct nm_os_extmem *);
int nm_os_extmem_nr_pages(struct nm_os_extmem *);
int nm_os_extmem_isequal(struct nm_os_extmem *, struct nm_os_extmem *);
void nm_os_extmem_delete(struct nm_os_extmem *);
#endif /* WITH_EXTMEM */
#endif

View file

@ -167,8 +167,8 @@ netmap_monitor_krings_create(struct netmap_adapter *na)
if (error)
return error;
/* override the host rings callbacks */
na->tx_rings[na->num_tx_rings].nm_sync = netmap_monitor_txsync;
na->rx_rings[na->num_rx_rings].nm_sync = netmap_monitor_rxsync;
na->tx_rings[na->num_tx_rings]->nm_sync = netmap_monitor_txsync;
na->rx_rings[na->num_rx_rings]->nm_sync = netmap_monitor_rxsync;
return 0;
}
@ -390,7 +390,7 @@ netmap_monitor_stop(struct netmap_adapter *na)
u_int i;
for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
struct netmap_kring *kring = &NMR(na, t)[i];
struct netmap_kring *kring = NMR(na, t)[i];
struct netmap_kring *zkring;
u_int j;
@ -456,7 +456,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon)
}
for_rx_tx(t) {
for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
mkring = &NMR(na, t)[i];
mkring = NMR(na, t)[i];
if (!nm_kring_pending_on(mkring))
continue;
mkring->nr_mode = NKR_NETMAP_ON;
@ -466,7 +466,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon)
if (i > nma_get_nrings(pna, s))
continue;
if (mna->flags & nm_txrx2flag(s)) {
kring = &NMR(pna, s)[i];
kring = NMR(pna, s)[i];
netmap_monitor_add(mkring, kring, zmon);
}
}
@ -478,7 +478,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon)
na->na_flags &= ~NAF_NETMAP_ON;
for_rx_tx(t) {
for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
mkring = &NMR(na, t)[i];
mkring = NMR(na, t)[i];
if (!nm_kring_pending_off(mkring))
continue;
mkring->nr_mode = NKR_NETMAP_OFF;
@ -494,7 +494,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon)
if (i > nma_get_nrings(pna, s))
continue;
if (mna->flags & nm_txrx2flag(s)) {
kring = &NMR(pna, s)[i];
kring = NMR(pna, s)[i];
netmap_monitor_del(mkring, kring);
}
}
@ -824,38 +824,41 @@ netmap_monitor_dtor(struct netmap_adapter *na)
}
/* check if nmr is a request for a monitor adapter that we can satisfy */
/* check if req is a request for a monitor adapter that we can satisfy */
int
netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
struct netmap_mem_d *nmd, int create)
netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na,
struct netmap_mem_d *nmd, int create)
{
struct nmreq pnmr;
struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
struct nmreq_register preq;
struct netmap_adapter *pna; /* parent adapter */
struct netmap_monitor_adapter *mna;
struct ifnet *ifp = NULL;
int error;
int zcopy = (nmr->nr_flags & NR_ZCOPY_MON);
int zcopy = (req->nr_flags & NR_ZCOPY_MON);
char monsuff[10] = "";
if (zcopy) {
nmr->nr_flags |= (NR_MONITOR_TX | NR_MONITOR_RX);
req->nr_flags |= (NR_MONITOR_TX | NR_MONITOR_RX);
}
if ((nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) {
if ((req->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) {
ND("not a monitor");
return 0;
}
/* this is a request for a monitor adapter */
ND("flags %x", nmr->nr_flags);
ND("flags %lx", req->nr_flags);
/* first, try to find the adapter that we want to monitor
* We use the same nmr, after we have turned off the monitor flags.
/* First, try to find the adapter that we want to monitor.
* We use the same req, after we have turned off the monitor flags.
* In this way we can potentially monitor everything netmap understands,
* except other monitors.
*/
memcpy(&pnmr, nmr, sizeof(pnmr));
pnmr.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON);
error = netmap_get_na(&pnmr, &pna, &ifp, nmd, create);
memcpy(&preq, req, sizeof(preq));
preq.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON);
hdr->nr_body = (uint64_t)&preq;
error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
hdr->nr_body = (uint64_t)req;
if (error) {
D("parent lookup failed: %d", error);
return error;
@ -881,7 +884,8 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
mna->priv.np_na = pna;
/* grab all the rings we need in the parent */
error = netmap_interp_ringid(&mna->priv, nmr->nr_ringid, nmr->nr_flags);
error = netmap_interp_ringid(&mna->priv, req->nr_mode, req->nr_ringid,
req->nr_flags);
if (error) {
D("ringid error");
goto free_out;
@ -892,8 +896,8 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
snprintf(mna->up.name, sizeof(mna->up.name), "%s%s/%s%s%s", pna->name,
monsuff,
zcopy ? "z" : "",
(nmr->nr_flags & NR_MONITOR_RX) ? "r" : "",
(nmr->nr_flags & NR_MONITOR_TX) ? "t" : "");
(req->nr_flags & NR_MONITOR_RX) ? "r" : "",
(req->nr_flags & NR_MONITOR_TX) ? "t" : "");
/* the monitor supports the host rings iff the parent does */
mna->up.na_flags |= (pna->na_flags & NAF_HOST_RINGS);
@ -913,10 +917,10 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
* the parent rings, but the user may ask for a different
* number
*/
mna->up.num_tx_desc = nmr->nr_tx_slots;
mna->up.num_tx_desc = req->nr_tx_slots;
nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc,
1, NM_MONITOR_MAXSLOTS, NULL);
mna->up.num_rx_desc = nmr->nr_rx_slots;
mna->up.num_rx_desc = req->nr_rx_slots;
nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc,
1, NM_MONITOR_MAXSLOTS, NULL);
if (zcopy) {
@ -950,7 +954,7 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na,
}
/* remember the traffic directions we have to monitor */
mna->flags = (nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON));
mna->flags = (req->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON));
*na = &mna->up;
netmap_adapter_get(*na);

View file

@ -77,6 +77,7 @@
#ifdef WITH_PIPES
#define NM_PIPE_MAXSLOTS 4096
#define NM_PIPE_MAXRINGS 256
static int netmap_default_pipes = 0; /* ignored, kept for compatibility */
SYSBEGIN(vars_pipes);
@ -129,14 +130,19 @@ netmap_pipe_dealloc(struct netmap_adapter *na)
/* find a pipe endpoint with the given id among the parent's pipes */
static struct netmap_pipe_adapter *
netmap_pipe_find(struct netmap_adapter *parent, u_int pipe_id)
netmap_pipe_find(struct netmap_adapter *parent, const char *pipe_id)
{
int i;
struct netmap_pipe_adapter *na;
for (i = 0; i < parent->na_next_pipe; i++) {
const char *na_pipe_id;
na = parent->na_pipes[i];
if (na->id == pipe_id) {
na_pipe_id = strrchr(na->up.name,
na->role == NM_PIPE_ROLE_MASTER ? '{' : '}');
KASSERT(na_pipe_id != NULL, ("Invalid pipe name"));
++na_pipe_id;
if (!strcmp(na_pipe_id, pipe_id)) {
return na;
}
}
@ -179,63 +185,46 @@ int
netmap_pipe_txsync(struct netmap_kring *txkring, int flags)
{
struct netmap_kring *rxkring = txkring->pipe;
u_int limit; /* slots to transfer */
u_int j, k, lim_tx = txkring->nkr_num_slots - 1,
lim_rx = rxkring->nkr_num_slots - 1;
int m, busy;
u_int k, lim = txkring->nkr_num_slots - 1;
int m; /* slots to transfer */
struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring;
ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
ND(2, "before: hwcur %d hwtail %d cur %d head %d tail %d", txkring->nr_hwcur, txkring->nr_hwtail,
ND(20, "TX before: hwcur %d hwtail %d cur %d head %d tail %d",
txkring->nr_hwcur, txkring->nr_hwtail,
txkring->rcur, txkring->rhead, txkring->rtail);
j = rxkring->nr_hwtail; /* RX */
k = txkring->nr_hwcur; /* TX */
m = txkring->rhead - txkring->nr_hwcur; /* new slots */
if (m < 0)
m += txkring->nkr_num_slots;
limit = m;
m = lim_rx; /* max avail space on destination */
busy = j - rxkring->nr_hwcur; /* busy slots */
if (busy < 0)
busy += rxkring->nkr_num_slots;
m -= busy; /* subtract busy slots */
ND(2, "m %d limit %d", m, limit);
if (m < limit)
limit = m;
if (limit == 0) {
/* either the rxring is full, or nothing to send */
if (m == 0) {
/* nothing to send */
return 0;
}
while (limit-- > 0) {
struct netmap_slot *rs = &rxring->slot[j];
for (k = txkring->nr_hwcur; m; m--, k = nm_next(k, lim)) {
struct netmap_slot *rs = &rxring->slot[k];
struct netmap_slot *ts = &txring->slot[k];
struct netmap_slot tmp;
__builtin_prefetch(ts + 1);
rs->len = ts->len;
rs->ptr = ts->ptr;
/* swap the slots and report the buffer change */
tmp = *rs;
tmp.flags |= NS_BUF_CHANGED;
*rs = *ts;
rs->flags |= NS_BUF_CHANGED;
*ts = tmp;
j = nm_next(j, lim_rx);
k = nm_next(k, lim_tx);
if (ts->flags & NS_BUF_CHANGED) {
rs->buf_idx = ts->buf_idx;
rs->flags |= NS_BUF_CHANGED;
ts->flags &= ~NS_BUF_CHANGED;
}
}
mb(); /* make sure the slots are updated before publishing them */
rxkring->nr_hwtail = j;
rxkring->nr_hwtail = k;
txkring->nr_hwcur = k;
txkring->nr_hwtail = nm_prev(k, lim_tx);
ND(2, "after: hwcur %d hwtail %d cur %d head %d tail %d j %d", txkring->nr_hwcur, txkring->nr_hwtail,
txkring->rcur, txkring->rhead, txkring->rtail, j);
ND(20, "TX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
txkring->nr_hwcur, txkring->nr_hwtail,
txkring->rcur, txkring->rhead, txkring->rtail, k);
mb(); /* make sure rxkring->nr_hwtail is updated before notifying */
rxkring->nm_notify(rxkring, 0);
return 0;
@ -245,20 +234,46 @@ int
netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags)
{
struct netmap_kring *txkring = rxkring->pipe;
uint32_t oldhwcur = rxkring->nr_hwcur;
u_int k, lim = rxkring->nkr_num_slots - 1;
int m; /* slots to release */
struct netmap_ring *txring = txkring->ring, *rxring = rxkring->ring;
ND("%s %x <- %s", rxkring->name, flags, txkring->name);
rxkring->nr_hwcur = rxkring->rhead; /* recover user-relased slots */
ND(5, "hwcur %d hwtail %d cur %d head %d tail %d", rxkring->nr_hwcur, rxkring->nr_hwtail,
ND("%p: %s %x -> %s", txkring, txkring->name, flags, rxkring->name);
ND(20, "RX before: hwcur %d hwtail %d cur %d head %d tail %d",
rxkring->nr_hwcur, rxkring->nr_hwtail,
rxkring->rcur, rxkring->rhead, rxkring->rtail);
mb(); /* paired with the first mb() in txsync */
if (oldhwcur != rxkring->nr_hwcur) {
/* we have released some slots, notify the other end */
mb(); /* make sure nr_hwcur is updated before notifying */
txkring->nm_notify(txkring, 0);
m = rxkring->rhead - rxkring->nr_hwcur; /* released slots */
if (m < 0)
m += rxkring->nkr_num_slots;
if (m == 0) {
/* nothing to release */
return 0;
}
return 0;
for (k = rxkring->nr_hwcur; m; m--, k = nm_next(k, lim)) {
struct netmap_slot *rs = &rxring->slot[k];
struct netmap_slot *ts = &txring->slot[k];
if (rs->flags & NS_BUF_CHANGED) {
/* copy the slot and report the buffer change */
*ts = *rs;
rs->flags &= ~NS_BUF_CHANGED;
}
}
mb(); /* make sure the slots are updated before publishing them */
txkring->nr_hwtail = nm_prev(k, lim);
rxkring->nr_hwcur = k;
ND(20, "RX after : hwcur %d hwtail %d cur %d head %d tail %d k %d",
rxkring->nr_hwcur, rxkring->nr_hwtail,
rxkring->rcur, rxkring->rhead, rxkring->rtail, k);
txkring->nm_notify(txkring, 0);
return 0;
}
/* Pipe endpoints are created and destroyed together, so that endopoints do not
@ -335,8 +350,10 @@ netmap_pipe_krings_create(struct netmap_adapter *na)
for_rx_tx(t) {
enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */
for (i = 0; i < nma_get_nrings(na, t); i++) {
NMR(na, t)[i].pipe = NMR(ona, r) + i;
NMR(ona, r)[i].pipe = NMR(na, t) + i;
NMR(na, t)[i]->pipe = NMR(ona, r)[i];
NMR(ona, r)[i]->pipe = NMR(na, t)[i];
/* mark all peer-adapter rings as fake */
NMR(ona, r)[i]->nr_kflags |= NKR_FAKERING;
}
}
@ -380,7 +397,7 @@ netmap_pipe_krings_create(struct netmap_adapter *na)
* usr1 --> e1 e2 <-- usr2
*
* and we are either e1 or e2. Add a ref from the
* other end and hide our rings.
* other end.
*/
static int
netmap_pipe_reg(struct netmap_adapter *na, int onoff)
@ -395,7 +412,7 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
if (onoff) {
for_rx_tx(t) {
for (i = 0; i < nma_get_nrings(na, t); i++) {
struct netmap_kring *kring = &NMR(na, t)[i];
struct netmap_kring *kring = NMR(na, t)[i];
if (nm_kring_pending_on(kring)) {
/* mark the peer ring as needed */
@ -404,7 +421,10 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
}
}
/* create all missing needed rings on the other end */
/* create all missing needed rings on the other end.
* Either our end, or the other, has been marked as
* fake, so the allocation will not be done twice.
*/
error = netmap_mem_rings_create(ona);
if (error)
return error;
@ -412,9 +432,32 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
/* In case of no error we put our rings in netmap mode */
for_rx_tx(t) {
for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
struct netmap_kring *kring = &NMR(na, t)[i];
struct netmap_kring *kring = NMR(na, t)[i];
if (nm_kring_pending_on(kring)) {
struct netmap_kring *sring, *dring;
/* copy the buffers from the non-fake ring */
if (kring->nr_kflags & NKR_FAKERING) {
sring = kring->pipe;
dring = kring;
} else {
sring = kring;
dring = kring->pipe;
}
memcpy(dring->ring->slot,
sring->ring->slot,
sizeof(struct netmap_slot) *
sring->nkr_num_slots);
/* mark both rings as fake and needed,
* so that buffers will not be
* deleted by the standard machinery
* (we will delete them by ourselves in
* netmap_pipe_krings_delete)
*/
sring->nr_kflags |=
(NKR_FAKERING | NKR_NEEDRING);
dring->nr_kflags |=
(NKR_FAKERING | NKR_NEEDRING);
kring->nr_mode = NKR_NETMAP_ON;
}
}
@ -426,21 +469,13 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
na->na_flags &= ~NAF_NETMAP_ON;
for_rx_tx(t) {
for (i = 0; i < nma_get_nrings(na, t) + 1; i++) {
struct netmap_kring *kring = &NMR(na, t)[i];
struct netmap_kring *kring = NMR(na, t)[i];
if (nm_kring_pending_off(kring)) {
kring->nr_mode = NKR_NETMAP_OFF;
/* mark the peer ring as no longer needed by us
* (it may still be kept if sombody else is using it)
*/
if (kring->pipe) {
kring->pipe->nr_kflags &= ~NKR_NEEDRING;
}
}
}
}
/* delete all the peer rings that are no longer needed */
netmap_mem_rings_delete(ona);
}
if (na->active_fds) {
@ -482,29 +517,73 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff)
* and we are either e1 or e2.
*
* In the former case we have to also delete the krings of e2;
* in the latter case we do nothing (note that our krings
* have already been hidden in the unregister callback).
* in the latter case we do nothing.
*/
static void
netmap_pipe_krings_delete(struct netmap_adapter *na)
{
struct netmap_pipe_adapter *pna =
(struct netmap_pipe_adapter *)na;
struct netmap_adapter *ona; /* na of the other end */
struct netmap_adapter *sna, *ona; /* na of the other end */
enum txrx t;
int i;
if (!pna->peer_ref) {
ND("%p: case 2, kept alive by peer", na);
return;
}
ona = &pna->peer->up;
/* case 1) above */
ND("%p: case 1, deleting everything", na);
/* To avoid double-frees we zero-out all the buffers in the kernel part
* of each ring. The reason is this: If the user is behaving correctly,
* all buffers are found in exactly one slot in the userspace part of
* some ring. If the user is not behaving correctly, we cannot release
* buffers cleanly anyway. In the latter case, the allocator will
* return to a clean state only when all its users will close.
*/
sna = na;
cleanup:
for_rx_tx(t) {
for (i = 0; i < nma_get_nrings(sna, t) + 1; i++) {
struct netmap_kring *kring = NMR(sna, t)[i];
struct netmap_ring *ring = kring->ring;
uint32_t j, lim = kring->nkr_num_slots - 1;
ND("%s ring %p hwtail %u hwcur %u",
kring->name, ring, kring->nr_hwtail, kring->nr_hwcur);
if (ring == NULL)
continue;
if (kring->nr_hwtail == kring->nr_hwcur)
ring->slot[kring->nr_hwtail].buf_idx = 0;
for (j = nm_next(kring->nr_hwtail, lim);
j != kring->nr_hwcur;
j = nm_next(j, lim))
{
ND("%s[%d] %u", kring->name, j, ring->slot[j].buf_idx);
ring->slot[j].buf_idx = 0;
}
kring->nr_kflags &= ~(NKR_FAKERING | NKR_NEEDRING);
}
}
if (sna != ona && ona->tx_rings) {
sna = ona;
goto cleanup;
}
netmap_mem_rings_delete(na);
netmap_krings_delete(na); /* also zeroes tx_rings etc. */
ona = &pna->peer->up;
if (ona->tx_rings == NULL) {
/* already deleted, we must be on an
* cleanup-after-error path */
return;
}
netmap_mem_rings_delete(ona);
netmap_krings_delete(ona);
}
@ -520,7 +599,7 @@ netmap_pipe_dtor(struct netmap_adapter *na)
pna->peer_ref = 0;
netmap_adapter_put(&pna->peer->up);
}
if (pna->role == NR_REG_PIPE_MASTER)
if (pna->role == NM_PIPE_ROLE_MASTER)
netmap_pipe_remove(pna->parent, pna);
if (pna->parent_ifp)
if_rele(pna->parent_ifp);
@ -529,34 +608,55 @@ netmap_pipe_dtor(struct netmap_adapter *na)
}
int
netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
netmap_get_pipe_na(struct nmreq_header *hdr, struct netmap_adapter **na,
struct netmap_mem_d *nmd, int create)
{
struct nmreq pnmr;
struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
struct netmap_adapter *pna; /* parent adapter */
struct netmap_pipe_adapter *mna, *sna, *req;
struct netmap_pipe_adapter *mna, *sna, *reqna;
struct ifnet *ifp = NULL;
u_int pipe_id;
int role = nmr->nr_flags & NR_REG_MASK;
const char *pipe_id = NULL;
int role = 0;
int error, retries = 0;
char *cbra;
ND("flags %x", nmr->nr_flags);
if (role != NR_REG_PIPE_MASTER && role != NR_REG_PIPE_SLAVE) {
ND("not a pipe");
return 0;
/* Try to parse the pipe syntax 'xx{yy' or 'xx}yy'. */
cbra = strrchr(hdr->nr_name, '{');
if (cbra != NULL) {
role = NM_PIPE_ROLE_MASTER;
} else {
cbra = strrchr(hdr->nr_name, '}');
if (cbra != NULL) {
role = NM_PIPE_ROLE_SLAVE;
} else {
ND("not a pipe");
return 0;
}
}
pipe_id = cbra + 1;
if (*pipe_id == '\0' || cbra == hdr->nr_name) {
/* Bracket is the last character, so pipe name is missing;
* or bracket is the first character, so base port name
* is missing. */
return EINVAL;
}
if (req->nr_mode != NR_REG_ALL_NIC && req->nr_mode != NR_REG_ONE_NIC) {
/* We only accept modes involving hardware rings. */
return EINVAL;
}
role = nmr->nr_flags & NR_REG_MASK;
/* first, try to find the parent adapter */
bzero(&pnmr, sizeof(pnmr));
memcpy(&pnmr.nr_name, nmr->nr_name, IFNAMSIZ);
/* pass to parent the requested number of pipes */
pnmr.nr_arg1 = nmr->nr_arg1;
for (;;) {
char nr_name_orig[NETMAP_REQ_IFNAMSIZ];
int create_error;
error = netmap_get_na(&pnmr, &pna, &ifp, nmd, create);
/* Temporarily remove the pipe suffix. */
strncpy(nr_name_orig, hdr->nr_name, sizeof(nr_name_orig));
*cbra = '\0';
error = netmap_get_na(hdr, &pna, &ifp, nmd, create);
/* Restore the pipe suffix. */
strncpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
if (!error)
break;
if (error != ENXIO || retries++) {
@ -565,9 +665,11 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
}
ND("try to create a persistent vale port");
/* create a persistent vale port and try again */
*cbra = '\0';
NMG_UNLOCK();
create_error = netmap_vi_create(&pnmr, 1 /* autodelete */);
create_error = netmap_vi_create(hdr, 1 /* autodelete */);
NMG_LOCK();
strncpy(hdr->nr_name, nr_name_orig, sizeof(hdr->nr_name));
if (create_error && create_error != EEXIST) {
if (create_error != EOPNOTSUPP) {
D("failed to create a persistent vale port: %d", create_error);
@ -583,16 +685,15 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
}
/* next, lookup the pipe id in the parent list */
req = NULL;
pipe_id = nmr->nr_ringid & NETMAP_RING_MASK;
reqna = NULL;
mna = netmap_pipe_find(pna, pipe_id);
if (mna) {
if (mna->role == role) {
ND("found %d directly at %d", pipe_id, mna->parent_slot);
req = mna;
ND("found %s directly at %d", pipe_id, mna->parent_slot);
reqna = mna;
} else {
ND("found %d indirectly at %d", pipe_id, mna->parent_slot);
req = mna->peer;
ND("found %s indirectly at %d", pipe_id, mna->parent_slot);
reqna = mna->peer;
}
/* the pipe we have found already holds a ref to the parent,
* so we need to drop the one we got from netmap_get_na()
@ -600,7 +701,7 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
netmap_unget_na(pna, ifp);
goto found;
}
ND("pipe %d not found, create %d", pipe_id, create);
ND("pipe %s not found, create %d", pipe_id, create);
if (!create) {
error = ENODEV;
goto put_out;
@ -614,10 +715,9 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
error = ENOMEM;
goto put_out;
}
snprintf(mna->up.name, sizeof(mna->up.name), "%s{%d", pna->name, pipe_id);
snprintf(mna->up.name, sizeof(mna->up.name), "%s{%s", pna->name, pipe_id);
mna->id = pipe_id;
mna->role = NR_REG_PIPE_MASTER;
mna->role = NM_PIPE_ROLE_MASTER;
mna->parent = pna;
mna->parent_ifp = ifp;
@ -631,12 +731,16 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
mna->up.na_flags |= NAF_MEM_OWNER;
mna->up.na_lut = pna->na_lut;
mna->up.num_tx_rings = 1;
mna->up.num_rx_rings = 1;
mna->up.num_tx_desc = nmr->nr_tx_slots;
mna->up.num_tx_rings = req->nr_tx_rings;
nm_bound_var(&mna->up.num_tx_rings, 1,
1, NM_PIPE_MAXRINGS, NULL);
mna->up.num_rx_rings = req->nr_rx_rings;
nm_bound_var(&mna->up.num_rx_rings, 1,
1, NM_PIPE_MAXRINGS, NULL);
mna->up.num_tx_desc = req->nr_tx_slots;
nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc,
1, NM_PIPE_MAXSLOTS, NULL);
mna->up.num_rx_desc = nmr->nr_rx_slots;
mna->up.num_rx_desc = req->nr_rx_slots;
nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc,
1, NM_PIPE_MAXSLOTS, NULL);
error = netmap_attach_common(&mna->up);
@ -656,8 +760,11 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
/* most fields are the same, copy from master and then fix */
*sna = *mna;
sna->up.nm_mem = netmap_mem_get(mna->up.nm_mem);
snprintf(sna->up.name, sizeof(sna->up.name), "%s}%d", pna->name, pipe_id);
sna->role = NR_REG_PIPE_SLAVE;
/* swap the number of tx/rx rings */
sna->up.num_tx_rings = mna->up.num_rx_rings;
sna->up.num_rx_rings = mna->up.num_tx_rings;
snprintf(sna->up.name, sizeof(sna->up.name), "%s}%s", pna->name, pipe_id);
sna->role = NM_PIPE_ROLE_SLAVE;
error = netmap_attach_common(&sna->up);
if (error)
goto free_sna;
@ -674,21 +781,21 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na,
if (ifp)
if_ref(ifp);
if (role == NR_REG_PIPE_MASTER) {
req = mna;
if (role == NM_PIPE_ROLE_MASTER) {
reqna = mna;
mna->peer_ref = 1;
netmap_adapter_get(&sna->up);
} else {
req = sna;
reqna = sna;
sna->peer_ref = 1;
netmap_adapter_get(&mna->up);
}
ND("created master %p and slave %p", mna, sna);
found:
ND("pipe %d %s at %p", pipe_id,
(req->role == NR_REG_PIPE_MASTER ? "master" : "slave"), req);
*na = &req->up;
ND("pipe %s %s at %p", pipe_id,
(reqna->role == NM_PIPE_ROLE_MASTER ? "master" : "slave"), reqna);
*na = &reqna->up;
netmap_adapter_get(*na);
/* keep the reference to the parent.

View file

@ -639,9 +639,9 @@ static struct netmap_kring *
ptnetmap_kring(struct netmap_pt_host_adapter *pth_na, int k)
{
if (k < pth_na->up.num_tx_rings) {
return pth_na->up.tx_rings + k;
return pth_na->up.tx_rings[k];
}
return pth_na->up.rx_rings + k - pth_na->up.num_tx_rings;
return pth_na->up.rx_rings[k - pth_na->up.num_tx_rings];
}
static int
@ -676,8 +676,19 @@ ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na,
struct nm_kctx_cfg nmk_cfg;
unsigned int num_rings;
uint8_t *cfg_entries = (uint8_t *)(cfg + 1);
unsigned int expected_cfgtype = 0;
int k;
#if defined(__FreeBSD__)
expected_cfgtype = PTNETMAP_CFGTYPE_BHYVE;
#elif defined(linux)
expected_cfgtype = PTNETMAP_CFGTYPE_QEMU;
#endif
if (cfg->cfgtype != expected_cfgtype) {
D("Unsupported cfgtype %u", cfg->cfgtype);
return EINVAL;
}
num_rings = pth_na->up.num_tx_rings +
pth_na->up.num_rx_rings;
@ -695,7 +706,7 @@ ptnetmap_create_kctxs(struct netmap_pt_host_adapter *pth_na,
}
ptns->kctxs[k] = nm_os_kctx_create(&nmk_cfg,
cfg->cfgtype, cfg_entries + k * cfg->entry_size);
cfg_entries + k * cfg->entry_size);
if (ptns->kctxs[k] == NULL) {
goto err;
}
@ -761,34 +772,6 @@ ptnetmap_stop_kctx_workers(struct netmap_pt_host_adapter *pth_na)
}
}
static struct ptnetmap_cfg *
ptnetmap_read_cfg(struct nmreq *nmr)
{
uintptr_t *nmr_ptncfg = (uintptr_t *)&nmr->nr_arg1;
struct ptnetmap_cfg *cfg;
struct ptnetmap_cfg tmp;
size_t cfglen;
if (copyin((const void *)*nmr_ptncfg, &tmp, sizeof(tmp))) {
D("Partial copyin() failed");
return NULL;
}
cfglen = sizeof(tmp) + tmp.num_rings * tmp.entry_size;
cfg = nm_os_malloc(cfglen);
if (!cfg) {
return NULL;
}
if (copyin((const void *)*nmr_ptncfg, cfg, cfglen)) {
D("Full copyin() failed");
nm_os_free(cfg);
return NULL;
}
return cfg;
}
static int nm_unused_notify(struct netmap_kring *, int);
static int nm_pt_host_notify(struct netmap_kring *, int);
@ -864,14 +847,14 @@ ptnetmap_create(struct netmap_pt_host_adapter *pth_na,
}
for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
pth_na->up.rx_rings[i].save_notify =
pth_na->up.rx_rings[i].nm_notify;
pth_na->up.rx_rings[i].nm_notify = nm_pt_host_notify;
pth_na->up.rx_rings[i]->save_notify =
pth_na->up.rx_rings[i]->nm_notify;
pth_na->up.rx_rings[i]->nm_notify = nm_pt_host_notify;
}
for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
pth_na->up.tx_rings[i].save_notify =
pth_na->up.tx_rings[i].nm_notify;
pth_na->up.tx_rings[i].nm_notify = nm_pt_host_notify;
pth_na->up.tx_rings[i]->save_notify =
pth_na->up.tx_rings[i]->nm_notify;
pth_na->up.tx_rings[i]->nm_notify = nm_pt_host_notify;
}
#ifdef RATE
@ -912,14 +895,14 @@ ptnetmap_delete(struct netmap_pt_host_adapter *pth_na)
pth_na->parent->na_flags = pth_na->parent_na_flags;
for (i = 0; i < pth_na->parent->num_rx_rings; i++) {
pth_na->up.rx_rings[i].nm_notify =
pth_na->up.rx_rings[i].save_notify;
pth_na->up.rx_rings[i].save_notify = NULL;
pth_na->up.rx_rings[i]->nm_notify =
pth_na->up.rx_rings[i]->save_notify;
pth_na->up.rx_rings[i]->save_notify = NULL;
}
for (i = 0; i < pth_na->parent->num_tx_rings; i++) {
pth_na->up.tx_rings[i].nm_notify =
pth_na->up.tx_rings[i].save_notify;
pth_na->up.tx_rings[i].save_notify = NULL;
pth_na->up.tx_rings[i]->nm_notify =
pth_na->up.tx_rings[i]->save_notify;
pth_na->up.tx_rings[i]->save_notify = NULL;
}
/* Destroy kernel contexts. */
@ -941,66 +924,55 @@ ptnetmap_delete(struct netmap_pt_host_adapter *pth_na)
/*
* Called by netmap_ioctl().
* Operation is indicated in nmr->nr_cmd.
* Operation is indicated in nr_name.
*
* Called without NMG_LOCK.
*/
int
ptnetmap_ctl(struct nmreq *nmr, struct netmap_adapter *na)
ptnetmap_ctl(const char *nr_name, int create, struct netmap_adapter *na)
{
struct netmap_pt_host_adapter *pth_na;
struct ptnetmap_cfg *cfg;
char *name;
int cmd, error = 0;
struct netmap_pt_host_adapter *pth_na;
struct ptnetmap_cfg *cfg = NULL;
int error = 0;
name = nmr->nr_name;
cmd = nmr->nr_cmd;
DBG(D("name: %s", nr_name));
DBG(D("name: %s", name));
if (!nm_ptnetmap_host_on(na)) {
D("ERROR Netmap adapter %p is not a ptnetmap host adapter",
na);
return ENXIO;
}
pth_na = (struct netmap_pt_host_adapter *)na;
if (!nm_ptnetmap_host_on(na)) {
D("ERROR Netmap adapter %p is not a ptnetmap host adapter", na);
error = ENXIO;
goto done;
}
pth_na = (struct netmap_pt_host_adapter *)na;
NMG_LOCK();
if (create) {
/* Read hypervisor configuration from userspace. */
/* TODO */
if (!cfg) {
goto out;
}
/* Create ptnetmap state (kctxs, ...) and switch parent
* adapter to ptnetmap mode. */
error = ptnetmap_create(pth_na, cfg);
nm_os_free(cfg);
if (error) {
goto out;
}
/* Start kthreads. */
error = ptnetmap_start_kctx_workers(pth_na);
if (error)
ptnetmap_delete(pth_na);
} else {
/* Stop kthreads. */
ptnetmap_stop_kctx_workers(pth_na);
/* Switch parent adapter back to normal mode and destroy
* ptnetmap state (kthreads, ...). */
ptnetmap_delete(pth_na);
}
out:
NMG_UNLOCK();
NMG_LOCK();
switch (cmd) {
case NETMAP_PT_HOST_CREATE:
/* Read hypervisor configuration from userspace. */
cfg = ptnetmap_read_cfg(nmr);
if (!cfg)
break;
/* Create ptnetmap state (kctxs, ...) and switch parent
* adapter to ptnetmap mode. */
error = ptnetmap_create(pth_na, cfg);
nm_os_free(cfg);
if (error)
break;
/* Start kthreads. */
error = ptnetmap_start_kctx_workers(pth_na);
if (error)
ptnetmap_delete(pth_na);
break;
case NETMAP_PT_HOST_DELETE:
/* Stop kthreads. */
ptnetmap_stop_kctx_workers(pth_na);
/* Switch parent adapter back to normal mode and destroy
* ptnetmap state (kthreads, ...). */
ptnetmap_delete(pth_na);
break;
default:
D("ERROR invalid cmd (nmr->nr_cmd) (0x%x)", cmd);
error = EINVAL;
break;
}
NMG_UNLOCK();
done:
return error;
return error;
}
/* nm_notify callbacks for ptnetmap */
@ -1048,8 +1020,7 @@ nm_unused_notify(struct netmap_kring *kring, int flags)
/* nm_config callback for bwrap */
static int
nm_pt_host_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
u_int *rxr, u_int *rxd)
nm_pt_host_config(struct netmap_adapter *na, struct nm_config_info *info)
{
struct netmap_pt_host_adapter *pth_na =
(struct netmap_pt_host_adapter *)na;
@ -1061,12 +1032,11 @@ nm_pt_host_config(struct netmap_adapter *na, u_int *txr, u_int *txd,
/* forward the request */
error = netmap_update_config(parent);
*rxr = na->num_rx_rings = parent->num_rx_rings;
*txr = na->num_tx_rings = parent->num_tx_rings;
*txd = na->num_tx_desc = parent->num_tx_desc;
*rxd = na->num_rx_desc = parent->num_rx_desc;
DBG(D("rxr: %d txr: %d txd: %d rxd: %d", *rxr, *txr, *txd, *rxd));
info->num_rx_rings = na->num_rx_rings = parent->num_rx_rings;
info->num_tx_rings = na->num_tx_rings = parent->num_tx_rings;
info->num_tx_descs = na->num_tx_desc = parent->num_tx_desc;
info->num_rx_descs = na->num_rx_desc = parent->num_rx_desc;
info->rx_buf_maxsize = na->rx_buf_maxsize = parent->rx_buf_maxsize;
return error;
}
@ -1107,7 +1077,7 @@ nm_pt_host_krings_create(struct netmap_adapter *na)
* host rings independently on what the regif asked for:
* these rings are needed by the guest ptnetmap adapter
* anyway. */
kring = &NMR(na, t)[nma_get_nrings(na, t)];
kring = NMR(na, t)[nma_get_nrings(na, t)];
kring->nr_kflags |= NKR_NEEDRING;
}
@ -1187,17 +1157,18 @@ nm_pt_host_dtor(struct netmap_adapter *na)
/* check if nmr is a request for a ptnetmap adapter that we can satisfy */
int
netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na,
netmap_get_pt_host_na(struct nmreq_header *hdr, struct netmap_adapter **na,
struct netmap_mem_d *nmd, int create)
{
struct nmreq parent_nmr;
struct nmreq_register *req = (struct nmreq_register *)hdr->nr_body;
struct nmreq_register preq;
struct netmap_adapter *parent; /* target adapter */
struct netmap_pt_host_adapter *pth_na;
struct ifnet *ifp = NULL;
int error;
/* Check if it is a request for a ptnetmap adapter */
if ((nmr->nr_flags & (NR_PTNETMAP_HOST)) == 0) {
if ((req->nr_flags & (NR_PTNETMAP_HOST)) == 0) {
return 0;
}
@ -1210,12 +1181,14 @@ netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na,
}
/* first, try to find the adapter that we want to passthrough
* We use the same nmr, after we have turned off the ptnetmap flag.
* We use the same req, after we have turned off the ptnetmap flag.
* In this way we can potentially passthrough everything netmap understands.
*/
memcpy(&parent_nmr, nmr, sizeof(parent_nmr));
parent_nmr.nr_flags &= ~(NR_PTNETMAP_HOST);
error = netmap_get_na(&parent_nmr, &parent, &ifp, nmd, create);
memcpy(&preq, req, sizeof(preq));
preq.nr_flags &= ~(NR_PTNETMAP_HOST);
hdr->nr_body = (uint64_t)&preq;
error = netmap_get_na(hdr, &parent, &ifp, nmd, create);
hdr->nr_body = (uint64_t)req;
if (error) {
D("parent lookup failed: %d", error);
goto put_out_noputparent;

File diff suppressed because it is too large Load diff

View file

@ -2933,7 +2933,7 @@ re_start_locked(struct ifnet *ifp)
#ifdef DEV_NETMAP
/* XXX is this necessary ? */
if (ifp->if_capenable & IFCAP_NETMAP) {
struct netmap_kring *kring = &NA(ifp)->tx_rings[0];
struct netmap_kring *kring = NA(ifp)->tx_rings[0];
if (sc->rl_ldata.rl_tx_prodidx != kring->nr_hwcur) {
/* kick the tx unit */
CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START);

View file

@ -21,6 +21,7 @@ SRCS += netmap_offloadings.c
SRCS += netmap_pipe.c
SRCS += netmap_monitor.c
SRCS += netmap_pt.c
SRCS += netmap_legacy.c
SRCS += if_ptnet.c
SRCS += opt_inet.h opt_inet6.h

View file

@ -1176,7 +1176,7 @@ iflib_netmap_txq_init(if_ctx_t ctx, iflib_txq_t txq)
* netmap_idx_n2k() maps a nic index, i, into the corresponding
* netmap slot index, si
*/
int si = netmap_idx_n2k(&na->tx_rings[txq->ift_id], i);
int si = netmap_idx_n2k(na->tx_rings[txq->ift_id], i);
netmap_load_map(na, txq->ift_desc_tag, txq->ift_sds.ifsd_map[i], NMB(na, slot + si));
}
}
@ -1185,7 +1185,7 @@ static void
iflib_netmap_rxq_init(if_ctx_t ctx, iflib_rxq_t rxq)
{
struct netmap_adapter *na = NA(ctx->ifc_ifp);
struct netmap_kring *kring = &na->rx_rings[rxq->ifr_id];
struct netmap_kring *kring = na->rx_rings[rxq->ifr_id];
struct netmap_slot *slot;
uint32_t nm_i;

View file

@ -41,7 +41,7 @@
#ifndef _NET_NETMAP_H_
#define _NET_NETMAP_H_
#define NETMAP_API 11 /* current API version */
#define NETMAP_API 12 /* current API version */
#define NETMAP_MIN_API 11 /* min and max versions accepted */
#define NETMAP_MAX_API 15
@ -326,6 +326,18 @@ struct netmap_ring {
* Enables the NS_FORWARD slot flag for the ring.
*/
/*
* Helper functions for kernel and userspace
*/
/*
* check if space is available in the ring.
*/
static inline int
nm_ring_empty(struct netmap_ring *ring)
{
return (ring->cur == ring->tail);
}
/*
* Netmap representation of an interface and its queue(s).
@ -368,86 +380,75 @@ struct netmap_if {
const ssize_t ring_ofs[0];
};
/* Legacy interface to interact with a netmap control device.
* Included for backward compatibility. The user should not include this
* file directly. */
#include "netmap_legacy.h"
#ifndef NIOCREGIF
/*
* ioctl names and related fields
* New API to control netmap control devices. New applications should only use
* nmreq_xyz structs with the NIOCCTRL ioctl() command.
*
* NIOCTXSYNC, NIOCRXSYNC synchronize tx or rx queues,
* whose identity is set in NIOCREGIF through nr_ringid.
* These are non blocking and take no argument.
* NIOCCTRL takes a nmreq_header struct, which contains the required
* API version, the name of a netmap port, a command type, and pointers
* to request body and options.
*
* NIOCGINFO takes a struct ifreq, the interface name is the input,
* the outputs are number of queues and number of descriptor
* for each queue (useful to set number of threads etc.).
* The info returned is only advisory and may change before
* the interface is bound to a file descriptor.
* nr_name (in)
* The name of the port (em0, valeXXX:YYY, eth0{pn1 etc.)
*
* NIOCREGIF takes an interface name within a struct nmre,
* and activates netmap mode on the interface (if possible).
* nr_version (in/out)
* Must match NETMAP_API as used in the kernel, error otherwise.
* Always returns the desired value on output.
*
* The argument to NIOCGINFO/NIOCREGIF overlays struct ifreq so we
* can pass it down to other NIC-related ioctls.
* nr_reqtype (in)
* One of the NETMAP_REQ_* command types below
*
* The actual argument (struct nmreq) has a number of options to request
* different functions.
* The following are used in NIOCREGIF when nr_cmd == 0:
* nr_body (in)
* Pointer to a command-specific struct, described by one
* of the struct nmreq_xyz below.
*
* nr_name (in)
* The name of the port (em0, valeXXX:YYY, etc.)
* limited to IFNAMSIZ for backward compatibility.
* nr_options (in)
* Command specific options, if any.
*
* nr_version (in/out)
* Must match NETMAP_API as used in the kernel, error otherwise.
* Always returns the desired value on output.
* A NETMAP_REQ_REGISTER command activates netmap mode on the netmap
* port (e.g. physical interface) specified by nmreq_header.nr_name.
* The request body (struct nmreq_register) has several arguments to
* specify how the port is to be registered.
*
* nr_tx_slots, nr_tx_slots, nr_tx_rings, nr_rx_rings (in/out)
* On input, non-zero values may be used to reconfigure the port
* according to the requested values, but this is not guaranteed.
* On output the actual values in use are reported.
* nr_tx_slots, nr_tx_slots, nr_tx_rings, nr_rx_rings (in/out)
* On input, non-zero values may be used to reconfigure the port
* according to the requested values, but this is not guaranteed.
* On output the actual values in use are reported.
*
* nr_ringid (in)
* Indicates how rings should be bound to the file descriptors.
* If nr_flags != 0, then the low bits (in NETMAP_RING_MASK)
* are used to indicate the ring number, and nr_flags specifies
* the actual rings to bind. NETMAP_NO_TX_POLL is unaffected.
* nr_mode (in)
* Indicate what set of rings must be bound to the netmap
* device (e.g. all NIC rings, host rings only, NIC and
* host rings, ...). Values are in NR_REG_*.
*
* NOTE: THE FOLLOWING (nr_flags == 0) IS DEPRECATED:
* If nr_flags == 0, NETMAP_HW_RING and NETMAP_SW_RING control
* the binding as follows:
* 0 (default) binds all physical rings
* NETMAP_HW_RING | ring number binds a single ring pair
* NETMAP_SW_RING binds only the host tx/rx rings
* nr_ringid (in)
* If nr_mode == NR_REG_ONE_NIC (only a single couple of TX/RX
* rings), indicate which NIC TX and/or RX ring is to be bound
* (0..nr_*x_rings-1).
*
* NETMAP_NO_TX_POLL can be OR-ed to make select()/poll() push
* packets on tx rings only if POLLOUT is set.
* The default is to push any pending packet.
* nr_flags (in)
* Indicate special options for how to open the port.
*
* NETMAP_DO_RX_POLL can be OR-ed to make select()/poll() release
* packets on rx rings also when POLLIN is NOT set.
* The default is to touch the rx ring only with POLLIN.
* Note that this is the opposite of TX because it
* reflects the common usage.
* NR_NO_TX_POLL can be OR-ed to make select()/poll() push
* packets on tx rings only if POLLOUT is set.
* The default is to push any pending packet.
*
* NOTE: NETMAP_PRIV_MEM IS DEPRECATED, use nr_arg2 instead.
* NETMAP_PRIV_MEM is set on return for ports that do not use
* the global memory allocator.
* This information is not significant and applications
* should look at the region id in nr_arg2
* NR_DO_RX_POLL can be OR-ed to make select()/poll() release
* packets on rx rings also when POLLIN is NOT set.
* The default is to touch the rx ring only with POLLIN.
* Note that this is the opposite of TX because it
* reflects the common usage.
*
* nr_flags is the recommended mode to indicate which rings should
* be bound to a file descriptor. Values are NR_REG_*
* Other options are NR_MONITOR_TX, NR_MONITOR_RX, NR_ZCOPY_MON,
* NR_EXCLUSIVE, NR_RX_RINGS_ONLY, NR_TX_RINGS_ONLY and
* NR_ACCEPT_VNET_HDR.
*
* nr_arg1 (in) The number of extra rings to be reserved.
* Especially when allocating a VALE port the system only
* allocates the amount of memory needed for the port.
* If more shared memory rings are desired (e.g. for pipes),
* the first invocation for the same basename/allocator
* should specify a suitable number. Memory cannot be
* extended after the first allocation without closing
* all ports on the same region.
*
* nr_arg2 (in/out) The identity of the memory region used.
* nr_mem_id (in/out)
* The identity of the memory region used.
* On input, 0 means the system decides autonomously,
* other values may try to select a specific region.
* On return the actual value is reported.
@ -455,101 +456,92 @@ struct netmap_if {
* by all interfaces. Other values are private regions.
* If two ports the same region zero-copy is possible.
*
* nr_arg3 (in/out) number of extra buffers to be allocated.
*
*
*
* nr_cmd (in) if non-zero indicates a special command:
* NETMAP_BDG_ATTACH and nr_name = vale*:ifname
* attaches the NIC to the switch; nr_ringid specifies
* which rings to use. Used by vale-ctl -a ...
* nr_arg1 = NETMAP_BDG_HOST also attaches the host port
* as in vale-ctl -h ...
*
* NETMAP_BDG_DETACH and nr_name = vale*:ifname
* disconnects a previously attached NIC.
* Used by vale-ctl -d ...
*
* NETMAP_BDG_LIST
* list the configuration of VALE switches.
*
* NETMAP_BDG_VNET_HDR
* Set the virtio-net header length used by the client
* of a VALE switch port.
*
* NETMAP_BDG_NEWIF
* create a persistent VALE port with name nr_name.
* Used by vale-ctl -n ...
*
* NETMAP_BDG_DELIF
* delete a persistent VALE port. Used by vale-ctl -d ...
*
* nr_arg1, nr_arg2, nr_arg3 (in/out) command specific
*
* nr_extra_bufs (in/out)
* Number of extra buffers to be allocated.
*
* The other NETMAP_REQ_* commands are described below.
*
*/
/* maximum size of a request, including all options */
#define NETMAP_REQ_MAXSIZE 4096
/* Header common to all request options. */
struct nmreq_option {
/* Pointer ot the next option. */
uint64_t nro_next;
/* Option type. */
uint32_t nro_reqtype;
/* (out) status of the option:
* 0: recognized and processed
* !=0: errno value
*/
uint32_t nro_status;
};
/* Header common to all requests. Do not reorder these fields, as we need
* the second one (nr_reqtype) to know how much to copy from/to userspace. */
struct nmreq_header {
uint16_t nr_version; /* API version */
uint16_t nr_reqtype; /* nmreq type (NETMAP_REQ_*) */
uint32_t nr_reserved; /* must be zero */
#define NETMAP_REQ_IFNAMSIZ 64
char nr_name[NETMAP_REQ_IFNAMSIZ]; /* port name */
uint64_t nr_options; /* command-specific options */
uint64_t nr_body; /* ptr to nmreq_xyz struct */
};
enum {
/* Register a netmap port with the device. */
NETMAP_REQ_REGISTER = 1,
/* Get information from a netmap port. */
NETMAP_REQ_PORT_INFO_GET,
/* Attach a netmap port to a VALE switch. */
NETMAP_REQ_VALE_ATTACH,
/* Detach a netmap port from a VALE switch. */
NETMAP_REQ_VALE_DETACH,
/* List the ports attached to a VALE switch. */
NETMAP_REQ_VALE_LIST,
/* Set the port header length (was virtio-net header length). */
NETMAP_REQ_PORT_HDR_SET,
/* Get the port header length (was virtio-net header length). */
NETMAP_REQ_PORT_HDR_GET,
/* Create a new persistent VALE port. */
NETMAP_REQ_VALE_NEWIF,
/* Delete a persistent VALE port. */
NETMAP_REQ_VALE_DELIF,
/* Enable polling kernel thread(s) on an attached VALE port. */
NETMAP_REQ_VALE_POLLING_ENABLE,
/* Disable polling kernel thread(s) on an attached VALE port. */
NETMAP_REQ_VALE_POLLING_DISABLE,
/* Get info about the pools of a memory allocator. */
NETMAP_REQ_POOLS_INFO_GET,
};
enum {
/* On NETMAP_REQ_REGISTER, ask netmap to use memory allocated
* from user-space allocated memory pools (e.g. hugepages). */
NETMAP_REQ_OPT_EXTMEM = 1,
};
/*
* struct nmreq overlays a struct ifreq (just the name)
* nr_reqtype: NETMAP_REQ_REGISTER
* Bind (register) a netmap port to this control device.
*/
struct nmreq {
char nr_name[IFNAMSIZ];
uint32_t nr_version; /* API version */
uint32_t nr_offset; /* nifp offset in the shared region */
uint32_t nr_memsize; /* size of the shared region */
struct nmreq_register {
uint64_t nr_offset; /* nifp offset in the shared region */
uint64_t nr_memsize; /* size of the shared region */
uint32_t nr_tx_slots; /* slots in tx rings */
uint32_t nr_rx_slots; /* slots in rx rings */
uint16_t nr_tx_rings; /* number of tx rings */
uint16_t nr_rx_rings; /* number of rx rings */
uint16_t nr_mem_id; /* id of the memory allocator */
uint16_t nr_ringid; /* ring(s) we care about */
#define NETMAP_HW_RING 0x4000 /* single NIC ring pair */
#define NETMAP_SW_RING 0x2000 /* only host ring pair */
uint32_t nr_mode; /* specify NR_REG_* modes */
#define NETMAP_RING_MASK 0x0fff /* the ring number */
#define NETMAP_NO_TX_POLL 0x1000 /* no automatic txsync on poll */
#define NETMAP_DO_RX_POLL 0x8000 /* DO automatic rxsync on poll */
uint16_t nr_cmd;
#define NETMAP_BDG_ATTACH 1 /* attach the NIC */
#define NETMAP_BDG_DETACH 2 /* detach the NIC */
#define NETMAP_BDG_REGOPS 3 /* register bridge callbacks */
#define NETMAP_BDG_LIST 4 /* get bridge's info */
#define NETMAP_BDG_VNET_HDR 5 /* set the port virtio-net-hdr length */
#define NETMAP_BDG_OFFSET NETMAP_BDG_VNET_HDR /* deprecated alias */
#define NETMAP_BDG_NEWIF 6 /* create a virtual port */
#define NETMAP_BDG_DELIF 7 /* destroy a virtual port */
#define NETMAP_PT_HOST_CREATE 8 /* create ptnetmap kthreads */
#define NETMAP_PT_HOST_DELETE 9 /* delete ptnetmap kthreads */
#define NETMAP_BDG_POLLING_ON 10 /* delete polling kthread */
#define NETMAP_BDG_POLLING_OFF 11 /* delete polling kthread */
#define NETMAP_VNET_HDR_GET 12 /* get the port virtio-net-hdr length */
#define NETMAP_POOLS_INFO_GET 13 /* get memory allocator pools info */
#define NETMAP_POOLS_CREATE 14 /* create a new memory allocator */
uint16_t nr_arg1; /* reserve extra rings in NIOCREGIF */
#define NETMAP_BDG_HOST 1 /* attach the host stack on ATTACH */
uint16_t nr_arg2;
uint32_t nr_arg3; /* req. extra buffers in NIOCREGIF */
uint32_t nr_flags;
/* various modes, extends nr_ringid */
uint32_t spare2[1];
};
#define NR_REG_MASK 0xf /* values for nr_flags */
enum { NR_REG_DEFAULT = 0, /* backward compat, should not be used. */
NR_REG_ALL_NIC = 1,
NR_REG_SW = 2,
NR_REG_NIC_SW = 3,
NR_REG_ONE_NIC = 4,
NR_REG_PIPE_MASTER = 5,
NR_REG_PIPE_SLAVE = 6,
};
/* monitor uses the NR_REG to select the rings to monitor */
uint64_t nr_flags; /* additional flags (see below) */
/* monitors use nr_ringid and nr_mode to select the rings to monitor */
#define NR_MONITOR_TX 0x100
#define NR_MONITOR_RX 0x200
#define NR_ZCOPY_MON 0x400
@ -566,87 +558,148 @@ enum { NR_REG_DEFAULT = 0, /* backward compat, should not be used. */
* to use those headers. If the flag is set, the application can use the
* NETMAP_VNET_HDR_GET command to figure out the header length. */
#define NR_ACCEPT_VNET_HDR 0x8000
/* The following two have the same meaning of NETMAP_NO_TX_POLL and
* NETMAP_DO_RX_POLL. */
#define NR_DO_RX_POLL 0x10000
#define NR_NO_TX_POLL 0x20000
uint32_t nr_extra_bufs; /* number of requested extra buffers */
};
/* Valid values for nmreq_register.nr_mode (see above). */
enum { NR_REG_DEFAULT = 0, /* backward compat, should not be used. */
NR_REG_ALL_NIC = 1,
NR_REG_SW = 2,
NR_REG_NIC_SW = 3,
NR_REG_ONE_NIC = 4,
NR_REG_PIPE_MASTER = 5, /* deprecated, use "x{y" port name syntax */
NR_REG_PIPE_SLAVE = 6, /* deprecated, use "x}y" port name syntax */
};
/* A single ioctl number is shared by all the new API command.
* Demultiplexing is done using the nr_hdr.nr_reqtype field.
* FreeBSD uses the size value embedded in the _IOWR to determine
* how much to copy in/out, so we define the ioctl() command
* specifying only nmreq_header, and copyin/copyout the rest. */
#define NIOCCTRL _IOWR('i', 151, struct nmreq_header)
/* The ioctl commands to sync TX/RX netmap rings.
* NIOCTXSYNC, NIOCRXSYNC synchronize tx or rx queues,
* whose identity is set in NIOCREGIF through nr_ringid.
* These are non blocking and take no argument. */
#define NIOCTXSYNC _IO('i', 148) /* sync tx queues */
#define NIOCRXSYNC _IO('i', 149) /* sync rx queues */
/*
* nr_reqtype: NETMAP_REQ_PORT_INFO_GET
* Get information about a netmap port, including number of rings.
* slots per ring, id of the memory allocator, etc.
*/
struct nmreq_port_info_get {
uint64_t nr_offset; /* nifp offset in the shared region */
uint64_t nr_memsize; /* size of the shared region */
uint32_t nr_tx_slots; /* slots in tx rings */
uint32_t nr_rx_slots; /* slots in rx rings */
uint16_t nr_tx_rings; /* number of tx rings */
uint16_t nr_rx_rings; /* number of rx rings */
uint16_t nr_mem_id; /* id of the memory allocator */
};
#define NM_BDG_NAME "vale" /* prefix for bridge port name */
#ifdef _WIN32
/*
* Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
* in ws2def.h but not sure if they are in the form we need.
* We therefore redefine them in a convenient way to use for DeviceIoControl
* signatures.
* nr_reqtype: NETMAP_REQ_VALE_ATTACH
* Attach a netmap port to a VALE switch. Both the name of the netmap
* port and the VALE switch are specified through the nr_name argument.
* The attach operation could need to register a port, so at least
* the same arguments are available.
* port_index will contain the index where the port has been attached.
*/
#undef _IO // ws2def.h
#define _WIN_NM_IOCTL_TYPE 40000
#define _IO(_c, _n) CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \
METHOD_BUFFERED, FILE_ANY_ACCESS )
#define _IO_direct(_c, _n) CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \
METHOD_OUT_DIRECT, FILE_ANY_ACCESS )
#define _IOWR(_c, _n, _s) _IO(_c, _n)
/* We havesome internal sysctl in addition to the externally visible ones */
#define NETMAP_MMAP _IO_direct('i', 160) // note METHOD_OUT_DIRECT
#define NETMAP_POLL _IO('i', 162)
/* and also two setsockopt for sysctl emulation */
#define NETMAP_SETSOCKOPT _IO('i', 140)
#define NETMAP_GETSOCKOPT _IO('i', 141)
//These linknames are for the Netmap Core Driver
#define NETMAP_NT_DEVICE_NAME L"\\Device\\NETMAP"
#define NETMAP_DOS_DEVICE_NAME L"\\DosDevices\\netmap"
//Definition of a structure used to pass a virtual address within an IOCTL
typedef struct _MEMORY_ENTRY {
PVOID pUsermodeVirtualAddress;
} MEMORY_ENTRY, *PMEMORY_ENTRY;
typedef struct _POLL_REQUEST_DATA {
int events;
int timeout;
int revents;
} POLL_REQUEST_DATA;
#endif /* _WIN32 */
struct nmreq_vale_attach {
struct nmreq_register reg;
uint32_t port_index;
};
/*
* FreeBSD uses the size value embedded in the _IOWR to determine
* how much to copy in/out. So we need it to match the actual
* data structure we pass. We put some spares in the structure
* to ease compatibility with other versions
* nr_reqtype: NETMAP_REQ_VALE_DETACH
* Detach a netmap port from a VALE switch. Both the name of the netmap
* port and the VALE switch are specified through the nr_name argument.
* port_index will contain the index where the port was attached.
*/
#define NIOCGINFO _IOWR('i', 145, struct nmreq) /* return IF info */
#define NIOCREGIF _IOWR('i', 146, struct nmreq) /* interface register */
#define NIOCTXSYNC _IO('i', 148) /* sync tx queues */
#define NIOCRXSYNC _IO('i', 149) /* sync rx queues */
#define NIOCCONFIG _IOWR('i',150, struct nm_ifreq) /* for ext. modules */
#endif /* !NIOCREGIF */
struct nmreq_vale_detach {
uint32_t port_index;
};
/*
* Helper functions for kernel and userspace
* nr_reqtype: NETMAP_REQ_VALE_LIST
* List the ports of a VALE switch.
*/
struct nmreq_vale_list {
/* Name of the VALE port (valeXXX:YYY) or empty. */
uint16_t nr_bridge_idx;
uint32_t nr_port_idx;
};
/*
* check if space is available in the ring.
* nr_reqtype: NETMAP_REQ_PORT_HDR_SET or NETMAP_REQ_PORT_HDR_GET
* Set the port header length.
*/
static inline int
nm_ring_empty(struct netmap_ring *ring)
{
return (ring->cur == ring->tail);
}
struct nmreq_port_hdr {
uint32_t nr_hdr_len;
};
/*
* Opaque structure that is passed to an external kernel
* module via ioctl(fd, NIOCCONFIG, req) for a user-owned
* bridge port (at this point ephemeral VALE interface).
* nr_reqtype: NETMAP_REQ_VALE_NEWIF
* Create a new persistent VALE port.
*/
#define NM_IFRDATA_LEN 256
struct nm_ifreq {
char nifr_name[IFNAMSIZ];
char data[NM_IFRDATA_LEN];
struct nmreq_vale_newif {
uint32_t nr_tx_slots; /* slots in tx rings */
uint32_t nr_rx_slots; /* slots in rx rings */
uint16_t nr_tx_rings; /* number of tx rings */
uint16_t nr_rx_rings; /* number of rx rings */
uint16_t nr_mem_id; /* id of the memory allocator */
};
/*
* nr_reqtype: NETMAP_REQ_VALE_POLLING_ENABLE or NETMAP_REQ_VALE_POLLING_DISABLE
* Enable or disable polling kthreads on a VALE port.
*/
struct nmreq_vale_polling {
uint32_t nr_mode;
#define NETMAP_POLLING_MODE_SINGLE_CPU 1
#define NETMAP_POLLING_MODE_MULTI_CPU 2
uint32_t nr_first_cpu_id;
uint32_t nr_num_polling_cpus;
};
/*
* nr_reqtype: NETMAP_REQ_POOLS_INFO_GET
* Get info about the pools of the memory allocator of the port bound
* to a given netmap control device (used i.e. by a ptnetmap-enabled
* hypervisor). The nr_hdr.nr_name field is ignored.
*/
struct nmreq_pools_info {
uint64_t nr_memsize;
uint16_t nr_mem_id;
uint64_t nr_if_pool_offset;
uint32_t nr_if_pool_objtotal;
uint32_t nr_if_pool_objsize;
uint64_t nr_ring_pool_offset;
uint32_t nr_ring_pool_objtotal;
uint32_t nr_ring_pool_objsize;
uint64_t nr_buf_pool_offset;
uint32_t nr_buf_pool_objtotal;
uint32_t nr_buf_pool_objsize;
};
/*
* data for NETMAP_REQ_OPT_* options
*/
struct nmreq_opt_extmem {
struct nmreq_option nro_opt; /* common header */
uint64_t nro_usrptr; /* (in) ptr to usr memory */
struct nmreq_pools_info nro_info; /* (in/out) */
};
#endif /* _NET_NETMAP_H_ */

264
sys/net/netmap_legacy.h Normal file
View file

@ -0,0 +1,264 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``S IS''AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _NET_NETMAP_LEGACY_H_
#define _NET_NETMAP_LEGACY_H_
/*
* $FreeBSD$
*
* ioctl names and related fields
*
* NIOCTXSYNC, NIOCRXSYNC synchronize tx or rx queues,
* whose identity is set in NIOCREGIF through nr_ringid.
* These are non blocking and take no argument.
*
* NIOCGINFO takes a struct ifreq, the interface name is the input,
* the outputs are number of queues and number of descriptor
* for each queue (useful to set number of threads etc.).
* The info returned is only advisory and may change before
* the interface is bound to a file descriptor.
*
* NIOCREGIF takes an interface name within a struct nmre,
* and activates netmap mode on the interface (if possible).
*
* The argument to NIOCGINFO/NIOCREGIF overlays struct ifreq so we
* can pass it down to other NIC-related ioctls.
*
* The actual argument (struct nmreq) has a number of options to request
* different functions.
* The following are used in NIOCREGIF when nr_cmd == 0:
*
* nr_name (in)
* The name of the port (em0, valeXXX:YYY, etc.)
* limited to IFNAMSIZ for backward compatibility.
*
* nr_version (in/out)
* Must match NETMAP_API as used in the kernel, error otherwise.
* Always returns the desired value on output.
*
* nr_tx_slots, nr_tx_slots, nr_tx_rings, nr_rx_rings (in/out)
* On input, non-zero values may be used to reconfigure the port
* according to the requested values, but this is not guaranteed.
* On output the actual values in use are reported.
*
* nr_ringid (in)
* Indicates how rings should be bound to the file descriptors.
* If nr_flags != 0, then the low bits (in NETMAP_RING_MASK)
* are used to indicate the ring number, and nr_flags specifies
* the actual rings to bind. NETMAP_NO_TX_POLL is unaffected.
*
* NOTE: THE FOLLOWING (nr_flags == 0) IS DEPRECATED:
* If nr_flags == 0, NETMAP_HW_RING and NETMAP_SW_RING control
* the binding as follows:
* 0 (default) binds all physical rings
* NETMAP_HW_RING | ring number binds a single ring pair
* NETMAP_SW_RING binds only the host tx/rx rings
*
* NETMAP_NO_TX_POLL can be OR-ed to make select()/poll() push
* packets on tx rings only if POLLOUT is set.
* The default is to push any pending packet.
*
* NETMAP_DO_RX_POLL can be OR-ed to make select()/poll() release
* packets on rx rings also when POLLIN is NOT set.
* The default is to touch the rx ring only with POLLIN.
* Note that this is the opposite of TX because it
* reflects the common usage.
*
* NOTE: NETMAP_PRIV_MEM IS DEPRECATED, use nr_arg2 instead.
* NETMAP_PRIV_MEM is set on return for ports that do not use
* the global memory allocator.
* This information is not significant and applications
* should look at the region id in nr_arg2
*
* nr_flags is the recommended mode to indicate which rings should
* be bound to a file descriptor. Values are NR_REG_*
*
* nr_arg1 (in) The number of extra rings to be reserved.
* Especially when allocating a VALE port the system only
* allocates the amount of memory needed for the port.
* If more shared memory rings are desired (e.g. for pipes),
* the first invocation for the same basename/allocator
* should specify a suitable number. Memory cannot be
* extended after the first allocation without closing
* all ports on the same region.
*
* nr_arg2 (in/out) The identity of the memory region used.
* On input, 0 means the system decides autonomously,
* other values may try to select a specific region.
* On return the actual value is reported.
* Region '1' is the global allocator, normally shared
* by all interfaces. Other values are private regions.
* If two ports the same region zero-copy is possible.
*
* nr_arg3 (in/out) number of extra buffers to be allocated.
*
*
*
* nr_cmd (in) if non-zero indicates a special command:
* NETMAP_BDG_ATTACH and nr_name = vale*:ifname
* attaches the NIC to the switch; nr_ringid specifies
* which rings to use. Used by vale-ctl -a ...
* nr_arg1 = NETMAP_BDG_HOST also attaches the host port
* as in vale-ctl -h ...
*
* NETMAP_BDG_DETACH and nr_name = vale*:ifname
* disconnects a previously attached NIC.
* Used by vale-ctl -d ...
*
* NETMAP_BDG_LIST
* list the configuration of VALE switches.
*
* NETMAP_BDG_VNET_HDR
* Set the virtio-net header length used by the client
* of a VALE switch port.
*
* NETMAP_BDG_NEWIF
* create a persistent VALE port with name nr_name.
* Used by vale-ctl -n ...
*
* NETMAP_BDG_DELIF
* delete a persistent VALE port. Used by vale-ctl -d ...
*
* nr_arg1, nr_arg2, nr_arg3 (in/out) command specific
*
*
*
*/
/*
* struct nmreq overlays a struct ifreq (just the name)
*/
struct nmreq {
char nr_name[IFNAMSIZ];
uint32_t nr_version; /* API version */
uint32_t nr_offset; /* nifp offset in the shared region */
uint32_t nr_memsize; /* size of the shared region */
uint32_t nr_tx_slots; /* slots in tx rings */
uint32_t nr_rx_slots; /* slots in rx rings */
uint16_t nr_tx_rings; /* number of tx rings */
uint16_t nr_rx_rings; /* number of rx rings */
uint16_t nr_ringid; /* ring(s) we care about */
#define NETMAP_HW_RING 0x4000 /* single NIC ring pair */
#define NETMAP_SW_RING 0x2000 /* only host ring pair */
#define NETMAP_RING_MASK 0x0fff /* the ring number */
#define NETMAP_NO_TX_POLL 0x1000 /* no automatic txsync on poll */
#define NETMAP_DO_RX_POLL 0x8000 /* DO automatic rxsync on poll */
uint16_t nr_cmd;
#define NETMAP_BDG_ATTACH 1 /* attach the NIC */
#define NETMAP_BDG_DETACH 2 /* detach the NIC */
#define NETMAP_BDG_REGOPS 3 /* register bridge callbacks */
#define NETMAP_BDG_LIST 4 /* get bridge's info */
#define NETMAP_BDG_VNET_HDR 5 /* set the port virtio-net-hdr length */
#define NETMAP_BDG_NEWIF 6 /* create a virtual port */
#define NETMAP_BDG_DELIF 7 /* destroy a virtual port */
#define NETMAP_PT_HOST_CREATE 8 /* create ptnetmap kthreads */
#define NETMAP_PT_HOST_DELETE 9 /* delete ptnetmap kthreads */
#define NETMAP_BDG_POLLING_ON 10 /* delete polling kthread */
#define NETMAP_BDG_POLLING_OFF 11 /* delete polling kthread */
#define NETMAP_VNET_HDR_GET 12 /* get the port virtio-net-hdr length */
uint16_t nr_arg1; /* reserve extra rings in NIOCREGIF */
#define NETMAP_BDG_HOST 1 /* nr_arg1 value for NETMAP_BDG_ATTACH */
uint16_t nr_arg2; /* id of the memory allocator */
uint32_t nr_arg3; /* req. extra buffers in NIOCREGIF */
uint32_t nr_flags; /* specify NR_REG_* mode and other flags */
#define NR_REG_MASK 0xf /* to extract NR_REG_* mode from nr_flags */
/* various modes, extends nr_ringid */
uint32_t spare2[1];
};
#ifdef _WIN32
/*
* Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
* in ws2def.h but not sure if they are in the form we need.
* We therefore redefine them in a convenient way to use for DeviceIoControl
* signatures.
*/
#undef _IO // ws2def.h
#define _WIN_NM_IOCTL_TYPE 40000
#define _IO(_c, _n) CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \
METHOD_BUFFERED, FILE_ANY_ACCESS )
#define _IO_direct(_c, _n) CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \
METHOD_OUT_DIRECT, FILE_ANY_ACCESS )
#define _IOWR(_c, _n, _s) _IO(_c, _n)
/* We havesome internal sysctl in addition to the externally visible ones */
#define NETMAP_MMAP _IO_direct('i', 160) // note METHOD_OUT_DIRECT
#define NETMAP_POLL _IO('i', 162)
/* and also two setsockopt for sysctl emulation */
#define NETMAP_SETSOCKOPT _IO('i', 140)
#define NETMAP_GETSOCKOPT _IO('i', 141)
/* These linknames are for the Netmap Core Driver */
#define NETMAP_NT_DEVICE_NAME L"\\Device\\NETMAP"
#define NETMAP_DOS_DEVICE_NAME L"\\DosDevices\\netmap"
/* Definition of a structure used to pass a virtual address within an IOCTL */
typedef struct _MEMORY_ENTRY {
PVOID pUsermodeVirtualAddress;
} MEMORY_ENTRY, *PMEMORY_ENTRY;
typedef struct _POLL_REQUEST_DATA {
int events;
int timeout;
int revents;
} POLL_REQUEST_DATA;
#endif /* _WIN32 */
/*
* Opaque structure that is passed to an external kernel
* module via ioctl(fd, NIOCCONFIG, req) for a user-owned
* bridge port (at this point ephemeral VALE interface).
*/
#define NM_IFRDATA_LEN 256
struct nm_ifreq {
char nifr_name[IFNAMSIZ];
char data[NM_IFRDATA_LEN];
};
/*
* FreeBSD uses the size value embedded in the _IOWR to determine
* how much to copy in/out. So we need it to match the actual
* data structure we pass. We put some spares in the structure
* to ease compatibility with other versions
*/
#define NIOCGINFO _IOWR('i', 145, struct nmreq) /* return IF info */
#define NIOCREGIF _IOWR('i', 146, struct nmreq) /* interface register */
#define NIOCCONFIG _IOWR('i',150, struct nm_ifreq) /* for ext. modules */
#endif /* _NET_NETMAP_LEGACY_H_ */

View file

@ -100,7 +100,6 @@
#endif /* likely and unlikely */
#include <net/netmap.h>
#include <net/netmap_virt.h> /* nmreq_pointer_get() */
/* helper macro */
#define _NETMAP_OFFSET(type, ptr, offset) \
@ -115,7 +114,7 @@
nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] )
#define NETMAP_BUF(ring, index) \
((char *)(ring) + (ring)->buf_ofs + ((long)(index)*(ring)->nr_buf_size))
((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size))
#define NETMAP_BUF_IDX(ring, buf) \
( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \
@ -225,7 +224,7 @@ struct nm_desc {
struct nm_desc *self; /* point to self if netmap. */
int fd;
void *mem;
uint64_t memsize;
uint32_t memsize;
int done_mmap; /* set if mem is the result of mmap */
struct netmap_if * const nifp;
uint16_t first_tx_ring, last_tx_ring, cur_tx_ring;
@ -351,7 +350,6 @@ enum {
NM_OPEN_ARG2 = 0x200000,
NM_OPEN_ARG3 = 0x400000,
NM_OPEN_RING_CFG = 0x800000, /* tx|rx rings|slots */
NM_OPEN_EXTMEM = 0x1000000,
};
@ -613,28 +611,9 @@ nm_is_identifier(const char *s, const char *e)
return 1;
}
static void
nm_init_offsets(struct nm_desc *d)
{
struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset);
struct netmap_ring *r = NETMAP_RXRING(nifp, d->first_rx_ring);
if ((void *)r == (void *)nifp) {
/* the descriptor is open for TX only */
r = NETMAP_TXRING(nifp, d->first_tx_ring);
}
*(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp;
*(struct netmap_ring **)(uintptr_t)&d->some_ring = r;
*(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0);
*(void **)(uintptr_t)&d->buf_end =
(char *)d->mem + d->memsize;
}
#define MAXERRMSG 80
#define NM_PARSE_OK 0
#define NM_PARSE_MEMID 1
static int
nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
nm_parse(const char *ifname, struct nm_desc *d, char *err)
{
int is_vale;
const char *port = NULL;
@ -648,13 +627,6 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
errno = 0;
if (strncmp(ifname, "netmap:", 7) &&
strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
snprintf(errmsg, MAXERRMSG, "invalid port name: %s", ifname);
errno = EINVAL;
goto fail;
}
is_vale = (ifname[0] == 'v');
if (is_vale) {
port = index(ifname, ':');
@ -685,13 +657,12 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
}
namelen = port - ifname;
if (namelen >= sizeof(d->nr_name)) {
if (namelen >= sizeof(d->req.nr_name)) {
snprintf(errmsg, MAXERRMSG, "name too long");
goto fail;
}
memcpy(d->nr_name, ifname, namelen);
d->nr_name[namelen] = '\0';
D("name %s", d->nr_name);
memcpy(d->req.nr_name, ifname, namelen);
d->req.nr_name[namelen] = '\0';
p_state = P_START;
nr_flags = NR_REG_ALL_NIC; /* default for no suffix */
@ -789,28 +760,21 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
p_state = P_FLAGSOK;
break;
case P_MEMID:
if (!memid_allowed) {
if (nr_arg2 != 0) {
snprintf(errmsg, MAXERRMSG, "double setting of memid");
goto fail;
}
num = strtol(port, (char **)&port, 10);
if (num <= 0) {
ND("non-numeric memid %s (out = %p)", port, out);
if (out == NULL)
goto fail;
*out = (char *)port;
while (*port)
port++;
} else {
nr_arg2 = num;
memid_allowed = 0;
p_state = P_RNGSFXOK;
snprintf(errmsg, MAXERRMSG, "invalid memid %ld, must be >0", num);
goto fail;
}
nr_arg2 = num;
p_state = P_RNGSFXOK;
break;
}
}
if (p_state != P_START && p_state != P_RNGSFXOK &&
p_state != P_FLAGSOK && p_state != P_MEMID) {
if (p_state != P_START && p_state != P_RNGSFXOK && p_state != P_FLAGSOK) {
snprintf(errmsg, MAXERRMSG, "unexpected end of port name");
goto fail;
}
@ -820,117 +784,28 @@ nm_parse_one(const char *ifname, struct nmreq *d, char **out, int memid_allowed)
(nr_flags & NR_MONITOR_TX) ? "MONITOR_TX" : "",
(nr_flags & NR_MONITOR_RX) ? "MONITOR_RX" : "");
d->nr_flags |= nr_flags;
d->nr_ringid |= nr_ringid;
d->nr_arg2 = nr_arg2;
d->req.nr_flags |= nr_flags;
d->req.nr_ringid |= nr_ringid;
d->req.nr_arg2 = nr_arg2;
return (p_state == P_MEMID) ? NM_PARSE_MEMID : NM_PARSE_OK;
d->self = d;
return 0;
fail:
if (!errno)
errno = EINVAL;
if (out)
*out = strdup(errmsg);
if (err)
strncpy(err, errmsg, MAXERRMSG);
return -1;
}
static int
nm_interp_memid(const char *memid, struct nmreq *req, char **err)
{
int fd = -1;
char errmsg[MAXERRMSG] = "";
struct nmreq greq;
off_t mapsize;
struct netmap_pools_info *pi;
/* first, try to look for a netmap port with this name */
fd = open("/dev/netmap", O_RDONLY);
if (fd < 0) {
snprintf(errmsg, MAXERRMSG, "cannot open /dev/netmap: %s", strerror(errno));
goto fail;
}
memset(&greq, 0, sizeof(greq));
if (nm_parse_one(memid, &greq, err, 0) == NM_PARSE_OK) {
greq.nr_version = NETMAP_API;
if (ioctl(fd, NIOCGINFO, &greq) < 0) {
if (errno == ENOENT || errno == ENXIO)
goto try_external;
snprintf(errmsg, MAXERRMSG, "cannot getinfo for %s: %s", memid, strerror(errno));
goto fail;
}
req->nr_arg2 = greq.nr_arg2;
close(fd);
return 0;
}
try_external:
D("trying with external memory");
close(fd);
fd = open(memid, O_RDWR);
if (fd < 0) {
snprintf(errmsg, MAXERRMSG, "cannot open %s: %s", memid, strerror(errno));
goto fail;
}
mapsize = lseek(fd, 0, SEEK_END);
if (mapsize < 0) {
snprintf(errmsg, MAXERRMSG, "failed to obtain filesize of %s: %s", memid, strerror(errno));
goto fail;
}
pi = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (pi == MAP_FAILED) {
snprintf(errmsg, MAXERRMSG, "cannot map %s: %s", memid, strerror(errno));
goto fail;
}
req->nr_cmd = NETMAP_POOLS_CREATE;
pi->memsize = mapsize;
nmreq_pointer_put(req, pi);
D("mapped %zu bytes at %p from file %s", mapsize, pi, memid);
return 0;
fail:
D("%s", errmsg);
close(fd);
if (err && !*err)
*err = strdup(errmsg);
return errno;
}
static int
nm_parse(const char *ifname, struct nm_desc *d, char *errmsg)
{
char *err;
switch (nm_parse_one(ifname, &d->req, &err, 1)) {
case NM_PARSE_OK:
D("parse OK");
break;
case NM_PARSE_MEMID:
D("memid: %s", err);
errno = nm_interp_memid(err, &d->req, &err);
D("errno = %d", errno);
if (!errno)
break;
/* fallthrough */
default:
D("error");
strncpy(errmsg, err, MAXERRMSG);
errmsg[MAXERRMSG-1] = '\0';
free(err);
return -1;
}
D("parsed name: %s", d->req.nr_name);
d->self = d;
return 0;
}
/*
* Try to open, return descriptor if successful, NULL otherwise.
* An invalid netmap name will return errno = 0;
* You can pass a pointer to a pre-filled nm_desc to add special
* parameters. Flags is used as follows
* NM_OPEN_NO_MMAP use the memory from arg, only
* NM_OPEN_NO_MMAP use the memory from arg, only XXX avoid mmap
* if the nr_arg2 (memory block) matches.
* Special case: if arg is NULL, skip the
* mmap entirely (maybe because you are going
* to do it by yourself, or you plan to call
* nm_mmap() only later)
* NM_OPEN_ARG1 use req.nr_arg1 from arg
* NM_OPEN_ARG2 use req.nr_arg2 from arg
* NM_OPEN_RING_CFG user ring config from arg
@ -943,7 +818,6 @@ nm_open(const char *ifname, const struct nmreq *req,
const struct nm_desc *parent = arg;
char errmsg[MAXERRMSG] = "";
uint32_t nr_reg;
struct netmap_pools_info *pi = NULL;
if (strncmp(ifname, "netmap:", 7) &&
strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) {
@ -964,60 +838,12 @@ nm_open(const char *ifname, const struct nmreq *req,
goto fail;
}
if (req) {
if (req)
d->req = *req;
} else {
d->req.nr_arg1 = 4;
d->req.nr_arg2 = 0;
d->req.nr_arg3 = 0;
}
if (!(new_flags & NM_OPEN_IFNAME)) {
char *err;
switch (nm_parse_one(ifname, &d->req, &err, 1)) {
case NM_PARSE_OK:
break;
case NM_PARSE_MEMID:
if ((new_flags & NM_OPEN_NO_MMAP) &&
IS_NETMAP_DESC(parent)) {
/* ignore the memid setting, since we are
* going to use the parent's one
*/
break;
}
errno = nm_interp_memid(err, &d->req, &err);
if (!errno)
break;
/* fallthrough */
default:
strncpy(errmsg, err, MAXERRMSG);
errmsg[MAXERRMSG-1] = '\0';
free(err);
if (nm_parse(ifname, d, errmsg) < 0)
goto fail;
}
d->self = d;
}
/* compatibility checks for POOL_SCREATE and NM_OPEN flags
* the first check may be dropped once we have a larger nreq
*/
if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
if (IS_NETMAP_DESC(parent)) {
if (new_flags & (NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3)) {
snprintf(errmsg, MAXERRMSG,
"POOLS_CREATE is incompatibile "
"with NM_OPEN_ARG? flags");
errno = EINVAL;
goto fail;
}
if (new_flags & NM_OPEN_NO_MMAP) {
snprintf(errmsg, MAXERRMSG,
"POOLS_CREATE is incompatible "
"with NM_OPEN_NO_MMAP flag");
errno = EINVAL;
goto fail;
}
}
}
d->req.nr_version = NETMAP_API;
@ -1025,26 +851,18 @@ nm_open(const char *ifname, const struct nmreq *req,
/* optionally import info from parent */
if (IS_NETMAP_DESC(parent) && new_flags) {
if (new_flags & NM_OPEN_EXTMEM) {
if (parent->req.nr_cmd == NETMAP_POOLS_CREATE) {
d->req.nr_cmd = NETMAP_POOLS_CREATE;
nmreq_pointer_put(&d->req, nmreq_pointer_get(&parent->req));
D("Warning: not overriding arg[1-3] since external memory is being used");
new_flags &= ~(NM_OPEN_ARG1 | NM_OPEN_ARG2 | NM_OPEN_ARG3);
}
}
if (new_flags & NM_OPEN_ARG1) {
if (new_flags & NM_OPEN_ARG1)
D("overriding ARG1 %d", parent->req.nr_arg1);
d->req.nr_arg1 = parent->req.nr_arg1;
}
if (new_flags & (NM_OPEN_ARG2 | NM_OPEN_NO_MMAP)) {
d->req.nr_arg1 = new_flags & NM_OPEN_ARG1 ?
parent->req.nr_arg1 : 4;
if (new_flags & NM_OPEN_ARG2) {
D("overriding ARG2 %d", parent->req.nr_arg2);
d->req.nr_arg2 = parent->req.nr_arg2;
d->req.nr_arg2 = parent->req.nr_arg2;
}
if (new_flags & NM_OPEN_ARG3) {
if (new_flags & NM_OPEN_ARG3)
D("overriding ARG3 %d", parent->req.nr_arg3);
d->req.nr_arg3 = parent->req.nr_arg3;
}
d->req.nr_arg3 = new_flags & NM_OPEN_ARG3 ?
parent->req.nr_arg3 : 0;
if (new_flags & NM_OPEN_RING_CFG) {
D("overriding RING_CFG");
d->req.nr_tx_slots = parent->req.nr_tx_slots;
@ -1065,28 +883,11 @@ nm_open(const char *ifname, const struct nmreq *req,
/* add the *XPOLL flags */
d->req.nr_ringid |= new_flags & (NETMAP_NO_TX_POLL | NETMAP_DO_RX_POLL);
if (d->req.nr_cmd == NETMAP_POOLS_CREATE) {
pi = nmreq_pointer_get(&d->req);
}
if (ioctl(d->fd, NIOCREGIF, &d->req)) {
snprintf(errmsg, MAXERRMSG, "NIOCREGIF failed: %s", strerror(errno));
goto fail;
}
if (pi != NULL) {
d->mem = pi;
d->memsize = pi->memsize;
nm_init_offsets(d);
} else if ((!(new_flags & NM_OPEN_NO_MMAP) || parent)) {
/* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */
errno = nm_mmap(d, parent);
if (errno) {
snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno));
goto fail;
}
}
nr_reg = d->req.nr_flags & NR_REG_MASK;
if (nr_reg == NR_REG_SW) { /* host stack */
@ -1111,6 +912,13 @@ nm_open(const char *ifname, const struct nmreq *req,
d->first_rx_ring = d->last_rx_ring = 0;
}
/* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */
if ((!(new_flags & NM_OPEN_NO_MMAP) || parent) && nm_mmap(d, parent)) {
snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno));
goto fail;
}
#ifdef DEBUG_NETMAP_USER
{ /* debugging code */
int i;
@ -1151,8 +959,7 @@ nm_close(struct nm_desc *d)
*/
static void *__xxzt[] __attribute__ ((unused)) =
{ (void *)nm_open, (void *)nm_inject,
(void *)nm_dispatch, (void *)nm_nextpkt,
(void *)nm_parse } ;
(void *)nm_dispatch, (void *)nm_nextpkt } ;
if (d == NULL || d->self != d)
return EINVAL;
@ -1189,8 +996,21 @@ nm_mmap(struct nm_desc *d, const struct nm_desc *parent)
}
d->done_mmap = 1;
}
{
struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset);
struct netmap_ring *r = NETMAP_RXRING(nifp, d->first_rx_ring);
if ((void *)r == (void *)nifp) {
/* the descriptor is open for TX only */
r = NETMAP_TXRING(nifp, d->first_tx_ring);
}
*(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp;
*(struct netmap_ring **)(uintptr_t)&d->some_ring = r;
*(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0);
*(void **)(uintptr_t)&d->buf_end =
(char *)d->mem + d->memsize;
}
nm_init_offsets(d);
return 0;
fail:

View file

@ -109,28 +109,10 @@ struct ptnetmap_cfgentry_bhyve {
} ioctl_data;
};
/*
* Structure filled-in by the kernel when asked for allocator info
* through NETMAP_POOLS_INFO_GET. Used by hypervisors supporting
* ptnetmap.
*/
struct netmap_pools_info {
uint64_t memsize; /* same as nmr->nr_memsize */
uint32_t memid; /* same as nmr->nr_arg2 */
uint32_t if_pool_offset;
uint32_t if_pool_objtotal;
uint32_t if_pool_objsize;
uint32_t ring_pool_offset;
uint32_t ring_pool_objtotal;
uint32_t ring_pool_objsize;
uint32_t buf_pool_offset;
uint32_t buf_pool_objtotal;
uint32_t buf_pool_objsize;
};
/*
* Pass a pointer to a userspace buffer to be passed to kernelspace for write
* or read. Used by NETMAP_PT_HOST_CREATE and NETMAP_POOLS_INFO_GET.
* or read. Used by NETMAP_PT_HOST_CREATE.
* XXX deprecated
*/
static inline void
nmreq_pointer_put(struct nmreq *nmr, void *userptr)
@ -142,7 +124,7 @@ nmreq_pointer_put(struct nmreq *nmr, void *userptr)
static inline void *
nmreq_pointer_get(const struct nmreq *nmr)
{
const uintptr_t * pp = (const uintptr_t *)&nmr->nr_arg1;
const uintptr_t *pp = (const uintptr_t *)&nmr->nr_arg1;
return (void *)*pp;
}

View file

@ -60,7 +60,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
#define __FreeBSD_version 1200061 /* Master, propagated to newvers */
#define __FreeBSD_version 1200062 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,