1*4bf50f18SLuigi Rizzo /* 2*4bf50f18SLuigi Rizzo * Copyright (C) 2014 Giuseppe Lettieri. All rights reserved. 3*4bf50f18SLuigi Rizzo * 4*4bf50f18SLuigi Rizzo * Redistribution and use in source and binary forms, with or without 5*4bf50f18SLuigi Rizzo * modification, are permitted provided that the following conditions 6*4bf50f18SLuigi Rizzo * are met: 7*4bf50f18SLuigi Rizzo * 1. Redistributions of source code must retain the above copyright 8*4bf50f18SLuigi Rizzo * notice, this list of conditions and the following disclaimer. 9*4bf50f18SLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 10*4bf50f18SLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 11*4bf50f18SLuigi Rizzo * documentation and/or other materials provided with the distribution. 12*4bf50f18SLuigi Rizzo * 13*4bf50f18SLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14*4bf50f18SLuigi Rizzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15*4bf50f18SLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16*4bf50f18SLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17*4bf50f18SLuigi Rizzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18*4bf50f18SLuigi Rizzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19*4bf50f18SLuigi Rizzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20*4bf50f18SLuigi Rizzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21*4bf50f18SLuigi Rizzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22*4bf50f18SLuigi Rizzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23*4bf50f18SLuigi Rizzo * SUCH DAMAGE. 24*4bf50f18SLuigi Rizzo */ 25*4bf50f18SLuigi Rizzo 26*4bf50f18SLuigi Rizzo /* 27*4bf50f18SLuigi Rizzo * $FreeBSD$ 28*4bf50f18SLuigi Rizzo * 29*4bf50f18SLuigi Rizzo * Monitors 30*4bf50f18SLuigi Rizzo * 31*4bf50f18SLuigi Rizzo * netmap monitors can be used to do zero-copy monitoring of network traffic 32*4bf50f18SLuigi Rizzo * on another adapter, when the latter adapter is working in netmap mode. 33*4bf50f18SLuigi Rizzo * 34*4bf50f18SLuigi Rizzo * Monitors offer to userspace the same interface as any other netmap port, 35*4bf50f18SLuigi Rizzo * with as many pairs of netmap rings as the monitored adapter. 36*4bf50f18SLuigi Rizzo * However, only the rx rings are actually used. Each monitor rx ring receives 37*4bf50f18SLuigi Rizzo * the traffic transiting on both the tx and rx corresponding rings in the 38*4bf50f18SLuigi Rizzo * monitored adapter. During registration, the user can choose if she wants 39*4bf50f18SLuigi Rizzo * to intercept tx only, rx only, or both tx and rx traffic. 40*4bf50f18SLuigi Rizzo * 41*4bf50f18SLuigi Rizzo * The monitor only sees the frames after they have been consumed in the 42*4bf50f18SLuigi Rizzo * monitored adapter: 43*4bf50f18SLuigi Rizzo * 44*4bf50f18SLuigi Rizzo * - For tx traffic, this is after the slots containing the frames have been 45*4bf50f18SLuigi Rizzo * marked as free. Note that this may happen at a considerably delay after 46*4bf50f18SLuigi Rizzo * frame transmission, since freeing of slots is often done lazily. 47*4bf50f18SLuigi Rizzo * 48*4bf50f18SLuigi Rizzo * - For rx traffic, this is after the consumer on the monitored adapter 49*4bf50f18SLuigi Rizzo * has released them. In most cases, the consumer is a userspace 50*4bf50f18SLuigi Rizzo * application which may have modified the frame contents. 51*4bf50f18SLuigi Rizzo * 52*4bf50f18SLuigi Rizzo * If the monitor is not able to cope with the stream of frames, excess traffic 53*4bf50f18SLuigi Rizzo * will be dropped. 54*4bf50f18SLuigi Rizzo * 55*4bf50f18SLuigi Rizzo * Each ring can be monitored by at most one monitor. This may change in the 56*4bf50f18SLuigi Rizzo * future, if we implement monitor chaining. 57*4bf50f18SLuigi Rizzo * 58*4bf50f18SLuigi Rizzo */ 59*4bf50f18SLuigi Rizzo 60*4bf50f18SLuigi Rizzo 61*4bf50f18SLuigi Rizzo #if defined(__FreeBSD__) 62*4bf50f18SLuigi Rizzo #include <sys/cdefs.h> /* prerequisite */ 63*4bf50f18SLuigi Rizzo 64*4bf50f18SLuigi Rizzo #include <sys/types.h> 65*4bf50f18SLuigi Rizzo #include <sys/errno.h> 66*4bf50f18SLuigi Rizzo #include <sys/param.h> /* defines used in kernel.h */ 67*4bf50f18SLuigi Rizzo #include <sys/kernel.h> /* types used in module initialization */ 68*4bf50f18SLuigi Rizzo #include <sys/malloc.h> 69*4bf50f18SLuigi Rizzo #include <sys/poll.h> 70*4bf50f18SLuigi Rizzo #include <sys/lock.h> 71*4bf50f18SLuigi Rizzo #include <sys/rwlock.h> 72*4bf50f18SLuigi Rizzo #include <sys/selinfo.h> 73*4bf50f18SLuigi Rizzo #include <sys/sysctl.h> 74*4bf50f18SLuigi Rizzo #include <sys/socket.h> /* sockaddrs */ 75*4bf50f18SLuigi Rizzo #include <net/if.h> 76*4bf50f18SLuigi Rizzo #include <net/if_var.h> 77*4bf50f18SLuigi Rizzo #include <machine/bus.h> /* bus_dmamap_* */ 78*4bf50f18SLuigi Rizzo #include <sys/refcount.h> 79*4bf50f18SLuigi Rizzo 80*4bf50f18SLuigi Rizzo 81*4bf50f18SLuigi Rizzo #elif defined(linux) 82*4bf50f18SLuigi Rizzo 83*4bf50f18SLuigi Rizzo #include "bsd_glue.h" 84*4bf50f18SLuigi Rizzo 85*4bf50f18SLuigi Rizzo #elif defined(__APPLE__) 86*4bf50f18SLuigi Rizzo 87*4bf50f18SLuigi Rizzo #warning OSX support is only partial 88*4bf50f18SLuigi Rizzo #include "osx_glue.h" 89*4bf50f18SLuigi Rizzo 90*4bf50f18SLuigi Rizzo #else 91*4bf50f18SLuigi Rizzo 92*4bf50f18SLuigi Rizzo #error Unsupported platform 93*4bf50f18SLuigi Rizzo 94*4bf50f18SLuigi Rizzo #endif /* unsupported */ 95*4bf50f18SLuigi Rizzo 96*4bf50f18SLuigi Rizzo /* 97*4bf50f18SLuigi Rizzo * common headers 98*4bf50f18SLuigi Rizzo */ 99*4bf50f18SLuigi Rizzo 100*4bf50f18SLuigi Rizzo #include <net/netmap.h> 101*4bf50f18SLuigi Rizzo #include <dev/netmap/netmap_kern.h> 102*4bf50f18SLuigi Rizzo #include <dev/netmap/netmap_mem2.h> 103*4bf50f18SLuigi Rizzo 104*4bf50f18SLuigi Rizzo #ifdef WITH_MONITOR 105*4bf50f18SLuigi Rizzo 106*4bf50f18SLuigi Rizzo #define NM_MONITOR_MAXSLOTS 4096 107*4bf50f18SLuigi Rizzo 108*4bf50f18SLuigi Rizzo /* monitor works by replacing the nm_sync callbacks in the monitored rings. 109*4bf50f18SLuigi Rizzo * The actions to be performed are the same on both tx and rx rings, so we 110*4bf50f18SLuigi Rizzo * have collected them here 111*4bf50f18SLuigi Rizzo */ 112*4bf50f18SLuigi Rizzo static int 113*4bf50f18SLuigi Rizzo netmap_monitor_parent_sync(struct netmap_kring *kring, int flags, u_int* ringptr) 114*4bf50f18SLuigi Rizzo { 115*4bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna = kring->monitor; 116*4bf50f18SLuigi Rizzo struct netmap_kring *mkring = &mna->up.rx_rings[kring->ring_id]; 117*4bf50f18SLuigi Rizzo struct netmap_ring *ring = kring->ring, *mring = mkring->ring; 118*4bf50f18SLuigi Rizzo int error; 119*4bf50f18SLuigi Rizzo int rel_slots, free_slots, busy; 120*4bf50f18SLuigi Rizzo u_int beg, end, i; 121*4bf50f18SLuigi Rizzo u_int lim = kring->nkr_num_slots - 1, 122*4bf50f18SLuigi Rizzo mlim = mkring->nkr_num_slots - 1; 123*4bf50f18SLuigi Rizzo 124*4bf50f18SLuigi Rizzo /* get the relased slots (rel_slots) */ 125*4bf50f18SLuigi Rizzo beg = *ringptr; 126*4bf50f18SLuigi Rizzo error = kring->save_sync(kring, flags); 127*4bf50f18SLuigi Rizzo if (error) 128*4bf50f18SLuigi Rizzo return error; 129*4bf50f18SLuigi Rizzo end = *ringptr; 130*4bf50f18SLuigi Rizzo rel_slots = end - beg; 131*4bf50f18SLuigi Rizzo if (rel_slots < 0) 132*4bf50f18SLuigi Rizzo rel_slots += kring->nkr_num_slots; 133*4bf50f18SLuigi Rizzo 134*4bf50f18SLuigi Rizzo if (!rel_slots) { 135*4bf50f18SLuigi Rizzo return 0; 136*4bf50f18SLuigi Rizzo } 137*4bf50f18SLuigi Rizzo 138*4bf50f18SLuigi Rizzo /* we need to lock the monitor receive ring, since it 139*4bf50f18SLuigi Rizzo * is the target of bot tx and rx traffic from the monitored 140*4bf50f18SLuigi Rizzo * adapter 141*4bf50f18SLuigi Rizzo */ 142*4bf50f18SLuigi Rizzo mtx_lock(&mkring->q_lock); 143*4bf50f18SLuigi Rizzo /* get the free slots available on the monitor ring */ 144*4bf50f18SLuigi Rizzo i = mkring->nr_hwtail; 145*4bf50f18SLuigi Rizzo busy = i - mkring->nr_hwcur; 146*4bf50f18SLuigi Rizzo if (busy < 0) 147*4bf50f18SLuigi Rizzo busy += mkring->nkr_num_slots; 148*4bf50f18SLuigi Rizzo free_slots = mlim - busy; 149*4bf50f18SLuigi Rizzo 150*4bf50f18SLuigi Rizzo if (!free_slots) { 151*4bf50f18SLuigi Rizzo mtx_unlock(&mkring->q_lock); 152*4bf50f18SLuigi Rizzo return 0; 153*4bf50f18SLuigi Rizzo } 154*4bf50f18SLuigi Rizzo 155*4bf50f18SLuigi Rizzo /* swap min(free_slots, rel_slots) slots */ 156*4bf50f18SLuigi Rizzo if (free_slots < rel_slots) { 157*4bf50f18SLuigi Rizzo beg += (rel_slots - free_slots); 158*4bf50f18SLuigi Rizzo if (beg > lim) 159*4bf50f18SLuigi Rizzo beg = 0; 160*4bf50f18SLuigi Rizzo rel_slots = free_slots; 161*4bf50f18SLuigi Rizzo } 162*4bf50f18SLuigi Rizzo 163*4bf50f18SLuigi Rizzo for ( ; rel_slots; rel_slots--) { 164*4bf50f18SLuigi Rizzo struct netmap_slot *s = &ring->slot[beg]; 165*4bf50f18SLuigi Rizzo struct netmap_slot *ms = &mring->slot[i]; 166*4bf50f18SLuigi Rizzo uint32_t tmp; 167*4bf50f18SLuigi Rizzo 168*4bf50f18SLuigi Rizzo tmp = ms->buf_idx; 169*4bf50f18SLuigi Rizzo ms->buf_idx = s->buf_idx; 170*4bf50f18SLuigi Rizzo s->buf_idx = tmp; 171*4bf50f18SLuigi Rizzo 172*4bf50f18SLuigi Rizzo tmp = ms->len; 173*4bf50f18SLuigi Rizzo ms->len = s->len; 174*4bf50f18SLuigi Rizzo s->len = tmp; 175*4bf50f18SLuigi Rizzo 176*4bf50f18SLuigi Rizzo s->flags |= NS_BUF_CHANGED; 177*4bf50f18SLuigi Rizzo 178*4bf50f18SLuigi Rizzo beg = nm_next(beg, lim); 179*4bf50f18SLuigi Rizzo i = nm_next(i, mlim); 180*4bf50f18SLuigi Rizzo 181*4bf50f18SLuigi Rizzo } 182*4bf50f18SLuigi Rizzo wmb(); 183*4bf50f18SLuigi Rizzo mkring->nr_hwtail = i; 184*4bf50f18SLuigi Rizzo 185*4bf50f18SLuigi Rizzo mtx_unlock(&mkring->q_lock); 186*4bf50f18SLuigi Rizzo /* notify the new frames to the monitor */ 187*4bf50f18SLuigi Rizzo mna->up.nm_notify(&mna->up, mkring->ring_id, NR_RX, 0); 188*4bf50f18SLuigi Rizzo return 0; 189*4bf50f18SLuigi Rizzo } 190*4bf50f18SLuigi Rizzo 191*4bf50f18SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored tx rings */ 192*4bf50f18SLuigi Rizzo static int 193*4bf50f18SLuigi Rizzo netmap_monitor_parent_txsync(struct netmap_kring *kring, int flags) 194*4bf50f18SLuigi Rizzo { 195*4bf50f18SLuigi Rizzo ND("%s %x", kring->name, flags); 196*4bf50f18SLuigi Rizzo return netmap_monitor_parent_sync(kring, flags, &kring->nr_hwtail); 197*4bf50f18SLuigi Rizzo } 198*4bf50f18SLuigi Rizzo 199*4bf50f18SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored rx rings */ 200*4bf50f18SLuigi Rizzo static int 201*4bf50f18SLuigi Rizzo netmap_monitor_parent_rxsync(struct netmap_kring *kring, int flags) 202*4bf50f18SLuigi Rizzo { 203*4bf50f18SLuigi Rizzo ND("%s %x", kring->name, flags); 204*4bf50f18SLuigi Rizzo return netmap_monitor_parent_sync(kring, flags, &kring->rcur); 205*4bf50f18SLuigi Rizzo } 206*4bf50f18SLuigi Rizzo 207*4bf50f18SLuigi Rizzo /* nm_sync callback for the monitor's own tx rings. 208*4bf50f18SLuigi Rizzo * This makes no sense and always returns error 209*4bf50f18SLuigi Rizzo */ 210*4bf50f18SLuigi Rizzo static int 211*4bf50f18SLuigi Rizzo netmap_monitor_txsync(struct netmap_kring *kring, int flags) 212*4bf50f18SLuigi Rizzo { 213*4bf50f18SLuigi Rizzo D("%s %x", kring->name, flags); 214*4bf50f18SLuigi Rizzo return EIO; 215*4bf50f18SLuigi Rizzo } 216*4bf50f18SLuigi Rizzo 217*4bf50f18SLuigi Rizzo /* nm_sync callback for the monitor's own rx rings. 218*4bf50f18SLuigi Rizzo * Note that the lock in netmap_monitor_parent_sync only protects 219*4bf50f18SLuigi Rizzo * writers among themselves. Synchronization between writers 220*4bf50f18SLuigi Rizzo * (i.e., netmap_monitor_parent_txsync and netmap_monitor_parent_rxsync) 221*4bf50f18SLuigi Rizzo * and readers (i.e., netmap_monitor_rxsync) relies on memory barriers. 222*4bf50f18SLuigi Rizzo */ 223*4bf50f18SLuigi Rizzo static int 224*4bf50f18SLuigi Rizzo netmap_monitor_rxsync(struct netmap_kring *kring, int flags) 225*4bf50f18SLuigi Rizzo { 226*4bf50f18SLuigi Rizzo ND("%s %x", kring->name, flags); 227*4bf50f18SLuigi Rizzo kring->nr_hwcur = kring->rcur; 228*4bf50f18SLuigi Rizzo rmb(); 229*4bf50f18SLuigi Rizzo nm_rxsync_finalize(kring); 230*4bf50f18SLuigi Rizzo return 0; 231*4bf50f18SLuigi Rizzo } 232*4bf50f18SLuigi Rizzo 233*4bf50f18SLuigi Rizzo /* nm_krings_create callbacks for monitors. 234*4bf50f18SLuigi Rizzo * We could use the default netmap_hw_krings_monitor, but 235*4bf50f18SLuigi Rizzo * we don't need the mbq. 236*4bf50f18SLuigi Rizzo */ 237*4bf50f18SLuigi Rizzo static int 238*4bf50f18SLuigi Rizzo netmap_monitor_krings_create(struct netmap_adapter *na) 239*4bf50f18SLuigi Rizzo { 240*4bf50f18SLuigi Rizzo return netmap_krings_create(na, 0); 241*4bf50f18SLuigi Rizzo } 242*4bf50f18SLuigi Rizzo 243*4bf50f18SLuigi Rizzo 244*4bf50f18SLuigi Rizzo /* nm_register callback for monitors. 245*4bf50f18SLuigi Rizzo * 246*4bf50f18SLuigi Rizzo * On registration, replace the nm_sync callbacks in the monitored 247*4bf50f18SLuigi Rizzo * rings with our own, saving the previous ones in the monitored 248*4bf50f18SLuigi Rizzo * rings themselves, where they are used by netmap_monitor_parent_sync. 249*4bf50f18SLuigi Rizzo * 250*4bf50f18SLuigi Rizzo * On de-registration, restore the original callbacks. We need to 251*4bf50f18SLuigi Rizzo * stop traffic while we are doing this, since the monitored adapter may 252*4bf50f18SLuigi Rizzo * have already started executing a netmap_monitor_parent_sync 253*4bf50f18SLuigi Rizzo * and may not like the kring->save_sync pointer to become NULL. 254*4bf50f18SLuigi Rizzo */ 255*4bf50f18SLuigi Rizzo static int 256*4bf50f18SLuigi Rizzo netmap_monitor_reg(struct netmap_adapter *na, int onoff) 257*4bf50f18SLuigi Rizzo { 258*4bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna = 259*4bf50f18SLuigi Rizzo (struct netmap_monitor_adapter *)na; 260*4bf50f18SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 261*4bf50f18SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 262*4bf50f18SLuigi Rizzo struct netmap_kring *kring; 263*4bf50f18SLuigi Rizzo int i; 264*4bf50f18SLuigi Rizzo 265*4bf50f18SLuigi Rizzo ND("%p: onoff %d", na, onoff); 266*4bf50f18SLuigi Rizzo if (onoff) { 267*4bf50f18SLuigi Rizzo if (!nm_netmap_on(pna)) { 268*4bf50f18SLuigi Rizzo /* parent left netmap mode, fatal */ 269*4bf50f18SLuigi Rizzo return ENXIO; 270*4bf50f18SLuigi Rizzo } 271*4bf50f18SLuigi Rizzo if (mna->flags & NR_MONITOR_TX) { 272*4bf50f18SLuigi Rizzo for (i = priv->np_txqfirst; i < priv->np_txqlast; i++) { 273*4bf50f18SLuigi Rizzo kring = &pna->tx_rings[i]; 274*4bf50f18SLuigi Rizzo kring->save_sync = kring->nm_sync; 275*4bf50f18SLuigi Rizzo kring->nm_sync = netmap_monitor_parent_txsync; 276*4bf50f18SLuigi Rizzo } 277*4bf50f18SLuigi Rizzo } 278*4bf50f18SLuigi Rizzo if (mna->flags & NR_MONITOR_RX) { 279*4bf50f18SLuigi Rizzo for (i = priv->np_rxqfirst; i < priv->np_rxqlast; i++) { 280*4bf50f18SLuigi Rizzo kring = &pna->rx_rings[i]; 281*4bf50f18SLuigi Rizzo kring->save_sync = kring->nm_sync; 282*4bf50f18SLuigi Rizzo kring->nm_sync = netmap_monitor_parent_rxsync; 283*4bf50f18SLuigi Rizzo } 284*4bf50f18SLuigi Rizzo } 285*4bf50f18SLuigi Rizzo na->na_flags |= NAF_NETMAP_ON; 286*4bf50f18SLuigi Rizzo } else { 287*4bf50f18SLuigi Rizzo if (!nm_netmap_on(pna)) { 288*4bf50f18SLuigi Rizzo /* parent left netmap mode, nothing to restore */ 289*4bf50f18SLuigi Rizzo return 0; 290*4bf50f18SLuigi Rizzo } 291*4bf50f18SLuigi Rizzo na->na_flags &= ~NAF_NETMAP_ON; 292*4bf50f18SLuigi Rizzo if (mna->flags & NR_MONITOR_TX) { 293*4bf50f18SLuigi Rizzo for (i = priv->np_txqfirst; i < priv->np_txqlast; i++) { 294*4bf50f18SLuigi Rizzo netmap_set_txring(pna, i, 1 /* stopped */); 295*4bf50f18SLuigi Rizzo kring = &pna->tx_rings[i]; 296*4bf50f18SLuigi Rizzo kring->nm_sync = kring->save_sync; 297*4bf50f18SLuigi Rizzo kring->save_sync = NULL; 298*4bf50f18SLuigi Rizzo netmap_set_txring(pna, i, 0 /* enabled */); 299*4bf50f18SLuigi Rizzo } 300*4bf50f18SLuigi Rizzo } 301*4bf50f18SLuigi Rizzo if (mna->flags & NR_MONITOR_RX) { 302*4bf50f18SLuigi Rizzo for (i = priv->np_rxqfirst; i < priv->np_rxqlast; i++) { 303*4bf50f18SLuigi Rizzo netmap_set_rxring(pna, i, 1 /* stopped */); 304*4bf50f18SLuigi Rizzo kring = &pna->rx_rings[i]; 305*4bf50f18SLuigi Rizzo kring->nm_sync = kring->save_sync; 306*4bf50f18SLuigi Rizzo kring->save_sync = NULL; 307*4bf50f18SLuigi Rizzo netmap_set_rxring(pna, i, 0 /* enabled */); 308*4bf50f18SLuigi Rizzo } 309*4bf50f18SLuigi Rizzo } 310*4bf50f18SLuigi Rizzo } 311*4bf50f18SLuigi Rizzo return 0; 312*4bf50f18SLuigi Rizzo } 313*4bf50f18SLuigi Rizzo /* nm_krings_delete callback for monitors */ 314*4bf50f18SLuigi Rizzo static void 315*4bf50f18SLuigi Rizzo netmap_monitor_krings_delete(struct netmap_adapter *na) 316*4bf50f18SLuigi Rizzo { 317*4bf50f18SLuigi Rizzo netmap_krings_delete(na); 318*4bf50f18SLuigi Rizzo } 319*4bf50f18SLuigi Rizzo 320*4bf50f18SLuigi Rizzo 321*4bf50f18SLuigi Rizzo /* nm_dtor callback for monitors */ 322*4bf50f18SLuigi Rizzo static void 323*4bf50f18SLuigi Rizzo netmap_monitor_dtor(struct netmap_adapter *na) 324*4bf50f18SLuigi Rizzo { 325*4bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna = 326*4bf50f18SLuigi Rizzo (struct netmap_monitor_adapter *)na; 327*4bf50f18SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 328*4bf50f18SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 329*4bf50f18SLuigi Rizzo int i; 330*4bf50f18SLuigi Rizzo 331*4bf50f18SLuigi Rizzo ND("%p", na); 332*4bf50f18SLuigi Rizzo if (nm_netmap_on(pna)) { 333*4bf50f18SLuigi Rizzo /* parent still in netmap mode, mark its krings as free */ 334*4bf50f18SLuigi Rizzo if (mna->flags & NR_MONITOR_TX) { 335*4bf50f18SLuigi Rizzo for (i = priv->np_txqfirst; i < priv->np_txqlast; i++) { 336*4bf50f18SLuigi Rizzo pna->tx_rings[i].monitor = NULL; 337*4bf50f18SLuigi Rizzo } 338*4bf50f18SLuigi Rizzo } 339*4bf50f18SLuigi Rizzo if (mna->flags & NR_MONITOR_RX) { 340*4bf50f18SLuigi Rizzo for (i = priv->np_rxqfirst; i < priv->np_rxqlast; i++) { 341*4bf50f18SLuigi Rizzo pna->rx_rings[i].monitor = NULL; 342*4bf50f18SLuigi Rizzo } 343*4bf50f18SLuigi Rizzo } 344*4bf50f18SLuigi Rizzo } 345*4bf50f18SLuigi Rizzo netmap_adapter_put(pna); 346*4bf50f18SLuigi Rizzo } 347*4bf50f18SLuigi Rizzo 348*4bf50f18SLuigi Rizzo 349*4bf50f18SLuigi Rizzo /* check if nmr is a request for a monitor adapter that we can satisfy */ 350*4bf50f18SLuigi Rizzo int 351*4bf50f18SLuigi Rizzo netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na, int create) 352*4bf50f18SLuigi Rizzo { 353*4bf50f18SLuigi Rizzo struct nmreq pnmr; 354*4bf50f18SLuigi Rizzo struct netmap_adapter *pna; /* parent adapter */ 355*4bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna; 356*4bf50f18SLuigi Rizzo int i, error; 357*4bf50f18SLuigi Rizzo 358*4bf50f18SLuigi Rizzo if ((nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) { 359*4bf50f18SLuigi Rizzo ND("not a monitor"); 360*4bf50f18SLuigi Rizzo return 0; 361*4bf50f18SLuigi Rizzo } 362*4bf50f18SLuigi Rizzo /* this is a request for a monitor adapter */ 363*4bf50f18SLuigi Rizzo 364*4bf50f18SLuigi Rizzo D("flags %x", nmr->nr_flags); 365*4bf50f18SLuigi Rizzo 366*4bf50f18SLuigi Rizzo mna = malloc(sizeof(*mna), M_DEVBUF, M_NOWAIT | M_ZERO); 367*4bf50f18SLuigi Rizzo if (mna == NULL) { 368*4bf50f18SLuigi Rizzo D("memory error"); 369*4bf50f18SLuigi Rizzo return ENOMEM; 370*4bf50f18SLuigi Rizzo } 371*4bf50f18SLuigi Rizzo 372*4bf50f18SLuigi Rizzo /* first, try to find the adapter that we want to monitor 373*4bf50f18SLuigi Rizzo * We use the same nmr, after we have turned off the monitor flags. 374*4bf50f18SLuigi Rizzo * In this way we can potentially monitor everything netmap understands, 375*4bf50f18SLuigi Rizzo * except other monitors. 376*4bf50f18SLuigi Rizzo */ 377*4bf50f18SLuigi Rizzo memcpy(&pnmr, nmr, sizeof(pnmr)); 378*4bf50f18SLuigi Rizzo pnmr.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX); 379*4bf50f18SLuigi Rizzo error = netmap_get_na(&pnmr, &pna, create); 380*4bf50f18SLuigi Rizzo if (error) { 381*4bf50f18SLuigi Rizzo D("parent lookup failed: %d", error); 382*4bf50f18SLuigi Rizzo return error; 383*4bf50f18SLuigi Rizzo } 384*4bf50f18SLuigi Rizzo D("found parent: %s", pna->name); 385*4bf50f18SLuigi Rizzo 386*4bf50f18SLuigi Rizzo if (!nm_netmap_on(pna)) { 387*4bf50f18SLuigi Rizzo /* parent not in netmap mode */ 388*4bf50f18SLuigi Rizzo /* XXX we can wait for the parent to enter netmap mode, 389*4bf50f18SLuigi Rizzo * by intercepting its nm_register callback (2014-03-16) 390*4bf50f18SLuigi Rizzo */ 391*4bf50f18SLuigi Rizzo D("%s not in netmap mode", pna->name); 392*4bf50f18SLuigi Rizzo error = EINVAL; 393*4bf50f18SLuigi Rizzo goto put_out; 394*4bf50f18SLuigi Rizzo } 395*4bf50f18SLuigi Rizzo 396*4bf50f18SLuigi Rizzo /* grab all the rings we need in the parent */ 397*4bf50f18SLuigi Rizzo mna->priv.np_na = pna; 398*4bf50f18SLuigi Rizzo error = netmap_interp_ringid(&mna->priv, nmr->nr_ringid, nmr->nr_flags); 399*4bf50f18SLuigi Rizzo if (error) { 400*4bf50f18SLuigi Rizzo D("ringid error"); 401*4bf50f18SLuigi Rizzo goto put_out; 402*4bf50f18SLuigi Rizzo } 403*4bf50f18SLuigi Rizzo if (nmr->nr_flags & NR_MONITOR_TX) { 404*4bf50f18SLuigi Rizzo for (i = mna->priv.np_txqfirst; i < mna->priv.np_txqlast; i++) { 405*4bf50f18SLuigi Rizzo struct netmap_kring *kring = &pna->tx_rings[i]; 406*4bf50f18SLuigi Rizzo if (kring->monitor) { 407*4bf50f18SLuigi Rizzo error = EBUSY; 408*4bf50f18SLuigi Rizzo D("ring busy"); 409*4bf50f18SLuigi Rizzo goto release_out; 410*4bf50f18SLuigi Rizzo } 411*4bf50f18SLuigi Rizzo kring->monitor = mna; 412*4bf50f18SLuigi Rizzo } 413*4bf50f18SLuigi Rizzo } 414*4bf50f18SLuigi Rizzo if (nmr->nr_flags & NR_MONITOR_RX) { 415*4bf50f18SLuigi Rizzo for (i = mna->priv.np_rxqfirst; i < mna->priv.np_rxqlast; i++) { 416*4bf50f18SLuigi Rizzo struct netmap_kring *kring = &pna->rx_rings[i]; 417*4bf50f18SLuigi Rizzo if (kring->monitor) { 418*4bf50f18SLuigi Rizzo error = EBUSY; 419*4bf50f18SLuigi Rizzo D("ring busy"); 420*4bf50f18SLuigi Rizzo goto release_out; 421*4bf50f18SLuigi Rizzo } 422*4bf50f18SLuigi Rizzo kring->monitor = mna; 423*4bf50f18SLuigi Rizzo } 424*4bf50f18SLuigi Rizzo } 425*4bf50f18SLuigi Rizzo 426*4bf50f18SLuigi Rizzo snprintf(mna->up.name, sizeof(mna->up.name), "mon:%s", pna->name); 427*4bf50f18SLuigi Rizzo 428*4bf50f18SLuigi Rizzo /* the monitor supports the host rings iff the parent does */ 429*4bf50f18SLuigi Rizzo mna->up.na_flags = (pna->na_flags & NAF_HOST_RINGS); 430*4bf50f18SLuigi Rizzo mna->up.nm_txsync = netmap_monitor_txsync; 431*4bf50f18SLuigi Rizzo mna->up.nm_rxsync = netmap_monitor_rxsync; 432*4bf50f18SLuigi Rizzo mna->up.nm_register = netmap_monitor_reg; 433*4bf50f18SLuigi Rizzo mna->up.nm_dtor = netmap_monitor_dtor; 434*4bf50f18SLuigi Rizzo mna->up.nm_krings_create = netmap_monitor_krings_create; 435*4bf50f18SLuigi Rizzo mna->up.nm_krings_delete = netmap_monitor_krings_delete; 436*4bf50f18SLuigi Rizzo mna->up.nm_mem = pna->nm_mem; 437*4bf50f18SLuigi Rizzo mna->up.na_lut = pna->na_lut; 438*4bf50f18SLuigi Rizzo mna->up.na_lut_objtotal = pna->na_lut_objtotal; 439*4bf50f18SLuigi Rizzo mna->up.na_lut_objsize = pna->na_lut_objsize; 440*4bf50f18SLuigi Rizzo 441*4bf50f18SLuigi Rizzo mna->up.num_tx_rings = 1; // XXX we don't need it, but field can't be zero 442*4bf50f18SLuigi Rizzo /* we set the number of our rx_rings to be max(num_rx_rings, num_rx_rings) 443*4bf50f18SLuigi Rizzo * in the parent 444*4bf50f18SLuigi Rizzo */ 445*4bf50f18SLuigi Rizzo mna->up.num_rx_rings = pna->num_rx_rings; 446*4bf50f18SLuigi Rizzo if (pna->num_tx_rings > pna->num_rx_rings) 447*4bf50f18SLuigi Rizzo mna->up.num_rx_rings = pna->num_tx_rings; 448*4bf50f18SLuigi Rizzo /* by default, the number of slots is the same as in 449*4bf50f18SLuigi Rizzo * the parent rings, but the user may ask for a different 450*4bf50f18SLuigi Rizzo * number 451*4bf50f18SLuigi Rizzo */ 452*4bf50f18SLuigi Rizzo mna->up.num_tx_desc = nmr->nr_tx_slots; 453*4bf50f18SLuigi Rizzo nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc, 454*4bf50f18SLuigi Rizzo 1, NM_MONITOR_MAXSLOTS, NULL); 455*4bf50f18SLuigi Rizzo mna->up.num_rx_desc = nmr->nr_rx_slots; 456*4bf50f18SLuigi Rizzo nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc, 457*4bf50f18SLuigi Rizzo 1, NM_MONITOR_MAXSLOTS, NULL); 458*4bf50f18SLuigi Rizzo error = netmap_attach_common(&mna->up); 459*4bf50f18SLuigi Rizzo if (error) { 460*4bf50f18SLuigi Rizzo D("attach_common error"); 461*4bf50f18SLuigi Rizzo goto release_out; 462*4bf50f18SLuigi Rizzo } 463*4bf50f18SLuigi Rizzo 464*4bf50f18SLuigi Rizzo /* remember the traffic directions we have to monitor */ 465*4bf50f18SLuigi Rizzo mna->flags = (nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)); 466*4bf50f18SLuigi Rizzo 467*4bf50f18SLuigi Rizzo *na = &mna->up; 468*4bf50f18SLuigi Rizzo netmap_adapter_get(*na); 469*4bf50f18SLuigi Rizzo 470*4bf50f18SLuigi Rizzo /* write the configuration back */ 471*4bf50f18SLuigi Rizzo nmr->nr_tx_rings = mna->up.num_tx_rings; 472*4bf50f18SLuigi Rizzo nmr->nr_rx_rings = mna->up.num_rx_rings; 473*4bf50f18SLuigi Rizzo nmr->nr_tx_slots = mna->up.num_tx_desc; 474*4bf50f18SLuigi Rizzo nmr->nr_rx_slots = mna->up.num_rx_desc; 475*4bf50f18SLuigi Rizzo 476*4bf50f18SLuigi Rizzo /* keep the reference to the parent */ 477*4bf50f18SLuigi Rizzo D("monitor ok"); 478*4bf50f18SLuigi Rizzo 479*4bf50f18SLuigi Rizzo return 0; 480*4bf50f18SLuigi Rizzo 481*4bf50f18SLuigi Rizzo release_out: 482*4bf50f18SLuigi Rizzo D("monitor error"); 483*4bf50f18SLuigi Rizzo for (i = mna->priv.np_txqfirst; i < mna->priv.np_txqlast; i++) { 484*4bf50f18SLuigi Rizzo if (pna->tx_rings[i].monitor == mna) 485*4bf50f18SLuigi Rizzo pna->tx_rings[i].monitor = NULL; 486*4bf50f18SLuigi Rizzo } 487*4bf50f18SLuigi Rizzo for (i = mna->priv.np_rxqfirst; i < mna->priv.np_rxqlast; i++) { 488*4bf50f18SLuigi Rizzo if (pna->rx_rings[i].monitor == mna) 489*4bf50f18SLuigi Rizzo pna->rx_rings[i].monitor = NULL; 490*4bf50f18SLuigi Rizzo } 491*4bf50f18SLuigi Rizzo put_out: 492*4bf50f18SLuigi Rizzo netmap_adapter_put(pna); 493*4bf50f18SLuigi Rizzo free(mna, M_DEVBUF); 494*4bf50f18SLuigi Rizzo return error; 495*4bf50f18SLuigi Rizzo } 496*4bf50f18SLuigi Rizzo 497*4bf50f18SLuigi Rizzo 498*4bf50f18SLuigi Rizzo #endif /* WITH_MONITOR */ 499