xref: /freebsd/sys/dev/netmap/netmap_monitor.c (revision a5921bc3653e2e286715e6fe8d473ec0d02da38c)
1 /*
2  * Copyright (C) 2014 Giuseppe Lettieri. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *   1. Redistributions of source code must retain the above copyright
8  *      notice, this list of conditions and the following disclaimer.
9  *   2. Redistributions in binary form must reproduce the above copyright
10  *      notice, this list of conditions and the following disclaimer in the
11  *      documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 /*
27  * $FreeBSD$
28  *
29  * Monitors
30  *
31  * netmap monitors can be used to do monitoring of network traffic
32  * on another adapter, when the latter adapter is working in netmap mode.
33  *
34  * Monitors offer to userspace the same interface as any other netmap port,
35  * with as many pairs of netmap rings as the monitored adapter.
36  * However, only the rx rings are actually used. Each monitor rx ring receives
37  * the traffic transiting on both the tx and rx corresponding rings in the
38  * monitored adapter. During registration, the user can choose if she wants
39  * to intercept tx only, rx only, or both tx and rx traffic.
40  *
41  * If the monitor is not able to cope with the stream of frames, excess traffic
42  * will be dropped.
43  *
44  * If the monitored adapter leaves netmap mode, the monitor has to be restarted.
45  *
46  * Monitors can be either zero-copy or copy-based.
47  *
48  * Copy monitors see the frames before they are consumed:
49  *
50  *  - For tx traffic, this is when the application sends them, before they are
51  *    passed down to the adapter.
52  *
53  *  - For rx traffic, this is when they are received by the adapter, before
54  *    they are sent up to the application, if any (note that, if no
55  *    application is reading from a monitored ring, the ring will eventually
56  *    fill up and traffic will stop).
57  *
58  * Zero-copy monitors only see the frames after they have been consumed:
59  *
60  *  - For tx traffic, this is after the slots containing the frames have been
61  *    marked as free. Note that this may happen at a considerably delay after
62  *    frame transmission, since freeing of slots is often done lazily.
63  *
64  *  - For rx traffic, this is after the consumer on the monitored adapter
65  *    has released them. In most cases, the consumer is a userspace
66  *    application which may have modified the frame contents.
67  *
68  * Several copy monitors may be active on any ring.  Zero-copy monitors,
69  * instead, need exclusive access to each of the monitored rings.  This may
70  * change in the future, if we implement zero-copy monitor chaining.
71  *
72  */
73 
74 
75 #if defined(__FreeBSD__)
76 #include <sys/cdefs.h> /* prerequisite */
77 
78 #include <sys/types.h>
79 #include <sys/errno.h>
80 #include <sys/param.h>	/* defines used in kernel.h */
81 #include <sys/kernel.h>	/* types used in module initialization */
82 #include <sys/malloc.h>
83 #include <sys/poll.h>
84 #include <sys/lock.h>
85 #include <sys/rwlock.h>
86 #include <sys/selinfo.h>
87 #include <sys/sysctl.h>
88 #include <sys/socket.h> /* sockaddrs */
89 #include <net/if.h>
90 #include <net/if_var.h>
91 #include <machine/bus.h>	/* bus_dmamap_* */
92 #include <sys/refcount.h>
93 
94 
95 #elif defined(linux)
96 
97 #include "bsd_glue.h"
98 
99 #elif defined(__APPLE__)
100 
101 #warning OSX support is only partial
102 #include "osx_glue.h"
103 
104 #else
105 
106 #error	Unsupported platform
107 
108 #endif /* unsupported */
109 
110 /*
111  * common headers
112  */
113 
114 #include <net/netmap.h>
115 #include <dev/netmap/netmap_kern.h>
116 #include <dev/netmap/netmap_mem2.h>
117 
118 #ifdef WITH_MONITOR
119 
120 #define NM_MONITOR_MAXSLOTS 4096
121 
122 /*
123  ********************************************************************
124  * functions common to both kind of monitors
125  ********************************************************************
126  */
127 
128 /* nm_sync callback for the monitor's own tx rings.
129  * This makes no sense and always returns error
130  */
131 static int
132 netmap_monitor_txsync(struct netmap_kring *kring, int flags)
133 {
134         RD(1, "%s %x", kring->name, flags);
135 	return EIO;
136 }
137 
138 /* nm_sync callback for the monitor's own rx rings.
139  * Note that the lock in netmap_zmon_parent_sync only protects
140  * writers among themselves. Synchronization between writers
141  * (i.e., netmap_zmon_parent_txsync and netmap_zmon_parent_rxsync)
142  * and readers (i.e., netmap_zmon_rxsync) relies on memory barriers.
143  */
144 static int
145 netmap_monitor_rxsync(struct netmap_kring *kring, int flags)
146 {
147         ND("%s %x", kring->name, flags);
148 	kring->nr_hwcur = kring->rcur;
149 	mb();
150         return 0;
151 }
152 
153 /* nm_krings_create callbacks for monitors.
154  * We could use the default netmap_hw_krings_zmon, but
155  * we don't need the mbq.
156  */
157 static int
158 netmap_monitor_krings_create(struct netmap_adapter *na)
159 {
160 	return netmap_krings_create(na, 0);
161 }
162 
163 /* nm_krings_delete callback for monitors */
164 static void
165 netmap_monitor_krings_delete(struct netmap_adapter *na)
166 {
167 	netmap_krings_delete(na);
168 }
169 
170 
171 static u_int
172 nm_txrx2flag(enum txrx t)
173 {
174 	return (t == NR_RX ? NR_MONITOR_RX : NR_MONITOR_TX);
175 }
176 
177 /* allocate the monitors array in the monitored kring */
178 static int
179 nm_monitor_alloc(struct netmap_kring *kring, u_int n)
180 {
181 	size_t len;
182 	struct netmap_kring **nm;
183 
184 	if (n <= kring->max_monitors)
185 		/* we already have more entries that requested */
186 		return 0;
187 
188         len = sizeof(struct netmap_kring *) * n;
189 	nm = realloc(kring->monitors, len, M_DEVBUF, M_NOWAIT | M_ZERO);
190 	if (nm == NULL)
191 		return ENOMEM;
192 
193 	kring->monitors = nm;
194 	kring->max_monitors = n;
195 
196 	return 0;
197 }
198 
199 /* deallocate the parent array in the parent adapter */
200 static void
201 nm_monitor_dealloc(struct netmap_kring *kring)
202 {
203 	if (kring->monitors) {
204 		if (kring->n_monitors > 0) {
205 			D("freeing not empty monitor array for %s (%d dangling monitors)!", kring->name,
206 					kring->n_monitors);
207 		}
208 		free(kring->monitors, M_DEVBUF);
209 		kring->monitors = NULL;
210 		kring->max_monitors = 0;
211 		kring->n_monitors = 0;
212 	}
213 }
214 
215 /*
216  * monitors work by replacing the nm_sync() and possibly the
217  * nm_notify() callbacks in the monitored rings.
218  */
219 static int netmap_zmon_parent_txsync(struct netmap_kring *, int);
220 static int netmap_zmon_parent_rxsync(struct netmap_kring *, int);
221 static int netmap_monitor_parent_txsync(struct netmap_kring *, int);
222 static int netmap_monitor_parent_rxsync(struct netmap_kring *, int);
223 static int netmap_monitor_parent_notify(struct netmap_kring *, int);
224 
225 
226 /* add the monitor mkring to the list of monitors of kring.
227  * If this is the first monitor, intercept the callbacks
228  */
229 static int
230 netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int zcopy)
231 {
232 	int error = 0;
233 
234 	/* sinchronize with concurrently running nm_sync()s */
235 	nm_kr_get(kring);
236 	/* make sure the monitor array exists and is big enough */
237 	error = nm_monitor_alloc(kring, kring->n_monitors + 1);
238 	if (error)
239 		goto out;
240 	kring->monitors[kring->n_monitors] = mkring;
241 	mkring->mon_pos = kring->n_monitors;
242 	kring->n_monitors++;
243 	if (kring->n_monitors == 1) {
244 		/* this is the first monitor, intercept callbacks */
245 		D("%s: intercept callbacks on %s", mkring->name, kring->name);
246 		kring->mon_sync = kring->nm_sync;
247 		/* zcopy monitors do not override nm_notify(), but
248 		 * we save the original one regardless, so that
249 		 * netmap_monitor_del() does not need to know the
250 		 * monitor type
251 		 */
252 		kring->mon_notify = kring->nm_notify;
253 		if (kring->tx == NR_TX) {
254 			kring->nm_sync = (zcopy ? netmap_zmon_parent_txsync :
255 						  netmap_monitor_parent_txsync);
256 		} else {
257 			kring->nm_sync = (zcopy ? netmap_zmon_parent_rxsync :
258 						  netmap_monitor_parent_rxsync);
259 			if (!zcopy) {
260 				/* also intercept notify */
261 				kring->nm_notify = netmap_monitor_parent_notify;
262 				kring->mon_tail = kring->nr_hwtail;
263 			}
264 		}
265 	}
266 
267 out:
268 	nm_kr_put(kring);
269 	return error;
270 }
271 
272 
273 /* remove the monitor mkring from the list of monitors of kring.
274  * If this is the last monitor, restore the original callbacks
275  */
276 static void
277 netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring)
278 {
279 	/* sinchronize with concurrently running nm_sync()s */
280 	nm_kr_get(kring);
281 	kring->n_monitors--;
282 	if (mkring->mon_pos != kring->n_monitors) {
283 		kring->monitors[mkring->mon_pos] = kring->monitors[kring->n_monitors];
284 		kring->monitors[mkring->mon_pos]->mon_pos = mkring->mon_pos;
285 	}
286 	kring->monitors[kring->n_monitors] = NULL;
287 	if (kring->n_monitors == 0) {
288 		/* this was the last monitor, restore callbacks  and delete monitor array */
289 		D("%s: restoring sync on %s: %p", mkring->name, kring->name, kring->mon_sync);
290 		kring->nm_sync = kring->mon_sync;
291 		kring->mon_sync = NULL;
292 		if (kring->tx == NR_RX) {
293 			D("%s: restoring notify on %s: %p",
294 					mkring->name, kring->name, kring->mon_notify);
295 			kring->nm_notify = kring->mon_notify;
296 			kring->mon_notify = NULL;
297 		}
298 		nm_monitor_dealloc(kring);
299 	}
300 	nm_kr_put(kring);
301 }
302 
303 
304 /* This is called when the monitored adapter leaves netmap mode
305  * (see netmap_do_unregif).
306  * We need to notify the monitors that the monitored rings are gone.
307  * We do this by setting their mna->priv.np_na to NULL.
308  * Note that the rings are already stopped when this happens, so
309  * no monitor ring callback can be active.
310  */
311 void
312 netmap_monitor_stop(struct netmap_adapter *na)
313 {
314 	enum txrx t;
315 
316 	for_rx_tx(t) {
317 		u_int i;
318 
319 		for (i = 0; i < nma_get_nrings(na, t); i++) {
320 			struct netmap_kring *kring = &NMR(na, t)[i];
321 			u_int j;
322 
323 			for (j = 0; j < kring->n_monitors; j++) {
324 				struct netmap_kring *mkring =
325 					kring->monitors[j];
326 				struct netmap_monitor_adapter *mna =
327 					(struct netmap_monitor_adapter *)mkring->na;
328 				/* forget about this adapter */
329 				netmap_adapter_put(mna->priv.np_na);
330 				mna->priv.np_na = NULL;
331 			}
332 		}
333 	}
334 }
335 
336 
337 /* common functions for the nm_register() callbacks of both kind of
338  * monitors.
339  */
340 static int
341 netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon)
342 {
343 	struct netmap_monitor_adapter *mna =
344 		(struct netmap_monitor_adapter *)na;
345 	struct netmap_priv_d *priv = &mna->priv;
346 	struct netmap_adapter *pna = priv->np_na;
347 	struct netmap_kring *kring, *mkring;
348 	int i;
349 	enum txrx t;
350 
351 	ND("%p: onoff %d", na, onoff);
352 	if (onoff) {
353 		if (pna == NULL) {
354 			/* parent left netmap mode, fatal */
355 			D("%s: internal error", na->name);
356 			return ENXIO;
357 		}
358 		for_rx_tx(t) {
359 			if (mna->flags & nm_txrx2flag(t)) {
360 				for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
361 					kring = &NMR(pna, t)[i];
362 					mkring = &na->rx_rings[i];
363 					netmap_monitor_add(mkring, kring, zmon);
364 				}
365 			}
366 		}
367 		na->na_flags |= NAF_NETMAP_ON;
368 	} else {
369 		if (pna == NULL) {
370 			D("%s: parent left netmap mode, nothing to restore", na->name);
371 			return 0;
372 		}
373 		na->na_flags &= ~NAF_NETMAP_ON;
374 		for_rx_tx(t) {
375 			if (mna->flags & nm_txrx2flag(t)) {
376 				for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
377 					kring = &NMR(pna, t)[i];
378 					mkring = &na->rx_rings[i];
379 					netmap_monitor_del(mkring, kring);
380 				}
381 			}
382 		}
383 	}
384 	return 0;
385 }
386 
387 /*
388  ****************************************************************
389  * functions specific for zero-copy monitors
390  ****************************************************************
391  */
392 
393 /*
394  * Common function for both zero-copy tx and rx nm_sync()
395  * callbacks
396  */
397 static int
398 netmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx)
399 {
400 	struct netmap_kring *mkring = kring->monitors[0];
401 	struct netmap_ring *ring = kring->ring, *mring;
402 	int error = 0;
403 	int rel_slots, free_slots, busy, sent = 0;
404 	u_int beg, end, i;
405 	u_int lim = kring->nkr_num_slots - 1,
406 	      mlim; // = mkring->nkr_num_slots - 1;
407 
408 	if (mkring == NULL) {
409 		RD(5, "NULL monitor on %s", kring->name);
410 		return 0;
411 	}
412 	mring = mkring->ring;
413 	mlim = mkring->nkr_num_slots - 1;
414 
415 	/* get the relased slots (rel_slots) */
416 	if (tx == NR_TX) {
417 		beg = kring->nr_hwtail;
418 		error = kring->mon_sync(kring, flags);
419 		if (error)
420 			return error;
421 		end = kring->nr_hwtail;
422 	} else { /* NR_RX */
423 		beg = kring->nr_hwcur;
424 		end = kring->rhead;
425 	}
426 
427 	rel_slots = end - beg;
428 	if (rel_slots < 0)
429 		rel_slots += kring->nkr_num_slots;
430 
431 	if (!rel_slots) {
432 		/* no released slots, but we still need
433 		 * to call rxsync if this is a rx ring
434 		 */
435 		goto out_rxsync;
436 	}
437 
438 	/* we need to lock the monitor receive ring, since it
439 	 * is the target of bot tx and rx traffic from the monitored
440 	 * adapter
441 	 */
442 	mtx_lock(&mkring->q_lock);
443 	/* get the free slots available on the monitor ring */
444 	i = mkring->nr_hwtail;
445 	busy = i - mkring->nr_hwcur;
446 	if (busy < 0)
447 		busy += mkring->nkr_num_slots;
448 	free_slots = mlim - busy;
449 
450 	if (!free_slots)
451 		goto out;
452 
453 	/* swap min(free_slots, rel_slots) slots */
454 	if (free_slots < rel_slots) {
455 		beg += (rel_slots - free_slots);
456 		if (beg >= kring->nkr_num_slots)
457 			beg -= kring->nkr_num_slots;
458 		rel_slots = free_slots;
459 	}
460 
461 	sent = rel_slots;
462 	for ( ; rel_slots; rel_slots--) {
463 		struct netmap_slot *s = &ring->slot[beg];
464 		struct netmap_slot *ms = &mring->slot[i];
465 		uint32_t tmp;
466 
467 		tmp = ms->buf_idx;
468 		ms->buf_idx = s->buf_idx;
469 		s->buf_idx = tmp;
470 		ND(5, "beg %d buf_idx %d", beg, tmp);
471 
472 		tmp = ms->len;
473 		ms->len = s->len;
474 		s->len = tmp;
475 
476 		s->flags |= NS_BUF_CHANGED;
477 
478 		beg = nm_next(beg, lim);
479 		i = nm_next(i, mlim);
480 
481 	}
482 	mb();
483 	mkring->nr_hwtail = i;
484 
485 out:
486 	mtx_unlock(&mkring->q_lock);
487 
488 	if (sent) {
489 		/* notify the new frames to the monitor */
490 		mkring->nm_notify(mkring, 0);
491 	}
492 
493 out_rxsync:
494 	if (tx == NR_RX)
495 		error = kring->mon_sync(kring, flags);
496 
497 	return error;
498 }
499 
500 /* callback used to replace the nm_sync callback in the monitored tx rings */
501 static int
502 netmap_zmon_parent_txsync(struct netmap_kring *kring, int flags)
503 {
504         ND("%s %x", kring->name, flags);
505         return netmap_zmon_parent_sync(kring, flags, NR_TX);
506 }
507 
508 /* callback used to replace the nm_sync callback in the monitored rx rings */
509 static int
510 netmap_zmon_parent_rxsync(struct netmap_kring *kring, int flags)
511 {
512         ND("%s %x", kring->name, flags);
513         return netmap_zmon_parent_sync(kring, flags, NR_RX);
514 }
515 
516 
517 static int
518 netmap_zmon_reg(struct netmap_adapter *na, int onoff)
519 {
520 	return netmap_monitor_reg_common(na, onoff, 1 /* zcopy */);
521 }
522 
523 /* nm_dtor callback for monitors */
524 static void
525 netmap_zmon_dtor(struct netmap_adapter *na)
526 {
527 	struct netmap_monitor_adapter *mna =
528 		(struct netmap_monitor_adapter *)na;
529 	struct netmap_priv_d *priv = &mna->priv;
530 	struct netmap_adapter *pna = priv->np_na;
531 
532 	netmap_adapter_put(pna);
533 }
534 
535 /*
536  ****************************************************************
537  * functions specific for copy monitors
538  ****************************************************************
539  */
540 
541 static void
542 netmap_monitor_parent_sync(struct netmap_kring *kring, u_int first_new, int new_slots)
543 {
544 	u_int j;
545 
546 	for (j = 0; j < kring->n_monitors; j++) {
547 		struct netmap_kring *mkring = kring->monitors[j];
548 		u_int i, mlim, beg;
549 		int free_slots, busy, sent = 0, m;
550 		u_int lim = kring->nkr_num_slots - 1;
551 		struct netmap_ring *ring = kring->ring, *mring = mkring->ring;
552 		u_int max_len = NETMAP_BUF_SIZE(mkring->na);
553 
554 		mlim = mkring->nkr_num_slots - 1;
555 
556 		/* we need to lock the monitor receive ring, since it
557 		 * is the target of bot tx and rx traffic from the monitored
558 		 * adapter
559 		 */
560 		mtx_lock(&mkring->q_lock);
561 		/* get the free slots available on the monitor ring */
562 		i = mkring->nr_hwtail;
563 		busy = i - mkring->nr_hwcur;
564 		if (busy < 0)
565 			busy += mkring->nkr_num_slots;
566 		free_slots = mlim - busy;
567 
568 		if (!free_slots)
569 			goto out;
570 
571 		/* copy min(free_slots, new_slots) slots */
572 		m = new_slots;
573 		beg = first_new;
574 		if (free_slots < m) {
575 			beg += (m - free_slots);
576 			if (beg >= kring->nkr_num_slots)
577 				beg -= kring->nkr_num_slots;
578 			m = free_slots;
579 		}
580 
581 		for ( ; m; m--) {
582 			struct netmap_slot *s = &ring->slot[beg];
583 			struct netmap_slot *ms = &mring->slot[i];
584 			u_int copy_len = s->len;
585 			char *src = NMB(kring->na, s),
586 			     *dst = NMB(mkring->na, ms);
587 
588 			if (unlikely(copy_len > max_len)) {
589 				RD(5, "%s->%s: truncating %d to %d", kring->name,
590 						mkring->name, copy_len, max_len);
591 				copy_len = max_len;
592 			}
593 
594 			memcpy(dst, src, copy_len);
595 			ms->len = copy_len;
596 			sent++;
597 
598 			beg = nm_next(beg, lim);
599 			i = nm_next(i, mlim);
600 		}
601 		mb();
602 		mkring->nr_hwtail = i;
603 	out:
604 		mtx_unlock(&mkring->q_lock);
605 
606 		if (sent) {
607 			/* notify the new frames to the monitor */
608 			mkring->nm_notify(mkring, 0);
609 		}
610 	}
611 }
612 
613 /* callback used to replace the nm_sync callback in the monitored tx rings */
614 static int
615 netmap_monitor_parent_txsync(struct netmap_kring *kring, int flags)
616 {
617 	u_int first_new;
618 	int new_slots;
619 
620 	/* get the new slots */
621 	first_new = kring->nr_hwcur;
622         new_slots = kring->rhead - first_new;
623         if (new_slots < 0)
624                 new_slots += kring->nkr_num_slots;
625 	if (new_slots)
626 		netmap_monitor_parent_sync(kring, first_new, new_slots);
627 	return kring->mon_sync(kring, flags);
628 }
629 
630 /* callback used to replace the nm_sync callback in the monitored rx rings */
631 static int
632 netmap_monitor_parent_rxsync(struct netmap_kring *kring, int flags)
633 {
634 	u_int first_new;
635 	int new_slots, error;
636 
637 	/* get the new slots */
638 	error =  kring->mon_sync(kring, flags);
639 	if (error)
640 		return error;
641 	first_new = kring->mon_tail;
642         new_slots = kring->nr_hwtail - first_new;
643         if (new_slots < 0)
644                 new_slots += kring->nkr_num_slots;
645 	if (new_slots)
646 		netmap_monitor_parent_sync(kring, first_new, new_slots);
647 	kring->mon_tail = kring->nr_hwtail;
648 	return 0;
649 }
650 
651 /* callback used to replace the nm_notify() callback in the monitored rx rings */
652 static int
653 netmap_monitor_parent_notify(struct netmap_kring *kring, int flags)
654 {
655 	ND(5, "%s %x", kring->name, flags);
656 	/* ?xsync callbacks have tryget called by their callers
657 	 * (NIOCREGIF and poll()), but here we have to call it
658 	 * by ourself
659 	 */
660 	if (nm_kr_tryget(kring))
661 		goto out;
662 	netmap_monitor_parent_rxsync(kring, NAF_FORCE_READ);
663 	nm_kr_put(kring);
664 out:
665         return kring->mon_notify(kring, flags);
666 }
667 
668 
669 static int
670 netmap_monitor_reg(struct netmap_adapter *na, int onoff)
671 {
672 	return netmap_monitor_reg_common(na, onoff, 0 /* no zcopy */);
673 }
674 
675 static void
676 netmap_monitor_dtor(struct netmap_adapter *na)
677 {
678 	struct netmap_monitor_adapter *mna =
679 		(struct netmap_monitor_adapter *)na;
680 	struct netmap_priv_d *priv = &mna->priv;
681 	struct netmap_adapter *pna = priv->np_na;
682 
683 	netmap_adapter_put(pna);
684 }
685 
686 
687 /* check if nmr is a request for a monitor adapter that we can satisfy */
688 int
689 netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na, int create)
690 {
691 	struct nmreq pnmr;
692 	struct netmap_adapter *pna; /* parent adapter */
693 	struct netmap_monitor_adapter *mna;
694 	int i, error;
695 	enum txrx t;
696 	int zcopy = (nmr->nr_flags & NR_ZCOPY_MON);
697 	char monsuff[10] = "";
698 
699 	if ((nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) {
700 		ND("not a monitor");
701 		return 0;
702 	}
703 	/* this is a request for a monitor adapter */
704 
705 	D("flags %x", nmr->nr_flags);
706 
707 	mna = malloc(sizeof(*mna), M_DEVBUF, M_NOWAIT | M_ZERO);
708 	if (mna == NULL) {
709 		D("memory error");
710 		return ENOMEM;
711 	}
712 
713 	/* first, try to find the adapter that we want to monitor
714 	 * We use the same nmr, after we have turned off the monitor flags.
715 	 * In this way we can potentially monitor everything netmap understands,
716 	 * except other monitors.
717 	 */
718 	memcpy(&pnmr, nmr, sizeof(pnmr));
719 	pnmr.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX);
720 	error = netmap_get_na(&pnmr, &pna, create);
721 	if (error) {
722 		D("parent lookup failed: %d", error);
723 		return error;
724 	}
725 	D("found parent: %s", pna->name);
726 
727 	if (!nm_netmap_on(pna)) {
728 		/* parent not in netmap mode */
729 		/* XXX we can wait for the parent to enter netmap mode,
730 		 * by intercepting its nm_register callback (2014-03-16)
731 		 */
732 		D("%s not in netmap mode", pna->name);
733 		error = EINVAL;
734 		goto put_out;
735 	}
736 
737 	/* grab all the rings we need in the parent */
738 	mna->priv.np_na = pna;
739 	error = netmap_interp_ringid(&mna->priv, nmr->nr_ringid, nmr->nr_flags);
740 	if (error) {
741 		D("ringid error");
742 		goto put_out;
743 	}
744 	if (mna->priv.np_qlast[NR_TX] - mna->priv.np_qfirst[NR_TX] == 1) {
745 		snprintf(monsuff, 10, "-%d", mna->priv.np_qfirst[NR_TX]);
746 	}
747 	snprintf(mna->up.name, sizeof(mna->up.name), "%s%s/%s%s%s", pna->name,
748 			monsuff,
749 			zcopy ? "z" : "",
750 			(nmr->nr_flags & NR_MONITOR_RX) ? "r" : "",
751 			(nmr->nr_flags & NR_MONITOR_TX) ? "t" : "");
752 
753 	if (zcopy) {
754 		/* zero copy monitors need exclusive access to the monitored rings */
755 		for_rx_tx(t) {
756 			if (! (nmr->nr_flags & nm_txrx2flag(t)))
757 				continue;
758 			for (i = mna->priv.np_qfirst[t]; i < mna->priv.np_qlast[t]; i++) {
759 				struct netmap_kring *kring = &NMR(pna, t)[i];
760 				if (kring->n_monitors > 0) {
761 					error = EBUSY;
762 					D("ring %s already monitored by %s", kring->name,
763 							kring->monitors[0]->name);
764 					goto put_out;
765 				}
766 			}
767 		}
768 		mna->up.nm_register = netmap_zmon_reg;
769 		mna->up.nm_dtor = netmap_zmon_dtor;
770 		/* to have zero copy, we need to use the same memory allocator
771 		 * as the monitored port
772 		 */
773 		mna->up.nm_mem = pna->nm_mem;
774 		mna->up.na_lut = pna->na_lut;
775 	} else {
776 		/* normal monitors are incompatible with zero copy ones */
777 		for_rx_tx(t) {
778 			if (! (nmr->nr_flags & nm_txrx2flag(t)))
779 				continue;
780 			for (i = mna->priv.np_qfirst[t]; i < mna->priv.np_qlast[t]; i++) {
781 				struct netmap_kring *kring = &NMR(pna, t)[i];
782 				if (kring->n_monitors > 0 &&
783 				    kring->monitors[0]->na->nm_register == netmap_zmon_reg)
784 				{
785 					error = EBUSY;
786 					D("ring busy");
787 					goto put_out;
788 				}
789 			}
790 		}
791 		mna->up.nm_rxsync = netmap_monitor_rxsync;
792 		mna->up.nm_register = netmap_monitor_reg;
793 		mna->up.nm_dtor = netmap_monitor_dtor;
794 	}
795 
796 	/* the monitor supports the host rings iff the parent does */
797 	mna->up.na_flags = (pna->na_flags & NAF_HOST_RINGS);
798 	/* a do-nothing txsync: monitors cannot be used to inject packets */
799 	mna->up.nm_txsync = netmap_monitor_txsync;
800 	mna->up.nm_rxsync = netmap_monitor_rxsync;
801 	mna->up.nm_krings_create = netmap_monitor_krings_create;
802 	mna->up.nm_krings_delete = netmap_monitor_krings_delete;
803 	mna->up.num_tx_rings = 1; // XXX we don't need it, but field can't be zero
804 	/* we set the number of our rx_rings to be max(num_rx_rings, num_rx_rings)
805 	 * in the parent
806 	 */
807 	mna->up.num_rx_rings = pna->num_rx_rings;
808 	if (pna->num_tx_rings > pna->num_rx_rings)
809 		mna->up.num_rx_rings = pna->num_tx_rings;
810 	/* by default, the number of slots is the same as in
811 	 * the parent rings, but the user may ask for a different
812 	 * number
813 	 */
814 	mna->up.num_tx_desc = nmr->nr_tx_slots;
815 	nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc,
816 			1, NM_MONITOR_MAXSLOTS, NULL);
817 	mna->up.num_rx_desc = nmr->nr_rx_slots;
818 	nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc,
819 			1, NM_MONITOR_MAXSLOTS, NULL);
820 	error = netmap_attach_common(&mna->up);
821 	if (error) {
822 		D("attach_common error");
823 		goto put_out;
824 	}
825 
826 	/* remember the traffic directions we have to monitor */
827 	mna->flags = (nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX));
828 
829 	*na = &mna->up;
830 	netmap_adapter_get(*na);
831 
832 	/* write the configuration back */
833 	nmr->nr_tx_rings = mna->up.num_tx_rings;
834 	nmr->nr_rx_rings = mna->up.num_rx_rings;
835 	nmr->nr_tx_slots = mna->up.num_tx_desc;
836 	nmr->nr_rx_slots = mna->up.num_rx_desc;
837 
838 	/* keep the reference to the parent */
839 	D("monitor ok");
840 
841 	return 0;
842 
843 put_out:
844 	netmap_adapter_put(pna);
845 	free(mna, M_DEVBUF);
846 	return error;
847 }
848 
849 
850 #endif /* WITH_MONITOR */
851