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. 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 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 131*c3e9b4dbSLuiz Otavio O Souza static int netmap_zmon_reg(struct netmap_adapter *, int); 132*c3e9b4dbSLuiz Otavio O Souza static int 133*c3e9b4dbSLuiz Otavio O Souza nm_is_zmon(struct netmap_adapter *na) 134*c3e9b4dbSLuiz Otavio O Souza { 135*c3e9b4dbSLuiz Otavio O Souza return na->nm_register == netmap_zmon_reg; 136*c3e9b4dbSLuiz Otavio O Souza } 137*c3e9b4dbSLuiz 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 { 144847bf383SLuigi Rizzo RD(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 { 157847bf383SLuigi Rizzo ND("%s %x", kring->name, flags); 158*c3e9b4dbSLuiz Otavio O Souza kring->nr_hwcur = kring->rhead; 159847bf383SLuigi Rizzo mb(); 160847bf383SLuigi Rizzo return 0; 161847bf383SLuigi Rizzo } 162847bf383SLuigi Rizzo 163847bf383SLuigi Rizzo /* nm_krings_create callbacks for monitors. 164847bf383SLuigi Rizzo */ 165847bf383SLuigi Rizzo static int 166847bf383SLuigi Rizzo netmap_monitor_krings_create(struct netmap_adapter *na) 167847bf383SLuigi Rizzo { 16837e3a6d3SLuigi Rizzo int error = netmap_krings_create(na, 0); 16937e3a6d3SLuigi Rizzo if (error) 17037e3a6d3SLuigi Rizzo return error; 17137e3a6d3SLuigi Rizzo /* override the host rings callbacks */ 17237e3a6d3SLuigi Rizzo na->tx_rings[na->num_tx_rings].nm_sync = netmap_monitor_txsync; 17337e3a6d3SLuigi Rizzo na->rx_rings[na->num_rx_rings].nm_sync = netmap_monitor_rxsync; 17437e3a6d3SLuigi Rizzo return 0; 175847bf383SLuigi Rizzo } 176847bf383SLuigi Rizzo 177847bf383SLuigi Rizzo /* nm_krings_delete callback for monitors */ 178847bf383SLuigi Rizzo static void 179847bf383SLuigi Rizzo netmap_monitor_krings_delete(struct netmap_adapter *na) 180847bf383SLuigi Rizzo { 181847bf383SLuigi Rizzo netmap_krings_delete(na); 182847bf383SLuigi Rizzo } 183847bf383SLuigi Rizzo 184847bf383SLuigi Rizzo 185847bf383SLuigi Rizzo static u_int 186847bf383SLuigi Rizzo nm_txrx2flag(enum txrx t) 187847bf383SLuigi Rizzo { 188847bf383SLuigi Rizzo return (t == NR_RX ? NR_MONITOR_RX : NR_MONITOR_TX); 189847bf383SLuigi Rizzo } 190847bf383SLuigi Rizzo 191847bf383SLuigi Rizzo /* allocate the monitors array in the monitored kring */ 192847bf383SLuigi Rizzo static int 193847bf383SLuigi Rizzo nm_monitor_alloc(struct netmap_kring *kring, u_int n) 194847bf383SLuigi Rizzo { 195*c3e9b4dbSLuiz Otavio O Souza size_t old_len, len; 196847bf383SLuigi Rizzo struct netmap_kring **nm; 197847bf383SLuigi Rizzo 198847bf383SLuigi Rizzo if (n <= kring->max_monitors) 199847bf383SLuigi Rizzo /* we already have more entries that requested */ 200847bf383SLuigi Rizzo return 0; 201847bf383SLuigi Rizzo 202*c3e9b4dbSLuiz Otavio O Souza old_len = sizeof(struct netmap_kring *)*kring->max_monitors; 203847bf383SLuigi Rizzo len = sizeof(struct netmap_kring *) * n; 204*c3e9b4dbSLuiz Otavio O Souza nm = nm_os_realloc(kring->monitors, len, old_len); 205847bf383SLuigi Rizzo if (nm == NULL) 206847bf383SLuigi Rizzo return ENOMEM; 207847bf383SLuigi Rizzo 208847bf383SLuigi Rizzo kring->monitors = nm; 209847bf383SLuigi Rizzo kring->max_monitors = n; 210847bf383SLuigi Rizzo 211847bf383SLuigi Rizzo return 0; 212847bf383SLuigi Rizzo } 213847bf383SLuigi Rizzo 214847bf383SLuigi Rizzo /* deallocate the parent array in the parent adapter */ 215847bf383SLuigi Rizzo static void 216847bf383SLuigi Rizzo nm_monitor_dealloc(struct netmap_kring *kring) 217847bf383SLuigi Rizzo { 218847bf383SLuigi Rizzo if (kring->monitors) { 219847bf383SLuigi Rizzo if (kring->n_monitors > 0) { 220847bf383SLuigi Rizzo D("freeing not empty monitor array for %s (%d dangling monitors)!", kring->name, 221847bf383SLuigi Rizzo kring->n_monitors); 222847bf383SLuigi Rizzo } 223*c3e9b4dbSLuiz Otavio O Souza nm_os_free(kring->monitors); 224847bf383SLuigi Rizzo kring->monitors = NULL; 225847bf383SLuigi Rizzo kring->max_monitors = 0; 226847bf383SLuigi Rizzo kring->n_monitors = 0; 227847bf383SLuigi Rizzo } 228847bf383SLuigi Rizzo } 229847bf383SLuigi Rizzo 230*c3e9b4dbSLuiz Otavio O Souza /* returns 1 iff kring has no monitors */ 231*c3e9b4dbSLuiz Otavio O Souza static inline int 232*c3e9b4dbSLuiz Otavio O Souza nm_monitor_none(struct netmap_kring *kring) 233*c3e9b4dbSLuiz Otavio O Souza { 234*c3e9b4dbSLuiz Otavio O Souza return kring->n_monitors == 0 && 235*c3e9b4dbSLuiz Otavio O Souza kring->zmon_list[NR_TX].next == NULL && 236*c3e9b4dbSLuiz Otavio O Souza kring->zmon_list[NR_RX].next == NULL; 237*c3e9b4dbSLuiz Otavio O Souza } 238*c3e9b4dbSLuiz Otavio O Souza 239847bf383SLuigi Rizzo /* 240847bf383SLuigi Rizzo * monitors work by replacing the nm_sync() and possibly the 241847bf383SLuigi Rizzo * nm_notify() callbacks in the monitored rings. 242847bf383SLuigi Rizzo */ 243847bf383SLuigi Rizzo static int netmap_zmon_parent_txsync(struct netmap_kring *, int); 244847bf383SLuigi Rizzo static int netmap_zmon_parent_rxsync(struct netmap_kring *, int); 245847bf383SLuigi Rizzo static int netmap_monitor_parent_txsync(struct netmap_kring *, int); 246847bf383SLuigi Rizzo static int netmap_monitor_parent_rxsync(struct netmap_kring *, int); 247847bf383SLuigi Rizzo static int netmap_monitor_parent_notify(struct netmap_kring *, int); 248847bf383SLuigi Rizzo 249847bf383SLuigi Rizzo /* add the monitor mkring to the list of monitors of kring. 250847bf383SLuigi Rizzo * If this is the first monitor, intercept the callbacks 251847bf383SLuigi Rizzo */ 252847bf383SLuigi Rizzo static int 253*c3e9b4dbSLuiz Otavio O Souza netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int zmon) 254847bf383SLuigi Rizzo { 25537e3a6d3SLuigi Rizzo int error = NM_IRQ_COMPLETED; 256*c3e9b4dbSLuiz Otavio O Souza enum txrx t = kring->tx; 257*c3e9b4dbSLuiz Otavio O Souza struct netmap_zmon_list *z = &kring->zmon_list[t]; 258*c3e9b4dbSLuiz Otavio O Souza struct netmap_zmon_list *mz = &mkring->zmon_list[t]; 259*c3e9b4dbSLuiz Otavio O Souza 260*c3e9b4dbSLuiz Otavio O Souza /* a zero-copy monitor which is not the first in the list 261*c3e9b4dbSLuiz Otavio O Souza * must monitor the previous monitor 262*c3e9b4dbSLuiz Otavio O Souza */ 263*c3e9b4dbSLuiz Otavio O Souza if (zmon && z->prev != NULL) 264*c3e9b4dbSLuiz Otavio O Souza kring = z->prev; 265847bf383SLuigi Rizzo 266847bf383SLuigi Rizzo /* sinchronize with concurrently running nm_sync()s */ 26737e3a6d3SLuigi Rizzo nm_kr_stop(kring, NM_KR_LOCKED); 268*c3e9b4dbSLuiz Otavio O Souza 269*c3e9b4dbSLuiz Otavio O Souza if (nm_monitor_none(kring)) { 270*c3e9b4dbSLuiz Otavio O Souza /* this is the first monitor, intercept callbacks */ 271*c3e9b4dbSLuiz Otavio O Souza ND("intercept callbacks on %s", kring->name); 272*c3e9b4dbSLuiz Otavio O Souza kring->mon_sync = kring->nm_sync; 273*c3e9b4dbSLuiz Otavio O Souza kring->mon_notify = kring->nm_notify; 274*c3e9b4dbSLuiz Otavio O Souza if (kring->tx == NR_TX) { 275*c3e9b4dbSLuiz Otavio O Souza kring->nm_sync = netmap_monitor_parent_txsync; 276*c3e9b4dbSLuiz Otavio O Souza } else { 277*c3e9b4dbSLuiz Otavio O Souza kring->nm_sync = netmap_monitor_parent_rxsync; 278*c3e9b4dbSLuiz Otavio O Souza kring->nm_notify = netmap_monitor_parent_notify; 279*c3e9b4dbSLuiz Otavio O Souza kring->mon_tail = kring->nr_hwtail; 280*c3e9b4dbSLuiz Otavio O Souza } 281*c3e9b4dbSLuiz Otavio O Souza } 282*c3e9b4dbSLuiz Otavio O Souza 283*c3e9b4dbSLuiz Otavio O Souza if (zmon) { 284*c3e9b4dbSLuiz Otavio O Souza /* append the zmon to the list */ 285*c3e9b4dbSLuiz Otavio O Souza struct netmap_monitor_adapter *mna = 286*c3e9b4dbSLuiz Otavio O Souza (struct netmap_monitor_adapter *)mkring->na; 287*c3e9b4dbSLuiz Otavio O Souza struct netmap_adapter *pna; 288*c3e9b4dbSLuiz Otavio O Souza 289*c3e9b4dbSLuiz Otavio O Souza if (z->prev != NULL) 290*c3e9b4dbSLuiz Otavio O Souza z->prev->zmon_list[t].next = mkring; 291*c3e9b4dbSLuiz Otavio O Souza mz->prev = z->prev; 292*c3e9b4dbSLuiz Otavio O Souza z->prev = mkring; 293*c3e9b4dbSLuiz Otavio O Souza if (z->next == NULL) 294*c3e9b4dbSLuiz Otavio O Souza z->next = mkring; 295*c3e9b4dbSLuiz Otavio O Souza 296*c3e9b4dbSLuiz Otavio O Souza /* grap a reference to the previous netmap adapter 297*c3e9b4dbSLuiz Otavio O Souza * in the chain (this may be the monitored port 298*c3e9b4dbSLuiz Otavio O Souza * or another zero-copy monitor) 299*c3e9b4dbSLuiz Otavio O Souza */ 300*c3e9b4dbSLuiz Otavio O Souza pna = kring->na; 301*c3e9b4dbSLuiz Otavio O Souza netmap_adapter_get(pna); 302*c3e9b4dbSLuiz Otavio O Souza netmap_adapter_put(mna->priv.np_na); 303*c3e9b4dbSLuiz Otavio O Souza mna->priv.np_na = pna; 304*c3e9b4dbSLuiz Otavio O Souza } else { 305847bf383SLuigi Rizzo /* make sure the monitor array exists and is big enough */ 306847bf383SLuigi Rizzo error = nm_monitor_alloc(kring, kring->n_monitors + 1); 307847bf383SLuigi Rizzo if (error) 308847bf383SLuigi Rizzo goto out; 309847bf383SLuigi Rizzo kring->monitors[kring->n_monitors] = mkring; 310*c3e9b4dbSLuiz Otavio O Souza mkring->mon_pos[kring->tx] = kring->n_monitors; 311847bf383SLuigi Rizzo kring->n_monitors++; 312847bf383SLuigi Rizzo } 313847bf383SLuigi Rizzo 314847bf383SLuigi Rizzo out: 31537e3a6d3SLuigi Rizzo nm_kr_start(kring); 316847bf383SLuigi Rizzo return error; 317847bf383SLuigi Rizzo } 318847bf383SLuigi Rizzo 319847bf383SLuigi Rizzo /* remove the monitor mkring from the list of monitors of kring. 320847bf383SLuigi Rizzo * If this is the last monitor, restore the original callbacks 321847bf383SLuigi Rizzo */ 322847bf383SLuigi Rizzo static void 323847bf383SLuigi Rizzo netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring) 324847bf383SLuigi Rizzo { 325*c3e9b4dbSLuiz Otavio O Souza struct netmap_zmon_list *mz = &mkring->zmon_list[kring->tx]; 326*c3e9b4dbSLuiz Otavio O Souza int zmon = nm_is_zmon(mkring->na); 327*c3e9b4dbSLuiz Otavio O Souza 328*c3e9b4dbSLuiz Otavio O Souza 329*c3e9b4dbSLuiz Otavio O Souza if (zmon && mz->prev != NULL) 330*c3e9b4dbSLuiz Otavio O Souza kring = mz->prev; 331*c3e9b4dbSLuiz Otavio O Souza 332847bf383SLuigi Rizzo /* sinchronize with concurrently running nm_sync()s */ 33337e3a6d3SLuigi Rizzo nm_kr_stop(kring, NM_KR_LOCKED); 334*c3e9b4dbSLuiz Otavio O Souza 335*c3e9b4dbSLuiz Otavio O Souza if (zmon) { 336*c3e9b4dbSLuiz Otavio O Souza /* remove the monitor from the list */ 337*c3e9b4dbSLuiz Otavio O Souza if (mz->prev != NULL) 338*c3e9b4dbSLuiz Otavio O Souza mz->prev->zmon_list[kring->tx].next = mz->next; 339*c3e9b4dbSLuiz Otavio O Souza else 340*c3e9b4dbSLuiz Otavio O Souza kring->zmon_list[kring->tx].next = mz->next; 341*c3e9b4dbSLuiz Otavio O Souza if (mz->next != NULL) { 342*c3e9b4dbSLuiz Otavio O Souza mz->next->zmon_list[kring->tx].prev = mz->prev; 343*c3e9b4dbSLuiz Otavio O Souza } else { 344*c3e9b4dbSLuiz Otavio O Souza kring->zmon_list[kring->tx].prev = mz->prev; 345*c3e9b4dbSLuiz Otavio O Souza } 346*c3e9b4dbSLuiz Otavio O Souza } else { 347*c3e9b4dbSLuiz Otavio O Souza /* this is a copy monitor */ 348*c3e9b4dbSLuiz Otavio O Souza uint32_t mon_pos = mkring->mon_pos[kring->tx]; 349847bf383SLuigi Rizzo kring->n_monitors--; 350*c3e9b4dbSLuiz Otavio O Souza if (mon_pos != kring->n_monitors) { 351*c3e9b4dbSLuiz Otavio O Souza kring->monitors[mon_pos] = 352*c3e9b4dbSLuiz Otavio O Souza kring->monitors[kring->n_monitors]; 353*c3e9b4dbSLuiz Otavio O Souza kring->monitors[mon_pos]->mon_pos[kring->tx] = mon_pos; 354847bf383SLuigi Rizzo } 355847bf383SLuigi Rizzo kring->monitors[kring->n_monitors] = NULL; 356847bf383SLuigi Rizzo if (kring->n_monitors == 0) { 357*c3e9b4dbSLuiz Otavio O Souza nm_monitor_dealloc(kring); 358*c3e9b4dbSLuiz Otavio O Souza } 359*c3e9b4dbSLuiz Otavio O Souza } 360*c3e9b4dbSLuiz Otavio O Souza 361*c3e9b4dbSLuiz Otavio O Souza if (nm_monitor_none(kring)) { 362*c3e9b4dbSLuiz Otavio O Souza /* this was the last monitor, restore the callbacks */ 363*c3e9b4dbSLuiz Otavio O Souza ND("%s: restoring sync on %s: %p", mkring->name, kring->name, 364*c3e9b4dbSLuiz Otavio O Souza kring->mon_sync); 365847bf383SLuigi Rizzo kring->nm_sync = kring->mon_sync; 366847bf383SLuigi Rizzo kring->mon_sync = NULL; 367847bf383SLuigi Rizzo if (kring->tx == NR_RX) { 36837e3a6d3SLuigi Rizzo ND("%s: restoring notify on %s: %p", 369847bf383SLuigi Rizzo mkring->name, kring->name, kring->mon_notify); 370847bf383SLuigi Rizzo kring->nm_notify = kring->mon_notify; 371847bf383SLuigi Rizzo kring->mon_notify = NULL; 372847bf383SLuigi Rizzo } 373847bf383SLuigi Rizzo } 374*c3e9b4dbSLuiz Otavio O Souza 37537e3a6d3SLuigi Rizzo nm_kr_start(kring); 376847bf383SLuigi Rizzo } 377847bf383SLuigi Rizzo 378847bf383SLuigi Rizzo 379847bf383SLuigi Rizzo /* This is called when the monitored adapter leaves netmap mode 380847bf383SLuigi Rizzo * (see netmap_do_unregif). 381847bf383SLuigi Rizzo * We need to notify the monitors that the monitored rings are gone. 382847bf383SLuigi Rizzo * We do this by setting their mna->priv.np_na to NULL. 383847bf383SLuigi Rizzo * Note that the rings are already stopped when this happens, so 384847bf383SLuigi Rizzo * no monitor ring callback can be active. 385847bf383SLuigi Rizzo */ 386847bf383SLuigi Rizzo void 387847bf383SLuigi Rizzo netmap_monitor_stop(struct netmap_adapter *na) 388847bf383SLuigi Rizzo { 389847bf383SLuigi Rizzo enum txrx t; 390847bf383SLuigi Rizzo 391847bf383SLuigi Rizzo for_rx_tx(t) { 392847bf383SLuigi Rizzo u_int i; 393847bf383SLuigi Rizzo 39437e3a6d3SLuigi Rizzo for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { 395847bf383SLuigi Rizzo struct netmap_kring *kring = &NMR(na, t)[i]; 396*c3e9b4dbSLuiz Otavio O Souza struct netmap_kring *zkring; 397847bf383SLuigi Rizzo u_int j; 398847bf383SLuigi Rizzo 399847bf383SLuigi Rizzo for (j = 0; j < kring->n_monitors; j++) { 400847bf383SLuigi Rizzo struct netmap_kring *mkring = 401847bf383SLuigi Rizzo kring->monitors[j]; 402847bf383SLuigi Rizzo struct netmap_monitor_adapter *mna = 403847bf383SLuigi Rizzo (struct netmap_monitor_adapter *)mkring->na; 404847bf383SLuigi Rizzo /* forget about this adapter */ 405*c3e9b4dbSLuiz Otavio O Souza if (mna->priv.np_na != NULL) { 40605f76057SLuigi Rizzo netmap_adapter_put(mna->priv.np_na); 407847bf383SLuigi Rizzo mna->priv.np_na = NULL; 408847bf383SLuigi Rizzo } 409847bf383SLuigi Rizzo } 410*c3e9b4dbSLuiz Otavio O Souza 411*c3e9b4dbSLuiz Otavio O Souza zkring = kring->zmon_list[kring->tx].next; 412*c3e9b4dbSLuiz Otavio O Souza if (zkring != NULL) { 413*c3e9b4dbSLuiz Otavio O Souza struct netmap_monitor_adapter *next = 414*c3e9b4dbSLuiz Otavio O Souza (struct netmap_monitor_adapter *)zkring->na; 415*c3e9b4dbSLuiz Otavio O Souza struct netmap_monitor_adapter *this = 416*c3e9b4dbSLuiz Otavio O Souza (struct netmap_monitor_adapter *)na; 417*c3e9b4dbSLuiz Otavio O Souza struct netmap_adapter *pna = this->priv.np_na; 418*c3e9b4dbSLuiz Otavio O Souza /* let the next monitor forget about us */ 419*c3e9b4dbSLuiz Otavio O Souza if (next->priv.np_na != NULL) { 420*c3e9b4dbSLuiz Otavio O Souza netmap_adapter_put(next->priv.np_na); 421*c3e9b4dbSLuiz Otavio O Souza } 422*c3e9b4dbSLuiz Otavio O Souza if (pna != NULL && nm_is_zmon(na)) { 423*c3e9b4dbSLuiz Otavio O Souza /* we are a monitor ourselves and we may 424*c3e9b4dbSLuiz Otavio O Souza * need to pass down the reference to 425*c3e9b4dbSLuiz Otavio O Souza * the previous adapter in the chain 426*c3e9b4dbSLuiz Otavio O Souza */ 427*c3e9b4dbSLuiz Otavio O Souza netmap_adapter_get(pna); 428*c3e9b4dbSLuiz Otavio O Souza next->priv.np_na = pna; 429*c3e9b4dbSLuiz Otavio O Souza continue; 430*c3e9b4dbSLuiz Otavio O Souza } 431*c3e9b4dbSLuiz Otavio O Souza next->priv.np_na = NULL; 432*c3e9b4dbSLuiz Otavio O Souza } 433*c3e9b4dbSLuiz Otavio O Souza } 434847bf383SLuigi Rizzo } 435847bf383SLuigi Rizzo } 436847bf383SLuigi Rizzo 437847bf383SLuigi Rizzo 438847bf383SLuigi Rizzo /* common functions for the nm_register() callbacks of both kind of 439847bf383SLuigi Rizzo * monitors. 440847bf383SLuigi Rizzo */ 441847bf383SLuigi Rizzo static int 442847bf383SLuigi Rizzo netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon) 443847bf383SLuigi Rizzo { 444847bf383SLuigi Rizzo struct netmap_monitor_adapter *mna = 445847bf383SLuigi Rizzo (struct netmap_monitor_adapter *)na; 446847bf383SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 447847bf383SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 448847bf383SLuigi Rizzo struct netmap_kring *kring, *mkring; 449847bf383SLuigi Rizzo int i; 450*c3e9b4dbSLuiz Otavio O Souza enum txrx t, s; 451847bf383SLuigi Rizzo 452847bf383SLuigi Rizzo ND("%p: onoff %d", na, onoff); 453847bf383SLuigi Rizzo if (onoff) { 454847bf383SLuigi Rizzo if (pna == NULL) { 455847bf383SLuigi Rizzo /* parent left netmap mode, fatal */ 456847bf383SLuigi Rizzo D("%s: internal error", na->name); 457847bf383SLuigi Rizzo return ENXIO; 458847bf383SLuigi Rizzo } 459847bf383SLuigi Rizzo for_rx_tx(t) { 460*c3e9b4dbSLuiz Otavio O Souza for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { 461*c3e9b4dbSLuiz Otavio O Souza mkring = &NMR(na, t)[i]; 462*c3e9b4dbSLuiz Otavio O Souza if (!nm_kring_pending_on(mkring)) 463*c3e9b4dbSLuiz Otavio O Souza continue; 46437e3a6d3SLuigi Rizzo mkring->nr_mode = NKR_NETMAP_ON; 465*c3e9b4dbSLuiz Otavio O Souza if (t == NR_TX) 466*c3e9b4dbSLuiz Otavio O Souza continue; 467*c3e9b4dbSLuiz Otavio O Souza for_rx_tx(s) { 468*c3e9b4dbSLuiz Otavio O Souza if (i > nma_get_nrings(pna, s)) 469*c3e9b4dbSLuiz Otavio O Souza continue; 470*c3e9b4dbSLuiz Otavio O Souza if (mna->flags & nm_txrx2flag(s)) { 471*c3e9b4dbSLuiz Otavio O Souza kring = &NMR(pna, s)[i]; 472*c3e9b4dbSLuiz Otavio O Souza netmap_monitor_add(mkring, kring, zmon); 47337e3a6d3SLuigi Rizzo } 474847bf383SLuigi Rizzo } 475847bf383SLuigi Rizzo } 476847bf383SLuigi Rizzo } 477847bf383SLuigi Rizzo na->na_flags |= NAF_NETMAP_ON; 478847bf383SLuigi Rizzo } else { 47937e3a6d3SLuigi Rizzo if (na->active_fds == 0) 480847bf383SLuigi Rizzo na->na_flags &= ~NAF_NETMAP_ON; 481847bf383SLuigi Rizzo for_rx_tx(t) { 482*c3e9b4dbSLuiz Otavio O Souza for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { 483*c3e9b4dbSLuiz Otavio O Souza mkring = &NMR(na, t)[i]; 484*c3e9b4dbSLuiz Otavio O Souza if (!nm_kring_pending_off(mkring)) 485*c3e9b4dbSLuiz Otavio O Souza continue; 48637e3a6d3SLuigi Rizzo mkring->nr_mode = NKR_NETMAP_OFF; 487*c3e9b4dbSLuiz Otavio O Souza if (t == NR_TX) 488*c3e9b4dbSLuiz Otavio O Souza continue; 48937e3a6d3SLuigi Rizzo /* we cannot access the parent krings if the parent 49037e3a6d3SLuigi Rizzo * has left netmap mode. This is signaled by a NULL 49137e3a6d3SLuigi Rizzo * pna pointer 49237e3a6d3SLuigi Rizzo */ 493*c3e9b4dbSLuiz Otavio O Souza if (pna == NULL) 494*c3e9b4dbSLuiz Otavio O Souza continue; 495*c3e9b4dbSLuiz Otavio O Souza for_rx_tx(s) { 496*c3e9b4dbSLuiz Otavio O Souza if (i > nma_get_nrings(pna, s)) 497*c3e9b4dbSLuiz Otavio O Souza continue; 498*c3e9b4dbSLuiz Otavio O Souza if (mna->flags & nm_txrx2flag(s)) { 499*c3e9b4dbSLuiz Otavio O Souza kring = &NMR(pna, s)[i]; 500847bf383SLuigi Rizzo netmap_monitor_del(mkring, kring); 501847bf383SLuigi Rizzo } 502847bf383SLuigi Rizzo } 503847bf383SLuigi Rizzo } 504847bf383SLuigi Rizzo } 50537e3a6d3SLuigi Rizzo } 506847bf383SLuigi Rizzo return 0; 507847bf383SLuigi Rizzo } 508847bf383SLuigi Rizzo 509847bf383SLuigi Rizzo /* 510847bf383SLuigi Rizzo **************************************************************** 511847bf383SLuigi Rizzo * functions specific for zero-copy monitors 512847bf383SLuigi Rizzo **************************************************************** 513847bf383SLuigi Rizzo */ 514847bf383SLuigi Rizzo 515847bf383SLuigi Rizzo /* 516847bf383SLuigi Rizzo * Common function for both zero-copy tx and rx nm_sync() 517847bf383SLuigi Rizzo * callbacks 518847bf383SLuigi Rizzo */ 519847bf383SLuigi Rizzo static int 520847bf383SLuigi Rizzo netmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx) 521847bf383SLuigi Rizzo { 522*c3e9b4dbSLuiz Otavio O Souza struct netmap_kring *mkring = kring->zmon_list[tx].next; 523847bf383SLuigi Rizzo struct netmap_ring *ring = kring->ring, *mring; 524847bf383SLuigi Rizzo int error = 0; 525847bf383SLuigi Rizzo int rel_slots, free_slots, busy, sent = 0; 5264bf50f18SLuigi Rizzo u_int beg, end, i; 5274bf50f18SLuigi Rizzo u_int lim = kring->nkr_num_slots - 1, 528847bf383SLuigi Rizzo mlim; // = mkring->nkr_num_slots - 1; 529847bf383SLuigi Rizzo 530847bf383SLuigi Rizzo if (mkring == NULL) { 531847bf383SLuigi Rizzo RD(5, "NULL monitor on %s", kring->name); 532847bf383SLuigi Rizzo return 0; 533847bf383SLuigi Rizzo } 534847bf383SLuigi Rizzo mring = mkring->ring; 5354bf50f18SLuigi Rizzo mlim = mkring->nkr_num_slots - 1; 5364bf50f18SLuigi Rizzo 5374bf50f18SLuigi Rizzo /* get the relased slots (rel_slots) */ 538847bf383SLuigi Rizzo if (tx == NR_TX) { 539*c3e9b4dbSLuiz Otavio O Souza beg = kring->nr_hwtail + 1; 540847bf383SLuigi Rizzo error = kring->mon_sync(kring, flags); 5414bf50f18SLuigi Rizzo if (error) 5424bf50f18SLuigi Rizzo return error; 543*c3e9b4dbSLuiz Otavio O Souza end = kring->nr_hwtail + 1; 544847bf383SLuigi Rizzo } else { /* NR_RX */ 545847bf383SLuigi Rizzo beg = kring->nr_hwcur; 546847bf383SLuigi Rizzo end = kring->rhead; 547847bf383SLuigi Rizzo } 548847bf383SLuigi Rizzo 5494bf50f18SLuigi Rizzo rel_slots = end - beg; 5504bf50f18SLuigi Rizzo if (rel_slots < 0) 5514bf50f18SLuigi Rizzo rel_slots += kring->nkr_num_slots; 5524bf50f18SLuigi Rizzo 5534bf50f18SLuigi Rizzo if (!rel_slots) { 554847bf383SLuigi Rizzo /* no released slots, but we still need 555847bf383SLuigi Rizzo * to call rxsync if this is a rx ring 556847bf383SLuigi Rizzo */ 557847bf383SLuigi Rizzo goto out_rxsync; 5584bf50f18SLuigi Rizzo } 5594bf50f18SLuigi Rizzo 5604bf50f18SLuigi Rizzo /* we need to lock the monitor receive ring, since it 5614bf50f18SLuigi Rizzo * is the target of bot tx and rx traffic from the monitored 5624bf50f18SLuigi Rizzo * adapter 5634bf50f18SLuigi Rizzo */ 5644bf50f18SLuigi Rizzo mtx_lock(&mkring->q_lock); 5654bf50f18SLuigi Rizzo /* get the free slots available on the monitor ring */ 5664bf50f18SLuigi Rizzo i = mkring->nr_hwtail; 5674bf50f18SLuigi Rizzo busy = i - mkring->nr_hwcur; 5684bf50f18SLuigi Rizzo if (busy < 0) 5694bf50f18SLuigi Rizzo busy += mkring->nkr_num_slots; 5704bf50f18SLuigi Rizzo free_slots = mlim - busy; 5714bf50f18SLuigi Rizzo 572847bf383SLuigi Rizzo if (!free_slots) 573847bf383SLuigi Rizzo goto out; 5744bf50f18SLuigi Rizzo 5754bf50f18SLuigi Rizzo /* swap min(free_slots, rel_slots) slots */ 5764bf50f18SLuigi Rizzo if (free_slots < rel_slots) { 5774bf50f18SLuigi Rizzo beg += (rel_slots - free_slots); 5784bf50f18SLuigi Rizzo rel_slots = free_slots; 5794bf50f18SLuigi Rizzo } 580*c3e9b4dbSLuiz Otavio O Souza if (unlikely(beg >= kring->nkr_num_slots)) 581*c3e9b4dbSLuiz Otavio O Souza beg -= kring->nkr_num_slots; 5824bf50f18SLuigi Rizzo 583847bf383SLuigi Rizzo sent = rel_slots; 5844bf50f18SLuigi Rizzo for ( ; rel_slots; rel_slots--) { 5854bf50f18SLuigi Rizzo struct netmap_slot *s = &ring->slot[beg]; 5864bf50f18SLuigi Rizzo struct netmap_slot *ms = &mring->slot[i]; 5874bf50f18SLuigi Rizzo uint32_t tmp; 5884bf50f18SLuigi Rizzo 5894bf50f18SLuigi Rizzo tmp = ms->buf_idx; 5904bf50f18SLuigi Rizzo ms->buf_idx = s->buf_idx; 5914bf50f18SLuigi Rizzo s->buf_idx = tmp; 592847bf383SLuigi Rizzo ND(5, "beg %d buf_idx %d", beg, tmp); 5934bf50f18SLuigi Rizzo 5944bf50f18SLuigi Rizzo tmp = ms->len; 5954bf50f18SLuigi Rizzo ms->len = s->len; 5964bf50f18SLuigi Rizzo s->len = tmp; 5974bf50f18SLuigi Rizzo 5984bf50f18SLuigi Rizzo s->flags |= NS_BUF_CHANGED; 5994bf50f18SLuigi Rizzo 6004bf50f18SLuigi Rizzo beg = nm_next(beg, lim); 6014bf50f18SLuigi Rizzo i = nm_next(i, mlim); 6024bf50f18SLuigi Rizzo 6034bf50f18SLuigi Rizzo } 604ad15cc59SLuigi Rizzo mb(); 6054bf50f18SLuigi Rizzo mkring->nr_hwtail = i; 6064bf50f18SLuigi Rizzo 607847bf383SLuigi Rizzo out: 6084bf50f18SLuigi Rizzo mtx_unlock(&mkring->q_lock); 609847bf383SLuigi Rizzo 610847bf383SLuigi Rizzo if (sent) { 6114bf50f18SLuigi Rizzo /* notify the new frames to the monitor */ 612847bf383SLuigi Rizzo mkring->nm_notify(mkring, 0); 613847bf383SLuigi Rizzo } 614847bf383SLuigi Rizzo 615847bf383SLuigi Rizzo out_rxsync: 616847bf383SLuigi Rizzo if (tx == NR_RX) 617847bf383SLuigi Rizzo error = kring->mon_sync(kring, flags); 618847bf383SLuigi Rizzo 619847bf383SLuigi Rizzo return error; 620847bf383SLuigi Rizzo } 621847bf383SLuigi Rizzo 622847bf383SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored tx rings */ 623847bf383SLuigi Rizzo static int 624847bf383SLuigi Rizzo netmap_zmon_parent_txsync(struct netmap_kring *kring, int flags) 625847bf383SLuigi Rizzo { 626847bf383SLuigi Rizzo return netmap_zmon_parent_sync(kring, flags, NR_TX); 627847bf383SLuigi Rizzo } 628847bf383SLuigi Rizzo 629847bf383SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored rx rings */ 630847bf383SLuigi Rizzo static int 631847bf383SLuigi Rizzo netmap_zmon_parent_rxsync(struct netmap_kring *kring, int flags) 632847bf383SLuigi Rizzo { 633847bf383SLuigi Rizzo return netmap_zmon_parent_sync(kring, flags, NR_RX); 634847bf383SLuigi Rizzo } 635847bf383SLuigi Rizzo 636847bf383SLuigi Rizzo static int 637847bf383SLuigi Rizzo netmap_zmon_reg(struct netmap_adapter *na, int onoff) 638847bf383SLuigi Rizzo { 639847bf383SLuigi Rizzo return netmap_monitor_reg_common(na, onoff, 1 /* zcopy */); 640847bf383SLuigi Rizzo } 641847bf383SLuigi Rizzo 642847bf383SLuigi Rizzo /* nm_dtor callback for monitors */ 643847bf383SLuigi Rizzo static void 644847bf383SLuigi Rizzo netmap_zmon_dtor(struct netmap_adapter *na) 645847bf383SLuigi Rizzo { 646847bf383SLuigi Rizzo struct netmap_monitor_adapter *mna = 647847bf383SLuigi Rizzo (struct netmap_monitor_adapter *)na; 648847bf383SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 649847bf383SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 650847bf383SLuigi Rizzo 651847bf383SLuigi Rizzo netmap_adapter_put(pna); 652847bf383SLuigi Rizzo } 653847bf383SLuigi Rizzo 654847bf383SLuigi Rizzo /* 655847bf383SLuigi Rizzo **************************************************************** 656847bf383SLuigi Rizzo * functions specific for copy monitors 657847bf383SLuigi Rizzo **************************************************************** 658847bf383SLuigi Rizzo */ 659847bf383SLuigi Rizzo 660847bf383SLuigi Rizzo static void 661847bf383SLuigi Rizzo netmap_monitor_parent_sync(struct netmap_kring *kring, u_int first_new, int new_slots) 662847bf383SLuigi Rizzo { 663847bf383SLuigi Rizzo u_int j; 664847bf383SLuigi Rizzo 665847bf383SLuigi Rizzo for (j = 0; j < kring->n_monitors; j++) { 666847bf383SLuigi Rizzo struct netmap_kring *mkring = kring->monitors[j]; 667847bf383SLuigi Rizzo u_int i, mlim, beg; 668847bf383SLuigi Rizzo int free_slots, busy, sent = 0, m; 669847bf383SLuigi Rizzo u_int lim = kring->nkr_num_slots - 1; 670847bf383SLuigi Rizzo struct netmap_ring *ring = kring->ring, *mring = mkring->ring; 671847bf383SLuigi Rizzo u_int max_len = NETMAP_BUF_SIZE(mkring->na); 672847bf383SLuigi Rizzo 673847bf383SLuigi Rizzo mlim = mkring->nkr_num_slots - 1; 674847bf383SLuigi Rizzo 675847bf383SLuigi Rizzo /* we need to lock the monitor receive ring, since it 676847bf383SLuigi Rizzo * is the target of bot tx and rx traffic from the monitored 677847bf383SLuigi Rizzo * adapter 678847bf383SLuigi Rizzo */ 679847bf383SLuigi Rizzo mtx_lock(&mkring->q_lock); 680847bf383SLuigi Rizzo /* get the free slots available on the monitor ring */ 681847bf383SLuigi Rizzo i = mkring->nr_hwtail; 682847bf383SLuigi Rizzo busy = i - mkring->nr_hwcur; 683847bf383SLuigi Rizzo if (busy < 0) 684847bf383SLuigi Rizzo busy += mkring->nkr_num_slots; 685847bf383SLuigi Rizzo free_slots = mlim - busy; 686847bf383SLuigi Rizzo 687847bf383SLuigi Rizzo if (!free_slots) 688847bf383SLuigi Rizzo goto out; 689847bf383SLuigi Rizzo 690847bf383SLuigi Rizzo /* copy min(free_slots, new_slots) slots */ 691847bf383SLuigi Rizzo m = new_slots; 692847bf383SLuigi Rizzo beg = first_new; 693847bf383SLuigi Rizzo if (free_slots < m) { 694847bf383SLuigi Rizzo beg += (m - free_slots); 695847bf383SLuigi Rizzo if (beg >= kring->nkr_num_slots) 696847bf383SLuigi Rizzo beg -= kring->nkr_num_slots; 697847bf383SLuigi Rizzo m = free_slots; 698847bf383SLuigi Rizzo } 699847bf383SLuigi Rizzo 700847bf383SLuigi Rizzo for ( ; m; m--) { 701847bf383SLuigi Rizzo struct netmap_slot *s = &ring->slot[beg]; 702847bf383SLuigi Rizzo struct netmap_slot *ms = &mring->slot[i]; 703847bf383SLuigi Rizzo u_int copy_len = s->len; 704847bf383SLuigi Rizzo char *src = NMB(kring->na, s), 705847bf383SLuigi Rizzo *dst = NMB(mkring->na, ms); 706847bf383SLuigi Rizzo 707847bf383SLuigi Rizzo if (unlikely(copy_len > max_len)) { 708847bf383SLuigi Rizzo RD(5, "%s->%s: truncating %d to %d", kring->name, 709847bf383SLuigi Rizzo mkring->name, copy_len, max_len); 710847bf383SLuigi Rizzo copy_len = max_len; 711847bf383SLuigi Rizzo } 712847bf383SLuigi Rizzo 713847bf383SLuigi Rizzo memcpy(dst, src, copy_len); 714847bf383SLuigi Rizzo ms->len = copy_len; 715847bf383SLuigi Rizzo sent++; 716847bf383SLuigi Rizzo 717847bf383SLuigi Rizzo beg = nm_next(beg, lim); 718847bf383SLuigi Rizzo i = nm_next(i, mlim); 719847bf383SLuigi Rizzo } 720847bf383SLuigi Rizzo mb(); 721847bf383SLuigi Rizzo mkring->nr_hwtail = i; 722847bf383SLuigi Rizzo out: 723847bf383SLuigi Rizzo mtx_unlock(&mkring->q_lock); 724847bf383SLuigi Rizzo 725847bf383SLuigi Rizzo if (sent) { 726847bf383SLuigi Rizzo /* notify the new frames to the monitor */ 727847bf383SLuigi Rizzo mkring->nm_notify(mkring, 0); 728847bf383SLuigi Rizzo } 729847bf383SLuigi Rizzo } 7304bf50f18SLuigi Rizzo } 7314bf50f18SLuigi Rizzo 7324bf50f18SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored tx rings */ 7334bf50f18SLuigi Rizzo static int 7344bf50f18SLuigi Rizzo netmap_monitor_parent_txsync(struct netmap_kring *kring, int flags) 7354bf50f18SLuigi Rizzo { 736847bf383SLuigi Rizzo u_int first_new; 737847bf383SLuigi Rizzo int new_slots; 738847bf383SLuigi Rizzo 739847bf383SLuigi Rizzo /* get the new slots */ 740*c3e9b4dbSLuiz Otavio O Souza if (kring->n_monitors > 0) { 741847bf383SLuigi Rizzo first_new = kring->nr_hwcur; 742847bf383SLuigi Rizzo new_slots = kring->rhead - first_new; 743847bf383SLuigi Rizzo if (new_slots < 0) 744847bf383SLuigi Rizzo new_slots += kring->nkr_num_slots; 745847bf383SLuigi Rizzo if (new_slots) 746847bf383SLuigi Rizzo netmap_monitor_parent_sync(kring, first_new, new_slots); 747*c3e9b4dbSLuiz Otavio O Souza } 748*c3e9b4dbSLuiz Otavio O Souza if (kring->zmon_list[NR_TX].next != NULL) { 749*c3e9b4dbSLuiz Otavio O Souza return netmap_zmon_parent_txsync(kring, flags); 750*c3e9b4dbSLuiz Otavio O Souza } 751847bf383SLuigi Rizzo return kring->mon_sync(kring, flags); 7524bf50f18SLuigi Rizzo } 7534bf50f18SLuigi Rizzo 7544bf50f18SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored rx rings */ 7554bf50f18SLuigi Rizzo static int 7564bf50f18SLuigi Rizzo netmap_monitor_parent_rxsync(struct netmap_kring *kring, int flags) 7574bf50f18SLuigi Rizzo { 758847bf383SLuigi Rizzo u_int first_new; 759847bf383SLuigi Rizzo int new_slots, error; 7604bf50f18SLuigi Rizzo 761847bf383SLuigi Rizzo /* get the new slots */ 762*c3e9b4dbSLuiz Otavio O Souza if (kring->zmon_list[NR_RX].next != NULL) { 763*c3e9b4dbSLuiz Otavio O Souza error = netmap_zmon_parent_rxsync(kring, flags); 764*c3e9b4dbSLuiz Otavio O Souza } else { 765847bf383SLuigi Rizzo error = kring->mon_sync(kring, flags); 766*c3e9b4dbSLuiz Otavio O Souza } 767847bf383SLuigi Rizzo if (error) 768847bf383SLuigi Rizzo return error; 769*c3e9b4dbSLuiz Otavio O Souza if (kring->n_monitors > 0) { 770847bf383SLuigi Rizzo first_new = kring->mon_tail; 771847bf383SLuigi Rizzo new_slots = kring->nr_hwtail - first_new; 772847bf383SLuigi Rizzo if (new_slots < 0) 773847bf383SLuigi Rizzo new_slots += kring->nkr_num_slots; 774847bf383SLuigi Rizzo if (new_slots) 775847bf383SLuigi Rizzo netmap_monitor_parent_sync(kring, first_new, new_slots); 776847bf383SLuigi Rizzo kring->mon_tail = kring->nr_hwtail; 777*c3e9b4dbSLuiz Otavio O Souza } 7784bf50f18SLuigi Rizzo return 0; 7794bf50f18SLuigi Rizzo } 7804bf50f18SLuigi Rizzo 781847bf383SLuigi Rizzo /* callback used to replace the nm_notify() callback in the monitored rx rings */ 7824bf50f18SLuigi Rizzo static int 783847bf383SLuigi Rizzo netmap_monitor_parent_notify(struct netmap_kring *kring, int flags) 7844bf50f18SLuigi Rizzo { 78537e3a6d3SLuigi Rizzo int (*notify)(struct netmap_kring*, int); 786847bf383SLuigi Rizzo ND(5, "%s %x", kring->name, flags); 787847bf383SLuigi Rizzo /* ?xsync callbacks have tryget called by their callers 788847bf383SLuigi Rizzo * (NIOCREGIF and poll()), but here we have to call it 789847bf383SLuigi Rizzo * by ourself 790847bf383SLuigi Rizzo */ 79137e3a6d3SLuigi Rizzo if (nm_kr_tryget(kring, 0, NULL)) { 79237e3a6d3SLuigi Rizzo /* in all cases, just skip the sync */ 79337e3a6d3SLuigi Rizzo return NM_IRQ_COMPLETED; 79437e3a6d3SLuigi Rizzo } 79537e3a6d3SLuigi Rizzo if (kring->n_monitors > 0) { 796847bf383SLuigi Rizzo netmap_monitor_parent_rxsync(kring, NAF_FORCE_READ); 797*c3e9b4dbSLuiz Otavio O Souza } 798*c3e9b4dbSLuiz Otavio O Souza if (nm_monitor_none(kring)) { 79937e3a6d3SLuigi Rizzo /* we are no longer monitoring this ring, so both 80037e3a6d3SLuigi Rizzo * mon_sync and mon_notify are NULL 80137e3a6d3SLuigi Rizzo */ 80237e3a6d3SLuigi Rizzo notify = kring->nm_notify; 803*c3e9b4dbSLuiz Otavio O Souza } else { 804*c3e9b4dbSLuiz Otavio O Souza notify = kring->mon_notify; 80537e3a6d3SLuigi Rizzo } 806847bf383SLuigi Rizzo nm_kr_put(kring); 80737e3a6d3SLuigi Rizzo return notify(kring, flags); 8084bf50f18SLuigi Rizzo } 8094bf50f18SLuigi Rizzo 8104bf50f18SLuigi Rizzo 8114bf50f18SLuigi Rizzo static int 8124bf50f18SLuigi Rizzo netmap_monitor_reg(struct netmap_adapter *na, int onoff) 8134bf50f18SLuigi Rizzo { 814847bf383SLuigi Rizzo return netmap_monitor_reg_common(na, onoff, 0 /* no zcopy */); 8154bf50f18SLuigi Rizzo } 8164bf50f18SLuigi Rizzo 8174bf50f18SLuigi Rizzo static void 8184bf50f18SLuigi Rizzo netmap_monitor_dtor(struct netmap_adapter *na) 8194bf50f18SLuigi Rizzo { 8204bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna = 8214bf50f18SLuigi Rizzo (struct netmap_monitor_adapter *)na; 8224bf50f18SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 8234bf50f18SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 8244bf50f18SLuigi Rizzo 8254bf50f18SLuigi Rizzo netmap_adapter_put(pna); 8264bf50f18SLuigi Rizzo } 8274bf50f18SLuigi Rizzo 8284bf50f18SLuigi Rizzo 8294bf50f18SLuigi Rizzo /* check if nmr is a request for a monitor adapter that we can satisfy */ 8304bf50f18SLuigi Rizzo int 831*c3e9b4dbSLuiz Otavio O Souza netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na, 832*c3e9b4dbSLuiz Otavio O Souza struct netmap_mem_d *nmd, int create) 8334bf50f18SLuigi Rizzo { 8344bf50f18SLuigi Rizzo struct nmreq pnmr; 8354bf50f18SLuigi Rizzo struct netmap_adapter *pna; /* parent adapter */ 8364bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna; 83737e3a6d3SLuigi Rizzo struct ifnet *ifp = NULL; 838*c3e9b4dbSLuiz Otavio O Souza int error; 839847bf383SLuigi Rizzo int zcopy = (nmr->nr_flags & NR_ZCOPY_MON); 840847bf383SLuigi Rizzo char monsuff[10] = ""; 8414bf50f18SLuigi Rizzo 842*c3e9b4dbSLuiz Otavio O Souza if (zcopy) { 843*c3e9b4dbSLuiz Otavio O Souza nmr->nr_flags |= (NR_MONITOR_TX | NR_MONITOR_RX); 84437e3a6d3SLuigi Rizzo } 845*c3e9b4dbSLuiz Otavio O Souza if ((nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) { 8464bf50f18SLuigi Rizzo ND("not a monitor"); 8474bf50f18SLuigi Rizzo return 0; 8484bf50f18SLuigi Rizzo } 8494bf50f18SLuigi Rizzo /* this is a request for a monitor adapter */ 8504bf50f18SLuigi Rizzo 85137e3a6d3SLuigi Rizzo ND("flags %x", nmr->nr_flags); 8524bf50f18SLuigi Rizzo 8534bf50f18SLuigi Rizzo /* first, try to find the adapter that we want to monitor 8544bf50f18SLuigi Rizzo * We use the same nmr, after we have turned off the monitor flags. 8554bf50f18SLuigi Rizzo * In this way we can potentially monitor everything netmap understands, 8564bf50f18SLuigi Rizzo * except other monitors. 8574bf50f18SLuigi Rizzo */ 8584bf50f18SLuigi Rizzo memcpy(&pnmr, nmr, sizeof(pnmr)); 85937e3a6d3SLuigi Rizzo pnmr.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON); 860*c3e9b4dbSLuiz Otavio O Souza error = netmap_get_na(&pnmr, &pna, &ifp, nmd, create); 8614bf50f18SLuigi Rizzo if (error) { 8624bf50f18SLuigi Rizzo D("parent lookup failed: %d", error); 8634bf50f18SLuigi Rizzo return error; 8644bf50f18SLuigi Rizzo } 86537e3a6d3SLuigi Rizzo ND("found parent: %s", pna->name); 8664bf50f18SLuigi Rizzo 8674bf50f18SLuigi Rizzo if (!nm_netmap_on(pna)) { 8684bf50f18SLuigi Rizzo /* parent not in netmap mode */ 8694bf50f18SLuigi Rizzo /* XXX we can wait for the parent to enter netmap mode, 8704bf50f18SLuigi Rizzo * by intercepting its nm_register callback (2014-03-16) 8714bf50f18SLuigi Rizzo */ 8724bf50f18SLuigi Rizzo D("%s not in netmap mode", pna->name); 8734bf50f18SLuigi Rizzo error = EINVAL; 8744bf50f18SLuigi Rizzo goto put_out; 8754bf50f18SLuigi Rizzo } 8764bf50f18SLuigi Rizzo 877*c3e9b4dbSLuiz Otavio O Souza mna = nm_os_malloc(sizeof(*mna)); 878*c3e9b4dbSLuiz Otavio O Souza if (mna == NULL) { 879*c3e9b4dbSLuiz Otavio O Souza D("memory error"); 880*c3e9b4dbSLuiz Otavio O Souza error = ENOMEM; 881*c3e9b4dbSLuiz Otavio O Souza goto put_out; 882*c3e9b4dbSLuiz Otavio O Souza } 8834bf50f18SLuigi Rizzo mna->priv.np_na = pna; 884*c3e9b4dbSLuiz Otavio O Souza 885*c3e9b4dbSLuiz Otavio O Souza /* grab all the rings we need in the parent */ 8864bf50f18SLuigi Rizzo error = netmap_interp_ringid(&mna->priv, nmr->nr_ringid, nmr->nr_flags); 8874bf50f18SLuigi Rizzo if (error) { 8884bf50f18SLuigi Rizzo D("ringid error"); 889*c3e9b4dbSLuiz Otavio O Souza goto free_out; 8904bf50f18SLuigi Rizzo } 891847bf383SLuigi Rizzo if (mna->priv.np_qlast[NR_TX] - mna->priv.np_qfirst[NR_TX] == 1) { 892847bf383SLuigi Rizzo snprintf(monsuff, 10, "-%d", mna->priv.np_qfirst[NR_TX]); 893847bf383SLuigi Rizzo } 894847bf383SLuigi Rizzo snprintf(mna->up.name, sizeof(mna->up.name), "%s%s/%s%s%s", pna->name, 895847bf383SLuigi Rizzo monsuff, 896847bf383SLuigi Rizzo zcopy ? "z" : "", 897847bf383SLuigi Rizzo (nmr->nr_flags & NR_MONITOR_RX) ? "r" : "", 898847bf383SLuigi Rizzo (nmr->nr_flags & NR_MONITOR_TX) ? "t" : ""); 899847bf383SLuigi Rizzo 900847bf383SLuigi Rizzo /* the monitor supports the host rings iff the parent does */ 901*c3e9b4dbSLuiz Otavio O Souza mna->up.na_flags |= (pna->na_flags & NAF_HOST_RINGS); 902847bf383SLuigi Rizzo /* a do-nothing txsync: monitors cannot be used to inject packets */ 903847bf383SLuigi Rizzo mna->up.nm_txsync = netmap_monitor_txsync; 904847bf383SLuigi Rizzo mna->up.nm_rxsync = netmap_monitor_rxsync; 9054bf50f18SLuigi Rizzo mna->up.nm_krings_create = netmap_monitor_krings_create; 9064bf50f18SLuigi Rizzo mna->up.nm_krings_delete = netmap_monitor_krings_delete; 907*c3e9b4dbSLuiz Otavio O Souza mna->up.num_tx_rings = 1; // XXX what should we do here with chained zmons? 9084bf50f18SLuigi Rizzo /* we set the number of our rx_rings to be max(num_rx_rings, num_rx_rings) 9094bf50f18SLuigi Rizzo * in the parent 9104bf50f18SLuigi Rizzo */ 9114bf50f18SLuigi Rizzo mna->up.num_rx_rings = pna->num_rx_rings; 9124bf50f18SLuigi Rizzo if (pna->num_tx_rings > pna->num_rx_rings) 9134bf50f18SLuigi Rizzo mna->up.num_rx_rings = pna->num_tx_rings; 9144bf50f18SLuigi Rizzo /* by default, the number of slots is the same as in 9154bf50f18SLuigi Rizzo * the parent rings, but the user may ask for a different 9164bf50f18SLuigi Rizzo * number 9174bf50f18SLuigi Rizzo */ 9184bf50f18SLuigi Rizzo mna->up.num_tx_desc = nmr->nr_tx_slots; 9194bf50f18SLuigi Rizzo nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc, 9204bf50f18SLuigi Rizzo 1, NM_MONITOR_MAXSLOTS, NULL); 9214bf50f18SLuigi Rizzo mna->up.num_rx_desc = nmr->nr_rx_slots; 9224bf50f18SLuigi Rizzo nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc, 9234bf50f18SLuigi Rizzo 1, NM_MONITOR_MAXSLOTS, NULL); 924*c3e9b4dbSLuiz Otavio O Souza if (zcopy) { 925*c3e9b4dbSLuiz Otavio O Souza mna->up.nm_register = netmap_zmon_reg; 926*c3e9b4dbSLuiz Otavio O Souza mna->up.nm_dtor = netmap_zmon_dtor; 927*c3e9b4dbSLuiz Otavio O Souza /* to have zero copy, we need to use the same memory allocator 928*c3e9b4dbSLuiz Otavio O Souza * as the monitored port 929*c3e9b4dbSLuiz Otavio O Souza */ 930*c3e9b4dbSLuiz Otavio O Souza mna->up.nm_mem = netmap_mem_get(pna->nm_mem); 931*c3e9b4dbSLuiz Otavio O Souza /* and the allocator cannot be changed */ 932*c3e9b4dbSLuiz Otavio O Souza mna->up.na_flags |= NAF_MEM_OWNER; 933*c3e9b4dbSLuiz Otavio O Souza } else { 934*c3e9b4dbSLuiz Otavio O Souza mna->up.nm_register = netmap_monitor_reg; 935*c3e9b4dbSLuiz Otavio O Souza mna->up.nm_dtor = netmap_monitor_dtor; 936*c3e9b4dbSLuiz Otavio O Souza mna->up.nm_mem = netmap_mem_private_new( 937*c3e9b4dbSLuiz Otavio O Souza mna->up.num_tx_rings, 938*c3e9b4dbSLuiz Otavio O Souza mna->up.num_tx_desc, 939*c3e9b4dbSLuiz Otavio O Souza mna->up.num_rx_rings, 940*c3e9b4dbSLuiz Otavio O Souza mna->up.num_rx_desc, 941*c3e9b4dbSLuiz Otavio O Souza 0, /* extra bufs */ 942*c3e9b4dbSLuiz Otavio O Souza 0, /* pipes */ 943*c3e9b4dbSLuiz Otavio O Souza &error); 944*c3e9b4dbSLuiz Otavio O Souza if (mna->up.nm_mem == NULL) 945847bf383SLuigi Rizzo goto put_out; 9464bf50f18SLuigi Rizzo } 9474bf50f18SLuigi Rizzo 948*c3e9b4dbSLuiz Otavio O Souza error = netmap_attach_common(&mna->up); 949*c3e9b4dbSLuiz Otavio O Souza if (error) { 950*c3e9b4dbSLuiz Otavio O Souza D("attach_common error"); 951*c3e9b4dbSLuiz Otavio O Souza goto mem_put_out; 952*c3e9b4dbSLuiz Otavio O Souza } 953*c3e9b4dbSLuiz Otavio O Souza 9544bf50f18SLuigi Rizzo /* remember the traffic directions we have to monitor */ 955*c3e9b4dbSLuiz Otavio O Souza mna->flags = (nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON)); 9564bf50f18SLuigi Rizzo 9574bf50f18SLuigi Rizzo *na = &mna->up; 9584bf50f18SLuigi Rizzo netmap_adapter_get(*na); 9594bf50f18SLuigi Rizzo 9604bf50f18SLuigi Rizzo /* keep the reference to the parent */ 96137e3a6d3SLuigi Rizzo ND("monitor ok"); 96237e3a6d3SLuigi Rizzo 96337e3a6d3SLuigi Rizzo /* drop the reference to the ifp, if any */ 96437e3a6d3SLuigi Rizzo if (ifp) 96537e3a6d3SLuigi Rizzo if_rele(ifp); 9664bf50f18SLuigi Rizzo 9674bf50f18SLuigi Rizzo return 0; 9684bf50f18SLuigi Rizzo 969*c3e9b4dbSLuiz Otavio O Souza mem_put_out: 970*c3e9b4dbSLuiz Otavio O Souza netmap_mem_put(mna->up.nm_mem); 971*c3e9b4dbSLuiz Otavio O Souza free_out: 972*c3e9b4dbSLuiz Otavio O Souza nm_os_free(mna); 9734bf50f18SLuigi Rizzo put_out: 97437e3a6d3SLuigi Rizzo netmap_unget_na(pna, ifp); 9754bf50f18SLuigi Rizzo return error; 9764bf50f18SLuigi Rizzo } 9774bf50f18SLuigi Rizzo 9784bf50f18SLuigi Rizzo 9794bf50f18SLuigi Rizzo #endif /* WITH_MONITOR */ 980