14bf50f18SLuigi Rizzo /* 237e3a6d3SLuigi Rizzo * Copyright (C) 2014-2016 Giuseppe Lettieri 337e3a6d3SLuigi 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. 41660a47cbSVincenzo Maffione * The slots containing traffic intercepted in the tx direction will have 42660a47cbSVincenzo Maffione * the NS_TXMON flag set. 434bf50f18SLuigi Rizzo * 44847bf383SLuigi Rizzo * If the monitor is not able to cope with the stream of frames, excess traffic 45847bf383SLuigi Rizzo * will be dropped. 46847bf383SLuigi Rizzo * 47847bf383SLuigi Rizzo * If the monitored adapter leaves netmap mode, the monitor has to be restarted. 48847bf383SLuigi Rizzo * 49847bf383SLuigi Rizzo * Monitors can be either zero-copy or copy-based. 50847bf383SLuigi Rizzo * 51847bf383SLuigi Rizzo * Copy monitors see the frames before they are consumed: 52847bf383SLuigi Rizzo * 53847bf383SLuigi Rizzo * - For tx traffic, this is when the application sends them, before they are 54847bf383SLuigi Rizzo * passed down to the adapter. 55847bf383SLuigi Rizzo * 56847bf383SLuigi Rizzo * - For rx traffic, this is when they are received by the adapter, before 57847bf383SLuigi Rizzo * they are sent up to the application, if any (note that, if no 58847bf383SLuigi Rizzo * application is reading from a monitored ring, the ring will eventually 59847bf383SLuigi Rizzo * fill up and traffic will stop). 60847bf383SLuigi Rizzo * 61847bf383SLuigi Rizzo * Zero-copy monitors only see the frames after they have been consumed: 624bf50f18SLuigi Rizzo * 634bf50f18SLuigi Rizzo * - For tx traffic, this is after the slots containing the frames have been 644bf50f18SLuigi Rizzo * marked as free. Note that this may happen at a considerably delay after 654bf50f18SLuigi Rizzo * frame transmission, since freeing of slots is often done lazily. 664bf50f18SLuigi Rizzo * 674bf50f18SLuigi Rizzo * - For rx traffic, this is after the consumer on the monitored adapter 684bf50f18SLuigi Rizzo * has released them. In most cases, the consumer is a userspace 694bf50f18SLuigi Rizzo * application which may have modified the frame contents. 704bf50f18SLuigi Rizzo * 714f80b14cSVincenzo Maffione * Several copy or zero-copy monitors may be active on any ring. 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 10537e3a6d3SLuigi Rizzo #elif defined(_WIN32) 10637e3a6d3SLuigi 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 131c3e9b4dbSLuiz Otavio O Souza static int netmap_zmon_reg(struct netmap_adapter *, int); 132c3e9b4dbSLuiz Otavio O Souza static int 133c3e9b4dbSLuiz Otavio O Souza nm_is_zmon(struct netmap_adapter *na) 134c3e9b4dbSLuiz Otavio O Souza { 135c3e9b4dbSLuiz Otavio O Souza return na->nm_register == netmap_zmon_reg; 136c3e9b4dbSLuiz Otavio O Souza } 137c3e9b4dbSLuiz Otavio O Souza 138847bf383SLuigi Rizzo /* nm_sync callback for the monitor's own tx rings. 139847bf383SLuigi Rizzo * This makes no sense and always returns error 1404bf50f18SLuigi Rizzo */ 1414bf50f18SLuigi Rizzo static int 142847bf383SLuigi Rizzo netmap_monitor_txsync(struct netmap_kring *kring, int flags) 1434bf50f18SLuigi Rizzo { 14475f4f3edSVincenzo Maffione nm_prlim(1, "%s %x", kring->name, flags); 145847bf383SLuigi Rizzo return EIO; 146847bf383SLuigi Rizzo } 147847bf383SLuigi Rizzo 148847bf383SLuigi Rizzo /* nm_sync callback for the monitor's own rx rings. 149847bf383SLuigi Rizzo * Note that the lock in netmap_zmon_parent_sync only protects 150847bf383SLuigi Rizzo * writers among themselves. Synchronization between writers 151847bf383SLuigi Rizzo * (i.e., netmap_zmon_parent_txsync and netmap_zmon_parent_rxsync) 152847bf383SLuigi Rizzo * and readers (i.e., netmap_zmon_rxsync) relies on memory barriers. 153847bf383SLuigi Rizzo */ 154847bf383SLuigi Rizzo static int 155847bf383SLuigi Rizzo netmap_monitor_rxsync(struct netmap_kring *kring, int flags) 156847bf383SLuigi Rizzo { 1572a7db7a6SVincenzo Maffione struct netmap_monitor_adapter *mna = 1582a7db7a6SVincenzo Maffione (struct netmap_monitor_adapter *)kring->na; 1592a7db7a6SVincenzo Maffione if (unlikely(mna->priv.np_na == NULL)) { 1602a7db7a6SVincenzo Maffione /* parent left netmap mode */ 1612a7db7a6SVincenzo Maffione return EIO; 1622a7db7a6SVincenzo Maffione } 16375f4f3edSVincenzo Maffione nm_prdis("%s %x", kring->name, flags); 164c3e9b4dbSLuiz Otavio O Souza kring->nr_hwcur = kring->rhead; 165847bf383SLuigi Rizzo mb(); 166847bf383SLuigi Rizzo return 0; 167847bf383SLuigi Rizzo } 168847bf383SLuigi Rizzo 169847bf383SLuigi Rizzo /* nm_krings_create callbacks for monitors. 170847bf383SLuigi Rizzo */ 171847bf383SLuigi Rizzo static int 172847bf383SLuigi Rizzo netmap_monitor_krings_create(struct netmap_adapter *na) 173847bf383SLuigi Rizzo { 17437e3a6d3SLuigi Rizzo int error = netmap_krings_create(na, 0); 1752a7db7a6SVincenzo Maffione enum txrx t; 1762a7db7a6SVincenzo Maffione 17737e3a6d3SLuigi Rizzo if (error) 17837e3a6d3SLuigi Rizzo return error; 17937e3a6d3SLuigi Rizzo /* override the host rings callbacks */ 1802a7db7a6SVincenzo Maffione for_rx_tx(t) { 1812a7db7a6SVincenzo Maffione int i; 1822a7db7a6SVincenzo Maffione u_int first = nma_get_nrings(na, t); 1832a7db7a6SVincenzo Maffione for (i = 0; i < nma_get_host_nrings(na, t); i++) { 1842a7db7a6SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[first + i]; 1852a7db7a6SVincenzo Maffione kring->nm_sync = t == NR_TX ? netmap_monitor_txsync : 1862a7db7a6SVincenzo Maffione netmap_monitor_rxsync; 1872a7db7a6SVincenzo Maffione } 1882a7db7a6SVincenzo Maffione } 18937e3a6d3SLuigi Rizzo return 0; 190847bf383SLuigi Rizzo } 191847bf383SLuigi Rizzo 192847bf383SLuigi Rizzo /* nm_krings_delete callback for monitors */ 193847bf383SLuigi Rizzo static void 194847bf383SLuigi Rizzo netmap_monitor_krings_delete(struct netmap_adapter *na) 195847bf383SLuigi Rizzo { 196847bf383SLuigi Rizzo netmap_krings_delete(na); 197847bf383SLuigi Rizzo } 198847bf383SLuigi Rizzo 199847bf383SLuigi Rizzo 200847bf383SLuigi Rizzo static u_int 201847bf383SLuigi Rizzo nm_txrx2flag(enum txrx t) 202847bf383SLuigi Rizzo { 203847bf383SLuigi Rizzo return (t == NR_RX ? NR_MONITOR_RX : NR_MONITOR_TX); 204847bf383SLuigi Rizzo } 205847bf383SLuigi Rizzo 206847bf383SLuigi Rizzo /* allocate the monitors array in the monitored kring */ 207847bf383SLuigi Rizzo static int 208847bf383SLuigi Rizzo nm_monitor_alloc(struct netmap_kring *kring, u_int n) 209847bf383SLuigi Rizzo { 210c3e9b4dbSLuiz Otavio O Souza size_t old_len, len; 211847bf383SLuigi Rizzo struct netmap_kring **nm; 212847bf383SLuigi Rizzo 213847bf383SLuigi Rizzo if (n <= kring->max_monitors) 214847bf383SLuigi Rizzo /* we already have more entries that requested */ 215847bf383SLuigi Rizzo return 0; 216847bf383SLuigi Rizzo 217c3e9b4dbSLuiz Otavio O Souza old_len = sizeof(struct netmap_kring *)*kring->max_monitors; 218847bf383SLuigi Rizzo len = sizeof(struct netmap_kring *) * n; 219c3e9b4dbSLuiz Otavio O Souza nm = nm_os_realloc(kring->monitors, len, old_len); 220847bf383SLuigi Rizzo if (nm == NULL) 221847bf383SLuigi Rizzo return ENOMEM; 222847bf383SLuigi Rizzo 223847bf383SLuigi Rizzo kring->monitors = nm; 224847bf383SLuigi Rizzo kring->max_monitors = n; 225847bf383SLuigi Rizzo 226847bf383SLuigi Rizzo return 0; 227847bf383SLuigi Rizzo } 228847bf383SLuigi Rizzo 229847bf383SLuigi Rizzo /* deallocate the parent array in the parent adapter */ 230847bf383SLuigi Rizzo static void 231847bf383SLuigi Rizzo nm_monitor_dealloc(struct netmap_kring *kring) 232847bf383SLuigi Rizzo { 233847bf383SLuigi Rizzo if (kring->monitors) { 234847bf383SLuigi Rizzo if (kring->n_monitors > 0) { 23575f4f3edSVincenzo Maffione nm_prerr("freeing not empty monitor array for %s (%d dangling monitors)!", 23675f4f3edSVincenzo Maffione kring->name, kring->n_monitors); 237847bf383SLuigi Rizzo } 238c3e9b4dbSLuiz Otavio O Souza nm_os_free(kring->monitors); 239847bf383SLuigi Rizzo kring->monitors = NULL; 240847bf383SLuigi Rizzo kring->max_monitors = 0; 241847bf383SLuigi Rizzo kring->n_monitors = 0; 242847bf383SLuigi Rizzo } 243847bf383SLuigi Rizzo } 244847bf383SLuigi Rizzo 245c3e9b4dbSLuiz Otavio O Souza /* returns 1 iff kring has no monitors */ 246c3e9b4dbSLuiz Otavio O Souza static inline int 247c3e9b4dbSLuiz Otavio O Souza nm_monitor_none(struct netmap_kring *kring) 248c3e9b4dbSLuiz Otavio O Souza { 249c3e9b4dbSLuiz Otavio O Souza return kring->n_monitors == 0 && 250c3e9b4dbSLuiz Otavio O Souza kring->zmon_list[NR_TX].next == NULL && 251c3e9b4dbSLuiz Otavio O Souza kring->zmon_list[NR_RX].next == NULL; 252c3e9b4dbSLuiz Otavio O Souza } 253c3e9b4dbSLuiz Otavio O Souza 254847bf383SLuigi Rizzo /* 255847bf383SLuigi Rizzo * monitors work by replacing the nm_sync() and possibly the 256847bf383SLuigi Rizzo * nm_notify() callbacks in the monitored rings. 257847bf383SLuigi Rizzo */ 258847bf383SLuigi Rizzo static int netmap_zmon_parent_txsync(struct netmap_kring *, int); 259847bf383SLuigi Rizzo static int netmap_zmon_parent_rxsync(struct netmap_kring *, int); 260847bf383SLuigi Rizzo static int netmap_monitor_parent_txsync(struct netmap_kring *, int); 261847bf383SLuigi Rizzo static int netmap_monitor_parent_rxsync(struct netmap_kring *, int); 262847bf383SLuigi Rizzo static int netmap_monitor_parent_notify(struct netmap_kring *, int); 263847bf383SLuigi Rizzo 264aa4dd64dSVincenzo Maffione static int 265aa4dd64dSVincenzo Maffione nm_monitor_dummycb(struct netmap_kring *kring, int flags) 266aa4dd64dSVincenzo Maffione { 267aa4dd64dSVincenzo Maffione (void)kring; 268aa4dd64dSVincenzo Maffione (void)flags; 269aa4dd64dSVincenzo Maffione return 0; 270aa4dd64dSVincenzo Maffione } 271aa4dd64dSVincenzo Maffione 2722a7db7a6SVincenzo Maffione static void 2732a7db7a6SVincenzo Maffione nm_monitor_intercept_callbacks(struct netmap_kring *kring) 274847bf383SLuigi Rizzo { 27575f4f3edSVincenzo Maffione nm_prdis("intercept callbacks on %s", kring->name); 276aa4dd64dSVincenzo Maffione kring->mon_sync = kring->nm_sync != NULL ? 277aa4dd64dSVincenzo Maffione kring->nm_sync : nm_monitor_dummycb; 278c3e9b4dbSLuiz Otavio O Souza kring->mon_notify = kring->nm_notify; 279c3e9b4dbSLuiz Otavio O Souza if (kring->tx == NR_TX) { 280c3e9b4dbSLuiz Otavio O Souza kring->nm_sync = netmap_monitor_parent_txsync; 281c3e9b4dbSLuiz Otavio O Souza } else { 282c3e9b4dbSLuiz Otavio O Souza kring->nm_sync = netmap_monitor_parent_rxsync; 283c3e9b4dbSLuiz Otavio O Souza kring->nm_notify = netmap_monitor_parent_notify; 284c3e9b4dbSLuiz Otavio O Souza kring->mon_tail = kring->nr_hwtail; 285c3e9b4dbSLuiz Otavio O Souza } 286c3e9b4dbSLuiz Otavio O Souza } 287c3e9b4dbSLuiz Otavio O Souza 2882a7db7a6SVincenzo Maffione static void 2892a7db7a6SVincenzo Maffione nm_monitor_restore_callbacks(struct netmap_kring *kring) 2902a7db7a6SVincenzo Maffione { 29175f4f3edSVincenzo Maffione nm_prdis("restoring callbacks on %s", kring->name); 2922a7db7a6SVincenzo Maffione kring->nm_sync = kring->mon_sync; 2932a7db7a6SVincenzo Maffione kring->mon_sync = NULL; 2942a7db7a6SVincenzo Maffione if (kring->tx == NR_RX) { 2952a7db7a6SVincenzo Maffione kring->nm_notify = kring->mon_notify; 2962a7db7a6SVincenzo Maffione } 2972a7db7a6SVincenzo Maffione kring->mon_notify = NULL; 2982a7db7a6SVincenzo Maffione } 2992a7db7a6SVincenzo Maffione 3002a7db7a6SVincenzo Maffione static struct netmap_kring * 3012a7db7a6SVincenzo Maffione nm_zmon_list_head(struct netmap_kring *mkring, enum txrx t) 3022a7db7a6SVincenzo Maffione { 3032a7db7a6SVincenzo Maffione struct netmap_adapter *na = mkring->na; 3042a7db7a6SVincenzo Maffione struct netmap_kring *kring = mkring; 3052a7db7a6SVincenzo Maffione struct netmap_zmon_list *z = &kring->zmon_list[t]; 3062a7db7a6SVincenzo Maffione /* reach the head of the list */ 3072a7db7a6SVincenzo Maffione while (nm_is_zmon(na) && z->prev != NULL) { 3082a7db7a6SVincenzo Maffione kring = z->prev; 3092a7db7a6SVincenzo Maffione na = kring->na; 3102a7db7a6SVincenzo Maffione z = &kring->zmon_list[t]; 3112a7db7a6SVincenzo Maffione } 3122a7db7a6SVincenzo Maffione return nm_is_zmon(na) ? NULL : kring; 3132a7db7a6SVincenzo Maffione } 3142a7db7a6SVincenzo Maffione 3152a7db7a6SVincenzo Maffione /* add the monitor mkring to the list of monitors of kring. 3162a7db7a6SVincenzo Maffione * If this is the first monitor, intercept the callbacks 3172a7db7a6SVincenzo Maffione */ 3182a7db7a6SVincenzo Maffione static int 3192a7db7a6SVincenzo Maffione netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int zmon) 3202a7db7a6SVincenzo Maffione { 3212a7db7a6SVincenzo Maffione int error = NM_IRQ_COMPLETED; 3222a7db7a6SVincenzo Maffione enum txrx t = kring->tx; 3232a7db7a6SVincenzo Maffione struct netmap_zmon_list *z = &kring->zmon_list[t]; 3242a7db7a6SVincenzo Maffione struct netmap_zmon_list *mz = &mkring->zmon_list[t]; 3252a7db7a6SVincenzo Maffione struct netmap_kring *ikring = kring; 3262a7db7a6SVincenzo Maffione 3272a7db7a6SVincenzo Maffione /* a zero-copy monitor which is not the first in the list 3282a7db7a6SVincenzo Maffione * must monitor the previous monitor 3292a7db7a6SVincenzo Maffione */ 3302a7db7a6SVincenzo Maffione if (zmon && z->prev != NULL) 3312a7db7a6SVincenzo Maffione ikring = z->prev; /* tail of the list */ 3322a7db7a6SVincenzo Maffione 3332a7db7a6SVincenzo Maffione /* synchronize with concurrently running nm_sync()s */ 3342a7db7a6SVincenzo Maffione nm_kr_stop(kring, NM_KR_LOCKED); 3352a7db7a6SVincenzo Maffione 3362a7db7a6SVincenzo Maffione if (nm_monitor_none(ikring)) { 3372a7db7a6SVincenzo Maffione /* this is the first monitor, intercept the callbacks */ 33875f4f3edSVincenzo Maffione nm_prdis("%s: intercept callbacks on %s", mkring->name, ikring->name); 3392a7db7a6SVincenzo Maffione nm_monitor_intercept_callbacks(ikring); 3402a7db7a6SVincenzo Maffione } 3412a7db7a6SVincenzo Maffione 342c3e9b4dbSLuiz Otavio O Souza if (zmon) { 343c3e9b4dbSLuiz Otavio O Souza /* append the zmon to the list */ 3442a7db7a6SVincenzo Maffione ikring->zmon_list[t].next = mkring; 3452a7db7a6SVincenzo Maffione z->prev = mkring; /* new tail */ 3462a7db7a6SVincenzo Maffione mz->prev = ikring; 3472a7db7a6SVincenzo Maffione mz->next = NULL; 3482a7db7a6SVincenzo Maffione /* grab a reference to the previous netmap adapter 349c3e9b4dbSLuiz Otavio O Souza * in the chain (this may be the monitored port 350c3e9b4dbSLuiz Otavio O Souza * or another zero-copy monitor) 351c3e9b4dbSLuiz Otavio O Souza */ 3522a7db7a6SVincenzo Maffione netmap_adapter_get(ikring->na); 353c3e9b4dbSLuiz Otavio O Souza } else { 354847bf383SLuigi Rizzo /* make sure the monitor array exists and is big enough */ 355847bf383SLuigi Rizzo error = nm_monitor_alloc(kring, kring->n_monitors + 1); 356847bf383SLuigi Rizzo if (error) 357847bf383SLuigi Rizzo goto out; 358847bf383SLuigi Rizzo kring->monitors[kring->n_monitors] = mkring; 359c3e9b4dbSLuiz Otavio O Souza mkring->mon_pos[kring->tx] = kring->n_monitors; 360847bf383SLuigi Rizzo kring->n_monitors++; 361847bf383SLuigi Rizzo } 362847bf383SLuigi Rizzo 363847bf383SLuigi Rizzo out: 36437e3a6d3SLuigi Rizzo nm_kr_start(kring); 365847bf383SLuigi Rizzo return error; 366847bf383SLuigi Rizzo } 367847bf383SLuigi Rizzo 368847bf383SLuigi Rizzo /* remove the monitor mkring from the list of monitors of kring. 369847bf383SLuigi Rizzo * If this is the last monitor, restore the original callbacks 370847bf383SLuigi Rizzo */ 371847bf383SLuigi Rizzo static void 3722a7db7a6SVincenzo Maffione netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring, enum txrx t) 373847bf383SLuigi Rizzo { 374c3e9b4dbSLuiz Otavio O Souza int zmon = nm_is_zmon(mkring->na); 3752a7db7a6SVincenzo Maffione struct netmap_zmon_list *mz = &mkring->zmon_list[t]; 3762a7db7a6SVincenzo Maffione struct netmap_kring *ikring = kring; 377c3e9b4dbSLuiz Otavio O Souza 378c3e9b4dbSLuiz Otavio O Souza 3792a7db7a6SVincenzo Maffione if (zmon) { 3802a7db7a6SVincenzo Maffione /* get to the head of the list */ 3812a7db7a6SVincenzo Maffione kring = nm_zmon_list_head(mkring, t); 3822a7db7a6SVincenzo Maffione ikring = mz->prev; 3832a7db7a6SVincenzo Maffione } 384c3e9b4dbSLuiz Otavio O Souza 3852a7db7a6SVincenzo Maffione /* synchronize with concurrently running nm_sync()s 3862a7db7a6SVincenzo Maffione * if kring is NULL (orphaned list) the monitored port 3872a7db7a6SVincenzo Maffione * has exited netmap mode, so there is nothing to stop 3882a7db7a6SVincenzo Maffione */ 3892a7db7a6SVincenzo Maffione if (kring != NULL) 39037e3a6d3SLuigi Rizzo nm_kr_stop(kring, NM_KR_LOCKED); 391c3e9b4dbSLuiz Otavio O Souza 392c3e9b4dbSLuiz Otavio O Souza if (zmon) { 393c3e9b4dbSLuiz Otavio O Souza /* remove the monitor from the list */ 394c3e9b4dbSLuiz Otavio O Souza if (mz->next != NULL) { 3952a7db7a6SVincenzo Maffione mz->next->zmon_list[t].prev = mz->prev; 3962a7db7a6SVincenzo Maffione /* we also need to let the next monitor drop the 3972a7db7a6SVincenzo Maffione * reference to us and grab the reference to the 3982a7db7a6SVincenzo Maffione * previous ring owner, instead 3992a7db7a6SVincenzo Maffione */ 4002a7db7a6SVincenzo Maffione if (mz->prev != NULL) 4012a7db7a6SVincenzo Maffione netmap_adapter_get(mz->prev->na); 4022a7db7a6SVincenzo Maffione netmap_adapter_put(mkring->na); 4032a7db7a6SVincenzo Maffione } else if (kring != NULL) { 4042a7db7a6SVincenzo Maffione /* in the monitored kring, prev is actually the 4052a7db7a6SVincenzo Maffione * pointer to the tail of the list 4062a7db7a6SVincenzo Maffione */ 4072a7db7a6SVincenzo Maffione kring->zmon_list[t].prev = 4082a7db7a6SVincenzo Maffione (mz->prev != kring ? mz->prev : NULL); 409c3e9b4dbSLuiz Otavio O Souza } 4102a7db7a6SVincenzo Maffione if (mz->prev != NULL) { 4112a7db7a6SVincenzo Maffione netmap_adapter_put(mz->prev->na); 4122a7db7a6SVincenzo Maffione mz->prev->zmon_list[t].next = mz->next; 4132a7db7a6SVincenzo Maffione } 4142a7db7a6SVincenzo Maffione mz->prev = NULL; 4152a7db7a6SVincenzo Maffione mz->next = NULL; 416c3e9b4dbSLuiz Otavio O Souza } else { 417c3e9b4dbSLuiz Otavio O Souza /* this is a copy monitor */ 418c3e9b4dbSLuiz Otavio O Souza uint32_t mon_pos = mkring->mon_pos[kring->tx]; 419847bf383SLuigi Rizzo kring->n_monitors--; 420c3e9b4dbSLuiz Otavio O Souza if (mon_pos != kring->n_monitors) { 421c3e9b4dbSLuiz Otavio O Souza kring->monitors[mon_pos] = 422c3e9b4dbSLuiz Otavio O Souza kring->monitors[kring->n_monitors]; 423c3e9b4dbSLuiz Otavio O Souza kring->monitors[mon_pos]->mon_pos[kring->tx] = mon_pos; 424847bf383SLuigi Rizzo } 425847bf383SLuigi Rizzo kring->monitors[kring->n_monitors] = NULL; 426847bf383SLuigi Rizzo if (kring->n_monitors == 0) { 427c3e9b4dbSLuiz Otavio O Souza nm_monitor_dealloc(kring); 428c3e9b4dbSLuiz Otavio O Souza } 429c3e9b4dbSLuiz Otavio O Souza } 430c3e9b4dbSLuiz Otavio O Souza 4312a7db7a6SVincenzo Maffione if (ikring != NULL && nm_monitor_none(ikring)) { 432c3e9b4dbSLuiz Otavio O Souza /* this was the last monitor, restore the callbacks */ 4332a7db7a6SVincenzo Maffione nm_monitor_restore_callbacks(ikring); 434847bf383SLuigi Rizzo } 435c3e9b4dbSLuiz Otavio O Souza 4362a7db7a6SVincenzo Maffione if (kring != NULL) 43737e3a6d3SLuigi Rizzo nm_kr_start(kring); 438847bf383SLuigi Rizzo } 439847bf383SLuigi Rizzo 440847bf383SLuigi Rizzo 441847bf383SLuigi Rizzo /* This is called when the monitored adapter leaves netmap mode 442847bf383SLuigi Rizzo * (see netmap_do_unregif). 443847bf383SLuigi Rizzo * We need to notify the monitors that the monitored rings are gone. 444847bf383SLuigi Rizzo * We do this by setting their mna->priv.np_na to NULL. 445847bf383SLuigi Rizzo * Note that the rings are already stopped when this happens, so 446847bf383SLuigi Rizzo * no monitor ring callback can be active. 447847bf383SLuigi Rizzo */ 448847bf383SLuigi Rizzo void 449847bf383SLuigi Rizzo netmap_monitor_stop(struct netmap_adapter *na) 450847bf383SLuigi Rizzo { 451847bf383SLuigi Rizzo enum txrx t; 452847bf383SLuigi Rizzo 453847bf383SLuigi Rizzo for_rx_tx(t) { 454847bf383SLuigi Rizzo u_int i; 455847bf383SLuigi Rizzo 4562a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(na, t); i++) { 4572ff91c17SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i]; 4582a7db7a6SVincenzo Maffione struct netmap_zmon_list *z = &kring->zmon_list[t]; 459847bf383SLuigi Rizzo u_int j; 460847bf383SLuigi Rizzo 461b41818a2SVincenzo Maffione if (nm_monitor_none(kring)) 462b41818a2SVincenzo Maffione continue; 463b41818a2SVincenzo Maffione 464847bf383SLuigi Rizzo for (j = 0; j < kring->n_monitors; j++) { 465847bf383SLuigi Rizzo struct netmap_kring *mkring = 466847bf383SLuigi Rizzo kring->monitors[j]; 467847bf383SLuigi Rizzo struct netmap_monitor_adapter *mna = 468847bf383SLuigi Rizzo (struct netmap_monitor_adapter *)mkring->na; 469847bf383SLuigi Rizzo /* forget about this adapter */ 470c3e9b4dbSLuiz Otavio O Souza if (mna->priv.np_na != NULL) { 47105f76057SLuigi Rizzo netmap_adapter_put(mna->priv.np_na); 472847bf383SLuigi Rizzo mna->priv.np_na = NULL; 473847bf383SLuigi Rizzo } 4742a7db7a6SVincenzo Maffione kring->monitors[j] = NULL; 475847bf383SLuigi Rizzo } 476b41818a2SVincenzo Maffione kring->n_monitors = 0; 477b41818a2SVincenzo Maffione nm_monitor_dealloc(kring); 478c3e9b4dbSLuiz Otavio O Souza 4792a7db7a6SVincenzo Maffione if (!nm_is_zmon(na)) { 4802a7db7a6SVincenzo Maffione /* we are the head of at most one list */ 4812a7db7a6SVincenzo Maffione struct netmap_kring *zkring; 4822a7db7a6SVincenzo Maffione for (zkring = z->next; zkring != NULL; 4832a7db7a6SVincenzo Maffione zkring = zkring->zmon_list[t].next) 4842a7db7a6SVincenzo Maffione { 485c3e9b4dbSLuiz Otavio O Souza struct netmap_monitor_adapter *next = 486c3e9b4dbSLuiz Otavio O Souza (struct netmap_monitor_adapter *)zkring->na; 4872a7db7a6SVincenzo Maffione /* let the monitor forget about us */ 4882a7db7a6SVincenzo Maffione netmap_adapter_put(next->priv.np_na); /* nop if null */ 489c3e9b4dbSLuiz Otavio O Souza next->priv.np_na = NULL; 49095fc1157SVincenzo Maffione /* drop the additional ref taken in netmap_monitor_add() */ 49195fc1157SVincenzo Maffione netmap_adapter_put(zkring->zmon_list[t].prev->na); 492c3e9b4dbSLuiz Otavio O Souza } 49345c67e8fSVincenzo Maffione /* orphan the zmon list */ 4942a7db7a6SVincenzo Maffione if (z->next != NULL) 4952a7db7a6SVincenzo Maffione z->next->zmon_list[t].prev = NULL; 4962a7db7a6SVincenzo Maffione z->next = NULL; 4972a7db7a6SVincenzo Maffione z->prev = NULL; 4982a7db7a6SVincenzo Maffione } 4992a7db7a6SVincenzo Maffione 5002a7db7a6SVincenzo Maffione nm_monitor_restore_callbacks(kring); 5012a7db7a6SVincenzo Maffione } 502c3e9b4dbSLuiz Otavio O Souza } 503847bf383SLuigi Rizzo } 504847bf383SLuigi Rizzo 505847bf383SLuigi Rizzo 506847bf383SLuigi Rizzo /* common functions for the nm_register() callbacks of both kind of 507847bf383SLuigi Rizzo * monitors. 508847bf383SLuigi Rizzo */ 509847bf383SLuigi Rizzo static int 510847bf383SLuigi Rizzo netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon) 511847bf383SLuigi Rizzo { 512847bf383SLuigi Rizzo struct netmap_monitor_adapter *mna = 513847bf383SLuigi Rizzo (struct netmap_monitor_adapter *)na; 514847bf383SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 515847bf383SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 516847bf383SLuigi Rizzo struct netmap_kring *kring, *mkring; 517847bf383SLuigi Rizzo int i; 518c3e9b4dbSLuiz Otavio O Souza enum txrx t, s; 519847bf383SLuigi Rizzo 52075f4f3edSVincenzo Maffione nm_prdis("%p: onoff %d", na, onoff); 521847bf383SLuigi Rizzo if (onoff) { 522847bf383SLuigi Rizzo if (pna == NULL) { 523847bf383SLuigi Rizzo /* parent left netmap mode, fatal */ 52475f4f3edSVincenzo Maffione nm_prerr("%s: parent left netmap mode", na->name); 525847bf383SLuigi Rizzo return ENXIO; 526847bf383SLuigi Rizzo } 527847bf383SLuigi Rizzo for_rx_tx(t) { 5282a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(na, t); i++) { 5292ff91c17SVincenzo Maffione mkring = NMR(na, t)[i]; 530c3e9b4dbSLuiz Otavio O Souza if (!nm_kring_pending_on(mkring)) 531c3e9b4dbSLuiz Otavio O Souza continue; 53237e3a6d3SLuigi Rizzo mkring->nr_mode = NKR_NETMAP_ON; 533c3e9b4dbSLuiz Otavio O Souza if (t == NR_TX) 534c3e9b4dbSLuiz Otavio O Souza continue; 535c3e9b4dbSLuiz Otavio O Souza for_rx_tx(s) { 536c3e9b4dbSLuiz Otavio O Souza if (i > nma_get_nrings(pna, s)) 537c3e9b4dbSLuiz Otavio O Souza continue; 538c3e9b4dbSLuiz Otavio O Souza if (mna->flags & nm_txrx2flag(s)) { 5392ff91c17SVincenzo Maffione kring = NMR(pna, s)[i]; 540c3e9b4dbSLuiz Otavio O Souza netmap_monitor_add(mkring, kring, zmon); 54137e3a6d3SLuigi Rizzo } 542847bf383SLuigi Rizzo } 543847bf383SLuigi Rizzo } 544847bf383SLuigi Rizzo } 545847bf383SLuigi Rizzo na->na_flags |= NAF_NETMAP_ON; 546847bf383SLuigi Rizzo } else { 54737e3a6d3SLuigi Rizzo if (na->active_fds == 0) 548847bf383SLuigi Rizzo na->na_flags &= ~NAF_NETMAP_ON; 549847bf383SLuigi Rizzo for_rx_tx(t) { 5502a7db7a6SVincenzo Maffione for (i = 0; i < netmap_all_rings(na, t); i++) { 5512ff91c17SVincenzo Maffione mkring = NMR(na, t)[i]; 552c3e9b4dbSLuiz Otavio O Souza if (!nm_kring_pending_off(mkring)) 553c3e9b4dbSLuiz Otavio O Souza continue; 55437e3a6d3SLuigi Rizzo mkring->nr_mode = NKR_NETMAP_OFF; 555c3e9b4dbSLuiz Otavio O Souza if (t == NR_TX) 556c3e9b4dbSLuiz Otavio O Souza continue; 55737e3a6d3SLuigi Rizzo /* we cannot access the parent krings if the parent 55837e3a6d3SLuigi Rizzo * has left netmap mode. This is signaled by a NULL 55937e3a6d3SLuigi Rizzo * pna pointer 56037e3a6d3SLuigi Rizzo */ 561c3e9b4dbSLuiz Otavio O Souza if (pna == NULL) 562c3e9b4dbSLuiz Otavio O Souza continue; 563c3e9b4dbSLuiz Otavio O Souza for_rx_tx(s) { 564c3e9b4dbSLuiz Otavio O Souza if (i > nma_get_nrings(pna, s)) 565c3e9b4dbSLuiz Otavio O Souza continue; 566c3e9b4dbSLuiz Otavio O Souza if (mna->flags & nm_txrx2flag(s)) { 5672ff91c17SVincenzo Maffione kring = NMR(pna, s)[i]; 5682a7db7a6SVincenzo Maffione netmap_monitor_del(mkring, kring, s); 569847bf383SLuigi Rizzo } 570847bf383SLuigi Rizzo } 571847bf383SLuigi Rizzo } 572847bf383SLuigi Rizzo } 57337e3a6d3SLuigi Rizzo } 574847bf383SLuigi Rizzo return 0; 575847bf383SLuigi Rizzo } 576847bf383SLuigi Rizzo 577847bf383SLuigi Rizzo /* 578847bf383SLuigi Rizzo **************************************************************** 579847bf383SLuigi Rizzo * functions specific for zero-copy monitors 580847bf383SLuigi Rizzo **************************************************************** 581847bf383SLuigi Rizzo */ 582847bf383SLuigi Rizzo 583847bf383SLuigi Rizzo /* 584847bf383SLuigi Rizzo * Common function for both zero-copy tx and rx nm_sync() 585847bf383SLuigi Rizzo * callbacks 586847bf383SLuigi Rizzo */ 587847bf383SLuigi Rizzo static int 588847bf383SLuigi Rizzo netmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx) 589847bf383SLuigi Rizzo { 590c3e9b4dbSLuiz Otavio O Souza struct netmap_kring *mkring = kring->zmon_list[tx].next; 591847bf383SLuigi Rizzo struct netmap_ring *ring = kring->ring, *mring; 592847bf383SLuigi Rizzo int error = 0; 593847bf383SLuigi Rizzo int rel_slots, free_slots, busy, sent = 0; 5944bf50f18SLuigi Rizzo u_int beg, end, i; 5954bf50f18SLuigi Rizzo u_int lim = kring->nkr_num_slots - 1, 596847bf383SLuigi Rizzo mlim; // = mkring->nkr_num_slots - 1; 597660a47cbSVincenzo Maffione uint16_t txmon = kring->tx == NR_TX ? NS_TXMON : 0; 598847bf383SLuigi Rizzo 599847bf383SLuigi Rizzo if (mkring == NULL) { 60075f4f3edSVincenzo Maffione nm_prlim(5, "NULL monitor on %s", kring->name); 601847bf383SLuigi Rizzo return 0; 602847bf383SLuigi Rizzo } 603847bf383SLuigi Rizzo mring = mkring->ring; 6044bf50f18SLuigi Rizzo mlim = mkring->nkr_num_slots - 1; 6054bf50f18SLuigi Rizzo 60645c67e8fSVincenzo Maffione /* get the released slots (rel_slots) */ 607847bf383SLuigi Rizzo if (tx == NR_TX) { 608c3e9b4dbSLuiz Otavio O Souza beg = kring->nr_hwtail + 1; 609847bf383SLuigi Rizzo error = kring->mon_sync(kring, flags); 6104bf50f18SLuigi Rizzo if (error) 6114bf50f18SLuigi Rizzo return error; 612c3e9b4dbSLuiz Otavio O Souza end = kring->nr_hwtail + 1; 613847bf383SLuigi Rizzo } else { /* NR_RX */ 614847bf383SLuigi Rizzo beg = kring->nr_hwcur; 615847bf383SLuigi Rizzo end = kring->rhead; 616847bf383SLuigi Rizzo } 617847bf383SLuigi Rizzo 6184bf50f18SLuigi Rizzo rel_slots = end - beg; 6194bf50f18SLuigi Rizzo if (rel_slots < 0) 6204bf50f18SLuigi Rizzo rel_slots += kring->nkr_num_slots; 6214bf50f18SLuigi Rizzo 6224bf50f18SLuigi Rizzo if (!rel_slots) { 623847bf383SLuigi Rizzo /* no released slots, but we still need 624847bf383SLuigi Rizzo * to call rxsync if this is a rx ring 625847bf383SLuigi Rizzo */ 626847bf383SLuigi Rizzo goto out_rxsync; 6274bf50f18SLuigi Rizzo } 6284bf50f18SLuigi Rizzo 6294bf50f18SLuigi Rizzo /* we need to lock the monitor receive ring, since it 6304bf50f18SLuigi Rizzo * is the target of bot tx and rx traffic from the monitored 6314bf50f18SLuigi Rizzo * adapter 6324bf50f18SLuigi Rizzo */ 6334bf50f18SLuigi Rizzo mtx_lock(&mkring->q_lock); 6344bf50f18SLuigi Rizzo /* get the free slots available on the monitor ring */ 6354bf50f18SLuigi Rizzo i = mkring->nr_hwtail; 6364bf50f18SLuigi Rizzo busy = i - mkring->nr_hwcur; 6374bf50f18SLuigi Rizzo if (busy < 0) 6384bf50f18SLuigi Rizzo busy += mkring->nkr_num_slots; 6394bf50f18SLuigi Rizzo free_slots = mlim - busy; 6404bf50f18SLuigi Rizzo 641847bf383SLuigi Rizzo if (!free_slots) 642847bf383SLuigi Rizzo goto out; 6434bf50f18SLuigi Rizzo 6444bf50f18SLuigi Rizzo /* swap min(free_slots, rel_slots) slots */ 6454bf50f18SLuigi Rizzo if (free_slots < rel_slots) { 6464bf50f18SLuigi Rizzo beg += (rel_slots - free_slots); 6474bf50f18SLuigi Rizzo rel_slots = free_slots; 6484bf50f18SLuigi Rizzo } 649c3e9b4dbSLuiz Otavio O Souza if (unlikely(beg >= kring->nkr_num_slots)) 650c3e9b4dbSLuiz Otavio O Souza beg -= kring->nkr_num_slots; 6514bf50f18SLuigi Rizzo 652847bf383SLuigi Rizzo sent = rel_slots; 6534bf50f18SLuigi Rizzo for ( ; rel_slots; rel_slots--) { 6544bf50f18SLuigi Rizzo struct netmap_slot *s = &ring->slot[beg]; 6554bf50f18SLuigi Rizzo struct netmap_slot *ms = &mring->slot[i]; 6564bf50f18SLuigi Rizzo uint32_t tmp; 6574bf50f18SLuigi Rizzo 6584bf50f18SLuigi Rizzo tmp = ms->buf_idx; 6594bf50f18SLuigi Rizzo ms->buf_idx = s->buf_idx; 6604bf50f18SLuigi Rizzo s->buf_idx = tmp; 66175f4f3edSVincenzo Maffione nm_prdis(5, "beg %d buf_idx %d", beg, tmp); 6624bf50f18SLuigi Rizzo 6634bf50f18SLuigi Rizzo tmp = ms->len; 6644bf50f18SLuigi Rizzo ms->len = s->len; 6654bf50f18SLuigi Rizzo s->len = tmp; 6664bf50f18SLuigi Rizzo 667660a47cbSVincenzo Maffione ms->flags = (s->flags & ~NS_TXMON) | txmon; 6684bf50f18SLuigi Rizzo s->flags |= NS_BUF_CHANGED; 6694bf50f18SLuigi Rizzo 6704bf50f18SLuigi Rizzo beg = nm_next(beg, lim); 6714bf50f18SLuigi Rizzo i = nm_next(i, mlim); 6724bf50f18SLuigi Rizzo 6734bf50f18SLuigi Rizzo } 674ad15cc59SLuigi Rizzo mb(); 6754bf50f18SLuigi Rizzo mkring->nr_hwtail = i; 6764bf50f18SLuigi Rizzo 677847bf383SLuigi Rizzo out: 6784bf50f18SLuigi Rizzo mtx_unlock(&mkring->q_lock); 679847bf383SLuigi Rizzo 680847bf383SLuigi Rizzo if (sent) { 6814bf50f18SLuigi Rizzo /* notify the new frames to the monitor */ 682847bf383SLuigi Rizzo mkring->nm_notify(mkring, 0); 683847bf383SLuigi Rizzo } 684847bf383SLuigi Rizzo 685847bf383SLuigi Rizzo out_rxsync: 686847bf383SLuigi Rizzo if (tx == NR_RX) 687847bf383SLuigi Rizzo error = kring->mon_sync(kring, flags); 688847bf383SLuigi Rizzo 689847bf383SLuigi Rizzo return error; 690847bf383SLuigi Rizzo } 691847bf383SLuigi Rizzo 692847bf383SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored tx rings */ 693847bf383SLuigi Rizzo static int 694847bf383SLuigi Rizzo netmap_zmon_parent_txsync(struct netmap_kring *kring, int flags) 695847bf383SLuigi Rizzo { 696847bf383SLuigi Rizzo return netmap_zmon_parent_sync(kring, flags, NR_TX); 697847bf383SLuigi Rizzo } 698847bf383SLuigi Rizzo 699847bf383SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored rx rings */ 700847bf383SLuigi Rizzo static int 701847bf383SLuigi Rizzo netmap_zmon_parent_rxsync(struct netmap_kring *kring, int flags) 702847bf383SLuigi Rizzo { 703847bf383SLuigi Rizzo return netmap_zmon_parent_sync(kring, flags, NR_RX); 704847bf383SLuigi Rizzo } 705847bf383SLuigi Rizzo 706847bf383SLuigi Rizzo static int 707847bf383SLuigi Rizzo netmap_zmon_reg(struct netmap_adapter *na, int onoff) 708847bf383SLuigi Rizzo { 709847bf383SLuigi Rizzo return netmap_monitor_reg_common(na, onoff, 1 /* zcopy */); 710847bf383SLuigi Rizzo } 711847bf383SLuigi Rizzo 712847bf383SLuigi Rizzo /* nm_dtor callback for monitors */ 713847bf383SLuigi Rizzo static void 714847bf383SLuigi Rizzo netmap_zmon_dtor(struct netmap_adapter *na) 715847bf383SLuigi Rizzo { 716847bf383SLuigi Rizzo struct netmap_monitor_adapter *mna = 717847bf383SLuigi Rizzo (struct netmap_monitor_adapter *)na; 718847bf383SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 719847bf383SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 720847bf383SLuigi Rizzo 721847bf383SLuigi Rizzo netmap_adapter_put(pna); 722847bf383SLuigi Rizzo } 723847bf383SLuigi Rizzo 724847bf383SLuigi Rizzo /* 725847bf383SLuigi Rizzo **************************************************************** 726847bf383SLuigi Rizzo * functions specific for copy monitors 727847bf383SLuigi Rizzo **************************************************************** 728847bf383SLuigi Rizzo */ 729847bf383SLuigi Rizzo 730847bf383SLuigi Rizzo static void 731847bf383SLuigi Rizzo netmap_monitor_parent_sync(struct netmap_kring *kring, u_int first_new, int new_slots) 732847bf383SLuigi Rizzo { 733847bf383SLuigi Rizzo u_int j; 734660a47cbSVincenzo Maffione uint16_t txmon = kring->tx == NR_TX ? NS_TXMON : 0; 735847bf383SLuigi Rizzo 736847bf383SLuigi Rizzo for (j = 0; j < kring->n_monitors; j++) { 737847bf383SLuigi Rizzo struct netmap_kring *mkring = kring->monitors[j]; 738847bf383SLuigi Rizzo u_int i, mlim, beg; 739847bf383SLuigi Rizzo int free_slots, busy, sent = 0, m; 740847bf383SLuigi Rizzo u_int lim = kring->nkr_num_slots - 1; 741847bf383SLuigi Rizzo struct netmap_ring *ring = kring->ring, *mring = mkring->ring; 7426127ce9dSVincenzo Maffione u_int max_len; 743847bf383SLuigi Rizzo mlim = mkring->nkr_num_slots - 1; 744847bf383SLuigi Rizzo 745847bf383SLuigi Rizzo /* we need to lock the monitor receive ring, since it 746847bf383SLuigi Rizzo * is the target of bot tx and rx traffic from the monitored 747847bf383SLuigi Rizzo * adapter 748847bf383SLuigi Rizzo */ 749847bf383SLuigi Rizzo mtx_lock(&mkring->q_lock); 750847bf383SLuigi Rizzo /* get the free slots available on the monitor ring */ 751847bf383SLuigi Rizzo i = mkring->nr_hwtail; 752847bf383SLuigi Rizzo busy = i - mkring->nr_hwcur; 753847bf383SLuigi Rizzo if (busy < 0) 754847bf383SLuigi Rizzo busy += mkring->nkr_num_slots; 755847bf383SLuigi Rizzo free_slots = mlim - busy; 756847bf383SLuigi Rizzo 757847bf383SLuigi Rizzo if (!free_slots) 758847bf383SLuigi Rizzo goto out; 759847bf383SLuigi Rizzo 760847bf383SLuigi Rizzo /* copy min(free_slots, new_slots) slots */ 761847bf383SLuigi Rizzo m = new_slots; 762847bf383SLuigi Rizzo beg = first_new; 763847bf383SLuigi Rizzo if (free_slots < m) { 764847bf383SLuigi Rizzo beg += (m - free_slots); 765847bf383SLuigi Rizzo if (beg >= kring->nkr_num_slots) 766847bf383SLuigi Rizzo beg -= kring->nkr_num_slots; 767847bf383SLuigi Rizzo m = free_slots; 768847bf383SLuigi Rizzo } 769847bf383SLuigi Rizzo 770847bf383SLuigi Rizzo for ( ; m; m--) { 771847bf383SLuigi Rizzo struct netmap_slot *s = &ring->slot[beg]; 772847bf383SLuigi Rizzo struct netmap_slot *ms = &mring->slot[i]; 773847bf383SLuigi Rizzo u_int copy_len = s->len; 7746127ce9dSVincenzo Maffione char *src = NMB_O(kring, s), 7756127ce9dSVincenzo Maffione *dst = NMB_O(mkring, ms); 776847bf383SLuigi Rizzo 7776127ce9dSVincenzo Maffione max_len = NETMAP_BUF_SIZE(mkring->na) - nm_get_offset(mkring, ms); 778847bf383SLuigi Rizzo if (unlikely(copy_len > max_len)) { 77975f4f3edSVincenzo Maffione nm_prlim(5, "%s->%s: truncating %d to %d", kring->name, 780847bf383SLuigi Rizzo mkring->name, copy_len, max_len); 781847bf383SLuigi Rizzo copy_len = max_len; 782847bf383SLuigi Rizzo } 783847bf383SLuigi Rizzo 784847bf383SLuigi Rizzo memcpy(dst, src, copy_len); 785847bf383SLuigi Rizzo ms->len = copy_len; 786660a47cbSVincenzo Maffione ms->flags = (s->flags & ~NS_TXMON) | txmon; 787847bf383SLuigi Rizzo sent++; 788847bf383SLuigi Rizzo 789847bf383SLuigi Rizzo beg = nm_next(beg, lim); 790847bf383SLuigi Rizzo i = nm_next(i, mlim); 791847bf383SLuigi Rizzo } 792847bf383SLuigi Rizzo mb(); 793847bf383SLuigi Rizzo mkring->nr_hwtail = i; 794847bf383SLuigi Rizzo out: 795847bf383SLuigi Rizzo mtx_unlock(&mkring->q_lock); 796847bf383SLuigi Rizzo 797847bf383SLuigi Rizzo if (sent) { 798847bf383SLuigi Rizzo /* notify the new frames to the monitor */ 799847bf383SLuigi Rizzo mkring->nm_notify(mkring, 0); 800847bf383SLuigi Rizzo } 801847bf383SLuigi Rizzo } 8024bf50f18SLuigi Rizzo } 8034bf50f18SLuigi Rizzo 8044bf50f18SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored tx rings */ 8054bf50f18SLuigi Rizzo static int 8064bf50f18SLuigi Rizzo netmap_monitor_parent_txsync(struct netmap_kring *kring, int flags) 8074bf50f18SLuigi Rizzo { 808847bf383SLuigi Rizzo u_int first_new; 809847bf383SLuigi Rizzo int new_slots; 810847bf383SLuigi Rizzo 811847bf383SLuigi Rizzo /* get the new slots */ 812c3e9b4dbSLuiz Otavio O Souza if (kring->n_monitors > 0) { 813847bf383SLuigi Rizzo first_new = kring->nr_hwcur; 814847bf383SLuigi Rizzo new_slots = kring->rhead - first_new; 815847bf383SLuigi Rizzo if (new_slots < 0) 816847bf383SLuigi Rizzo new_slots += kring->nkr_num_slots; 817847bf383SLuigi Rizzo if (new_slots) 818847bf383SLuigi Rizzo netmap_monitor_parent_sync(kring, first_new, new_slots); 819c3e9b4dbSLuiz Otavio O Souza } 820c3e9b4dbSLuiz Otavio O Souza if (kring->zmon_list[NR_TX].next != NULL) { 821c3e9b4dbSLuiz Otavio O Souza return netmap_zmon_parent_txsync(kring, flags); 822c3e9b4dbSLuiz Otavio O Souza } 823847bf383SLuigi Rizzo return kring->mon_sync(kring, flags); 8244bf50f18SLuigi Rizzo } 8254bf50f18SLuigi Rizzo 8264bf50f18SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored rx rings */ 8274bf50f18SLuigi Rizzo static int 8284bf50f18SLuigi Rizzo netmap_monitor_parent_rxsync(struct netmap_kring *kring, int flags) 8294bf50f18SLuigi Rizzo { 830847bf383SLuigi Rizzo u_int first_new; 831847bf383SLuigi Rizzo int new_slots, error; 8324bf50f18SLuigi Rizzo 833847bf383SLuigi Rizzo /* get the new slots */ 834c3e9b4dbSLuiz Otavio O Souza if (kring->zmon_list[NR_RX].next != NULL) { 835c3e9b4dbSLuiz Otavio O Souza error = netmap_zmon_parent_rxsync(kring, flags); 836c3e9b4dbSLuiz Otavio O Souza } else { 837847bf383SLuigi Rizzo error = kring->mon_sync(kring, flags); 838c3e9b4dbSLuiz Otavio O Souza } 839847bf383SLuigi Rizzo if (error) 840847bf383SLuigi Rizzo return error; 841c3e9b4dbSLuiz Otavio O Souza if (kring->n_monitors > 0) { 842847bf383SLuigi Rizzo first_new = kring->mon_tail; 843847bf383SLuigi Rizzo new_slots = kring->nr_hwtail - first_new; 844847bf383SLuigi Rizzo if (new_slots < 0) 845847bf383SLuigi Rizzo new_slots += kring->nkr_num_slots; 846847bf383SLuigi Rizzo if (new_slots) 847847bf383SLuigi Rizzo netmap_monitor_parent_sync(kring, first_new, new_slots); 848847bf383SLuigi Rizzo kring->mon_tail = kring->nr_hwtail; 849c3e9b4dbSLuiz Otavio O Souza } 8504bf50f18SLuigi Rizzo return 0; 8514bf50f18SLuigi Rizzo } 8524bf50f18SLuigi Rizzo 853847bf383SLuigi Rizzo /* callback used to replace the nm_notify() callback in the monitored rx rings */ 8544bf50f18SLuigi Rizzo static int 855847bf383SLuigi Rizzo netmap_monitor_parent_notify(struct netmap_kring *kring, int flags) 8564bf50f18SLuigi Rizzo { 85737e3a6d3SLuigi Rizzo int (*notify)(struct netmap_kring*, int); 85875f4f3edSVincenzo Maffione nm_prdis(5, "%s %x", kring->name, flags); 859847bf383SLuigi Rizzo /* ?xsync callbacks have tryget called by their callers 860847bf383SLuigi Rizzo * (NIOCREGIF and poll()), but here we have to call it 861847bf383SLuigi Rizzo * by ourself 862847bf383SLuigi Rizzo */ 86337e3a6d3SLuigi Rizzo if (nm_kr_tryget(kring, 0, NULL)) { 86437e3a6d3SLuigi Rizzo /* in all cases, just skip the sync */ 86537e3a6d3SLuigi Rizzo return NM_IRQ_COMPLETED; 86637e3a6d3SLuigi Rizzo } 86737e3a6d3SLuigi Rizzo if (kring->n_monitors > 0) { 868847bf383SLuigi Rizzo netmap_monitor_parent_rxsync(kring, NAF_FORCE_READ); 869c3e9b4dbSLuiz Otavio O Souza } 870c3e9b4dbSLuiz Otavio O Souza if (nm_monitor_none(kring)) { 87137e3a6d3SLuigi Rizzo /* we are no longer monitoring this ring, so both 87237e3a6d3SLuigi Rizzo * mon_sync and mon_notify are NULL 87337e3a6d3SLuigi Rizzo */ 87437e3a6d3SLuigi Rizzo notify = kring->nm_notify; 875c3e9b4dbSLuiz Otavio O Souza } else { 876c3e9b4dbSLuiz Otavio O Souza notify = kring->mon_notify; 87737e3a6d3SLuigi Rizzo } 878847bf383SLuigi Rizzo nm_kr_put(kring); 87937e3a6d3SLuigi Rizzo return notify(kring, flags); 8804bf50f18SLuigi Rizzo } 8814bf50f18SLuigi Rizzo 8824bf50f18SLuigi Rizzo 8834bf50f18SLuigi Rizzo static int 8844bf50f18SLuigi Rizzo netmap_monitor_reg(struct netmap_adapter *na, int onoff) 8854bf50f18SLuigi Rizzo { 886847bf383SLuigi Rizzo return netmap_monitor_reg_common(na, onoff, 0 /* no zcopy */); 8874bf50f18SLuigi Rizzo } 8884bf50f18SLuigi Rizzo 8894bf50f18SLuigi Rizzo static void 8904bf50f18SLuigi Rizzo netmap_monitor_dtor(struct netmap_adapter *na) 8914bf50f18SLuigi Rizzo { 8924bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna = 8934bf50f18SLuigi Rizzo (struct netmap_monitor_adapter *)na; 8944bf50f18SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 8954bf50f18SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 8964bf50f18SLuigi Rizzo 8974bf50f18SLuigi Rizzo netmap_adapter_put(pna); 8984bf50f18SLuigi Rizzo } 8994bf50f18SLuigi Rizzo 9004bf50f18SLuigi Rizzo 9012ff91c17SVincenzo Maffione /* check if req is a request for a monitor adapter that we can satisfy */ 9024bf50f18SLuigi Rizzo int 9032ff91c17SVincenzo Maffione netmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na, 904c3e9b4dbSLuiz Otavio O Souza struct netmap_mem_d *nmd, int create) 9054bf50f18SLuigi Rizzo { 906cfa866f6SMatt Macy struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body; 9072ff91c17SVincenzo Maffione struct nmreq_register preq; 9084bf50f18SLuigi Rizzo struct netmap_adapter *pna; /* parent adapter */ 9094bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna; 910*e330262fSJustin Hibbits if_t ifp = NULL; 911c3e9b4dbSLuiz Otavio O Souza int error; 9122ff91c17SVincenzo Maffione int zcopy = (req->nr_flags & NR_ZCOPY_MON); 9134bf50f18SLuigi Rizzo 914c3e9b4dbSLuiz Otavio O Souza if (zcopy) { 9152ff91c17SVincenzo Maffione req->nr_flags |= (NR_MONITOR_TX | NR_MONITOR_RX); 91637e3a6d3SLuigi Rizzo } 9172ff91c17SVincenzo Maffione if ((req->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) { 91875f4f3edSVincenzo Maffione nm_prdis("not a monitor"); 9194bf50f18SLuigi Rizzo return 0; 9204bf50f18SLuigi Rizzo } 9214bf50f18SLuigi Rizzo /* this is a request for a monitor adapter */ 9224bf50f18SLuigi Rizzo 92375f4f3edSVincenzo Maffione nm_prdis("flags %lx", req->nr_flags); 9244bf50f18SLuigi Rizzo 9252ff91c17SVincenzo Maffione /* First, try to find the adapter that we want to monitor. 9262ff91c17SVincenzo Maffione * We use the same req, after we have turned off the monitor flags. 9274bf50f18SLuigi Rizzo * In this way we can potentially monitor everything netmap understands, 9284bf50f18SLuigi Rizzo * except other monitors. 9294bf50f18SLuigi Rizzo */ 9302ff91c17SVincenzo Maffione memcpy(&preq, req, sizeof(preq)); 9312ff91c17SVincenzo Maffione preq.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON); 932cfa866f6SMatt Macy hdr->nr_body = (uintptr_t)&preq; 9332ff91c17SVincenzo Maffione error = netmap_get_na(hdr, &pna, &ifp, nmd, create); 934cfa866f6SMatt Macy hdr->nr_body = (uintptr_t)req; 9354bf50f18SLuigi Rizzo if (error) { 93675f4f3edSVincenzo Maffione nm_prerr("parent lookup failed: %d", error); 9374bf50f18SLuigi Rizzo return error; 9384bf50f18SLuigi Rizzo } 93975f4f3edSVincenzo Maffione nm_prdis("found parent: %s", pna->name); 9404bf50f18SLuigi Rizzo 9414bf50f18SLuigi Rizzo if (!nm_netmap_on(pna)) { 9424bf50f18SLuigi Rizzo /* parent not in netmap mode */ 9434bf50f18SLuigi Rizzo /* XXX we can wait for the parent to enter netmap mode, 9444bf50f18SLuigi Rizzo * by intercepting its nm_register callback (2014-03-16) 9454bf50f18SLuigi Rizzo */ 94675f4f3edSVincenzo Maffione nm_prerr("%s not in netmap mode", pna->name); 9474bf50f18SLuigi Rizzo error = EINVAL; 9484bf50f18SLuigi Rizzo goto put_out; 9494bf50f18SLuigi Rizzo } 9504bf50f18SLuigi Rizzo 951c3e9b4dbSLuiz Otavio O Souza mna = nm_os_malloc(sizeof(*mna)); 952c3e9b4dbSLuiz Otavio O Souza if (mna == NULL) { 953c3e9b4dbSLuiz Otavio O Souza error = ENOMEM; 954c3e9b4dbSLuiz Otavio O Souza goto put_out; 955c3e9b4dbSLuiz Otavio O Souza } 9564bf50f18SLuigi Rizzo mna->priv.np_na = pna; 957c3e9b4dbSLuiz Otavio O Souza 958c3e9b4dbSLuiz Otavio O Souza /* grab all the rings we need in the parent */ 959ee0005f1SVincenzo Maffione error = netmap_interp_ringid(&mna->priv, hdr); 9604bf50f18SLuigi Rizzo if (error) { 96175f4f3edSVincenzo Maffione nm_prerr("ringid error"); 962c3e9b4dbSLuiz Otavio O Souza goto free_out; 9634bf50f18SLuigi Rizzo } 9642a7db7a6SVincenzo Maffione snprintf(mna->up.name, sizeof(mna->up.name), "%s/%s%s%s#%lu", pna->name, 965847bf383SLuigi Rizzo zcopy ? "z" : "", 9662ff91c17SVincenzo Maffione (req->nr_flags & NR_MONITOR_RX) ? "r" : "", 9672a7db7a6SVincenzo Maffione (req->nr_flags & NR_MONITOR_TX) ? "t" : "", 9682a7db7a6SVincenzo Maffione pna->monitor_id++); 969847bf383SLuigi Rizzo 970847bf383SLuigi Rizzo /* the monitor supports the host rings iff the parent does */ 9716127ce9dSVincenzo Maffione mna->up.na_flags |= (pna->na_flags & NAF_HOST_RINGS) & ~NAF_OFFSETS; 9726127ce9dSVincenzo Maffione if (!zcopy) 9736127ce9dSVincenzo Maffione mna->up.na_flags |= NAF_OFFSETS; 974847bf383SLuigi Rizzo /* a do-nothing txsync: monitors cannot be used to inject packets */ 975847bf383SLuigi Rizzo mna->up.nm_txsync = netmap_monitor_txsync; 976847bf383SLuigi Rizzo mna->up.nm_rxsync = netmap_monitor_rxsync; 9774bf50f18SLuigi Rizzo mna->up.nm_krings_create = netmap_monitor_krings_create; 9784bf50f18SLuigi Rizzo mna->up.nm_krings_delete = netmap_monitor_krings_delete; 979c3e9b4dbSLuiz Otavio O Souza mna->up.num_tx_rings = 1; // XXX what should we do here with chained zmons? 9804bf50f18SLuigi Rizzo /* we set the number of our rx_rings to be max(num_rx_rings, num_rx_rings) 9814bf50f18SLuigi Rizzo * in the parent 9824bf50f18SLuigi Rizzo */ 9834bf50f18SLuigi Rizzo mna->up.num_rx_rings = pna->num_rx_rings; 9844bf50f18SLuigi Rizzo if (pna->num_tx_rings > pna->num_rx_rings) 9854bf50f18SLuigi Rizzo mna->up.num_rx_rings = pna->num_tx_rings; 9864bf50f18SLuigi Rizzo /* by default, the number of slots is the same as in 9874bf50f18SLuigi Rizzo * the parent rings, but the user may ask for a different 9884bf50f18SLuigi Rizzo * number 9894bf50f18SLuigi Rizzo */ 9902ff91c17SVincenzo Maffione mna->up.num_tx_desc = req->nr_tx_slots; 9914bf50f18SLuigi Rizzo nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc, 9924bf50f18SLuigi Rizzo 1, NM_MONITOR_MAXSLOTS, NULL); 9932ff91c17SVincenzo Maffione mna->up.num_rx_desc = req->nr_rx_slots; 9944bf50f18SLuigi Rizzo nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc, 9954bf50f18SLuigi Rizzo 1, NM_MONITOR_MAXSLOTS, NULL); 996c3e9b4dbSLuiz Otavio O Souza if (zcopy) { 997c3e9b4dbSLuiz Otavio O Souza mna->up.nm_register = netmap_zmon_reg; 998c3e9b4dbSLuiz Otavio O Souza mna->up.nm_dtor = netmap_zmon_dtor; 999c3e9b4dbSLuiz Otavio O Souza /* to have zero copy, we need to use the same memory allocator 1000c3e9b4dbSLuiz Otavio O Souza * as the monitored port 1001c3e9b4dbSLuiz Otavio O Souza */ 1002c3e9b4dbSLuiz Otavio O Souza mna->up.nm_mem = netmap_mem_get(pna->nm_mem); 1003c3e9b4dbSLuiz Otavio O Souza /* and the allocator cannot be changed */ 1004c3e9b4dbSLuiz Otavio O Souza mna->up.na_flags |= NAF_MEM_OWNER; 1005c3e9b4dbSLuiz Otavio O Souza } else { 1006c3e9b4dbSLuiz Otavio O Souza mna->up.nm_register = netmap_monitor_reg; 1007c3e9b4dbSLuiz Otavio O Souza mna->up.nm_dtor = netmap_monitor_dtor; 1008c3e9b4dbSLuiz Otavio O Souza mna->up.nm_mem = netmap_mem_private_new( 1009c3e9b4dbSLuiz Otavio O Souza mna->up.num_tx_rings, 1010c3e9b4dbSLuiz Otavio O Souza mna->up.num_tx_desc, 1011c3e9b4dbSLuiz Otavio O Souza mna->up.num_rx_rings, 1012c3e9b4dbSLuiz Otavio O Souza mna->up.num_rx_desc, 1013c3e9b4dbSLuiz Otavio O Souza 0, /* extra bufs */ 1014c3e9b4dbSLuiz Otavio O Souza 0, /* pipes */ 1015c3e9b4dbSLuiz Otavio O Souza &error); 1016c3e9b4dbSLuiz Otavio O Souza if (mna->up.nm_mem == NULL) 1017847bf383SLuigi Rizzo goto put_out; 10184bf50f18SLuigi Rizzo } 10194bf50f18SLuigi Rizzo 1020c3e9b4dbSLuiz Otavio O Souza error = netmap_attach_common(&mna->up); 1021c3e9b4dbSLuiz Otavio O Souza if (error) { 102275f4f3edSVincenzo Maffione nm_prerr("netmap_attach_common failed"); 1023c3e9b4dbSLuiz Otavio O Souza goto mem_put_out; 1024c3e9b4dbSLuiz Otavio O Souza } 1025c3e9b4dbSLuiz Otavio O Souza 10264bf50f18SLuigi Rizzo /* remember the traffic directions we have to monitor */ 10272ff91c17SVincenzo Maffione mna->flags = (req->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON)); 10284bf50f18SLuigi Rizzo 10294bf50f18SLuigi Rizzo *na = &mna->up; 10304bf50f18SLuigi Rizzo netmap_adapter_get(*na); 10314bf50f18SLuigi Rizzo 10324bf50f18SLuigi Rizzo /* keep the reference to the parent */ 103375f4f3edSVincenzo Maffione nm_prdis("monitor ok"); 103437e3a6d3SLuigi Rizzo 103537e3a6d3SLuigi Rizzo /* drop the reference to the ifp, if any */ 103637e3a6d3SLuigi Rizzo if (ifp) 103737e3a6d3SLuigi Rizzo if_rele(ifp); 10384bf50f18SLuigi Rizzo 10394bf50f18SLuigi Rizzo return 0; 10404bf50f18SLuigi Rizzo 1041c3e9b4dbSLuiz Otavio O Souza mem_put_out: 1042c3e9b4dbSLuiz Otavio O Souza netmap_mem_put(mna->up.nm_mem); 1043c3e9b4dbSLuiz Otavio O Souza free_out: 1044c3e9b4dbSLuiz Otavio O Souza nm_os_free(mna); 10454bf50f18SLuigi Rizzo put_out: 104637e3a6d3SLuigi Rizzo netmap_unget_na(pna, ifp); 10474bf50f18SLuigi Rizzo return error; 10484bf50f18SLuigi Rizzo } 10494bf50f18SLuigi Rizzo 10504bf50f18SLuigi Rizzo 10514bf50f18SLuigi Rizzo #endif /* WITH_MONITOR */ 1052