14bf50f18SLuigi Rizzo /* 2*37e3a6d3SLuigi Rizzo * Copyright (C) 2014-2016 Giuseppe Lettieri 3*37e3a6d3SLuigi Rizzo * All rights reserved. 44bf50f18SLuigi Rizzo * 54bf50f18SLuigi Rizzo * Redistribution and use in source and binary forms, with or without 64bf50f18SLuigi Rizzo * modification, are permitted provided that the following conditions 74bf50f18SLuigi Rizzo * are met: 84bf50f18SLuigi Rizzo * 1. Redistributions of source code must retain the above copyright 94bf50f18SLuigi Rizzo * notice, this list of conditions and the following disclaimer. 104bf50f18SLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 114bf50f18SLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 124bf50f18SLuigi Rizzo * documentation and/or other materials provided with the distribution. 134bf50f18SLuigi Rizzo * 144bf50f18SLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 154bf50f18SLuigi Rizzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 164bf50f18SLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 174bf50f18SLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 184bf50f18SLuigi Rizzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 194bf50f18SLuigi Rizzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 204bf50f18SLuigi Rizzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 214bf50f18SLuigi Rizzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 224bf50f18SLuigi Rizzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 234bf50f18SLuigi Rizzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 244bf50f18SLuigi Rizzo * SUCH DAMAGE. 254bf50f18SLuigi Rizzo */ 264bf50f18SLuigi Rizzo 274bf50f18SLuigi Rizzo /* 284bf50f18SLuigi Rizzo * $FreeBSD$ 294bf50f18SLuigi Rizzo * 304bf50f18SLuigi Rizzo * Monitors 314bf50f18SLuigi Rizzo * 32847bf383SLuigi Rizzo * netmap monitors can be used to do monitoring of network traffic 334bf50f18SLuigi Rizzo * on another adapter, when the latter adapter is working in netmap mode. 344bf50f18SLuigi Rizzo * 354bf50f18SLuigi Rizzo * Monitors offer to userspace the same interface as any other netmap port, 364bf50f18SLuigi Rizzo * with as many pairs of netmap rings as the monitored adapter. 374bf50f18SLuigi Rizzo * However, only the rx rings are actually used. Each monitor rx ring receives 384bf50f18SLuigi Rizzo * the traffic transiting on both the tx and rx corresponding rings in the 394bf50f18SLuigi Rizzo * monitored adapter. During registration, the user can choose if she wants 404bf50f18SLuigi Rizzo * to intercept tx only, rx only, or both tx and rx traffic. 414bf50f18SLuigi Rizzo * 42847bf383SLuigi Rizzo * If the monitor is not able to cope with the stream of frames, excess traffic 43847bf383SLuigi Rizzo * will be dropped. 44847bf383SLuigi Rizzo * 45847bf383SLuigi Rizzo * If the monitored adapter leaves netmap mode, the monitor has to be restarted. 46847bf383SLuigi Rizzo * 47847bf383SLuigi Rizzo * Monitors can be either zero-copy or copy-based. 48847bf383SLuigi Rizzo * 49847bf383SLuigi Rizzo * Copy monitors see the frames before they are consumed: 50847bf383SLuigi Rizzo * 51847bf383SLuigi Rizzo * - For tx traffic, this is when the application sends them, before they are 52847bf383SLuigi Rizzo * passed down to the adapter. 53847bf383SLuigi Rizzo * 54847bf383SLuigi Rizzo * - For rx traffic, this is when they are received by the adapter, before 55847bf383SLuigi Rizzo * they are sent up to the application, if any (note that, if no 56847bf383SLuigi Rizzo * application is reading from a monitored ring, the ring will eventually 57847bf383SLuigi Rizzo * fill up and traffic will stop). 58847bf383SLuigi Rizzo * 59847bf383SLuigi Rizzo * Zero-copy monitors only see the frames after they have been consumed: 604bf50f18SLuigi Rizzo * 614bf50f18SLuigi Rizzo * - For tx traffic, this is after the slots containing the frames have been 624bf50f18SLuigi Rizzo * marked as free. Note that this may happen at a considerably delay after 634bf50f18SLuigi Rizzo * frame transmission, since freeing of slots is often done lazily. 644bf50f18SLuigi Rizzo * 654bf50f18SLuigi Rizzo * - For rx traffic, this is after the consumer on the monitored adapter 664bf50f18SLuigi Rizzo * has released them. In most cases, the consumer is a userspace 674bf50f18SLuigi Rizzo * application which may have modified the frame contents. 684bf50f18SLuigi Rizzo * 69847bf383SLuigi Rizzo * Several copy monitors may be active on any ring. Zero-copy monitors, 70847bf383SLuigi Rizzo * instead, need exclusive access to each of the monitored rings. This may 71847bf383SLuigi Rizzo * change in the future, if we implement zero-copy monitor chaining. 724bf50f18SLuigi Rizzo * 734bf50f18SLuigi Rizzo */ 744bf50f18SLuigi Rizzo 754bf50f18SLuigi Rizzo 764bf50f18SLuigi Rizzo #if defined(__FreeBSD__) 774bf50f18SLuigi Rizzo #include <sys/cdefs.h> /* prerequisite */ 784bf50f18SLuigi Rizzo 794bf50f18SLuigi Rizzo #include <sys/types.h> 804bf50f18SLuigi Rizzo #include <sys/errno.h> 814bf50f18SLuigi Rizzo #include <sys/param.h> /* defines used in kernel.h */ 824bf50f18SLuigi Rizzo #include <sys/kernel.h> /* types used in module initialization */ 834bf50f18SLuigi Rizzo #include <sys/malloc.h> 844bf50f18SLuigi Rizzo #include <sys/poll.h> 854bf50f18SLuigi Rizzo #include <sys/lock.h> 864bf50f18SLuigi Rizzo #include <sys/rwlock.h> 874bf50f18SLuigi Rizzo #include <sys/selinfo.h> 884bf50f18SLuigi Rizzo #include <sys/sysctl.h> 894bf50f18SLuigi Rizzo #include <sys/socket.h> /* sockaddrs */ 904bf50f18SLuigi Rizzo #include <net/if.h> 914bf50f18SLuigi Rizzo #include <net/if_var.h> 924bf50f18SLuigi Rizzo #include <machine/bus.h> /* bus_dmamap_* */ 934bf50f18SLuigi Rizzo #include <sys/refcount.h> 944bf50f18SLuigi Rizzo 954bf50f18SLuigi Rizzo 964bf50f18SLuigi Rizzo #elif defined(linux) 974bf50f18SLuigi Rizzo 984bf50f18SLuigi Rizzo #include "bsd_glue.h" 994bf50f18SLuigi Rizzo 1004bf50f18SLuigi Rizzo #elif defined(__APPLE__) 1014bf50f18SLuigi Rizzo 1024bf50f18SLuigi Rizzo #warning OSX support is only partial 1034bf50f18SLuigi Rizzo #include "osx_glue.h" 1044bf50f18SLuigi Rizzo 105*37e3a6d3SLuigi Rizzo #elif defined(_WIN32) 106*37e3a6d3SLuigi Rizzo #include "win_glue.h" 1074bf50f18SLuigi Rizzo #else 1084bf50f18SLuigi Rizzo 1094bf50f18SLuigi Rizzo #error Unsupported platform 1104bf50f18SLuigi Rizzo 1114bf50f18SLuigi Rizzo #endif /* unsupported */ 1124bf50f18SLuigi Rizzo 1134bf50f18SLuigi Rizzo /* 1144bf50f18SLuigi Rizzo * common headers 1154bf50f18SLuigi Rizzo */ 1164bf50f18SLuigi Rizzo 1174bf50f18SLuigi Rizzo #include <net/netmap.h> 1184bf50f18SLuigi Rizzo #include <dev/netmap/netmap_kern.h> 1194bf50f18SLuigi Rizzo #include <dev/netmap/netmap_mem2.h> 1204bf50f18SLuigi Rizzo 1214bf50f18SLuigi Rizzo #ifdef WITH_MONITOR 1224bf50f18SLuigi Rizzo 1234bf50f18SLuigi Rizzo #define NM_MONITOR_MAXSLOTS 4096 1244bf50f18SLuigi Rizzo 125847bf383SLuigi Rizzo /* 126847bf383SLuigi Rizzo ******************************************************************** 127847bf383SLuigi Rizzo * functions common to both kind of monitors 128847bf383SLuigi Rizzo ******************************************************************** 129847bf383SLuigi Rizzo */ 130847bf383SLuigi Rizzo 131847bf383SLuigi Rizzo /* nm_sync callback for the monitor's own tx rings. 132847bf383SLuigi Rizzo * This makes no sense and always returns error 1334bf50f18SLuigi Rizzo */ 1344bf50f18SLuigi Rizzo static int 135847bf383SLuigi Rizzo netmap_monitor_txsync(struct netmap_kring *kring, int flags) 1364bf50f18SLuigi Rizzo { 137847bf383SLuigi Rizzo RD(1, "%s %x", kring->name, flags); 138847bf383SLuigi Rizzo return EIO; 139847bf383SLuigi Rizzo } 140847bf383SLuigi Rizzo 141847bf383SLuigi Rizzo /* nm_sync callback for the monitor's own rx rings. 142847bf383SLuigi Rizzo * Note that the lock in netmap_zmon_parent_sync only protects 143847bf383SLuigi Rizzo * writers among themselves. Synchronization between writers 144847bf383SLuigi Rizzo * (i.e., netmap_zmon_parent_txsync and netmap_zmon_parent_rxsync) 145847bf383SLuigi Rizzo * and readers (i.e., netmap_zmon_rxsync) relies on memory barriers. 146847bf383SLuigi Rizzo */ 147847bf383SLuigi Rizzo static int 148847bf383SLuigi Rizzo netmap_monitor_rxsync(struct netmap_kring *kring, int flags) 149847bf383SLuigi Rizzo { 150847bf383SLuigi Rizzo ND("%s %x", kring->name, flags); 151847bf383SLuigi Rizzo kring->nr_hwcur = kring->rcur; 152847bf383SLuigi Rizzo mb(); 153847bf383SLuigi Rizzo return 0; 154847bf383SLuigi Rizzo } 155847bf383SLuigi Rizzo 156847bf383SLuigi Rizzo /* nm_krings_create callbacks for monitors. 157847bf383SLuigi Rizzo */ 158847bf383SLuigi Rizzo static int 159847bf383SLuigi Rizzo netmap_monitor_krings_create(struct netmap_adapter *na) 160847bf383SLuigi Rizzo { 161*37e3a6d3SLuigi Rizzo int error = netmap_krings_create(na, 0); 162*37e3a6d3SLuigi Rizzo if (error) 163*37e3a6d3SLuigi Rizzo return error; 164*37e3a6d3SLuigi Rizzo /* override the host rings callbacks */ 165*37e3a6d3SLuigi Rizzo na->tx_rings[na->num_tx_rings].nm_sync = netmap_monitor_txsync; 166*37e3a6d3SLuigi Rizzo na->rx_rings[na->num_rx_rings].nm_sync = netmap_monitor_rxsync; 167*37e3a6d3SLuigi Rizzo return 0; 168847bf383SLuigi Rizzo } 169847bf383SLuigi Rizzo 170847bf383SLuigi Rizzo /* nm_krings_delete callback for monitors */ 171847bf383SLuigi Rizzo static void 172847bf383SLuigi Rizzo netmap_monitor_krings_delete(struct netmap_adapter *na) 173847bf383SLuigi Rizzo { 174847bf383SLuigi Rizzo netmap_krings_delete(na); 175847bf383SLuigi Rizzo } 176847bf383SLuigi Rizzo 177847bf383SLuigi Rizzo 178847bf383SLuigi Rizzo static u_int 179847bf383SLuigi Rizzo nm_txrx2flag(enum txrx t) 180847bf383SLuigi Rizzo { 181847bf383SLuigi Rizzo return (t == NR_RX ? NR_MONITOR_RX : NR_MONITOR_TX); 182847bf383SLuigi Rizzo } 183847bf383SLuigi Rizzo 184847bf383SLuigi Rizzo /* allocate the monitors array in the monitored kring */ 185847bf383SLuigi Rizzo static int 186847bf383SLuigi Rizzo nm_monitor_alloc(struct netmap_kring *kring, u_int n) 187847bf383SLuigi Rizzo { 188847bf383SLuigi Rizzo size_t len; 189847bf383SLuigi Rizzo struct netmap_kring **nm; 190847bf383SLuigi Rizzo 191847bf383SLuigi Rizzo if (n <= kring->max_monitors) 192847bf383SLuigi Rizzo /* we already have more entries that requested */ 193847bf383SLuigi Rizzo return 0; 194847bf383SLuigi Rizzo 195847bf383SLuigi Rizzo len = sizeof(struct netmap_kring *) * n; 196*37e3a6d3SLuigi Rizzo #ifndef _WIN32 197847bf383SLuigi Rizzo nm = realloc(kring->monitors, len, M_DEVBUF, M_NOWAIT | M_ZERO); 198*37e3a6d3SLuigi Rizzo #else 199*37e3a6d3SLuigi Rizzo nm = realloc(kring->monitors, len, sizeof(struct netmap_kring *)*kring->max_monitors); 200*37e3a6d3SLuigi Rizzo #endif 201847bf383SLuigi Rizzo if (nm == NULL) 202847bf383SLuigi Rizzo return ENOMEM; 203847bf383SLuigi Rizzo 204847bf383SLuigi Rizzo kring->monitors = nm; 205847bf383SLuigi Rizzo kring->max_monitors = n; 206847bf383SLuigi Rizzo 207847bf383SLuigi Rizzo return 0; 208847bf383SLuigi Rizzo } 209847bf383SLuigi Rizzo 210847bf383SLuigi Rizzo /* deallocate the parent array in the parent adapter */ 211847bf383SLuigi Rizzo static void 212847bf383SLuigi Rizzo nm_monitor_dealloc(struct netmap_kring *kring) 213847bf383SLuigi Rizzo { 214847bf383SLuigi Rizzo if (kring->monitors) { 215847bf383SLuigi Rizzo if (kring->n_monitors > 0) { 216847bf383SLuigi Rizzo D("freeing not empty monitor array for %s (%d dangling monitors)!", kring->name, 217847bf383SLuigi Rizzo kring->n_monitors); 218847bf383SLuigi Rizzo } 219847bf383SLuigi Rizzo free(kring->monitors, M_DEVBUF); 220847bf383SLuigi Rizzo kring->monitors = NULL; 221847bf383SLuigi Rizzo kring->max_monitors = 0; 222847bf383SLuigi Rizzo kring->n_monitors = 0; 223847bf383SLuigi Rizzo } 224847bf383SLuigi Rizzo } 225847bf383SLuigi Rizzo 226847bf383SLuigi Rizzo /* 227847bf383SLuigi Rizzo * monitors work by replacing the nm_sync() and possibly the 228847bf383SLuigi Rizzo * nm_notify() callbacks in the monitored rings. 229847bf383SLuigi Rizzo */ 230847bf383SLuigi Rizzo static int netmap_zmon_parent_txsync(struct netmap_kring *, int); 231847bf383SLuigi Rizzo static int netmap_zmon_parent_rxsync(struct netmap_kring *, int); 232847bf383SLuigi Rizzo static int netmap_monitor_parent_txsync(struct netmap_kring *, int); 233847bf383SLuigi Rizzo static int netmap_monitor_parent_rxsync(struct netmap_kring *, int); 234847bf383SLuigi Rizzo static int netmap_monitor_parent_notify(struct netmap_kring *, int); 235847bf383SLuigi Rizzo 236847bf383SLuigi Rizzo 237847bf383SLuigi Rizzo /* add the monitor mkring to the list of monitors of kring. 238847bf383SLuigi Rizzo * If this is the first monitor, intercept the callbacks 239847bf383SLuigi Rizzo */ 240847bf383SLuigi Rizzo static int 241847bf383SLuigi Rizzo netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int zcopy) 242847bf383SLuigi Rizzo { 243*37e3a6d3SLuigi Rizzo int error = NM_IRQ_COMPLETED; 244847bf383SLuigi Rizzo 245847bf383SLuigi Rizzo /* sinchronize with concurrently running nm_sync()s */ 246*37e3a6d3SLuigi Rizzo nm_kr_stop(kring, NM_KR_LOCKED); 247847bf383SLuigi Rizzo /* make sure the monitor array exists and is big enough */ 248847bf383SLuigi Rizzo error = nm_monitor_alloc(kring, kring->n_monitors + 1); 249847bf383SLuigi Rizzo if (error) 250847bf383SLuigi Rizzo goto out; 251847bf383SLuigi Rizzo kring->monitors[kring->n_monitors] = mkring; 252847bf383SLuigi Rizzo mkring->mon_pos = kring->n_monitors; 253847bf383SLuigi Rizzo kring->n_monitors++; 254847bf383SLuigi Rizzo if (kring->n_monitors == 1) { 255847bf383SLuigi Rizzo /* this is the first monitor, intercept callbacks */ 256*37e3a6d3SLuigi Rizzo ND("%s: intercept callbacks on %s", mkring->name, kring->name); 257847bf383SLuigi Rizzo kring->mon_sync = kring->nm_sync; 258847bf383SLuigi Rizzo /* zcopy monitors do not override nm_notify(), but 259847bf383SLuigi Rizzo * we save the original one regardless, so that 260847bf383SLuigi Rizzo * netmap_monitor_del() does not need to know the 261847bf383SLuigi Rizzo * monitor type 262847bf383SLuigi Rizzo */ 263847bf383SLuigi Rizzo kring->mon_notify = kring->nm_notify; 264847bf383SLuigi Rizzo if (kring->tx == NR_TX) { 265847bf383SLuigi Rizzo kring->nm_sync = (zcopy ? netmap_zmon_parent_txsync : 266847bf383SLuigi Rizzo netmap_monitor_parent_txsync); 267847bf383SLuigi Rizzo } else { 268847bf383SLuigi Rizzo kring->nm_sync = (zcopy ? netmap_zmon_parent_rxsync : 269847bf383SLuigi Rizzo netmap_monitor_parent_rxsync); 270847bf383SLuigi Rizzo if (!zcopy) { 271847bf383SLuigi Rizzo /* also intercept notify */ 272847bf383SLuigi Rizzo kring->nm_notify = netmap_monitor_parent_notify; 273847bf383SLuigi Rizzo kring->mon_tail = kring->nr_hwtail; 274847bf383SLuigi Rizzo } 275847bf383SLuigi Rizzo } 276847bf383SLuigi Rizzo } 277847bf383SLuigi Rizzo 278847bf383SLuigi Rizzo out: 279*37e3a6d3SLuigi Rizzo nm_kr_start(kring); 280847bf383SLuigi Rizzo return error; 281847bf383SLuigi Rizzo } 282847bf383SLuigi Rizzo 283847bf383SLuigi Rizzo 284847bf383SLuigi Rizzo /* remove the monitor mkring from the list of monitors of kring. 285847bf383SLuigi Rizzo * If this is the last monitor, restore the original callbacks 286847bf383SLuigi Rizzo */ 287847bf383SLuigi Rizzo static void 288847bf383SLuigi Rizzo netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring) 289847bf383SLuigi Rizzo { 290847bf383SLuigi Rizzo /* sinchronize with concurrently running nm_sync()s */ 291*37e3a6d3SLuigi Rizzo nm_kr_stop(kring, NM_KR_LOCKED); 292847bf383SLuigi Rizzo kring->n_monitors--; 293847bf383SLuigi Rizzo if (mkring->mon_pos != kring->n_monitors) { 294847bf383SLuigi Rizzo kring->monitors[mkring->mon_pos] = kring->monitors[kring->n_monitors]; 295847bf383SLuigi Rizzo kring->monitors[mkring->mon_pos]->mon_pos = mkring->mon_pos; 296847bf383SLuigi Rizzo } 297847bf383SLuigi Rizzo kring->monitors[kring->n_monitors] = NULL; 298847bf383SLuigi Rizzo if (kring->n_monitors == 0) { 299847bf383SLuigi Rizzo /* this was the last monitor, restore callbacks and delete monitor array */ 300*37e3a6d3SLuigi Rizzo ND("%s: restoring sync on %s: %p", mkring->name, kring->name, kring->mon_sync); 301847bf383SLuigi Rizzo kring->nm_sync = kring->mon_sync; 302847bf383SLuigi Rizzo kring->mon_sync = NULL; 303847bf383SLuigi Rizzo if (kring->tx == NR_RX) { 304*37e3a6d3SLuigi Rizzo ND("%s: restoring notify on %s: %p", 305847bf383SLuigi Rizzo mkring->name, kring->name, kring->mon_notify); 306847bf383SLuigi Rizzo kring->nm_notify = kring->mon_notify; 307847bf383SLuigi Rizzo kring->mon_notify = NULL; 308847bf383SLuigi Rizzo } 309847bf383SLuigi Rizzo nm_monitor_dealloc(kring); 310847bf383SLuigi Rizzo } 311*37e3a6d3SLuigi Rizzo nm_kr_start(kring); 312847bf383SLuigi Rizzo } 313847bf383SLuigi Rizzo 314847bf383SLuigi Rizzo 315847bf383SLuigi Rizzo /* This is called when the monitored adapter leaves netmap mode 316847bf383SLuigi Rizzo * (see netmap_do_unregif). 317847bf383SLuigi Rizzo * We need to notify the monitors that the monitored rings are gone. 318847bf383SLuigi Rizzo * We do this by setting their mna->priv.np_na to NULL. 319847bf383SLuigi Rizzo * Note that the rings are already stopped when this happens, so 320847bf383SLuigi Rizzo * no monitor ring callback can be active. 321847bf383SLuigi Rizzo */ 322847bf383SLuigi Rizzo void 323847bf383SLuigi Rizzo netmap_monitor_stop(struct netmap_adapter *na) 324847bf383SLuigi Rizzo { 325847bf383SLuigi Rizzo enum txrx t; 326847bf383SLuigi Rizzo 327847bf383SLuigi Rizzo for_rx_tx(t) { 328847bf383SLuigi Rizzo u_int i; 329847bf383SLuigi Rizzo 330*37e3a6d3SLuigi Rizzo for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { 331847bf383SLuigi Rizzo struct netmap_kring *kring = &NMR(na, t)[i]; 332847bf383SLuigi Rizzo u_int j; 333847bf383SLuigi Rizzo 334847bf383SLuigi Rizzo for (j = 0; j < kring->n_monitors; j++) { 335847bf383SLuigi Rizzo struct netmap_kring *mkring = 336847bf383SLuigi Rizzo kring->monitors[j]; 337847bf383SLuigi Rizzo struct netmap_monitor_adapter *mna = 338847bf383SLuigi Rizzo (struct netmap_monitor_adapter *)mkring->na; 339847bf383SLuigi Rizzo /* forget about this adapter */ 34005f76057SLuigi Rizzo netmap_adapter_put(mna->priv.np_na); 341847bf383SLuigi Rizzo mna->priv.np_na = NULL; 342847bf383SLuigi Rizzo } 343847bf383SLuigi Rizzo } 344847bf383SLuigi Rizzo } 345847bf383SLuigi Rizzo } 346847bf383SLuigi Rizzo 347847bf383SLuigi Rizzo 348847bf383SLuigi Rizzo /* common functions for the nm_register() callbacks of both kind of 349847bf383SLuigi Rizzo * monitors. 350847bf383SLuigi Rizzo */ 351847bf383SLuigi Rizzo static int 352847bf383SLuigi Rizzo netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon) 353847bf383SLuigi Rizzo { 354847bf383SLuigi Rizzo struct netmap_monitor_adapter *mna = 355847bf383SLuigi Rizzo (struct netmap_monitor_adapter *)na; 356847bf383SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 357847bf383SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 358847bf383SLuigi Rizzo struct netmap_kring *kring, *mkring; 359847bf383SLuigi Rizzo int i; 360847bf383SLuigi Rizzo enum txrx t; 361847bf383SLuigi Rizzo 362847bf383SLuigi Rizzo ND("%p: onoff %d", na, onoff); 363847bf383SLuigi Rizzo if (onoff) { 364847bf383SLuigi Rizzo if (pna == NULL) { 365847bf383SLuigi Rizzo /* parent left netmap mode, fatal */ 366847bf383SLuigi Rizzo D("%s: internal error", na->name); 367847bf383SLuigi Rizzo return ENXIO; 368847bf383SLuigi Rizzo } 369847bf383SLuigi Rizzo for_rx_tx(t) { 370847bf383SLuigi Rizzo if (mna->flags & nm_txrx2flag(t)) { 371847bf383SLuigi Rizzo for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) { 372847bf383SLuigi Rizzo kring = &NMR(pna, t)[i]; 373847bf383SLuigi Rizzo mkring = &na->rx_rings[i]; 374*37e3a6d3SLuigi Rizzo if (nm_kring_pending_on(mkring)) { 375847bf383SLuigi Rizzo netmap_monitor_add(mkring, kring, zmon); 376*37e3a6d3SLuigi Rizzo mkring->nr_mode = NKR_NETMAP_ON; 377*37e3a6d3SLuigi Rizzo } 378847bf383SLuigi Rizzo } 379847bf383SLuigi Rizzo } 380847bf383SLuigi Rizzo } 381847bf383SLuigi Rizzo na->na_flags |= NAF_NETMAP_ON; 382847bf383SLuigi Rizzo } else { 383*37e3a6d3SLuigi Rizzo if (na->active_fds == 0) 384847bf383SLuigi Rizzo na->na_flags &= ~NAF_NETMAP_ON; 385847bf383SLuigi Rizzo for_rx_tx(t) { 386847bf383SLuigi Rizzo if (mna->flags & nm_txrx2flag(t)) { 387847bf383SLuigi Rizzo for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) { 388847bf383SLuigi Rizzo mkring = &na->rx_rings[i]; 389*37e3a6d3SLuigi Rizzo if (nm_kring_pending_off(mkring)) { 390*37e3a6d3SLuigi Rizzo mkring->nr_mode = NKR_NETMAP_OFF; 391*37e3a6d3SLuigi Rizzo /* we cannot access the parent krings if the parent 392*37e3a6d3SLuigi Rizzo * has left netmap mode. This is signaled by a NULL 393*37e3a6d3SLuigi Rizzo * pna pointer 394*37e3a6d3SLuigi Rizzo */ 395*37e3a6d3SLuigi Rizzo if (pna) { 396*37e3a6d3SLuigi Rizzo kring = &NMR(pna, t)[i]; 397847bf383SLuigi Rizzo netmap_monitor_del(mkring, kring); 398847bf383SLuigi Rizzo } 399847bf383SLuigi Rizzo } 400847bf383SLuigi Rizzo } 401847bf383SLuigi Rizzo } 402*37e3a6d3SLuigi Rizzo } 403*37e3a6d3SLuigi Rizzo } 404847bf383SLuigi Rizzo return 0; 405847bf383SLuigi Rizzo } 406847bf383SLuigi Rizzo 407847bf383SLuigi Rizzo /* 408847bf383SLuigi Rizzo **************************************************************** 409847bf383SLuigi Rizzo * functions specific for zero-copy monitors 410847bf383SLuigi Rizzo **************************************************************** 411847bf383SLuigi Rizzo */ 412847bf383SLuigi Rizzo 413847bf383SLuigi Rizzo /* 414847bf383SLuigi Rizzo * Common function for both zero-copy tx and rx nm_sync() 415847bf383SLuigi Rizzo * callbacks 416847bf383SLuigi Rizzo */ 417847bf383SLuigi Rizzo static int 418847bf383SLuigi Rizzo netmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx) 419847bf383SLuigi Rizzo { 420847bf383SLuigi Rizzo struct netmap_kring *mkring = kring->monitors[0]; 421847bf383SLuigi Rizzo struct netmap_ring *ring = kring->ring, *mring; 422847bf383SLuigi Rizzo int error = 0; 423847bf383SLuigi Rizzo int rel_slots, free_slots, busy, sent = 0; 4244bf50f18SLuigi Rizzo u_int beg, end, i; 4254bf50f18SLuigi Rizzo u_int lim = kring->nkr_num_slots - 1, 426847bf383SLuigi Rizzo mlim; // = mkring->nkr_num_slots - 1; 427847bf383SLuigi Rizzo 428847bf383SLuigi Rizzo if (mkring == NULL) { 429847bf383SLuigi Rizzo RD(5, "NULL monitor on %s", kring->name); 430847bf383SLuigi Rizzo return 0; 431847bf383SLuigi Rizzo } 432847bf383SLuigi Rizzo mring = mkring->ring; 4334bf50f18SLuigi Rizzo mlim = mkring->nkr_num_slots - 1; 4344bf50f18SLuigi Rizzo 4354bf50f18SLuigi Rizzo /* get the relased slots (rel_slots) */ 436847bf383SLuigi Rizzo if (tx == NR_TX) { 437847bf383SLuigi Rizzo beg = kring->nr_hwtail; 438847bf383SLuigi Rizzo error = kring->mon_sync(kring, flags); 4394bf50f18SLuigi Rizzo if (error) 4404bf50f18SLuigi Rizzo return error; 441847bf383SLuigi Rizzo end = kring->nr_hwtail; 442847bf383SLuigi Rizzo } else { /* NR_RX */ 443847bf383SLuigi Rizzo beg = kring->nr_hwcur; 444847bf383SLuigi Rizzo end = kring->rhead; 445847bf383SLuigi Rizzo } 446847bf383SLuigi Rizzo 4474bf50f18SLuigi Rizzo rel_slots = end - beg; 4484bf50f18SLuigi Rizzo if (rel_slots < 0) 4494bf50f18SLuigi Rizzo rel_slots += kring->nkr_num_slots; 4504bf50f18SLuigi Rizzo 4514bf50f18SLuigi Rizzo if (!rel_slots) { 452847bf383SLuigi Rizzo /* no released slots, but we still need 453847bf383SLuigi Rizzo * to call rxsync if this is a rx ring 454847bf383SLuigi Rizzo */ 455847bf383SLuigi Rizzo goto out_rxsync; 4564bf50f18SLuigi Rizzo } 4574bf50f18SLuigi Rizzo 4584bf50f18SLuigi Rizzo /* we need to lock the monitor receive ring, since it 4594bf50f18SLuigi Rizzo * is the target of bot tx and rx traffic from the monitored 4604bf50f18SLuigi Rizzo * adapter 4614bf50f18SLuigi Rizzo */ 4624bf50f18SLuigi Rizzo mtx_lock(&mkring->q_lock); 4634bf50f18SLuigi Rizzo /* get the free slots available on the monitor ring */ 4644bf50f18SLuigi Rizzo i = mkring->nr_hwtail; 4654bf50f18SLuigi Rizzo busy = i - mkring->nr_hwcur; 4664bf50f18SLuigi Rizzo if (busy < 0) 4674bf50f18SLuigi Rizzo busy += mkring->nkr_num_slots; 4684bf50f18SLuigi Rizzo free_slots = mlim - busy; 4694bf50f18SLuigi Rizzo 470847bf383SLuigi Rizzo if (!free_slots) 471847bf383SLuigi Rizzo goto out; 4724bf50f18SLuigi Rizzo 4734bf50f18SLuigi Rizzo /* swap min(free_slots, rel_slots) slots */ 4744bf50f18SLuigi Rizzo if (free_slots < rel_slots) { 4754bf50f18SLuigi Rizzo beg += (rel_slots - free_slots); 476847bf383SLuigi Rizzo if (beg >= kring->nkr_num_slots) 477847bf383SLuigi Rizzo beg -= kring->nkr_num_slots; 4784bf50f18SLuigi Rizzo rel_slots = free_slots; 4794bf50f18SLuigi Rizzo } 4804bf50f18SLuigi Rizzo 481847bf383SLuigi Rizzo sent = rel_slots; 4824bf50f18SLuigi Rizzo for ( ; rel_slots; rel_slots--) { 4834bf50f18SLuigi Rizzo struct netmap_slot *s = &ring->slot[beg]; 4844bf50f18SLuigi Rizzo struct netmap_slot *ms = &mring->slot[i]; 4854bf50f18SLuigi Rizzo uint32_t tmp; 4864bf50f18SLuigi Rizzo 4874bf50f18SLuigi Rizzo tmp = ms->buf_idx; 4884bf50f18SLuigi Rizzo ms->buf_idx = s->buf_idx; 4894bf50f18SLuigi Rizzo s->buf_idx = tmp; 490847bf383SLuigi Rizzo ND(5, "beg %d buf_idx %d", beg, tmp); 4914bf50f18SLuigi Rizzo 4924bf50f18SLuigi Rizzo tmp = ms->len; 4934bf50f18SLuigi Rizzo ms->len = s->len; 4944bf50f18SLuigi Rizzo s->len = tmp; 4954bf50f18SLuigi Rizzo 4964bf50f18SLuigi Rizzo s->flags |= NS_BUF_CHANGED; 4974bf50f18SLuigi Rizzo 4984bf50f18SLuigi Rizzo beg = nm_next(beg, lim); 4994bf50f18SLuigi Rizzo i = nm_next(i, mlim); 5004bf50f18SLuigi Rizzo 5014bf50f18SLuigi Rizzo } 502ad15cc59SLuigi Rizzo mb(); 5034bf50f18SLuigi Rizzo mkring->nr_hwtail = i; 5044bf50f18SLuigi Rizzo 505847bf383SLuigi Rizzo out: 5064bf50f18SLuigi Rizzo mtx_unlock(&mkring->q_lock); 507847bf383SLuigi Rizzo 508847bf383SLuigi Rizzo if (sent) { 5094bf50f18SLuigi Rizzo /* notify the new frames to the monitor */ 510847bf383SLuigi Rizzo mkring->nm_notify(mkring, 0); 511847bf383SLuigi Rizzo } 512847bf383SLuigi Rizzo 513847bf383SLuigi Rizzo out_rxsync: 514847bf383SLuigi Rizzo if (tx == NR_RX) 515847bf383SLuigi Rizzo error = kring->mon_sync(kring, flags); 516847bf383SLuigi Rizzo 517847bf383SLuigi Rizzo return error; 518847bf383SLuigi Rizzo } 519847bf383SLuigi Rizzo 520847bf383SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored tx rings */ 521847bf383SLuigi Rizzo static int 522847bf383SLuigi Rizzo netmap_zmon_parent_txsync(struct netmap_kring *kring, int flags) 523847bf383SLuigi Rizzo { 524847bf383SLuigi Rizzo ND("%s %x", kring->name, flags); 525847bf383SLuigi Rizzo return netmap_zmon_parent_sync(kring, flags, NR_TX); 526847bf383SLuigi Rizzo } 527847bf383SLuigi Rizzo 528847bf383SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored rx rings */ 529847bf383SLuigi Rizzo static int 530847bf383SLuigi Rizzo netmap_zmon_parent_rxsync(struct netmap_kring *kring, int flags) 531847bf383SLuigi Rizzo { 532847bf383SLuigi Rizzo ND("%s %x", kring->name, flags); 533847bf383SLuigi Rizzo return netmap_zmon_parent_sync(kring, flags, NR_RX); 534847bf383SLuigi Rizzo } 535847bf383SLuigi Rizzo 536847bf383SLuigi Rizzo 537847bf383SLuigi Rizzo static int 538847bf383SLuigi Rizzo netmap_zmon_reg(struct netmap_adapter *na, int onoff) 539847bf383SLuigi Rizzo { 540847bf383SLuigi Rizzo return netmap_monitor_reg_common(na, onoff, 1 /* zcopy */); 541847bf383SLuigi Rizzo } 542847bf383SLuigi Rizzo 543847bf383SLuigi Rizzo /* nm_dtor callback for monitors */ 544847bf383SLuigi Rizzo static void 545847bf383SLuigi Rizzo netmap_zmon_dtor(struct netmap_adapter *na) 546847bf383SLuigi Rizzo { 547847bf383SLuigi Rizzo struct netmap_monitor_adapter *mna = 548847bf383SLuigi Rizzo (struct netmap_monitor_adapter *)na; 549847bf383SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 550847bf383SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 551847bf383SLuigi Rizzo 552847bf383SLuigi Rizzo netmap_adapter_put(pna); 553847bf383SLuigi Rizzo } 554847bf383SLuigi Rizzo 555847bf383SLuigi Rizzo /* 556847bf383SLuigi Rizzo **************************************************************** 557847bf383SLuigi Rizzo * functions specific for copy monitors 558847bf383SLuigi Rizzo **************************************************************** 559847bf383SLuigi Rizzo */ 560847bf383SLuigi Rizzo 561847bf383SLuigi Rizzo static void 562847bf383SLuigi Rizzo netmap_monitor_parent_sync(struct netmap_kring *kring, u_int first_new, int new_slots) 563847bf383SLuigi Rizzo { 564847bf383SLuigi Rizzo u_int j; 565847bf383SLuigi Rizzo 566847bf383SLuigi Rizzo for (j = 0; j < kring->n_monitors; j++) { 567847bf383SLuigi Rizzo struct netmap_kring *mkring = kring->monitors[j]; 568847bf383SLuigi Rizzo u_int i, mlim, beg; 569847bf383SLuigi Rizzo int free_slots, busy, sent = 0, m; 570847bf383SLuigi Rizzo u_int lim = kring->nkr_num_slots - 1; 571847bf383SLuigi Rizzo struct netmap_ring *ring = kring->ring, *mring = mkring->ring; 572847bf383SLuigi Rizzo u_int max_len = NETMAP_BUF_SIZE(mkring->na); 573847bf383SLuigi Rizzo 574847bf383SLuigi Rizzo mlim = mkring->nkr_num_slots - 1; 575847bf383SLuigi Rizzo 576847bf383SLuigi Rizzo /* we need to lock the monitor receive ring, since it 577847bf383SLuigi Rizzo * is the target of bot tx and rx traffic from the monitored 578847bf383SLuigi Rizzo * adapter 579847bf383SLuigi Rizzo */ 580847bf383SLuigi Rizzo mtx_lock(&mkring->q_lock); 581847bf383SLuigi Rizzo /* get the free slots available on the monitor ring */ 582847bf383SLuigi Rizzo i = mkring->nr_hwtail; 583847bf383SLuigi Rizzo busy = i - mkring->nr_hwcur; 584847bf383SLuigi Rizzo if (busy < 0) 585847bf383SLuigi Rizzo busy += mkring->nkr_num_slots; 586847bf383SLuigi Rizzo free_slots = mlim - busy; 587847bf383SLuigi Rizzo 588847bf383SLuigi Rizzo if (!free_slots) 589847bf383SLuigi Rizzo goto out; 590847bf383SLuigi Rizzo 591847bf383SLuigi Rizzo /* copy min(free_slots, new_slots) slots */ 592847bf383SLuigi Rizzo m = new_slots; 593847bf383SLuigi Rizzo beg = first_new; 594847bf383SLuigi Rizzo if (free_slots < m) { 595847bf383SLuigi Rizzo beg += (m - free_slots); 596847bf383SLuigi Rizzo if (beg >= kring->nkr_num_slots) 597847bf383SLuigi Rizzo beg -= kring->nkr_num_slots; 598847bf383SLuigi Rizzo m = free_slots; 599847bf383SLuigi Rizzo } 600847bf383SLuigi Rizzo 601847bf383SLuigi Rizzo for ( ; m; m--) { 602847bf383SLuigi Rizzo struct netmap_slot *s = &ring->slot[beg]; 603847bf383SLuigi Rizzo struct netmap_slot *ms = &mring->slot[i]; 604847bf383SLuigi Rizzo u_int copy_len = s->len; 605847bf383SLuigi Rizzo char *src = NMB(kring->na, s), 606847bf383SLuigi Rizzo *dst = NMB(mkring->na, ms); 607847bf383SLuigi Rizzo 608847bf383SLuigi Rizzo if (unlikely(copy_len > max_len)) { 609847bf383SLuigi Rizzo RD(5, "%s->%s: truncating %d to %d", kring->name, 610847bf383SLuigi Rizzo mkring->name, copy_len, max_len); 611847bf383SLuigi Rizzo copy_len = max_len; 612847bf383SLuigi Rizzo } 613847bf383SLuigi Rizzo 614847bf383SLuigi Rizzo memcpy(dst, src, copy_len); 615847bf383SLuigi Rizzo ms->len = copy_len; 616847bf383SLuigi Rizzo sent++; 617847bf383SLuigi Rizzo 618847bf383SLuigi Rizzo beg = nm_next(beg, lim); 619847bf383SLuigi Rizzo i = nm_next(i, mlim); 620847bf383SLuigi Rizzo } 621847bf383SLuigi Rizzo mb(); 622847bf383SLuigi Rizzo mkring->nr_hwtail = i; 623847bf383SLuigi Rizzo out: 624847bf383SLuigi Rizzo mtx_unlock(&mkring->q_lock); 625847bf383SLuigi Rizzo 626847bf383SLuigi Rizzo if (sent) { 627847bf383SLuigi Rizzo /* notify the new frames to the monitor */ 628847bf383SLuigi Rizzo mkring->nm_notify(mkring, 0); 629847bf383SLuigi Rizzo } 630847bf383SLuigi Rizzo } 6314bf50f18SLuigi Rizzo } 6324bf50f18SLuigi Rizzo 6334bf50f18SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored tx rings */ 6344bf50f18SLuigi Rizzo static int 6354bf50f18SLuigi Rizzo netmap_monitor_parent_txsync(struct netmap_kring *kring, int flags) 6364bf50f18SLuigi Rizzo { 637847bf383SLuigi Rizzo u_int first_new; 638847bf383SLuigi Rizzo int new_slots; 639847bf383SLuigi Rizzo 640847bf383SLuigi Rizzo /* get the new slots */ 641847bf383SLuigi Rizzo first_new = kring->nr_hwcur; 642847bf383SLuigi Rizzo new_slots = kring->rhead - first_new; 643847bf383SLuigi Rizzo if (new_slots < 0) 644847bf383SLuigi Rizzo new_slots += kring->nkr_num_slots; 645847bf383SLuigi Rizzo if (new_slots) 646847bf383SLuigi Rizzo netmap_monitor_parent_sync(kring, first_new, new_slots); 647847bf383SLuigi Rizzo return kring->mon_sync(kring, flags); 6484bf50f18SLuigi Rizzo } 6494bf50f18SLuigi Rizzo 6504bf50f18SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored rx rings */ 6514bf50f18SLuigi Rizzo static int 6524bf50f18SLuigi Rizzo netmap_monitor_parent_rxsync(struct netmap_kring *kring, int flags) 6534bf50f18SLuigi Rizzo { 654847bf383SLuigi Rizzo u_int first_new; 655847bf383SLuigi Rizzo int new_slots, error; 6564bf50f18SLuigi Rizzo 657847bf383SLuigi Rizzo /* get the new slots */ 658847bf383SLuigi Rizzo error = kring->mon_sync(kring, flags); 659847bf383SLuigi Rizzo if (error) 660847bf383SLuigi Rizzo return error; 661847bf383SLuigi Rizzo first_new = kring->mon_tail; 662847bf383SLuigi Rizzo new_slots = kring->nr_hwtail - first_new; 663847bf383SLuigi Rizzo if (new_slots < 0) 664847bf383SLuigi Rizzo new_slots += kring->nkr_num_slots; 665847bf383SLuigi Rizzo if (new_slots) 666847bf383SLuigi Rizzo netmap_monitor_parent_sync(kring, first_new, new_slots); 667847bf383SLuigi Rizzo kring->mon_tail = kring->nr_hwtail; 6684bf50f18SLuigi Rizzo return 0; 6694bf50f18SLuigi Rizzo } 6704bf50f18SLuigi Rizzo 671847bf383SLuigi Rizzo /* callback used to replace the nm_notify() callback in the monitored rx rings */ 6724bf50f18SLuigi Rizzo static int 673847bf383SLuigi Rizzo netmap_monitor_parent_notify(struct netmap_kring *kring, int flags) 6744bf50f18SLuigi Rizzo { 675*37e3a6d3SLuigi Rizzo int (*notify)(struct netmap_kring*, int); 676847bf383SLuigi Rizzo ND(5, "%s %x", kring->name, flags); 677847bf383SLuigi Rizzo /* ?xsync callbacks have tryget called by their callers 678847bf383SLuigi Rizzo * (NIOCREGIF and poll()), but here we have to call it 679847bf383SLuigi Rizzo * by ourself 680847bf383SLuigi Rizzo */ 681*37e3a6d3SLuigi Rizzo if (nm_kr_tryget(kring, 0, NULL)) { 682*37e3a6d3SLuigi Rizzo /* in all cases, just skip the sync */ 683*37e3a6d3SLuigi Rizzo return NM_IRQ_COMPLETED; 684*37e3a6d3SLuigi Rizzo } 685*37e3a6d3SLuigi Rizzo if (kring->n_monitors > 0) { 686847bf383SLuigi Rizzo netmap_monitor_parent_rxsync(kring, NAF_FORCE_READ); 687*37e3a6d3SLuigi Rizzo notify = kring->mon_notify; 688*37e3a6d3SLuigi Rizzo } else { 689*37e3a6d3SLuigi Rizzo /* we are no longer monitoring this ring, so both 690*37e3a6d3SLuigi Rizzo * mon_sync and mon_notify are NULL 691*37e3a6d3SLuigi Rizzo */ 692*37e3a6d3SLuigi Rizzo notify = kring->nm_notify; 693*37e3a6d3SLuigi Rizzo } 694847bf383SLuigi Rizzo nm_kr_put(kring); 695*37e3a6d3SLuigi Rizzo return notify(kring, flags); 6964bf50f18SLuigi Rizzo } 6974bf50f18SLuigi Rizzo 6984bf50f18SLuigi Rizzo 6994bf50f18SLuigi Rizzo static int 7004bf50f18SLuigi Rizzo netmap_monitor_reg(struct netmap_adapter *na, int onoff) 7014bf50f18SLuigi Rizzo { 702847bf383SLuigi Rizzo return netmap_monitor_reg_common(na, onoff, 0 /* no zcopy */); 7034bf50f18SLuigi Rizzo } 7044bf50f18SLuigi Rizzo 7054bf50f18SLuigi Rizzo static void 7064bf50f18SLuigi Rizzo netmap_monitor_dtor(struct netmap_adapter *na) 7074bf50f18SLuigi Rizzo { 7084bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna = 7094bf50f18SLuigi Rizzo (struct netmap_monitor_adapter *)na; 7104bf50f18SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 7114bf50f18SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 7124bf50f18SLuigi Rizzo 7134bf50f18SLuigi Rizzo netmap_adapter_put(pna); 7144bf50f18SLuigi Rizzo } 7154bf50f18SLuigi Rizzo 7164bf50f18SLuigi Rizzo 7174bf50f18SLuigi Rizzo /* check if nmr is a request for a monitor adapter that we can satisfy */ 7184bf50f18SLuigi Rizzo int 7194bf50f18SLuigi Rizzo netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na, int create) 7204bf50f18SLuigi Rizzo { 7214bf50f18SLuigi Rizzo struct nmreq pnmr; 7224bf50f18SLuigi Rizzo struct netmap_adapter *pna; /* parent adapter */ 7234bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna; 724*37e3a6d3SLuigi Rizzo struct ifnet *ifp = NULL; 7254bf50f18SLuigi Rizzo int i, error; 726847bf383SLuigi Rizzo enum txrx t; 727847bf383SLuigi Rizzo int zcopy = (nmr->nr_flags & NR_ZCOPY_MON); 728847bf383SLuigi Rizzo char monsuff[10] = ""; 7294bf50f18SLuigi Rizzo 7304bf50f18SLuigi Rizzo if ((nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) { 731*37e3a6d3SLuigi Rizzo if (nmr->nr_flags & NR_ZCOPY_MON) { 732*37e3a6d3SLuigi Rizzo /* the flag makes no sense unless you are 733*37e3a6d3SLuigi Rizzo * creating a monitor 734*37e3a6d3SLuigi Rizzo */ 735*37e3a6d3SLuigi Rizzo return EINVAL; 736*37e3a6d3SLuigi Rizzo } 7374bf50f18SLuigi Rizzo ND("not a monitor"); 7384bf50f18SLuigi Rizzo return 0; 7394bf50f18SLuigi Rizzo } 7404bf50f18SLuigi Rizzo /* this is a request for a monitor adapter */ 7414bf50f18SLuigi Rizzo 742*37e3a6d3SLuigi Rizzo ND("flags %x", nmr->nr_flags); 7434bf50f18SLuigi Rizzo 7444bf50f18SLuigi Rizzo mna = malloc(sizeof(*mna), M_DEVBUF, M_NOWAIT | M_ZERO); 7454bf50f18SLuigi Rizzo if (mna == NULL) { 7464bf50f18SLuigi Rizzo D("memory error"); 7474bf50f18SLuigi Rizzo return ENOMEM; 7484bf50f18SLuigi Rizzo } 7494bf50f18SLuigi Rizzo 7504bf50f18SLuigi Rizzo /* first, try to find the adapter that we want to monitor 7514bf50f18SLuigi Rizzo * We use the same nmr, after we have turned off the monitor flags. 7524bf50f18SLuigi Rizzo * In this way we can potentially monitor everything netmap understands, 7534bf50f18SLuigi Rizzo * except other monitors. 7544bf50f18SLuigi Rizzo */ 7554bf50f18SLuigi Rizzo memcpy(&pnmr, nmr, sizeof(pnmr)); 756*37e3a6d3SLuigi Rizzo pnmr.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON); 757*37e3a6d3SLuigi Rizzo error = netmap_get_na(&pnmr, &pna, &ifp, create); 7584bf50f18SLuigi Rizzo if (error) { 7594bf50f18SLuigi Rizzo D("parent lookup failed: %d", error); 760*37e3a6d3SLuigi Rizzo free(mna, M_DEVBUF); 7614bf50f18SLuigi Rizzo return error; 7624bf50f18SLuigi Rizzo } 763*37e3a6d3SLuigi Rizzo ND("found parent: %s", pna->name); 7644bf50f18SLuigi Rizzo 7654bf50f18SLuigi Rizzo if (!nm_netmap_on(pna)) { 7664bf50f18SLuigi Rizzo /* parent not in netmap mode */ 7674bf50f18SLuigi Rizzo /* XXX we can wait for the parent to enter netmap mode, 7684bf50f18SLuigi Rizzo * by intercepting its nm_register callback (2014-03-16) 7694bf50f18SLuigi Rizzo */ 7704bf50f18SLuigi Rizzo D("%s not in netmap mode", pna->name); 7714bf50f18SLuigi Rizzo error = EINVAL; 7724bf50f18SLuigi Rizzo goto put_out; 7734bf50f18SLuigi Rizzo } 7744bf50f18SLuigi Rizzo 7754bf50f18SLuigi Rizzo /* grab all the rings we need in the parent */ 7764bf50f18SLuigi Rizzo mna->priv.np_na = pna; 7774bf50f18SLuigi Rizzo error = netmap_interp_ringid(&mna->priv, nmr->nr_ringid, nmr->nr_flags); 7784bf50f18SLuigi Rizzo if (error) { 7794bf50f18SLuigi Rizzo D("ringid error"); 7804bf50f18SLuigi Rizzo goto put_out; 7814bf50f18SLuigi Rizzo } 782847bf383SLuigi Rizzo if (mna->priv.np_qlast[NR_TX] - mna->priv.np_qfirst[NR_TX] == 1) { 783847bf383SLuigi Rizzo snprintf(monsuff, 10, "-%d", mna->priv.np_qfirst[NR_TX]); 784847bf383SLuigi Rizzo } 785847bf383SLuigi Rizzo snprintf(mna->up.name, sizeof(mna->up.name), "%s%s/%s%s%s", pna->name, 786847bf383SLuigi Rizzo monsuff, 787847bf383SLuigi Rizzo zcopy ? "z" : "", 788847bf383SLuigi Rizzo (nmr->nr_flags & NR_MONITOR_RX) ? "r" : "", 789847bf383SLuigi Rizzo (nmr->nr_flags & NR_MONITOR_TX) ? "t" : ""); 790847bf383SLuigi Rizzo 791847bf383SLuigi Rizzo if (zcopy) { 792847bf383SLuigi Rizzo /* zero copy monitors need exclusive access to the monitored rings */ 793847bf383SLuigi Rizzo for_rx_tx(t) { 794847bf383SLuigi Rizzo if (! (nmr->nr_flags & nm_txrx2flag(t))) 795847bf383SLuigi Rizzo continue; 796847bf383SLuigi Rizzo for (i = mna->priv.np_qfirst[t]; i < mna->priv.np_qlast[t]; i++) { 797847bf383SLuigi Rizzo struct netmap_kring *kring = &NMR(pna, t)[i]; 798847bf383SLuigi Rizzo if (kring->n_monitors > 0) { 799847bf383SLuigi Rizzo error = EBUSY; 800847bf383SLuigi Rizzo D("ring %s already monitored by %s", kring->name, 801847bf383SLuigi Rizzo kring->monitors[0]->name); 802847bf383SLuigi Rizzo goto put_out; 803847bf383SLuigi Rizzo } 804847bf383SLuigi Rizzo } 805847bf383SLuigi Rizzo } 806847bf383SLuigi Rizzo mna->up.nm_register = netmap_zmon_reg; 807847bf383SLuigi Rizzo mna->up.nm_dtor = netmap_zmon_dtor; 808847bf383SLuigi Rizzo /* to have zero copy, we need to use the same memory allocator 809847bf383SLuigi Rizzo * as the monitored port 810847bf383SLuigi Rizzo */ 811847bf383SLuigi Rizzo mna->up.nm_mem = pna->nm_mem; 812847bf383SLuigi Rizzo mna->up.na_lut = pna->na_lut; 813847bf383SLuigi Rizzo } else { 814847bf383SLuigi Rizzo /* normal monitors are incompatible with zero copy ones */ 815847bf383SLuigi Rizzo for_rx_tx(t) { 816847bf383SLuigi Rizzo if (! (nmr->nr_flags & nm_txrx2flag(t))) 817847bf383SLuigi Rizzo continue; 818847bf383SLuigi Rizzo for (i = mna->priv.np_qfirst[t]; i < mna->priv.np_qlast[t]; i++) { 819847bf383SLuigi Rizzo struct netmap_kring *kring = &NMR(pna, t)[i]; 820847bf383SLuigi Rizzo if (kring->n_monitors > 0 && 821847bf383SLuigi Rizzo kring->monitors[0]->na->nm_register == netmap_zmon_reg) 822847bf383SLuigi Rizzo { 8234bf50f18SLuigi Rizzo error = EBUSY; 8244bf50f18SLuigi Rizzo D("ring busy"); 825847bf383SLuigi Rizzo goto put_out; 8264bf50f18SLuigi Rizzo } 8274bf50f18SLuigi Rizzo } 8284bf50f18SLuigi Rizzo } 8294bf50f18SLuigi Rizzo mna->up.nm_rxsync = netmap_monitor_rxsync; 8304bf50f18SLuigi Rizzo mna->up.nm_register = netmap_monitor_reg; 8314bf50f18SLuigi Rizzo mna->up.nm_dtor = netmap_monitor_dtor; 832847bf383SLuigi Rizzo } 833847bf383SLuigi Rizzo 834847bf383SLuigi Rizzo /* the monitor supports the host rings iff the parent does */ 835847bf383SLuigi Rizzo mna->up.na_flags = (pna->na_flags & NAF_HOST_RINGS); 836847bf383SLuigi Rizzo /* a do-nothing txsync: monitors cannot be used to inject packets */ 837847bf383SLuigi Rizzo mna->up.nm_txsync = netmap_monitor_txsync; 838847bf383SLuigi Rizzo mna->up.nm_rxsync = netmap_monitor_rxsync; 8394bf50f18SLuigi Rizzo mna->up.nm_krings_create = netmap_monitor_krings_create; 8404bf50f18SLuigi Rizzo mna->up.nm_krings_delete = netmap_monitor_krings_delete; 8414bf50f18SLuigi Rizzo mna->up.num_tx_rings = 1; // XXX we don't need it, but field can't be zero 8424bf50f18SLuigi Rizzo /* we set the number of our rx_rings to be max(num_rx_rings, num_rx_rings) 8434bf50f18SLuigi Rizzo * in the parent 8444bf50f18SLuigi Rizzo */ 8454bf50f18SLuigi Rizzo mna->up.num_rx_rings = pna->num_rx_rings; 8464bf50f18SLuigi Rizzo if (pna->num_tx_rings > pna->num_rx_rings) 8474bf50f18SLuigi Rizzo mna->up.num_rx_rings = pna->num_tx_rings; 8484bf50f18SLuigi Rizzo /* by default, the number of slots is the same as in 8494bf50f18SLuigi Rizzo * the parent rings, but the user may ask for a different 8504bf50f18SLuigi Rizzo * number 8514bf50f18SLuigi Rizzo */ 8524bf50f18SLuigi Rizzo mna->up.num_tx_desc = nmr->nr_tx_slots; 8534bf50f18SLuigi Rizzo nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc, 8544bf50f18SLuigi Rizzo 1, NM_MONITOR_MAXSLOTS, NULL); 8554bf50f18SLuigi Rizzo mna->up.num_rx_desc = nmr->nr_rx_slots; 8564bf50f18SLuigi Rizzo nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc, 8574bf50f18SLuigi Rizzo 1, NM_MONITOR_MAXSLOTS, NULL); 8584bf50f18SLuigi Rizzo error = netmap_attach_common(&mna->up); 8594bf50f18SLuigi Rizzo if (error) { 8604bf50f18SLuigi Rizzo D("attach_common error"); 861847bf383SLuigi Rizzo goto put_out; 8624bf50f18SLuigi Rizzo } 8634bf50f18SLuigi Rizzo 8644bf50f18SLuigi Rizzo /* remember the traffic directions we have to monitor */ 8654bf50f18SLuigi Rizzo mna->flags = (nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)); 8664bf50f18SLuigi Rizzo 8674bf50f18SLuigi Rizzo *na = &mna->up; 8684bf50f18SLuigi Rizzo netmap_adapter_get(*na); 8694bf50f18SLuigi Rizzo 8704bf50f18SLuigi Rizzo /* keep the reference to the parent */ 871*37e3a6d3SLuigi Rizzo ND("monitor ok"); 872*37e3a6d3SLuigi Rizzo 873*37e3a6d3SLuigi Rizzo /* drop the reference to the ifp, if any */ 874*37e3a6d3SLuigi Rizzo if (ifp) 875*37e3a6d3SLuigi Rizzo if_rele(ifp); 8764bf50f18SLuigi Rizzo 8774bf50f18SLuigi Rizzo return 0; 8784bf50f18SLuigi Rizzo 8794bf50f18SLuigi Rizzo put_out: 880*37e3a6d3SLuigi Rizzo netmap_unget_na(pna, ifp); 8814bf50f18SLuigi Rizzo free(mna, M_DEVBUF); 8824bf50f18SLuigi Rizzo return error; 8834bf50f18SLuigi Rizzo } 8844bf50f18SLuigi Rizzo 8854bf50f18SLuigi Rizzo 8864bf50f18SLuigi Rizzo #endif /* WITH_MONITOR */ 887