1270063Sluigi/* 2341477Svmaffione * Copyright (C) 2014-2016 Giuseppe Lettieri 3341477Svmaffione * All rights reserved. 4270063Sluigi * 5270063Sluigi * Redistribution and use in source and binary forms, with or without 6270063Sluigi * modification, are permitted provided that the following conditions 7270063Sluigi * are met: 8270063Sluigi * 1. Redistributions of source code must retain the above copyright 9270063Sluigi * notice, this list of conditions and the following disclaimer. 10270063Sluigi * 2. Redistributions in binary form must reproduce the above copyright 11270063Sluigi * notice, this list of conditions and the following disclaimer in the 12270063Sluigi * documentation and/or other materials provided with the distribution. 13270063Sluigi * 14270063Sluigi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15270063Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16270063Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17270063Sluigi * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18270063Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19270063Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20270063Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21270063Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22270063Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23270063Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24270063Sluigi * SUCH DAMAGE. 25270063Sluigi */ 26270063Sluigi 27270063Sluigi/* 28270063Sluigi * $FreeBSD: stable/11/sys/dev/netmap/netmap_monitor.c 344047 2019-02-12 09:26:05Z vmaffione $ 29270063Sluigi * 30270063Sluigi * Monitors 31270063Sluigi * 32285349Sluigi * netmap monitors can be used to do monitoring of network traffic 33270063Sluigi * on another adapter, when the latter adapter is working in netmap mode. 34270063Sluigi * 35270063Sluigi * Monitors offer to userspace the same interface as any other netmap port, 36270063Sluigi * with as many pairs of netmap rings as the monitored adapter. 37270063Sluigi * However, only the rx rings are actually used. Each monitor rx ring receives 38270063Sluigi * the traffic transiting on both the tx and rx corresponding rings in the 39270063Sluigi * monitored adapter. During registration, the user can choose if she wants 40270063Sluigi * to intercept tx only, rx only, or both tx and rx traffic. 41270063Sluigi * 42285349Sluigi * If the monitor is not able to cope with the stream of frames, excess traffic 43285349Sluigi * will be dropped. 44270063Sluigi * 45285349Sluigi * If the monitored adapter leaves netmap mode, the monitor has to be restarted. 46285349Sluigi * 47285349Sluigi * Monitors can be either zero-copy or copy-based. 48285349Sluigi * 49285349Sluigi * Copy monitors see the frames before they are consumed: 50285349Sluigi * 51285349Sluigi * - For tx traffic, this is when the application sends them, before they are 52285349Sluigi * passed down to the adapter. 53285349Sluigi * 54285349Sluigi * - For rx traffic, this is when they are received by the adapter, before 55285349Sluigi * they are sent up to the application, if any (note that, if no 56285349Sluigi * application is reading from a monitored ring, the ring will eventually 57285349Sluigi * fill up and traffic will stop). 58285349Sluigi * 59285349Sluigi * Zero-copy monitors only see the frames after they have been consumed: 60285349Sluigi * 61270063Sluigi * - For tx traffic, this is after the slots containing the frames have been 62270063Sluigi * marked as free. Note that this may happen at a considerably delay after 63270063Sluigi * frame transmission, since freeing of slots is often done lazily. 64270063Sluigi * 65270063Sluigi * - For rx traffic, this is after the consumer on the monitored adapter 66270063Sluigi * has released them. In most cases, the consumer is a userspace 67270063Sluigi * application which may have modified the frame contents. 68270063Sluigi * 69341477Svmaffione * Several copy or zero-copy monitors may be active on any ring. 70270063Sluigi * 71270063Sluigi */ 72270063Sluigi 73270063Sluigi 74270063Sluigi#if defined(__FreeBSD__) 75270063Sluigi#include <sys/cdefs.h> /* prerequisite */ 76270063Sluigi 77270063Sluigi#include <sys/types.h> 78270063Sluigi#include <sys/errno.h> 79270063Sluigi#include <sys/param.h> /* defines used in kernel.h */ 80270063Sluigi#include <sys/kernel.h> /* types used in module initialization */ 81270063Sluigi#include <sys/malloc.h> 82270063Sluigi#include <sys/poll.h> 83270063Sluigi#include <sys/lock.h> 84270063Sluigi#include <sys/rwlock.h> 85270063Sluigi#include <sys/selinfo.h> 86270063Sluigi#include <sys/sysctl.h> 87270063Sluigi#include <sys/socket.h> /* sockaddrs */ 88270063Sluigi#include <net/if.h> 89270063Sluigi#include <net/if_var.h> 90270063Sluigi#include <machine/bus.h> /* bus_dmamap_* */ 91270063Sluigi#include <sys/refcount.h> 92270063Sluigi 93270063Sluigi 94270063Sluigi#elif defined(linux) 95270063Sluigi 96270063Sluigi#include "bsd_glue.h" 97270063Sluigi 98270063Sluigi#elif defined(__APPLE__) 99270063Sluigi 100270063Sluigi#warning OSX support is only partial 101270063Sluigi#include "osx_glue.h" 102270063Sluigi 103341477Svmaffione#elif defined(_WIN32) 104341477Svmaffione#include "win_glue.h" 105270063Sluigi#else 106270063Sluigi 107270063Sluigi#error Unsupported platform 108270063Sluigi 109270063Sluigi#endif /* unsupported */ 110270063Sluigi 111270063Sluigi/* 112270063Sluigi * common headers 113270063Sluigi */ 114270063Sluigi 115270063Sluigi#include <net/netmap.h> 116270063Sluigi#include <dev/netmap/netmap_kern.h> 117270063Sluigi#include <dev/netmap/netmap_mem2.h> 118270063Sluigi 119270063Sluigi#ifdef WITH_MONITOR 120270063Sluigi 121270063Sluigi#define NM_MONITOR_MAXSLOTS 4096 122270063Sluigi 123285349Sluigi/* 124285349Sluigi ******************************************************************** 125285349Sluigi * functions common to both kind of monitors 126285349Sluigi ******************************************************************** 127270063Sluigi */ 128285349Sluigi 129341477Svmaffionestatic int netmap_zmon_reg(struct netmap_adapter *, int); 130341477Svmaffionestatic int 131341477Svmaffionenm_is_zmon(struct netmap_adapter *na) 132341477Svmaffione{ 133341477Svmaffione return na->nm_register == netmap_zmon_reg; 134341477Svmaffione} 135341477Svmaffione 136285349Sluigi/* nm_sync callback for the monitor's own tx rings. 137285349Sluigi * This makes no sense and always returns error 138285349Sluigi */ 139270063Sluigistatic int 140285349Sluiginetmap_monitor_txsync(struct netmap_kring *kring, int flags) 141270063Sluigi{ 142344047Svmaffione nm_prlim(1, "%s %x", kring->name, flags); 143285349Sluigi return EIO; 144285349Sluigi} 145285349Sluigi 146285349Sluigi/* nm_sync callback for the monitor's own rx rings. 147285349Sluigi * Note that the lock in netmap_zmon_parent_sync only protects 148285349Sluigi * writers among themselves. Synchronization between writers 149285349Sluigi * (i.e., netmap_zmon_parent_txsync and netmap_zmon_parent_rxsync) 150285349Sluigi * and readers (i.e., netmap_zmon_rxsync) relies on memory barriers. 151285349Sluigi */ 152285349Sluigistatic int 153285349Sluiginetmap_monitor_rxsync(struct netmap_kring *kring, int flags) 154285349Sluigi{ 155341477Svmaffione struct netmap_monitor_adapter *mna = 156341477Svmaffione (struct netmap_monitor_adapter *)kring->na; 157341477Svmaffione if (unlikely(mna->priv.np_na == NULL)) { 158341477Svmaffione /* parent left netmap mode */ 159341477Svmaffione return EIO; 160341477Svmaffione } 161344047Svmaffione nm_prdis("%s %x", kring->name, flags); 162341477Svmaffione kring->nr_hwcur = kring->rhead; 163285349Sluigi mb(); 164341477Svmaffione return 0; 165285349Sluigi} 166285349Sluigi 167285349Sluigi/* nm_krings_create callbacks for monitors. 168285349Sluigi */ 169285349Sluigistatic int 170285349Sluiginetmap_monitor_krings_create(struct netmap_adapter *na) 171285349Sluigi{ 172341477Svmaffione int error = netmap_krings_create(na, 0); 173341477Svmaffione enum txrx t; 174341477Svmaffione 175341477Svmaffione if (error) 176341477Svmaffione return error; 177341477Svmaffione /* override the host rings callbacks */ 178341477Svmaffione for_rx_tx(t) { 179341477Svmaffione int i; 180341477Svmaffione u_int first = nma_get_nrings(na, t); 181341477Svmaffione for (i = 0; i < nma_get_host_nrings(na, t); i++) { 182341477Svmaffione struct netmap_kring *kring = NMR(na, t)[first + i]; 183341477Svmaffione kring->nm_sync = t == NR_TX ? netmap_monitor_txsync : 184341477Svmaffione netmap_monitor_rxsync; 185341477Svmaffione } 186341477Svmaffione } 187341477Svmaffione return 0; 188285349Sluigi} 189285349Sluigi 190285349Sluigi/* nm_krings_delete callback for monitors */ 191285349Sluigistatic void 192285349Sluiginetmap_monitor_krings_delete(struct netmap_adapter *na) 193285349Sluigi{ 194285349Sluigi netmap_krings_delete(na); 195285349Sluigi} 196285349Sluigi 197285349Sluigi 198285349Sluigistatic u_int 199285349Sluiginm_txrx2flag(enum txrx t) 200285349Sluigi{ 201285349Sluigi return (t == NR_RX ? NR_MONITOR_RX : NR_MONITOR_TX); 202285349Sluigi} 203285349Sluigi 204285349Sluigi/* allocate the monitors array in the monitored kring */ 205285349Sluigistatic int 206285349Sluiginm_monitor_alloc(struct netmap_kring *kring, u_int n) 207285349Sluigi{ 208341477Svmaffione size_t old_len, len; 209285349Sluigi struct netmap_kring **nm; 210285349Sluigi 211285349Sluigi if (n <= kring->max_monitors) 212285349Sluigi /* we already have more entries that requested */ 213285349Sluigi return 0; 214341477Svmaffione 215341477Svmaffione old_len = sizeof(struct netmap_kring *)*kring->max_monitors; 216341477Svmaffione len = sizeof(struct netmap_kring *) * n; 217341477Svmaffione nm = nm_os_realloc(kring->monitors, len, old_len); 218285349Sluigi if (nm == NULL) 219285349Sluigi return ENOMEM; 220285349Sluigi 221285349Sluigi kring->monitors = nm; 222285349Sluigi kring->max_monitors = n; 223285349Sluigi 224285349Sluigi return 0; 225285349Sluigi} 226285349Sluigi 227285349Sluigi/* deallocate the parent array in the parent adapter */ 228285349Sluigistatic void 229285349Sluiginm_monitor_dealloc(struct netmap_kring *kring) 230285349Sluigi{ 231285349Sluigi if (kring->monitors) { 232285349Sluigi if (kring->n_monitors > 0) { 233344047Svmaffione nm_prerr("freeing not empty monitor array for %s (%d dangling monitors)!", 234344047Svmaffione kring->name, kring->n_monitors); 235285349Sluigi } 236341477Svmaffione nm_os_free(kring->monitors); 237285349Sluigi kring->monitors = NULL; 238285349Sluigi kring->max_monitors = 0; 239285349Sluigi kring->n_monitors = 0; 240285349Sluigi } 241285349Sluigi} 242285349Sluigi 243341477Svmaffione/* returns 1 iff kring has no monitors */ 244341477Svmaffionestatic inline int 245341477Svmaffionenm_monitor_none(struct netmap_kring *kring) 246341477Svmaffione{ 247341477Svmaffione return kring->n_monitors == 0 && 248341477Svmaffione kring->zmon_list[NR_TX].next == NULL && 249341477Svmaffione kring->zmon_list[NR_RX].next == NULL; 250341477Svmaffione} 251341477Svmaffione 252285349Sluigi/* 253285349Sluigi * monitors work by replacing the nm_sync() and possibly the 254285349Sluigi * nm_notify() callbacks in the monitored rings. 255285349Sluigi */ 256285349Sluigistatic int netmap_zmon_parent_txsync(struct netmap_kring *, int); 257285349Sluigistatic int netmap_zmon_parent_rxsync(struct netmap_kring *, int); 258285349Sluigistatic int netmap_monitor_parent_txsync(struct netmap_kring *, int); 259285349Sluigistatic int netmap_monitor_parent_rxsync(struct netmap_kring *, int); 260285349Sluigistatic int netmap_monitor_parent_notify(struct netmap_kring *, int); 261285349Sluigi 262343522Svmaffionestatic int 263343522Svmaffionenm_monitor_dummycb(struct netmap_kring *kring, int flags) 264343522Svmaffione{ 265343522Svmaffione (void)kring; 266343522Svmaffione (void)flags; 267343522Svmaffione return 0; 268343522Svmaffione} 269343522Svmaffione 270341477Svmaffionestatic void 271341477Svmaffionenm_monitor_intercept_callbacks(struct netmap_kring *kring) 272341477Svmaffione{ 273344047Svmaffione nm_prdis("intercept callbacks on %s", kring->name); 274343522Svmaffione kring->mon_sync = kring->nm_sync != NULL ? 275343522Svmaffione kring->nm_sync : nm_monitor_dummycb; 276341477Svmaffione kring->mon_notify = kring->nm_notify; 277341477Svmaffione if (kring->tx == NR_TX) { 278341477Svmaffione kring->nm_sync = netmap_monitor_parent_txsync; 279341477Svmaffione } else { 280341477Svmaffione kring->nm_sync = netmap_monitor_parent_rxsync; 281341477Svmaffione kring->nm_notify = netmap_monitor_parent_notify; 282341477Svmaffione kring->mon_tail = kring->nr_hwtail; 283341477Svmaffione } 284341477Svmaffione} 285285349Sluigi 286341477Svmaffionestatic void 287341477Svmaffionenm_monitor_restore_callbacks(struct netmap_kring *kring) 288341477Svmaffione{ 289344047Svmaffione nm_prdis("restoring callbacks on %s", kring->name); 290341477Svmaffione kring->nm_sync = kring->mon_sync; 291341477Svmaffione kring->mon_sync = NULL; 292341477Svmaffione if (kring->tx == NR_RX) { 293341477Svmaffione kring->nm_notify = kring->mon_notify; 294341477Svmaffione } 295341477Svmaffione kring->mon_notify = NULL; 296341477Svmaffione} 297341477Svmaffione 298341477Svmaffionestatic struct netmap_kring * 299341477Svmaffionenm_zmon_list_head(struct netmap_kring *mkring, enum txrx t) 300341477Svmaffione{ 301341477Svmaffione struct netmap_adapter *na = mkring->na; 302341477Svmaffione struct netmap_kring *kring = mkring; 303341477Svmaffione struct netmap_zmon_list *z = &kring->zmon_list[t]; 304341477Svmaffione /* reach the head of the list */ 305341477Svmaffione while (nm_is_zmon(na) && z->prev != NULL) { 306341477Svmaffione kring = z->prev; 307341477Svmaffione na = kring->na; 308341477Svmaffione z = &kring->zmon_list[t]; 309341477Svmaffione } 310341477Svmaffione return nm_is_zmon(na) ? NULL : kring; 311341477Svmaffione} 312341477Svmaffione 313285349Sluigi/* add the monitor mkring to the list of monitors of kring. 314285349Sluigi * If this is the first monitor, intercept the callbacks 315285349Sluigi */ 316285349Sluigistatic int 317341477Svmaffionenetmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int zmon) 318285349Sluigi{ 319341477Svmaffione int error = NM_IRQ_COMPLETED; 320341477Svmaffione enum txrx t = kring->tx; 321341477Svmaffione struct netmap_zmon_list *z = &kring->zmon_list[t]; 322341477Svmaffione struct netmap_zmon_list *mz = &mkring->zmon_list[t]; 323341477Svmaffione struct netmap_kring *ikring = kring; 324285349Sluigi 325341477Svmaffione /* a zero-copy monitor which is not the first in the list 326341477Svmaffione * must monitor the previous monitor 327341477Svmaffione */ 328341477Svmaffione if (zmon && z->prev != NULL) 329341477Svmaffione ikring = z->prev; /* tail of the list */ 330341477Svmaffione 331341477Svmaffione /* synchronize with concurrently running nm_sync()s */ 332341477Svmaffione nm_kr_stop(kring, NM_KR_LOCKED); 333341477Svmaffione 334341477Svmaffione if (nm_monitor_none(ikring)) { 335341477Svmaffione /* this is the first monitor, intercept the callbacks */ 336344047Svmaffione nm_prdis("%s: intercept callbacks on %s", mkring->name, ikring->name); 337341477Svmaffione nm_monitor_intercept_callbacks(ikring); 338341477Svmaffione } 339341477Svmaffione 340341477Svmaffione if (zmon) { 341341477Svmaffione /* append the zmon to the list */ 342341477Svmaffione ikring->zmon_list[t].next = mkring; 343341477Svmaffione z->prev = mkring; /* new tail */ 344341477Svmaffione mz->prev = ikring; 345341477Svmaffione mz->next = NULL; 346341477Svmaffione /* grab a reference to the previous netmap adapter 347341477Svmaffione * in the chain (this may be the monitored port 348341477Svmaffione * or another zero-copy monitor) 349285349Sluigi */ 350341477Svmaffione netmap_adapter_get(ikring->na); 351341477Svmaffione } else { 352341477Svmaffione /* make sure the monitor array exists and is big enough */ 353341477Svmaffione error = nm_monitor_alloc(kring, kring->n_monitors + 1); 354341477Svmaffione if (error) 355341477Svmaffione goto out; 356341477Svmaffione kring->monitors[kring->n_monitors] = mkring; 357341477Svmaffione mkring->mon_pos[kring->tx] = kring->n_monitors; 358341477Svmaffione kring->n_monitors++; 359285349Sluigi } 360285349Sluigi 361285349Sluigiout: 362341477Svmaffione nm_kr_start(kring); 363285349Sluigi return error; 364285349Sluigi} 365285349Sluigi 366285349Sluigi/* remove the monitor mkring from the list of monitors of kring. 367285349Sluigi * If this is the last monitor, restore the original callbacks 368285349Sluigi */ 369285349Sluigistatic void 370341477Svmaffionenetmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring, enum txrx t) 371285349Sluigi{ 372341477Svmaffione int zmon = nm_is_zmon(mkring->na); 373341477Svmaffione struct netmap_zmon_list *mz = &mkring->zmon_list[t]; 374341477Svmaffione struct netmap_kring *ikring = kring; 375341477Svmaffione 376341477Svmaffione 377341477Svmaffione if (zmon) { 378341477Svmaffione /* get to the head of the list */ 379341477Svmaffione kring = nm_zmon_list_head(mkring, t); 380341477Svmaffione ikring = mz->prev; 381285349Sluigi } 382341477Svmaffione 383341477Svmaffione /* synchronize with concurrently running nm_sync()s 384341477Svmaffione * if kring is NULL (orphaned list) the monitored port 385341477Svmaffione * has exited netmap mode, so there is nothing to stop 386341477Svmaffione */ 387341477Svmaffione if (kring != NULL) 388341477Svmaffione nm_kr_stop(kring, NM_KR_LOCKED); 389341477Svmaffione 390341477Svmaffione if (zmon) { 391341477Svmaffione /* remove the monitor from the list */ 392341477Svmaffione if (mz->next != NULL) { 393341477Svmaffione mz->next->zmon_list[t].prev = mz->prev; 394341477Svmaffione /* we also need to let the next monitor drop the 395341477Svmaffione * reference to us and grab the reference to the 396341477Svmaffione * previous ring owner, instead 397341477Svmaffione */ 398341477Svmaffione if (mz->prev != NULL) 399341477Svmaffione netmap_adapter_get(mz->prev->na); 400341477Svmaffione netmap_adapter_put(mkring->na); 401341477Svmaffione } else if (kring != NULL) { 402341477Svmaffione /* in the monitored kring, prev is actually the 403341477Svmaffione * pointer to the tail of the list 404341477Svmaffione */ 405341477Svmaffione kring->zmon_list[t].prev = 406341477Svmaffione (mz->prev != kring ? mz->prev : NULL); 407285349Sluigi } 408341477Svmaffione if (mz->prev != NULL) { 409341477Svmaffione netmap_adapter_put(mz->prev->na); 410341477Svmaffione mz->prev->zmon_list[t].next = mz->next; 411341477Svmaffione } 412341477Svmaffione mz->prev = NULL; 413341477Svmaffione mz->next = NULL; 414341477Svmaffione } else { 415341477Svmaffione /* this is a copy monitor */ 416341477Svmaffione uint32_t mon_pos = mkring->mon_pos[kring->tx]; 417341477Svmaffione kring->n_monitors--; 418341477Svmaffione if (mon_pos != kring->n_monitors) { 419341477Svmaffione kring->monitors[mon_pos] = 420341477Svmaffione kring->monitors[kring->n_monitors]; 421341477Svmaffione kring->monitors[mon_pos]->mon_pos[kring->tx] = mon_pos; 422341477Svmaffione } 423341477Svmaffione kring->monitors[kring->n_monitors] = NULL; 424341477Svmaffione if (kring->n_monitors == 0) { 425341477Svmaffione nm_monitor_dealloc(kring); 426341477Svmaffione } 427285349Sluigi } 428341477Svmaffione 429341477Svmaffione if (ikring != NULL && nm_monitor_none(ikring)) { 430341477Svmaffione /* this was the last monitor, restore the callbacks */ 431341477Svmaffione nm_monitor_restore_callbacks(ikring); 432341477Svmaffione } 433341477Svmaffione 434341477Svmaffione if (kring != NULL) 435341477Svmaffione nm_kr_start(kring); 436285349Sluigi} 437285349Sluigi 438285349Sluigi 439285349Sluigi/* This is called when the monitored adapter leaves netmap mode 440285349Sluigi * (see netmap_do_unregif). 441285349Sluigi * We need to notify the monitors that the monitored rings are gone. 442285349Sluigi * We do this by setting their mna->priv.np_na to NULL. 443285349Sluigi * Note that the rings are already stopped when this happens, so 444285349Sluigi * no monitor ring callback can be active. 445285349Sluigi */ 446285349Sluigivoid 447285349Sluiginetmap_monitor_stop(struct netmap_adapter *na) 448285349Sluigi{ 449285349Sluigi enum txrx t; 450285349Sluigi 451285349Sluigi for_rx_tx(t) { 452285349Sluigi u_int i; 453285349Sluigi 454341477Svmaffione for (i = 0; i < netmap_all_rings(na, t); i++) { 455341477Svmaffione struct netmap_kring *kring = NMR(na, t)[i]; 456341477Svmaffione struct netmap_zmon_list *z = &kring->zmon_list[t]; 457285349Sluigi u_int j; 458285349Sluigi 459285349Sluigi for (j = 0; j < kring->n_monitors; j++) { 460285349Sluigi struct netmap_kring *mkring = 461285349Sluigi kring->monitors[j]; 462285349Sluigi struct netmap_monitor_adapter *mna = 463285349Sluigi (struct netmap_monitor_adapter *)mkring->na; 464285349Sluigi /* forget about this adapter */ 465341477Svmaffione if (mna->priv.np_na != NULL) { 466341477Svmaffione netmap_adapter_put(mna->priv.np_na); 467341477Svmaffione mna->priv.np_na = NULL; 468341477Svmaffione } 469341477Svmaffione kring->monitors[j] = NULL; 470285349Sluigi } 471341477Svmaffione 472341477Svmaffione if (!nm_is_zmon(na)) { 473341477Svmaffione /* we are the head of at most one list */ 474341477Svmaffione struct netmap_kring *zkring; 475341477Svmaffione for (zkring = z->next; zkring != NULL; 476341477Svmaffione zkring = zkring->zmon_list[t].next) 477341477Svmaffione { 478341477Svmaffione struct netmap_monitor_adapter *next = 479341477Svmaffione (struct netmap_monitor_adapter *)zkring->na; 480341477Svmaffione /* let the monitor forget about us */ 481341477Svmaffione netmap_adapter_put(next->priv.np_na); /* nop if null */ 482341477Svmaffione next->priv.np_na = NULL; 483341477Svmaffione } 484341477Svmaffione /* orhpan the zmon list */ 485341477Svmaffione if (z->next != NULL) 486341477Svmaffione z->next->zmon_list[t].prev = NULL; 487341477Svmaffione z->next = NULL; 488341477Svmaffione z->prev = NULL; 489341477Svmaffione } 490341477Svmaffione 491341477Svmaffione if (!nm_monitor_none(kring)) { 492341477Svmaffione 493341477Svmaffione kring->n_monitors = 0; 494341477Svmaffione nm_monitor_dealloc(kring); 495341477Svmaffione nm_monitor_restore_callbacks(kring); 496341477Svmaffione } 497285349Sluigi } 498285349Sluigi } 499285349Sluigi} 500285349Sluigi 501285349Sluigi 502285349Sluigi/* common functions for the nm_register() callbacks of both kind of 503285349Sluigi * monitors. 504285349Sluigi */ 505285349Sluigistatic int 506285349Sluiginetmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon) 507285349Sluigi{ 508285349Sluigi struct netmap_monitor_adapter *mna = 509285349Sluigi (struct netmap_monitor_adapter *)na; 510285349Sluigi struct netmap_priv_d *priv = &mna->priv; 511285349Sluigi struct netmap_adapter *pna = priv->np_na; 512285349Sluigi struct netmap_kring *kring, *mkring; 513285349Sluigi int i; 514341477Svmaffione enum txrx t, s; 515285349Sluigi 516344047Svmaffione nm_prdis("%p: onoff %d", na, onoff); 517285349Sluigi if (onoff) { 518285349Sluigi if (pna == NULL) { 519285349Sluigi /* parent left netmap mode, fatal */ 520344047Svmaffione nm_prerr("%s: parent left netmap mode", na->name); 521285349Sluigi return ENXIO; 522285349Sluigi } 523285349Sluigi for_rx_tx(t) { 524341477Svmaffione for (i = 0; i < netmap_all_rings(na, t); i++) { 525341477Svmaffione mkring = NMR(na, t)[i]; 526341477Svmaffione if (!nm_kring_pending_on(mkring)) 527341477Svmaffione continue; 528341477Svmaffione mkring->nr_mode = NKR_NETMAP_ON; 529341477Svmaffione if (t == NR_TX) 530341477Svmaffione continue; 531341477Svmaffione for_rx_tx(s) { 532341477Svmaffione if (i > nma_get_nrings(pna, s)) 533341477Svmaffione continue; 534341477Svmaffione if (mna->flags & nm_txrx2flag(s)) { 535341477Svmaffione kring = NMR(pna, s)[i]; 536341477Svmaffione netmap_monitor_add(mkring, kring, zmon); 537341477Svmaffione } 538285349Sluigi } 539285349Sluigi } 540285349Sluigi } 541285349Sluigi na->na_flags |= NAF_NETMAP_ON; 542285349Sluigi } else { 543341477Svmaffione if (na->active_fds == 0) 544341477Svmaffione na->na_flags &= ~NAF_NETMAP_ON; 545285349Sluigi for_rx_tx(t) { 546341477Svmaffione for (i = 0; i < netmap_all_rings(na, t); i++) { 547341477Svmaffione mkring = NMR(na, t)[i]; 548341477Svmaffione if (!nm_kring_pending_off(mkring)) 549341477Svmaffione continue; 550341477Svmaffione mkring->nr_mode = NKR_NETMAP_OFF; 551341477Svmaffione if (t == NR_TX) 552341477Svmaffione continue; 553341477Svmaffione /* we cannot access the parent krings if the parent 554341477Svmaffione * has left netmap mode. This is signaled by a NULL 555341477Svmaffione * pna pointer 556341477Svmaffione */ 557341477Svmaffione if (pna == NULL) 558341477Svmaffione continue; 559341477Svmaffione for_rx_tx(s) { 560341477Svmaffione if (i > nma_get_nrings(pna, s)) 561341477Svmaffione continue; 562341477Svmaffione if (mna->flags & nm_txrx2flag(s)) { 563341477Svmaffione kring = NMR(pna, s)[i]; 564341477Svmaffione netmap_monitor_del(mkring, kring, s); 565341477Svmaffione } 566285349Sluigi } 567285349Sluigi } 568285349Sluigi } 569285349Sluigi } 570285349Sluigi return 0; 571285349Sluigi} 572285349Sluigi 573285349Sluigi/* 574285349Sluigi **************************************************************** 575341477Svmaffione * functions specific for zero-copy monitors 576285349Sluigi **************************************************************** 577285349Sluigi */ 578285349Sluigi 579285349Sluigi/* 580285349Sluigi * Common function for both zero-copy tx and rx nm_sync() 581285349Sluigi * callbacks 582285349Sluigi */ 583285349Sluigistatic int 584285349Sluiginetmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx) 585285349Sluigi{ 586341477Svmaffione struct netmap_kring *mkring = kring->zmon_list[tx].next; 587285349Sluigi struct netmap_ring *ring = kring->ring, *mring; 588285349Sluigi int error = 0; 589285349Sluigi int rel_slots, free_slots, busy, sent = 0; 590270063Sluigi u_int beg, end, i; 591270063Sluigi u_int lim = kring->nkr_num_slots - 1, 592285349Sluigi mlim; // = mkring->nkr_num_slots - 1; 593270063Sluigi 594285349Sluigi if (mkring == NULL) { 595344047Svmaffione nm_prlim(5, "NULL monitor on %s", kring->name); 596285349Sluigi return 0; 597285349Sluigi } 598285349Sluigi mring = mkring->ring; 599285349Sluigi mlim = mkring->nkr_num_slots - 1; 600285349Sluigi 601270063Sluigi /* get the relased slots (rel_slots) */ 602285349Sluigi if (tx == NR_TX) { 603341477Svmaffione beg = kring->nr_hwtail + 1; 604285349Sluigi error = kring->mon_sync(kring, flags); 605285349Sluigi if (error) 606285349Sluigi return error; 607341477Svmaffione end = kring->nr_hwtail + 1; 608285349Sluigi } else { /* NR_RX */ 609285349Sluigi beg = kring->nr_hwcur; 610285349Sluigi end = kring->rhead; 611285349Sluigi } 612285349Sluigi 613270063Sluigi rel_slots = end - beg; 614270063Sluigi if (rel_slots < 0) 615270063Sluigi rel_slots += kring->nkr_num_slots; 616270063Sluigi 617270063Sluigi if (!rel_slots) { 618285349Sluigi /* no released slots, but we still need 619285349Sluigi * to call rxsync if this is a rx ring 620285349Sluigi */ 621285349Sluigi goto out_rxsync; 622270063Sluigi } 623270063Sluigi 624270063Sluigi /* we need to lock the monitor receive ring, since it 625270063Sluigi * is the target of bot tx and rx traffic from the monitored 626270063Sluigi * adapter 627270063Sluigi */ 628270063Sluigi mtx_lock(&mkring->q_lock); 629270063Sluigi /* get the free slots available on the monitor ring */ 630270063Sluigi i = mkring->nr_hwtail; 631270063Sluigi busy = i - mkring->nr_hwcur; 632270063Sluigi if (busy < 0) 633270063Sluigi busy += mkring->nkr_num_slots; 634270063Sluigi free_slots = mlim - busy; 635270063Sluigi 636285349Sluigi if (!free_slots) 637285349Sluigi goto out; 638270063Sluigi 639270063Sluigi /* swap min(free_slots, rel_slots) slots */ 640270063Sluigi if (free_slots < rel_slots) { 641270063Sluigi beg += (rel_slots - free_slots); 642270063Sluigi rel_slots = free_slots; 643270063Sluigi } 644341477Svmaffione if (unlikely(beg >= kring->nkr_num_slots)) 645341477Svmaffione beg -= kring->nkr_num_slots; 646270063Sluigi 647285349Sluigi sent = rel_slots; 648270063Sluigi for ( ; rel_slots; rel_slots--) { 649270063Sluigi struct netmap_slot *s = &ring->slot[beg]; 650270063Sluigi struct netmap_slot *ms = &mring->slot[i]; 651270063Sluigi uint32_t tmp; 652270063Sluigi 653270063Sluigi tmp = ms->buf_idx; 654270063Sluigi ms->buf_idx = s->buf_idx; 655270063Sluigi s->buf_idx = tmp; 656344047Svmaffione nm_prdis(5, "beg %d buf_idx %d", beg, tmp); 657270063Sluigi 658270063Sluigi tmp = ms->len; 659270063Sluigi ms->len = s->len; 660270063Sluigi s->len = tmp; 661270063Sluigi 662341477Svmaffione ms->flags = s->flags; 663270063Sluigi s->flags |= NS_BUF_CHANGED; 664270063Sluigi 665270063Sluigi beg = nm_next(beg, lim); 666270063Sluigi i = nm_next(i, mlim); 667270063Sluigi 668270063Sluigi } 669274457Sluigi mb(); 670270063Sluigi mkring->nr_hwtail = i; 671270063Sluigi 672285349Sluigiout: 673270063Sluigi mtx_unlock(&mkring->q_lock); 674285349Sluigi 675285349Sluigi if (sent) { 676285349Sluigi /* notify the new frames to the monitor */ 677285349Sluigi mkring->nm_notify(mkring, 0); 678285349Sluigi } 679285349Sluigi 680285349Sluigiout_rxsync: 681285349Sluigi if (tx == NR_RX) 682285349Sluigi error = kring->mon_sync(kring, flags); 683285349Sluigi 684285349Sluigi return error; 685270063Sluigi} 686270063Sluigi 687270063Sluigi/* callback used to replace the nm_sync callback in the monitored tx rings */ 688270063Sluigistatic int 689285349Sluiginetmap_zmon_parent_txsync(struct netmap_kring *kring, int flags) 690270063Sluigi{ 691341477Svmaffione return netmap_zmon_parent_sync(kring, flags, NR_TX); 692270063Sluigi} 693270063Sluigi 694270063Sluigi/* callback used to replace the nm_sync callback in the monitored rx rings */ 695270063Sluigistatic int 696285349Sluiginetmap_zmon_parent_rxsync(struct netmap_kring *kring, int flags) 697270063Sluigi{ 698341477Svmaffione return netmap_zmon_parent_sync(kring, flags, NR_RX); 699270063Sluigi} 700270063Sluigi 701270063Sluigistatic int 702285349Sluiginetmap_zmon_reg(struct netmap_adapter *na, int onoff) 703270063Sluigi{ 704285349Sluigi return netmap_monitor_reg_common(na, onoff, 1 /* zcopy */); 705270063Sluigi} 706270063Sluigi 707285349Sluigi/* nm_dtor callback for monitors */ 708285349Sluigistatic void 709285349Sluiginetmap_zmon_dtor(struct netmap_adapter *na) 710270063Sluigi{ 711285349Sluigi struct netmap_monitor_adapter *mna = 712285349Sluigi (struct netmap_monitor_adapter *)na; 713285349Sluigi struct netmap_priv_d *priv = &mna->priv; 714285349Sluigi struct netmap_adapter *pna = priv->np_na; 715285349Sluigi 716285349Sluigi netmap_adapter_put(pna); 717270063Sluigi} 718270063Sluigi 719285349Sluigi/* 720285349Sluigi **************************************************************** 721341477Svmaffione * functions specific for copy monitors 722285349Sluigi **************************************************************** 723270063Sluigi */ 724285349Sluigi 725285349Sluigistatic void 726285349Sluiginetmap_monitor_parent_sync(struct netmap_kring *kring, u_int first_new, int new_slots) 727270063Sluigi{ 728285349Sluigi u_int j; 729270063Sluigi 730285349Sluigi for (j = 0; j < kring->n_monitors; j++) { 731285349Sluigi struct netmap_kring *mkring = kring->monitors[j]; 732285349Sluigi u_int i, mlim, beg; 733285349Sluigi int free_slots, busy, sent = 0, m; 734285349Sluigi u_int lim = kring->nkr_num_slots - 1; 735285349Sluigi struct netmap_ring *ring = kring->ring, *mring = mkring->ring; 736285349Sluigi u_int max_len = NETMAP_BUF_SIZE(mkring->na); 737270063Sluigi 738285349Sluigi mlim = mkring->nkr_num_slots - 1; 739270063Sluigi 740285349Sluigi /* we need to lock the monitor receive ring, since it 741285349Sluigi * is the target of bot tx and rx traffic from the monitored 742285349Sluigi * adapter 743285349Sluigi */ 744285349Sluigi mtx_lock(&mkring->q_lock); 745285349Sluigi /* get the free slots available on the monitor ring */ 746285349Sluigi i = mkring->nr_hwtail; 747285349Sluigi busy = i - mkring->nr_hwcur; 748285349Sluigi if (busy < 0) 749285349Sluigi busy += mkring->nkr_num_slots; 750285349Sluigi free_slots = mlim - busy; 751285349Sluigi 752285349Sluigi if (!free_slots) 753285349Sluigi goto out; 754285349Sluigi 755285349Sluigi /* copy min(free_slots, new_slots) slots */ 756285349Sluigi m = new_slots; 757285349Sluigi beg = first_new; 758285349Sluigi if (free_slots < m) { 759285349Sluigi beg += (m - free_slots); 760285349Sluigi if (beg >= kring->nkr_num_slots) 761285349Sluigi beg -= kring->nkr_num_slots; 762285349Sluigi m = free_slots; 763270063Sluigi } 764285349Sluigi 765285349Sluigi for ( ; m; m--) { 766285349Sluigi struct netmap_slot *s = &ring->slot[beg]; 767285349Sluigi struct netmap_slot *ms = &mring->slot[i]; 768285349Sluigi u_int copy_len = s->len; 769285349Sluigi char *src = NMB(kring->na, s), 770285349Sluigi *dst = NMB(mkring->na, ms); 771285349Sluigi 772285349Sluigi if (unlikely(copy_len > max_len)) { 773344047Svmaffione nm_prlim(5, "%s->%s: truncating %d to %d", kring->name, 774285349Sluigi mkring->name, copy_len, max_len); 775285349Sluigi copy_len = max_len; 776270063Sluigi } 777285349Sluigi 778285349Sluigi memcpy(dst, src, copy_len); 779285349Sluigi ms->len = copy_len; 780341477Svmaffione ms->flags = s->flags; 781285349Sluigi sent++; 782285349Sluigi 783285349Sluigi beg = nm_next(beg, lim); 784285349Sluigi i = nm_next(i, mlim); 785270063Sluigi } 786285349Sluigi mb(); 787285349Sluigi mkring->nr_hwtail = i; 788285349Sluigi out: 789285349Sluigi mtx_unlock(&mkring->q_lock); 790285349Sluigi 791285349Sluigi if (sent) { 792285349Sluigi /* notify the new frames to the monitor */ 793285349Sluigi mkring->nm_notify(mkring, 0); 794270063Sluigi } 795270063Sluigi } 796285349Sluigi} 797285349Sluigi 798285349Sluigi/* callback used to replace the nm_sync callback in the monitored tx rings */ 799285349Sluigistatic int 800285349Sluiginetmap_monitor_parent_txsync(struct netmap_kring *kring, int flags) 801285349Sluigi{ 802285349Sluigi u_int first_new; 803285349Sluigi int new_slots; 804285349Sluigi 805285349Sluigi /* get the new slots */ 806341477Svmaffione if (kring->n_monitors > 0) { 807341477Svmaffione first_new = kring->nr_hwcur; 808341477Svmaffione new_slots = kring->rhead - first_new; 809341477Svmaffione if (new_slots < 0) 810341477Svmaffione new_slots += kring->nkr_num_slots; 811341477Svmaffione if (new_slots) 812341477Svmaffione netmap_monitor_parent_sync(kring, first_new, new_slots); 813341477Svmaffione } 814341477Svmaffione if (kring->zmon_list[NR_TX].next != NULL) { 815341477Svmaffione return netmap_zmon_parent_txsync(kring, flags); 816341477Svmaffione } 817285349Sluigi return kring->mon_sync(kring, flags); 818285349Sluigi} 819285349Sluigi 820285349Sluigi/* callback used to replace the nm_sync callback in the monitored rx rings */ 821285349Sluigistatic int 822285349Sluiginetmap_monitor_parent_rxsync(struct netmap_kring *kring, int flags) 823285349Sluigi{ 824285349Sluigi u_int first_new; 825285349Sluigi int new_slots, error; 826285349Sluigi 827285349Sluigi /* get the new slots */ 828341477Svmaffione if (kring->zmon_list[NR_RX].next != NULL) { 829341477Svmaffione error = netmap_zmon_parent_rxsync(kring, flags); 830341477Svmaffione } else { 831341477Svmaffione error = kring->mon_sync(kring, flags); 832341477Svmaffione } 833285349Sluigi if (error) 834285349Sluigi return error; 835341477Svmaffione if (kring->n_monitors > 0) { 836341477Svmaffione first_new = kring->mon_tail; 837341477Svmaffione new_slots = kring->nr_hwtail - first_new; 838341477Svmaffione if (new_slots < 0) 839341477Svmaffione new_slots += kring->nkr_num_slots; 840341477Svmaffione if (new_slots) 841341477Svmaffione netmap_monitor_parent_sync(kring, first_new, new_slots); 842341477Svmaffione kring->mon_tail = kring->nr_hwtail; 843341477Svmaffione } 844270063Sluigi return 0; 845270063Sluigi} 846285349Sluigi 847285349Sluigi/* callback used to replace the nm_notify() callback in the monitored rx rings */ 848285349Sluigistatic int 849285349Sluiginetmap_monitor_parent_notify(struct netmap_kring *kring, int flags) 850270063Sluigi{ 851341477Svmaffione int (*notify)(struct netmap_kring*, int); 852344047Svmaffione nm_prdis(5, "%s %x", kring->name, flags); 853285349Sluigi /* ?xsync callbacks have tryget called by their callers 854285349Sluigi * (NIOCREGIF and poll()), but here we have to call it 855285349Sluigi * by ourself 856285349Sluigi */ 857341477Svmaffione if (nm_kr_tryget(kring, 0, NULL)) { 858341477Svmaffione /* in all cases, just skip the sync */ 859341477Svmaffione return NM_IRQ_COMPLETED; 860341477Svmaffione } 861341477Svmaffione if (kring->n_monitors > 0) { 862341477Svmaffione netmap_monitor_parent_rxsync(kring, NAF_FORCE_READ); 863341477Svmaffione } 864341477Svmaffione if (nm_monitor_none(kring)) { 865341477Svmaffione /* we are no longer monitoring this ring, so both 866341477Svmaffione * mon_sync and mon_notify are NULL 867341477Svmaffione */ 868341477Svmaffione notify = kring->nm_notify; 869341477Svmaffione } else { 870341477Svmaffione notify = kring->mon_notify; 871341477Svmaffione } 872285349Sluigi nm_kr_put(kring); 873341477Svmaffione return notify(kring, flags); 874270063Sluigi} 875270063Sluigi 876270063Sluigi 877285349Sluigistatic int 878285349Sluiginetmap_monitor_reg(struct netmap_adapter *na, int onoff) 879285349Sluigi{ 880285349Sluigi return netmap_monitor_reg_common(na, onoff, 0 /* no zcopy */); 881285349Sluigi} 882285349Sluigi 883270063Sluigistatic void 884270063Sluiginetmap_monitor_dtor(struct netmap_adapter *na) 885270063Sluigi{ 886270063Sluigi struct netmap_monitor_adapter *mna = 887270063Sluigi (struct netmap_monitor_adapter *)na; 888270063Sluigi struct netmap_priv_d *priv = &mna->priv; 889270063Sluigi struct netmap_adapter *pna = priv->np_na; 890270063Sluigi 891270063Sluigi netmap_adapter_put(pna); 892270063Sluigi} 893270063Sluigi 894270063Sluigi 895341477Svmaffione/* check if req is a request for a monitor adapter that we can satisfy */ 896270063Sluigiint 897341477Svmaffionenetmap_get_monitor_na(struct nmreq_header *hdr, struct netmap_adapter **na, 898341477Svmaffione struct netmap_mem_d *nmd, int create) 899270063Sluigi{ 900341477Svmaffione struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body; 901341477Svmaffione struct nmreq_register preq; 902270063Sluigi struct netmap_adapter *pna; /* parent adapter */ 903270063Sluigi struct netmap_monitor_adapter *mna; 904341477Svmaffione struct ifnet *ifp = NULL; 905341477Svmaffione int error; 906341477Svmaffione int zcopy = (req->nr_flags & NR_ZCOPY_MON); 907270063Sluigi 908341477Svmaffione if (zcopy) { 909341477Svmaffione req->nr_flags |= (NR_MONITOR_TX | NR_MONITOR_RX); 910341477Svmaffione } 911341477Svmaffione if ((req->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) { 912344047Svmaffione nm_prdis("not a monitor"); 913270063Sluigi return 0; 914270063Sluigi } 915270063Sluigi /* this is a request for a monitor adapter */ 916270063Sluigi 917344047Svmaffione nm_prdis("flags %lx", req->nr_flags); 918270063Sluigi 919341477Svmaffione /* First, try to find the adapter that we want to monitor. 920341477Svmaffione * We use the same req, after we have turned off the monitor flags. 921270063Sluigi * In this way we can potentially monitor everything netmap understands, 922270063Sluigi * except other monitors. 923270063Sluigi */ 924341477Svmaffione memcpy(&preq, req, sizeof(preq)); 925341477Svmaffione preq.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON); 926341477Svmaffione hdr->nr_body = (uintptr_t)&preq; 927341477Svmaffione error = netmap_get_na(hdr, &pna, &ifp, nmd, create); 928341477Svmaffione hdr->nr_body = (uintptr_t)req; 929270063Sluigi if (error) { 930344047Svmaffione nm_prerr("parent lookup failed: %d", error); 931270063Sluigi return error; 932270063Sluigi } 933344047Svmaffione nm_prdis("found parent: %s", pna->name); 934270063Sluigi 935270063Sluigi if (!nm_netmap_on(pna)) { 936270063Sluigi /* parent not in netmap mode */ 937270063Sluigi /* XXX we can wait for the parent to enter netmap mode, 938270063Sluigi * by intercepting its nm_register callback (2014-03-16) 939270063Sluigi */ 940344047Svmaffione nm_prerr("%s not in netmap mode", pna->name); 941270063Sluigi error = EINVAL; 942270063Sluigi goto put_out; 943270063Sluigi } 944270063Sluigi 945341477Svmaffione mna = nm_os_malloc(sizeof(*mna)); 946341477Svmaffione if (mna == NULL) { 947341477Svmaffione error = ENOMEM; 948341477Svmaffione goto put_out; 949341477Svmaffione } 950341477Svmaffione mna->priv.np_na = pna; 951341477Svmaffione 952270063Sluigi /* grab all the rings we need in the parent */ 953341477Svmaffione error = netmap_interp_ringid(&mna->priv, req->nr_mode, req->nr_ringid, 954341477Svmaffione req->nr_flags); 955270063Sluigi if (error) { 956344047Svmaffione nm_prerr("ringid error"); 957341477Svmaffione goto free_out; 958270063Sluigi } 959341477Svmaffione snprintf(mna->up.name, sizeof(mna->up.name), "%s/%s%s%s#%lu", pna->name, 960285349Sluigi zcopy ? "z" : "", 961341477Svmaffione (req->nr_flags & NR_MONITOR_RX) ? "r" : "", 962341477Svmaffione (req->nr_flags & NR_MONITOR_TX) ? "t" : "", 963341477Svmaffione pna->monitor_id++); 964285349Sluigi 965270063Sluigi /* the monitor supports the host rings iff the parent does */ 966341477Svmaffione mna->up.na_flags |= (pna->na_flags & NAF_HOST_RINGS); 967285349Sluigi /* a do-nothing txsync: monitors cannot be used to inject packets */ 968270063Sluigi mna->up.nm_txsync = netmap_monitor_txsync; 969270063Sluigi mna->up.nm_rxsync = netmap_monitor_rxsync; 970270063Sluigi mna->up.nm_krings_create = netmap_monitor_krings_create; 971270063Sluigi mna->up.nm_krings_delete = netmap_monitor_krings_delete; 972341477Svmaffione mna->up.num_tx_rings = 1; // XXX what should we do here with chained zmons? 973270063Sluigi /* we set the number of our rx_rings to be max(num_rx_rings, num_rx_rings) 974270063Sluigi * in the parent 975270063Sluigi */ 976270063Sluigi mna->up.num_rx_rings = pna->num_rx_rings; 977270063Sluigi if (pna->num_tx_rings > pna->num_rx_rings) 978270063Sluigi mna->up.num_rx_rings = pna->num_tx_rings; 979270063Sluigi /* by default, the number of slots is the same as in 980270063Sluigi * the parent rings, but the user may ask for a different 981270063Sluigi * number 982270063Sluigi */ 983341477Svmaffione mna->up.num_tx_desc = req->nr_tx_slots; 984270063Sluigi nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc, 985270063Sluigi 1, NM_MONITOR_MAXSLOTS, NULL); 986341477Svmaffione mna->up.num_rx_desc = req->nr_rx_slots; 987270063Sluigi nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc, 988270063Sluigi 1, NM_MONITOR_MAXSLOTS, NULL); 989341477Svmaffione if (zcopy) { 990341477Svmaffione mna->up.nm_register = netmap_zmon_reg; 991341477Svmaffione mna->up.nm_dtor = netmap_zmon_dtor; 992341477Svmaffione /* to have zero copy, we need to use the same memory allocator 993341477Svmaffione * as the monitored port 994341477Svmaffione */ 995341477Svmaffione mna->up.nm_mem = netmap_mem_get(pna->nm_mem); 996341477Svmaffione /* and the allocator cannot be changed */ 997341477Svmaffione mna->up.na_flags |= NAF_MEM_OWNER; 998341477Svmaffione } else { 999341477Svmaffione mna->up.nm_register = netmap_monitor_reg; 1000341477Svmaffione mna->up.nm_dtor = netmap_monitor_dtor; 1001341477Svmaffione mna->up.nm_mem = netmap_mem_private_new( 1002341477Svmaffione mna->up.num_tx_rings, 1003341477Svmaffione mna->up.num_tx_desc, 1004341477Svmaffione mna->up.num_rx_rings, 1005341477Svmaffione mna->up.num_rx_desc, 1006341477Svmaffione 0, /* extra bufs */ 1007341477Svmaffione 0, /* pipes */ 1008341477Svmaffione &error); 1009341477Svmaffione if (mna->up.nm_mem == NULL) 1010341477Svmaffione goto put_out; 1011341477Svmaffione } 1012341477Svmaffione 1013270063Sluigi error = netmap_attach_common(&mna->up); 1014270063Sluigi if (error) { 1015344047Svmaffione nm_prerr("netmap_attach_common failed"); 1016341477Svmaffione goto mem_put_out; 1017270063Sluigi } 1018270063Sluigi 1019270063Sluigi /* remember the traffic directions we have to monitor */ 1020341477Svmaffione mna->flags = (req->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON)); 1021270063Sluigi 1022270063Sluigi *na = &mna->up; 1023270063Sluigi netmap_adapter_get(*na); 1024270063Sluigi 1025270063Sluigi /* keep the reference to the parent */ 1026344047Svmaffione nm_prdis("monitor ok"); 1027270063Sluigi 1028341477Svmaffione /* drop the reference to the ifp, if any */ 1029341477Svmaffione if (ifp) 1030341477Svmaffione if_rele(ifp); 1031341477Svmaffione 1032270063Sluigi return 0; 1033270063Sluigi 1034341477Svmaffionemem_put_out: 1035341477Svmaffione netmap_mem_put(mna->up.nm_mem); 1036341477Svmaffionefree_out: 1037341477Svmaffione nm_os_free(mna); 1038270063Sluigiput_out: 1039341477Svmaffione netmap_unget_na(pna, ifp); 1040270063Sluigi return error; 1041270063Sluigi} 1042270063Sluigi 1043270063Sluigi 1044270063Sluigi#endif /* WITH_MONITOR */ 1045