14bf50f18SLuigi Rizzo /* 24bf50f18SLuigi Rizzo * Copyright (C) 2014 Giuseppe Lettieri. All rights reserved. 34bf50f18SLuigi Rizzo * 44bf50f18SLuigi Rizzo * Redistribution and use in source and binary forms, with or without 54bf50f18SLuigi Rizzo * modification, are permitted provided that the following conditions 64bf50f18SLuigi Rizzo * are met: 74bf50f18SLuigi Rizzo * 1. Redistributions of source code must retain the above copyright 84bf50f18SLuigi Rizzo * notice, this list of conditions and the following disclaimer. 94bf50f18SLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 104bf50f18SLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 114bf50f18SLuigi Rizzo * documentation and/or other materials provided with the distribution. 124bf50f18SLuigi Rizzo * 134bf50f18SLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 144bf50f18SLuigi Rizzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 154bf50f18SLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 164bf50f18SLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 174bf50f18SLuigi Rizzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 184bf50f18SLuigi Rizzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 194bf50f18SLuigi Rizzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 204bf50f18SLuigi Rizzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 214bf50f18SLuigi Rizzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 224bf50f18SLuigi Rizzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 234bf50f18SLuigi Rizzo * SUCH DAMAGE. 244bf50f18SLuigi Rizzo */ 254bf50f18SLuigi Rizzo 264bf50f18SLuigi Rizzo /* 274bf50f18SLuigi Rizzo * $FreeBSD$ 284bf50f18SLuigi Rizzo * 294bf50f18SLuigi Rizzo * Monitors 304bf50f18SLuigi Rizzo * 31*847bf383SLuigi Rizzo * netmap monitors can be used to do monitoring of network traffic 324bf50f18SLuigi Rizzo * on another adapter, when the latter adapter is working in netmap mode. 334bf50f18SLuigi Rizzo * 344bf50f18SLuigi Rizzo * Monitors offer to userspace the same interface as any other netmap port, 354bf50f18SLuigi Rizzo * with as many pairs of netmap rings as the monitored adapter. 364bf50f18SLuigi Rizzo * However, only the rx rings are actually used. Each monitor rx ring receives 374bf50f18SLuigi Rizzo * the traffic transiting on both the tx and rx corresponding rings in the 384bf50f18SLuigi Rizzo * monitored adapter. During registration, the user can choose if she wants 394bf50f18SLuigi Rizzo * to intercept tx only, rx only, or both tx and rx traffic. 404bf50f18SLuigi Rizzo * 41*847bf383SLuigi Rizzo * If the monitor is not able to cope with the stream of frames, excess traffic 42*847bf383SLuigi Rizzo * will be dropped. 43*847bf383SLuigi Rizzo * 44*847bf383SLuigi Rizzo * If the monitored adapter leaves netmap mode, the monitor has to be restarted. 45*847bf383SLuigi Rizzo * 46*847bf383SLuigi Rizzo * Monitors can be either zero-copy or copy-based. 47*847bf383SLuigi Rizzo * 48*847bf383SLuigi Rizzo * Copy monitors see the frames before they are consumed: 49*847bf383SLuigi Rizzo * 50*847bf383SLuigi Rizzo * - For tx traffic, this is when the application sends them, before they are 51*847bf383SLuigi Rizzo * passed down to the adapter. 52*847bf383SLuigi Rizzo * 53*847bf383SLuigi Rizzo * - For rx traffic, this is when they are received by the adapter, before 54*847bf383SLuigi Rizzo * they are sent up to the application, if any (note that, if no 55*847bf383SLuigi Rizzo * application is reading from a monitored ring, the ring will eventually 56*847bf383SLuigi Rizzo * fill up and traffic will stop). 57*847bf383SLuigi Rizzo * 58*847bf383SLuigi Rizzo * Zero-copy monitors only see the frames after they have been consumed: 594bf50f18SLuigi Rizzo * 604bf50f18SLuigi Rizzo * - For tx traffic, this is after the slots containing the frames have been 614bf50f18SLuigi Rizzo * marked as free. Note that this may happen at a considerably delay after 624bf50f18SLuigi Rizzo * frame transmission, since freeing of slots is often done lazily. 634bf50f18SLuigi Rizzo * 644bf50f18SLuigi Rizzo * - For rx traffic, this is after the consumer on the monitored adapter 654bf50f18SLuigi Rizzo * has released them. In most cases, the consumer is a userspace 664bf50f18SLuigi Rizzo * application which may have modified the frame contents. 674bf50f18SLuigi Rizzo * 68*847bf383SLuigi Rizzo * Several copy monitors may be active on any ring. Zero-copy monitors, 69*847bf383SLuigi Rizzo * instead, need exclusive access to each of the monitored rings. This may 70*847bf383SLuigi Rizzo * change in the future, if we implement zero-copy monitor chaining. 714bf50f18SLuigi Rizzo * 724bf50f18SLuigi Rizzo */ 734bf50f18SLuigi Rizzo 744bf50f18SLuigi Rizzo 754bf50f18SLuigi Rizzo #if defined(__FreeBSD__) 764bf50f18SLuigi Rizzo #include <sys/cdefs.h> /* prerequisite */ 774bf50f18SLuigi Rizzo 784bf50f18SLuigi Rizzo #include <sys/types.h> 794bf50f18SLuigi Rizzo #include <sys/errno.h> 804bf50f18SLuigi Rizzo #include <sys/param.h> /* defines used in kernel.h */ 814bf50f18SLuigi Rizzo #include <sys/kernel.h> /* types used in module initialization */ 824bf50f18SLuigi Rizzo #include <sys/malloc.h> 834bf50f18SLuigi Rizzo #include <sys/poll.h> 844bf50f18SLuigi Rizzo #include <sys/lock.h> 854bf50f18SLuigi Rizzo #include <sys/rwlock.h> 864bf50f18SLuigi Rizzo #include <sys/selinfo.h> 874bf50f18SLuigi Rizzo #include <sys/sysctl.h> 884bf50f18SLuigi Rizzo #include <sys/socket.h> /* sockaddrs */ 894bf50f18SLuigi Rizzo #include <net/if.h> 904bf50f18SLuigi Rizzo #include <net/if_var.h> 914bf50f18SLuigi Rizzo #include <machine/bus.h> /* bus_dmamap_* */ 924bf50f18SLuigi Rizzo #include <sys/refcount.h> 934bf50f18SLuigi Rizzo 944bf50f18SLuigi Rizzo 954bf50f18SLuigi Rizzo #elif defined(linux) 964bf50f18SLuigi Rizzo 974bf50f18SLuigi Rizzo #include "bsd_glue.h" 984bf50f18SLuigi Rizzo 994bf50f18SLuigi Rizzo #elif defined(__APPLE__) 1004bf50f18SLuigi Rizzo 1014bf50f18SLuigi Rizzo #warning OSX support is only partial 1024bf50f18SLuigi Rizzo #include "osx_glue.h" 1034bf50f18SLuigi Rizzo 1044bf50f18SLuigi Rizzo #else 1054bf50f18SLuigi Rizzo 1064bf50f18SLuigi Rizzo #error Unsupported platform 1074bf50f18SLuigi Rizzo 1084bf50f18SLuigi Rizzo #endif /* unsupported */ 1094bf50f18SLuigi Rizzo 1104bf50f18SLuigi Rizzo /* 1114bf50f18SLuigi Rizzo * common headers 1124bf50f18SLuigi Rizzo */ 1134bf50f18SLuigi Rizzo 1144bf50f18SLuigi Rizzo #include <net/netmap.h> 1154bf50f18SLuigi Rizzo #include <dev/netmap/netmap_kern.h> 1164bf50f18SLuigi Rizzo #include <dev/netmap/netmap_mem2.h> 1174bf50f18SLuigi Rizzo 1184bf50f18SLuigi Rizzo #ifdef WITH_MONITOR 1194bf50f18SLuigi Rizzo 1204bf50f18SLuigi Rizzo #define NM_MONITOR_MAXSLOTS 4096 1214bf50f18SLuigi Rizzo 122*847bf383SLuigi Rizzo /* 123*847bf383SLuigi Rizzo ******************************************************************** 124*847bf383SLuigi Rizzo * functions common to both kind of monitors 125*847bf383SLuigi Rizzo ******************************************************************** 126*847bf383SLuigi Rizzo */ 127*847bf383SLuigi Rizzo 128*847bf383SLuigi Rizzo /* nm_sync callback for the monitor's own tx rings. 129*847bf383SLuigi Rizzo * This makes no sense and always returns error 1304bf50f18SLuigi Rizzo */ 1314bf50f18SLuigi Rizzo static int 132*847bf383SLuigi Rizzo netmap_monitor_txsync(struct netmap_kring *kring, int flags) 1334bf50f18SLuigi Rizzo { 134*847bf383SLuigi Rizzo RD(1, "%s %x", kring->name, flags); 135*847bf383SLuigi Rizzo return EIO; 136*847bf383SLuigi Rizzo } 137*847bf383SLuigi Rizzo 138*847bf383SLuigi Rizzo /* nm_sync callback for the monitor's own rx rings. 139*847bf383SLuigi Rizzo * Note that the lock in netmap_zmon_parent_sync only protects 140*847bf383SLuigi Rizzo * writers among themselves. Synchronization between writers 141*847bf383SLuigi Rizzo * (i.e., netmap_zmon_parent_txsync and netmap_zmon_parent_rxsync) 142*847bf383SLuigi Rizzo * and readers (i.e., netmap_zmon_rxsync) relies on memory barriers. 143*847bf383SLuigi Rizzo */ 144*847bf383SLuigi Rizzo static int 145*847bf383SLuigi Rizzo netmap_monitor_rxsync(struct netmap_kring *kring, int flags) 146*847bf383SLuigi Rizzo { 147*847bf383SLuigi Rizzo ND("%s %x", kring->name, flags); 148*847bf383SLuigi Rizzo kring->nr_hwcur = kring->rcur; 149*847bf383SLuigi Rizzo mb(); 150*847bf383SLuigi Rizzo return 0; 151*847bf383SLuigi Rizzo } 152*847bf383SLuigi Rizzo 153*847bf383SLuigi Rizzo /* nm_krings_create callbacks for monitors. 154*847bf383SLuigi Rizzo * We could use the default netmap_hw_krings_zmon, but 155*847bf383SLuigi Rizzo * we don't need the mbq. 156*847bf383SLuigi Rizzo */ 157*847bf383SLuigi Rizzo static int 158*847bf383SLuigi Rizzo netmap_monitor_krings_create(struct netmap_adapter *na) 159*847bf383SLuigi Rizzo { 160*847bf383SLuigi Rizzo return netmap_krings_create(na, 0); 161*847bf383SLuigi Rizzo } 162*847bf383SLuigi Rizzo 163*847bf383SLuigi Rizzo /* nm_krings_delete callback for monitors */ 164*847bf383SLuigi Rizzo static void 165*847bf383SLuigi Rizzo netmap_monitor_krings_delete(struct netmap_adapter *na) 166*847bf383SLuigi Rizzo { 167*847bf383SLuigi Rizzo netmap_krings_delete(na); 168*847bf383SLuigi Rizzo } 169*847bf383SLuigi Rizzo 170*847bf383SLuigi Rizzo 171*847bf383SLuigi Rizzo static u_int 172*847bf383SLuigi Rizzo nm_txrx2flag(enum txrx t) 173*847bf383SLuigi Rizzo { 174*847bf383SLuigi Rizzo return (t == NR_RX ? NR_MONITOR_RX : NR_MONITOR_TX); 175*847bf383SLuigi Rizzo } 176*847bf383SLuigi Rizzo 177*847bf383SLuigi Rizzo /* allocate the monitors array in the monitored kring */ 178*847bf383SLuigi Rizzo static int 179*847bf383SLuigi Rizzo nm_monitor_alloc(struct netmap_kring *kring, u_int n) 180*847bf383SLuigi Rizzo { 181*847bf383SLuigi Rizzo size_t len; 182*847bf383SLuigi Rizzo struct netmap_kring **nm; 183*847bf383SLuigi Rizzo 184*847bf383SLuigi Rizzo if (n <= kring->max_monitors) 185*847bf383SLuigi Rizzo /* we already have more entries that requested */ 186*847bf383SLuigi Rizzo return 0; 187*847bf383SLuigi Rizzo 188*847bf383SLuigi Rizzo len = sizeof(struct netmap_kring *) * n; 189*847bf383SLuigi Rizzo nm = realloc(kring->monitors, len, M_DEVBUF, M_NOWAIT | M_ZERO); 190*847bf383SLuigi Rizzo if (nm == NULL) 191*847bf383SLuigi Rizzo return ENOMEM; 192*847bf383SLuigi Rizzo 193*847bf383SLuigi Rizzo kring->monitors = nm; 194*847bf383SLuigi Rizzo kring->max_monitors = n; 195*847bf383SLuigi Rizzo 196*847bf383SLuigi Rizzo return 0; 197*847bf383SLuigi Rizzo } 198*847bf383SLuigi Rizzo 199*847bf383SLuigi Rizzo /* deallocate the parent array in the parent adapter */ 200*847bf383SLuigi Rizzo static void 201*847bf383SLuigi Rizzo nm_monitor_dealloc(struct netmap_kring *kring) 202*847bf383SLuigi Rizzo { 203*847bf383SLuigi Rizzo if (kring->monitors) { 204*847bf383SLuigi Rizzo if (kring->n_monitors > 0) { 205*847bf383SLuigi Rizzo D("freeing not empty monitor array for %s (%d dangling monitors)!", kring->name, 206*847bf383SLuigi Rizzo kring->n_monitors); 207*847bf383SLuigi Rizzo } 208*847bf383SLuigi Rizzo free(kring->monitors, M_DEVBUF); 209*847bf383SLuigi Rizzo kring->monitors = NULL; 210*847bf383SLuigi Rizzo kring->max_monitors = 0; 211*847bf383SLuigi Rizzo kring->n_monitors = 0; 212*847bf383SLuigi Rizzo } 213*847bf383SLuigi Rizzo } 214*847bf383SLuigi Rizzo 215*847bf383SLuigi Rizzo /* 216*847bf383SLuigi Rizzo * monitors work by replacing the nm_sync() and possibly the 217*847bf383SLuigi Rizzo * nm_notify() callbacks in the monitored rings. 218*847bf383SLuigi Rizzo */ 219*847bf383SLuigi Rizzo static int netmap_zmon_parent_txsync(struct netmap_kring *, int); 220*847bf383SLuigi Rizzo static int netmap_zmon_parent_rxsync(struct netmap_kring *, int); 221*847bf383SLuigi Rizzo static int netmap_monitor_parent_txsync(struct netmap_kring *, int); 222*847bf383SLuigi Rizzo static int netmap_monitor_parent_rxsync(struct netmap_kring *, int); 223*847bf383SLuigi Rizzo static int netmap_monitor_parent_notify(struct netmap_kring *, int); 224*847bf383SLuigi Rizzo 225*847bf383SLuigi Rizzo 226*847bf383SLuigi Rizzo /* add the monitor mkring to the list of monitors of kring. 227*847bf383SLuigi Rizzo * If this is the first monitor, intercept the callbacks 228*847bf383SLuigi Rizzo */ 229*847bf383SLuigi Rizzo static int 230*847bf383SLuigi Rizzo netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int zcopy) 231*847bf383SLuigi Rizzo { 232*847bf383SLuigi Rizzo int error = 0; 233*847bf383SLuigi Rizzo 234*847bf383SLuigi Rizzo /* sinchronize with concurrently running nm_sync()s */ 235*847bf383SLuigi Rizzo nm_kr_get(kring); 236*847bf383SLuigi Rizzo /* make sure the monitor array exists and is big enough */ 237*847bf383SLuigi Rizzo error = nm_monitor_alloc(kring, kring->n_monitors + 1); 238*847bf383SLuigi Rizzo if (error) 239*847bf383SLuigi Rizzo goto out; 240*847bf383SLuigi Rizzo kring->monitors[kring->n_monitors] = mkring; 241*847bf383SLuigi Rizzo mkring->mon_pos = kring->n_monitors; 242*847bf383SLuigi Rizzo kring->n_monitors++; 243*847bf383SLuigi Rizzo if (kring->n_monitors == 1) { 244*847bf383SLuigi Rizzo /* this is the first monitor, intercept callbacks */ 245*847bf383SLuigi Rizzo D("%s: intercept callbacks on %s", mkring->name, kring->name); 246*847bf383SLuigi Rizzo kring->mon_sync = kring->nm_sync; 247*847bf383SLuigi Rizzo /* zcopy monitors do not override nm_notify(), but 248*847bf383SLuigi Rizzo * we save the original one regardless, so that 249*847bf383SLuigi Rizzo * netmap_monitor_del() does not need to know the 250*847bf383SLuigi Rizzo * monitor type 251*847bf383SLuigi Rizzo */ 252*847bf383SLuigi Rizzo kring->mon_notify = kring->nm_notify; 253*847bf383SLuigi Rizzo if (kring->tx == NR_TX) { 254*847bf383SLuigi Rizzo kring->nm_sync = (zcopy ? netmap_zmon_parent_txsync : 255*847bf383SLuigi Rizzo netmap_monitor_parent_txsync); 256*847bf383SLuigi Rizzo } else { 257*847bf383SLuigi Rizzo kring->nm_sync = (zcopy ? netmap_zmon_parent_rxsync : 258*847bf383SLuigi Rizzo netmap_monitor_parent_rxsync); 259*847bf383SLuigi Rizzo if (!zcopy) { 260*847bf383SLuigi Rizzo /* also intercept notify */ 261*847bf383SLuigi Rizzo kring->nm_notify = netmap_monitor_parent_notify; 262*847bf383SLuigi Rizzo kring->mon_tail = kring->nr_hwtail; 263*847bf383SLuigi Rizzo } 264*847bf383SLuigi Rizzo } 265*847bf383SLuigi Rizzo } 266*847bf383SLuigi Rizzo 267*847bf383SLuigi Rizzo out: 268*847bf383SLuigi Rizzo nm_kr_put(kring); 269*847bf383SLuigi Rizzo return error; 270*847bf383SLuigi Rizzo } 271*847bf383SLuigi Rizzo 272*847bf383SLuigi Rizzo 273*847bf383SLuigi Rizzo /* remove the monitor mkring from the list of monitors of kring. 274*847bf383SLuigi Rizzo * If this is the last monitor, restore the original callbacks 275*847bf383SLuigi Rizzo */ 276*847bf383SLuigi Rizzo static void 277*847bf383SLuigi Rizzo netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring) 278*847bf383SLuigi Rizzo { 279*847bf383SLuigi Rizzo /* sinchronize with concurrently running nm_sync()s */ 280*847bf383SLuigi Rizzo nm_kr_get(kring); 281*847bf383SLuigi Rizzo kring->n_monitors--; 282*847bf383SLuigi Rizzo if (mkring->mon_pos != kring->n_monitors) { 283*847bf383SLuigi Rizzo kring->monitors[mkring->mon_pos] = kring->monitors[kring->n_monitors]; 284*847bf383SLuigi Rizzo kring->monitors[mkring->mon_pos]->mon_pos = mkring->mon_pos; 285*847bf383SLuigi Rizzo } 286*847bf383SLuigi Rizzo kring->monitors[kring->n_monitors] = NULL; 287*847bf383SLuigi Rizzo if (kring->n_monitors == 0) { 288*847bf383SLuigi Rizzo /* this was the last monitor, restore callbacks and delete monitor array */ 289*847bf383SLuigi Rizzo D("%s: restoring sync on %s: %p", mkring->name, kring->name, kring->mon_sync); 290*847bf383SLuigi Rizzo kring->nm_sync = kring->mon_sync; 291*847bf383SLuigi Rizzo kring->mon_sync = NULL; 292*847bf383SLuigi Rizzo if (kring->tx == NR_RX) { 293*847bf383SLuigi Rizzo D("%s: restoring notify on %s: %p", 294*847bf383SLuigi Rizzo mkring->name, kring->name, kring->mon_notify); 295*847bf383SLuigi Rizzo kring->nm_notify = kring->mon_notify; 296*847bf383SLuigi Rizzo kring->mon_notify = NULL; 297*847bf383SLuigi Rizzo } 298*847bf383SLuigi Rizzo nm_monitor_dealloc(kring); 299*847bf383SLuigi Rizzo } 300*847bf383SLuigi Rizzo nm_kr_put(kring); 301*847bf383SLuigi Rizzo } 302*847bf383SLuigi Rizzo 303*847bf383SLuigi Rizzo 304*847bf383SLuigi Rizzo /* This is called when the monitored adapter leaves netmap mode 305*847bf383SLuigi Rizzo * (see netmap_do_unregif). 306*847bf383SLuigi Rizzo * We need to notify the monitors that the monitored rings are gone. 307*847bf383SLuigi Rizzo * We do this by setting their mna->priv.np_na to NULL. 308*847bf383SLuigi Rizzo * Note that the rings are already stopped when this happens, so 309*847bf383SLuigi Rizzo * no monitor ring callback can be active. 310*847bf383SLuigi Rizzo */ 311*847bf383SLuigi Rizzo void 312*847bf383SLuigi Rizzo netmap_monitor_stop(struct netmap_adapter *na) 313*847bf383SLuigi Rizzo { 314*847bf383SLuigi Rizzo enum txrx t; 315*847bf383SLuigi Rizzo 316*847bf383SLuigi Rizzo for_rx_tx(t) { 317*847bf383SLuigi Rizzo u_int i; 318*847bf383SLuigi Rizzo 319*847bf383SLuigi Rizzo for (i = 0; i < nma_get_nrings(na, t); i++) { 320*847bf383SLuigi Rizzo struct netmap_kring *kring = &NMR(na, t)[i]; 321*847bf383SLuigi Rizzo u_int j; 322*847bf383SLuigi Rizzo 323*847bf383SLuigi Rizzo for (j = 0; j < kring->n_monitors; j++) { 324*847bf383SLuigi Rizzo struct netmap_kring *mkring = 325*847bf383SLuigi Rizzo kring->monitors[j]; 326*847bf383SLuigi Rizzo struct netmap_monitor_adapter *mna = 327*847bf383SLuigi Rizzo (struct netmap_monitor_adapter *)mkring->na; 328*847bf383SLuigi Rizzo /* forget about this adapter */ 329*847bf383SLuigi Rizzo mna->priv.np_na = NULL; 330*847bf383SLuigi Rizzo } 331*847bf383SLuigi Rizzo } 332*847bf383SLuigi Rizzo } 333*847bf383SLuigi Rizzo } 334*847bf383SLuigi Rizzo 335*847bf383SLuigi Rizzo 336*847bf383SLuigi Rizzo /* common functions for the nm_register() callbacks of both kind of 337*847bf383SLuigi Rizzo * monitors. 338*847bf383SLuigi Rizzo */ 339*847bf383SLuigi Rizzo static int 340*847bf383SLuigi Rizzo netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon) 341*847bf383SLuigi Rizzo { 342*847bf383SLuigi Rizzo struct netmap_monitor_adapter *mna = 343*847bf383SLuigi Rizzo (struct netmap_monitor_adapter *)na; 344*847bf383SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 345*847bf383SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 346*847bf383SLuigi Rizzo struct netmap_kring *kring, *mkring; 347*847bf383SLuigi Rizzo int i; 348*847bf383SLuigi Rizzo enum txrx t; 349*847bf383SLuigi Rizzo 350*847bf383SLuigi Rizzo ND("%p: onoff %d", na, onoff); 351*847bf383SLuigi Rizzo if (onoff) { 352*847bf383SLuigi Rizzo if (pna == NULL) { 353*847bf383SLuigi Rizzo /* parent left netmap mode, fatal */ 354*847bf383SLuigi Rizzo D("%s: internal error", na->name); 355*847bf383SLuigi Rizzo return ENXIO; 356*847bf383SLuigi Rizzo } 357*847bf383SLuigi Rizzo for_rx_tx(t) { 358*847bf383SLuigi Rizzo if (mna->flags & nm_txrx2flag(t)) { 359*847bf383SLuigi Rizzo for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) { 360*847bf383SLuigi Rizzo kring = &NMR(pna, t)[i]; 361*847bf383SLuigi Rizzo mkring = &na->rx_rings[i]; 362*847bf383SLuigi Rizzo netmap_monitor_add(mkring, kring, zmon); 363*847bf383SLuigi Rizzo } 364*847bf383SLuigi Rizzo } 365*847bf383SLuigi Rizzo } 366*847bf383SLuigi Rizzo na->na_flags |= NAF_NETMAP_ON; 367*847bf383SLuigi Rizzo } else { 368*847bf383SLuigi Rizzo if (pna == NULL) { 369*847bf383SLuigi Rizzo D("%s: parent left netmap mode, nothing to restore", na->name); 370*847bf383SLuigi Rizzo return 0; 371*847bf383SLuigi Rizzo } 372*847bf383SLuigi Rizzo na->na_flags &= ~NAF_NETMAP_ON; 373*847bf383SLuigi Rizzo for_rx_tx(t) { 374*847bf383SLuigi Rizzo if (mna->flags & nm_txrx2flag(t)) { 375*847bf383SLuigi Rizzo for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) { 376*847bf383SLuigi Rizzo kring = &NMR(pna, t)[i]; 377*847bf383SLuigi Rizzo mkring = &na->rx_rings[i]; 378*847bf383SLuigi Rizzo netmap_monitor_del(mkring, kring); 379*847bf383SLuigi Rizzo } 380*847bf383SLuigi Rizzo } 381*847bf383SLuigi Rizzo } 382*847bf383SLuigi Rizzo } 383*847bf383SLuigi Rizzo return 0; 384*847bf383SLuigi Rizzo } 385*847bf383SLuigi Rizzo 386*847bf383SLuigi Rizzo /* 387*847bf383SLuigi Rizzo **************************************************************** 388*847bf383SLuigi Rizzo * functions specific for zero-copy monitors 389*847bf383SLuigi Rizzo **************************************************************** 390*847bf383SLuigi Rizzo */ 391*847bf383SLuigi Rizzo 392*847bf383SLuigi Rizzo /* 393*847bf383SLuigi Rizzo * Common function for both zero-copy tx and rx nm_sync() 394*847bf383SLuigi Rizzo * callbacks 395*847bf383SLuigi Rizzo */ 396*847bf383SLuigi Rizzo static int 397*847bf383SLuigi Rizzo netmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx) 398*847bf383SLuigi Rizzo { 399*847bf383SLuigi Rizzo struct netmap_kring *mkring = kring->monitors[0]; 400*847bf383SLuigi Rizzo struct netmap_ring *ring = kring->ring, *mring; 401*847bf383SLuigi Rizzo int error = 0; 402*847bf383SLuigi Rizzo int rel_slots, free_slots, busy, sent = 0; 4034bf50f18SLuigi Rizzo u_int beg, end, i; 4044bf50f18SLuigi Rizzo u_int lim = kring->nkr_num_slots - 1, 405*847bf383SLuigi Rizzo mlim; // = mkring->nkr_num_slots - 1; 406*847bf383SLuigi Rizzo 407*847bf383SLuigi Rizzo if (mkring == NULL) { 408*847bf383SLuigi Rizzo RD(5, "NULL monitor on %s", kring->name); 409*847bf383SLuigi Rizzo return 0; 410*847bf383SLuigi Rizzo } 411*847bf383SLuigi Rizzo mring = mkring->ring; 4124bf50f18SLuigi Rizzo mlim = mkring->nkr_num_slots - 1; 4134bf50f18SLuigi Rizzo 4144bf50f18SLuigi Rizzo /* get the relased slots (rel_slots) */ 415*847bf383SLuigi Rizzo if (tx == NR_TX) { 416*847bf383SLuigi Rizzo beg = kring->nr_hwtail; 417*847bf383SLuigi Rizzo error = kring->mon_sync(kring, flags); 4184bf50f18SLuigi Rizzo if (error) 4194bf50f18SLuigi Rizzo return error; 420*847bf383SLuigi Rizzo end = kring->nr_hwtail; 421*847bf383SLuigi Rizzo } else { /* NR_RX */ 422*847bf383SLuigi Rizzo beg = kring->nr_hwcur; 423*847bf383SLuigi Rizzo end = kring->rhead; 424*847bf383SLuigi Rizzo } 425*847bf383SLuigi Rizzo 4264bf50f18SLuigi Rizzo rel_slots = end - beg; 4274bf50f18SLuigi Rizzo if (rel_slots < 0) 4284bf50f18SLuigi Rizzo rel_slots += kring->nkr_num_slots; 4294bf50f18SLuigi Rizzo 4304bf50f18SLuigi Rizzo if (!rel_slots) { 431*847bf383SLuigi Rizzo /* no released slots, but we still need 432*847bf383SLuigi Rizzo * to call rxsync if this is a rx ring 433*847bf383SLuigi Rizzo */ 434*847bf383SLuigi Rizzo goto out_rxsync; 4354bf50f18SLuigi Rizzo } 4364bf50f18SLuigi Rizzo 4374bf50f18SLuigi Rizzo /* we need to lock the monitor receive ring, since it 4384bf50f18SLuigi Rizzo * is the target of bot tx and rx traffic from the monitored 4394bf50f18SLuigi Rizzo * adapter 4404bf50f18SLuigi Rizzo */ 4414bf50f18SLuigi Rizzo mtx_lock(&mkring->q_lock); 4424bf50f18SLuigi Rizzo /* get the free slots available on the monitor ring */ 4434bf50f18SLuigi Rizzo i = mkring->nr_hwtail; 4444bf50f18SLuigi Rizzo busy = i - mkring->nr_hwcur; 4454bf50f18SLuigi Rizzo if (busy < 0) 4464bf50f18SLuigi Rizzo busy += mkring->nkr_num_slots; 4474bf50f18SLuigi Rizzo free_slots = mlim - busy; 4484bf50f18SLuigi Rizzo 449*847bf383SLuigi Rizzo if (!free_slots) 450*847bf383SLuigi Rizzo goto out; 4514bf50f18SLuigi Rizzo 4524bf50f18SLuigi Rizzo /* swap min(free_slots, rel_slots) slots */ 4534bf50f18SLuigi Rizzo if (free_slots < rel_slots) { 4544bf50f18SLuigi Rizzo beg += (rel_slots - free_slots); 455*847bf383SLuigi Rizzo if (beg >= kring->nkr_num_slots) 456*847bf383SLuigi Rizzo beg -= kring->nkr_num_slots; 4574bf50f18SLuigi Rizzo rel_slots = free_slots; 4584bf50f18SLuigi Rizzo } 4594bf50f18SLuigi Rizzo 460*847bf383SLuigi Rizzo sent = rel_slots; 4614bf50f18SLuigi Rizzo for ( ; rel_slots; rel_slots--) { 4624bf50f18SLuigi Rizzo struct netmap_slot *s = &ring->slot[beg]; 4634bf50f18SLuigi Rizzo struct netmap_slot *ms = &mring->slot[i]; 4644bf50f18SLuigi Rizzo uint32_t tmp; 4654bf50f18SLuigi Rizzo 4664bf50f18SLuigi Rizzo tmp = ms->buf_idx; 4674bf50f18SLuigi Rizzo ms->buf_idx = s->buf_idx; 4684bf50f18SLuigi Rizzo s->buf_idx = tmp; 469*847bf383SLuigi Rizzo ND(5, "beg %d buf_idx %d", beg, tmp); 4704bf50f18SLuigi Rizzo 4714bf50f18SLuigi Rizzo tmp = ms->len; 4724bf50f18SLuigi Rizzo ms->len = s->len; 4734bf50f18SLuigi Rizzo s->len = tmp; 4744bf50f18SLuigi Rizzo 4754bf50f18SLuigi Rizzo s->flags |= NS_BUF_CHANGED; 4764bf50f18SLuigi Rizzo 4774bf50f18SLuigi Rizzo beg = nm_next(beg, lim); 4784bf50f18SLuigi Rizzo i = nm_next(i, mlim); 4794bf50f18SLuigi Rizzo 4804bf50f18SLuigi Rizzo } 481ad15cc59SLuigi Rizzo mb(); 4824bf50f18SLuigi Rizzo mkring->nr_hwtail = i; 4834bf50f18SLuigi Rizzo 484*847bf383SLuigi Rizzo out: 4854bf50f18SLuigi Rizzo mtx_unlock(&mkring->q_lock); 486*847bf383SLuigi Rizzo 487*847bf383SLuigi Rizzo if (sent) { 4884bf50f18SLuigi Rizzo /* notify the new frames to the monitor */ 489*847bf383SLuigi Rizzo mkring->nm_notify(mkring, 0); 490*847bf383SLuigi Rizzo } 491*847bf383SLuigi Rizzo 492*847bf383SLuigi Rizzo out_rxsync: 493*847bf383SLuigi Rizzo if (tx == NR_RX) 494*847bf383SLuigi Rizzo error = kring->mon_sync(kring, flags); 495*847bf383SLuigi Rizzo 496*847bf383SLuigi Rizzo return error; 497*847bf383SLuigi Rizzo } 498*847bf383SLuigi Rizzo 499*847bf383SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored tx rings */ 500*847bf383SLuigi Rizzo static int 501*847bf383SLuigi Rizzo netmap_zmon_parent_txsync(struct netmap_kring *kring, int flags) 502*847bf383SLuigi Rizzo { 503*847bf383SLuigi Rizzo ND("%s %x", kring->name, flags); 504*847bf383SLuigi Rizzo return netmap_zmon_parent_sync(kring, flags, NR_TX); 505*847bf383SLuigi Rizzo } 506*847bf383SLuigi Rizzo 507*847bf383SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored rx rings */ 508*847bf383SLuigi Rizzo static int 509*847bf383SLuigi Rizzo netmap_zmon_parent_rxsync(struct netmap_kring *kring, int flags) 510*847bf383SLuigi Rizzo { 511*847bf383SLuigi Rizzo ND("%s %x", kring->name, flags); 512*847bf383SLuigi Rizzo return netmap_zmon_parent_sync(kring, flags, NR_RX); 513*847bf383SLuigi Rizzo } 514*847bf383SLuigi Rizzo 515*847bf383SLuigi Rizzo 516*847bf383SLuigi Rizzo static int 517*847bf383SLuigi Rizzo netmap_zmon_reg(struct netmap_adapter *na, int onoff) 518*847bf383SLuigi Rizzo { 519*847bf383SLuigi Rizzo return netmap_monitor_reg_common(na, onoff, 1 /* zcopy */); 520*847bf383SLuigi Rizzo } 521*847bf383SLuigi Rizzo 522*847bf383SLuigi Rizzo /* nm_dtor callback for monitors */ 523*847bf383SLuigi Rizzo static void 524*847bf383SLuigi Rizzo netmap_zmon_dtor(struct netmap_adapter *na) 525*847bf383SLuigi Rizzo { 526*847bf383SLuigi Rizzo struct netmap_monitor_adapter *mna = 527*847bf383SLuigi Rizzo (struct netmap_monitor_adapter *)na; 528*847bf383SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 529*847bf383SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 530*847bf383SLuigi Rizzo 531*847bf383SLuigi Rizzo netmap_adapter_put(pna); 532*847bf383SLuigi Rizzo } 533*847bf383SLuigi Rizzo 534*847bf383SLuigi Rizzo /* 535*847bf383SLuigi Rizzo **************************************************************** 536*847bf383SLuigi Rizzo * functions specific for copy monitors 537*847bf383SLuigi Rizzo **************************************************************** 538*847bf383SLuigi Rizzo */ 539*847bf383SLuigi Rizzo 540*847bf383SLuigi Rizzo static void 541*847bf383SLuigi Rizzo netmap_monitor_parent_sync(struct netmap_kring *kring, u_int first_new, int new_slots) 542*847bf383SLuigi Rizzo { 543*847bf383SLuigi Rizzo u_int j; 544*847bf383SLuigi Rizzo 545*847bf383SLuigi Rizzo for (j = 0; j < kring->n_monitors; j++) { 546*847bf383SLuigi Rizzo struct netmap_kring *mkring = kring->monitors[j]; 547*847bf383SLuigi Rizzo u_int i, mlim, beg; 548*847bf383SLuigi Rizzo int free_slots, busy, sent = 0, m; 549*847bf383SLuigi Rizzo u_int lim = kring->nkr_num_slots - 1; 550*847bf383SLuigi Rizzo struct netmap_ring *ring = kring->ring, *mring = mkring->ring; 551*847bf383SLuigi Rizzo u_int max_len = NETMAP_BUF_SIZE(mkring->na); 552*847bf383SLuigi Rizzo 553*847bf383SLuigi Rizzo mlim = mkring->nkr_num_slots - 1; 554*847bf383SLuigi Rizzo 555*847bf383SLuigi Rizzo /* we need to lock the monitor receive ring, since it 556*847bf383SLuigi Rizzo * is the target of bot tx and rx traffic from the monitored 557*847bf383SLuigi Rizzo * adapter 558*847bf383SLuigi Rizzo */ 559*847bf383SLuigi Rizzo mtx_lock(&mkring->q_lock); 560*847bf383SLuigi Rizzo /* get the free slots available on the monitor ring */ 561*847bf383SLuigi Rizzo i = mkring->nr_hwtail; 562*847bf383SLuigi Rizzo busy = i - mkring->nr_hwcur; 563*847bf383SLuigi Rizzo if (busy < 0) 564*847bf383SLuigi Rizzo busy += mkring->nkr_num_slots; 565*847bf383SLuigi Rizzo free_slots = mlim - busy; 566*847bf383SLuigi Rizzo 567*847bf383SLuigi Rizzo if (!free_slots) 568*847bf383SLuigi Rizzo goto out; 569*847bf383SLuigi Rizzo 570*847bf383SLuigi Rizzo /* copy min(free_slots, new_slots) slots */ 571*847bf383SLuigi Rizzo m = new_slots; 572*847bf383SLuigi Rizzo beg = first_new; 573*847bf383SLuigi Rizzo if (free_slots < m) { 574*847bf383SLuigi Rizzo beg += (m - free_slots); 575*847bf383SLuigi Rizzo if (beg >= kring->nkr_num_slots) 576*847bf383SLuigi Rizzo beg -= kring->nkr_num_slots; 577*847bf383SLuigi Rizzo m = free_slots; 578*847bf383SLuigi Rizzo } 579*847bf383SLuigi Rizzo 580*847bf383SLuigi Rizzo for ( ; m; m--) { 581*847bf383SLuigi Rizzo struct netmap_slot *s = &ring->slot[beg]; 582*847bf383SLuigi Rizzo struct netmap_slot *ms = &mring->slot[i]; 583*847bf383SLuigi Rizzo u_int copy_len = s->len; 584*847bf383SLuigi Rizzo char *src = NMB(kring->na, s), 585*847bf383SLuigi Rizzo *dst = NMB(mkring->na, ms); 586*847bf383SLuigi Rizzo 587*847bf383SLuigi Rizzo if (unlikely(copy_len > max_len)) { 588*847bf383SLuigi Rizzo RD(5, "%s->%s: truncating %d to %d", kring->name, 589*847bf383SLuigi Rizzo mkring->name, copy_len, max_len); 590*847bf383SLuigi Rizzo copy_len = max_len; 591*847bf383SLuigi Rizzo } 592*847bf383SLuigi Rizzo 593*847bf383SLuigi Rizzo memcpy(dst, src, copy_len); 594*847bf383SLuigi Rizzo ms->len = copy_len; 595*847bf383SLuigi Rizzo sent++; 596*847bf383SLuigi Rizzo 597*847bf383SLuigi Rizzo beg = nm_next(beg, lim); 598*847bf383SLuigi Rizzo i = nm_next(i, mlim); 599*847bf383SLuigi Rizzo } 600*847bf383SLuigi Rizzo mb(); 601*847bf383SLuigi Rizzo mkring->nr_hwtail = i; 602*847bf383SLuigi Rizzo out: 603*847bf383SLuigi Rizzo mtx_unlock(&mkring->q_lock); 604*847bf383SLuigi Rizzo 605*847bf383SLuigi Rizzo if (sent) { 606*847bf383SLuigi Rizzo /* notify the new frames to the monitor */ 607*847bf383SLuigi Rizzo mkring->nm_notify(mkring, 0); 608*847bf383SLuigi Rizzo } 609*847bf383SLuigi Rizzo } 6104bf50f18SLuigi Rizzo } 6114bf50f18SLuigi Rizzo 6124bf50f18SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored tx rings */ 6134bf50f18SLuigi Rizzo static int 6144bf50f18SLuigi Rizzo netmap_monitor_parent_txsync(struct netmap_kring *kring, int flags) 6154bf50f18SLuigi Rizzo { 616*847bf383SLuigi Rizzo u_int first_new; 617*847bf383SLuigi Rizzo int new_slots; 618*847bf383SLuigi Rizzo 619*847bf383SLuigi Rizzo /* get the new slots */ 620*847bf383SLuigi Rizzo first_new = kring->nr_hwcur; 621*847bf383SLuigi Rizzo new_slots = kring->rhead - first_new; 622*847bf383SLuigi Rizzo if (new_slots < 0) 623*847bf383SLuigi Rizzo new_slots += kring->nkr_num_slots; 624*847bf383SLuigi Rizzo if (new_slots) 625*847bf383SLuigi Rizzo netmap_monitor_parent_sync(kring, first_new, new_slots); 626*847bf383SLuigi Rizzo return kring->mon_sync(kring, flags); 6274bf50f18SLuigi Rizzo } 6284bf50f18SLuigi Rizzo 6294bf50f18SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored rx rings */ 6304bf50f18SLuigi Rizzo static int 6314bf50f18SLuigi Rizzo netmap_monitor_parent_rxsync(struct netmap_kring *kring, int flags) 6324bf50f18SLuigi Rizzo { 633*847bf383SLuigi Rizzo u_int first_new; 634*847bf383SLuigi Rizzo int new_slots, error; 6354bf50f18SLuigi Rizzo 636*847bf383SLuigi Rizzo /* get the new slots */ 637*847bf383SLuigi Rizzo error = kring->mon_sync(kring, flags); 638*847bf383SLuigi Rizzo if (error) 639*847bf383SLuigi Rizzo return error; 640*847bf383SLuigi Rizzo first_new = kring->mon_tail; 641*847bf383SLuigi Rizzo new_slots = kring->nr_hwtail - first_new; 642*847bf383SLuigi Rizzo if (new_slots < 0) 643*847bf383SLuigi Rizzo new_slots += kring->nkr_num_slots; 644*847bf383SLuigi Rizzo if (new_slots) 645*847bf383SLuigi Rizzo netmap_monitor_parent_sync(kring, first_new, new_slots); 646*847bf383SLuigi Rizzo kring->mon_tail = kring->nr_hwtail; 6474bf50f18SLuigi Rizzo return 0; 6484bf50f18SLuigi Rizzo } 6494bf50f18SLuigi Rizzo 650*847bf383SLuigi Rizzo /* callback used to replace the nm_notify() callback in the monitored rx rings */ 6514bf50f18SLuigi Rizzo static int 652*847bf383SLuigi Rizzo netmap_monitor_parent_notify(struct netmap_kring *kring, int flags) 6534bf50f18SLuigi Rizzo { 654*847bf383SLuigi Rizzo ND(5, "%s %x", kring->name, flags); 655*847bf383SLuigi Rizzo /* ?xsync callbacks have tryget called by their callers 656*847bf383SLuigi Rizzo * (NIOCREGIF and poll()), but here we have to call it 657*847bf383SLuigi Rizzo * by ourself 658*847bf383SLuigi Rizzo */ 659*847bf383SLuigi Rizzo if (nm_kr_tryget(kring)) 660*847bf383SLuigi Rizzo goto out; 661*847bf383SLuigi Rizzo netmap_monitor_parent_rxsync(kring, NAF_FORCE_READ); 662*847bf383SLuigi Rizzo nm_kr_put(kring); 663*847bf383SLuigi Rizzo out: 664*847bf383SLuigi Rizzo return kring->mon_notify(kring, flags); 6654bf50f18SLuigi Rizzo } 6664bf50f18SLuigi Rizzo 6674bf50f18SLuigi Rizzo 6684bf50f18SLuigi Rizzo static int 6694bf50f18SLuigi Rizzo netmap_monitor_reg(struct netmap_adapter *na, int onoff) 6704bf50f18SLuigi Rizzo { 671*847bf383SLuigi Rizzo return netmap_monitor_reg_common(na, onoff, 0 /* no zcopy */); 6724bf50f18SLuigi Rizzo } 6734bf50f18SLuigi Rizzo 6744bf50f18SLuigi Rizzo static void 6754bf50f18SLuigi Rizzo netmap_monitor_dtor(struct netmap_adapter *na) 6764bf50f18SLuigi Rizzo { 6774bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna = 6784bf50f18SLuigi Rizzo (struct netmap_monitor_adapter *)na; 6794bf50f18SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 6804bf50f18SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 6814bf50f18SLuigi Rizzo 6824bf50f18SLuigi Rizzo netmap_adapter_put(pna); 6834bf50f18SLuigi Rizzo } 6844bf50f18SLuigi Rizzo 6854bf50f18SLuigi Rizzo 6864bf50f18SLuigi Rizzo /* check if nmr is a request for a monitor adapter that we can satisfy */ 6874bf50f18SLuigi Rizzo int 6884bf50f18SLuigi Rizzo netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na, int create) 6894bf50f18SLuigi Rizzo { 6904bf50f18SLuigi Rizzo struct nmreq pnmr; 6914bf50f18SLuigi Rizzo struct netmap_adapter *pna; /* parent adapter */ 6924bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna; 6934bf50f18SLuigi Rizzo int i, error; 694*847bf383SLuigi Rizzo enum txrx t; 695*847bf383SLuigi Rizzo int zcopy = (nmr->nr_flags & NR_ZCOPY_MON); 696*847bf383SLuigi Rizzo char monsuff[10] = ""; 6974bf50f18SLuigi Rizzo 6984bf50f18SLuigi Rizzo if ((nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) { 6994bf50f18SLuigi Rizzo ND("not a monitor"); 7004bf50f18SLuigi Rizzo return 0; 7014bf50f18SLuigi Rizzo } 7024bf50f18SLuigi Rizzo /* this is a request for a monitor adapter */ 7034bf50f18SLuigi Rizzo 7044bf50f18SLuigi Rizzo D("flags %x", nmr->nr_flags); 7054bf50f18SLuigi Rizzo 7064bf50f18SLuigi Rizzo mna = malloc(sizeof(*mna), M_DEVBUF, M_NOWAIT | M_ZERO); 7074bf50f18SLuigi Rizzo if (mna == NULL) { 7084bf50f18SLuigi Rizzo D("memory error"); 7094bf50f18SLuigi Rizzo return ENOMEM; 7104bf50f18SLuigi Rizzo } 7114bf50f18SLuigi Rizzo 7124bf50f18SLuigi Rizzo /* first, try to find the adapter that we want to monitor 7134bf50f18SLuigi Rizzo * We use the same nmr, after we have turned off the monitor flags. 7144bf50f18SLuigi Rizzo * In this way we can potentially monitor everything netmap understands, 7154bf50f18SLuigi Rizzo * except other monitors. 7164bf50f18SLuigi Rizzo */ 7174bf50f18SLuigi Rizzo memcpy(&pnmr, nmr, sizeof(pnmr)); 7184bf50f18SLuigi Rizzo pnmr.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX); 7194bf50f18SLuigi Rizzo error = netmap_get_na(&pnmr, &pna, create); 7204bf50f18SLuigi Rizzo if (error) { 7214bf50f18SLuigi Rizzo D("parent lookup failed: %d", error); 7224bf50f18SLuigi Rizzo return error; 7234bf50f18SLuigi Rizzo } 7244bf50f18SLuigi Rizzo D("found parent: %s", pna->name); 7254bf50f18SLuigi Rizzo 7264bf50f18SLuigi Rizzo if (!nm_netmap_on(pna)) { 7274bf50f18SLuigi Rizzo /* parent not in netmap mode */ 7284bf50f18SLuigi Rizzo /* XXX we can wait for the parent to enter netmap mode, 7294bf50f18SLuigi Rizzo * by intercepting its nm_register callback (2014-03-16) 7304bf50f18SLuigi Rizzo */ 7314bf50f18SLuigi Rizzo D("%s not in netmap mode", pna->name); 7324bf50f18SLuigi Rizzo error = EINVAL; 7334bf50f18SLuigi Rizzo goto put_out; 7344bf50f18SLuigi Rizzo } 7354bf50f18SLuigi Rizzo 7364bf50f18SLuigi Rizzo /* grab all the rings we need in the parent */ 7374bf50f18SLuigi Rizzo mna->priv.np_na = pna; 7384bf50f18SLuigi Rizzo error = netmap_interp_ringid(&mna->priv, nmr->nr_ringid, nmr->nr_flags); 7394bf50f18SLuigi Rizzo if (error) { 7404bf50f18SLuigi Rizzo D("ringid error"); 7414bf50f18SLuigi Rizzo goto put_out; 7424bf50f18SLuigi Rizzo } 743*847bf383SLuigi Rizzo if (mna->priv.np_qlast[NR_TX] - mna->priv.np_qfirst[NR_TX] == 1) { 744*847bf383SLuigi Rizzo snprintf(monsuff, 10, "-%d", mna->priv.np_qfirst[NR_TX]); 745*847bf383SLuigi Rizzo } 746*847bf383SLuigi Rizzo snprintf(mna->up.name, sizeof(mna->up.name), "%s%s/%s%s%s", pna->name, 747*847bf383SLuigi Rizzo monsuff, 748*847bf383SLuigi Rizzo zcopy ? "z" : "", 749*847bf383SLuigi Rizzo (nmr->nr_flags & NR_MONITOR_RX) ? "r" : "", 750*847bf383SLuigi Rizzo (nmr->nr_flags & NR_MONITOR_TX) ? "t" : ""); 751*847bf383SLuigi Rizzo 752*847bf383SLuigi Rizzo if (zcopy) { 753*847bf383SLuigi Rizzo /* zero copy monitors need exclusive access to the monitored rings */ 754*847bf383SLuigi Rizzo for_rx_tx(t) { 755*847bf383SLuigi Rizzo if (! (nmr->nr_flags & nm_txrx2flag(t))) 756*847bf383SLuigi Rizzo continue; 757*847bf383SLuigi Rizzo for (i = mna->priv.np_qfirst[t]; i < mna->priv.np_qlast[t]; i++) { 758*847bf383SLuigi Rizzo struct netmap_kring *kring = &NMR(pna, t)[i]; 759*847bf383SLuigi Rizzo if (kring->n_monitors > 0) { 760*847bf383SLuigi Rizzo error = EBUSY; 761*847bf383SLuigi Rizzo D("ring %s already monitored by %s", kring->name, 762*847bf383SLuigi Rizzo kring->monitors[0]->name); 763*847bf383SLuigi Rizzo goto put_out; 764*847bf383SLuigi Rizzo } 765*847bf383SLuigi Rizzo } 766*847bf383SLuigi Rizzo } 767*847bf383SLuigi Rizzo mna->up.nm_register = netmap_zmon_reg; 768*847bf383SLuigi Rizzo mna->up.nm_dtor = netmap_zmon_dtor; 769*847bf383SLuigi Rizzo /* to have zero copy, we need to use the same memory allocator 770*847bf383SLuigi Rizzo * as the monitored port 771*847bf383SLuigi Rizzo */ 772*847bf383SLuigi Rizzo mna->up.nm_mem = pna->nm_mem; 773*847bf383SLuigi Rizzo mna->up.na_lut = pna->na_lut; 774*847bf383SLuigi Rizzo } else { 775*847bf383SLuigi Rizzo /* normal monitors are incompatible with zero copy ones */ 776*847bf383SLuigi Rizzo for_rx_tx(t) { 777*847bf383SLuigi Rizzo if (! (nmr->nr_flags & nm_txrx2flag(t))) 778*847bf383SLuigi Rizzo continue; 779*847bf383SLuigi Rizzo for (i = mna->priv.np_qfirst[t]; i < mna->priv.np_qlast[t]; i++) { 780*847bf383SLuigi Rizzo struct netmap_kring *kring = &NMR(pna, t)[i]; 781*847bf383SLuigi Rizzo if (kring->n_monitors > 0 && 782*847bf383SLuigi Rizzo kring->monitors[0]->na->nm_register == netmap_zmon_reg) 783*847bf383SLuigi Rizzo { 7844bf50f18SLuigi Rizzo error = EBUSY; 7854bf50f18SLuigi Rizzo D("ring busy"); 786*847bf383SLuigi Rizzo goto put_out; 7874bf50f18SLuigi Rizzo } 7884bf50f18SLuigi Rizzo } 7894bf50f18SLuigi Rizzo } 7904bf50f18SLuigi Rizzo mna->up.nm_rxsync = netmap_monitor_rxsync; 7914bf50f18SLuigi Rizzo mna->up.nm_register = netmap_monitor_reg; 7924bf50f18SLuigi Rizzo mna->up.nm_dtor = netmap_monitor_dtor; 793*847bf383SLuigi Rizzo } 794*847bf383SLuigi Rizzo 795*847bf383SLuigi Rizzo /* the monitor supports the host rings iff the parent does */ 796*847bf383SLuigi Rizzo mna->up.na_flags = (pna->na_flags & NAF_HOST_RINGS); 797*847bf383SLuigi Rizzo /* a do-nothing txsync: monitors cannot be used to inject packets */ 798*847bf383SLuigi Rizzo mna->up.nm_txsync = netmap_monitor_txsync; 799*847bf383SLuigi Rizzo mna->up.nm_rxsync = netmap_monitor_rxsync; 8004bf50f18SLuigi Rizzo mna->up.nm_krings_create = netmap_monitor_krings_create; 8014bf50f18SLuigi Rizzo mna->up.nm_krings_delete = netmap_monitor_krings_delete; 8024bf50f18SLuigi Rizzo mna->up.num_tx_rings = 1; // XXX we don't need it, but field can't be zero 8034bf50f18SLuigi Rizzo /* we set the number of our rx_rings to be max(num_rx_rings, num_rx_rings) 8044bf50f18SLuigi Rizzo * in the parent 8054bf50f18SLuigi Rizzo */ 8064bf50f18SLuigi Rizzo mna->up.num_rx_rings = pna->num_rx_rings; 8074bf50f18SLuigi Rizzo if (pna->num_tx_rings > pna->num_rx_rings) 8084bf50f18SLuigi Rizzo mna->up.num_rx_rings = pna->num_tx_rings; 8094bf50f18SLuigi Rizzo /* by default, the number of slots is the same as in 8104bf50f18SLuigi Rizzo * the parent rings, but the user may ask for a different 8114bf50f18SLuigi Rizzo * number 8124bf50f18SLuigi Rizzo */ 8134bf50f18SLuigi Rizzo mna->up.num_tx_desc = nmr->nr_tx_slots; 8144bf50f18SLuigi Rizzo nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc, 8154bf50f18SLuigi Rizzo 1, NM_MONITOR_MAXSLOTS, NULL); 8164bf50f18SLuigi Rizzo mna->up.num_rx_desc = nmr->nr_rx_slots; 8174bf50f18SLuigi Rizzo nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc, 8184bf50f18SLuigi Rizzo 1, NM_MONITOR_MAXSLOTS, NULL); 8194bf50f18SLuigi Rizzo error = netmap_attach_common(&mna->up); 8204bf50f18SLuigi Rizzo if (error) { 8214bf50f18SLuigi Rizzo D("attach_common error"); 822*847bf383SLuigi Rizzo goto put_out; 8234bf50f18SLuigi Rizzo } 8244bf50f18SLuigi Rizzo 8254bf50f18SLuigi Rizzo /* remember the traffic directions we have to monitor */ 8264bf50f18SLuigi Rizzo mna->flags = (nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)); 8274bf50f18SLuigi Rizzo 8284bf50f18SLuigi Rizzo *na = &mna->up; 8294bf50f18SLuigi Rizzo netmap_adapter_get(*na); 8304bf50f18SLuigi Rizzo 8314bf50f18SLuigi Rizzo /* write the configuration back */ 8324bf50f18SLuigi Rizzo nmr->nr_tx_rings = mna->up.num_tx_rings; 8334bf50f18SLuigi Rizzo nmr->nr_rx_rings = mna->up.num_rx_rings; 8344bf50f18SLuigi Rizzo nmr->nr_tx_slots = mna->up.num_tx_desc; 8354bf50f18SLuigi Rizzo nmr->nr_rx_slots = mna->up.num_rx_desc; 8364bf50f18SLuigi Rizzo 8374bf50f18SLuigi Rizzo /* keep the reference to the parent */ 8384bf50f18SLuigi Rizzo D("monitor ok"); 8394bf50f18SLuigi Rizzo 8404bf50f18SLuigi Rizzo return 0; 8414bf50f18SLuigi Rizzo 8424bf50f18SLuigi Rizzo put_out: 8434bf50f18SLuigi Rizzo netmap_adapter_put(pna); 8444bf50f18SLuigi Rizzo free(mna, M_DEVBUF); 8454bf50f18SLuigi Rizzo return error; 8464bf50f18SLuigi Rizzo } 8474bf50f18SLuigi Rizzo 8484bf50f18SLuigi Rizzo 8494bf50f18SLuigi Rizzo #endif /* WITH_MONITOR */ 850