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 				mna->priv.np_na = NULL;
330 			}
331 		}
332 	}
333 }
334 
335 
336 /* common functions for the nm_register() callbacks of both kind of
337  * monitors.
338  */
339 static int
340 netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon)
341 {
342 	struct netmap_monitor_adapter *mna =
343 		(struct netmap_monitor_adapter *)na;
344 	struct netmap_priv_d *priv = &mna->priv;
345 	struct netmap_adapter *pna = priv->np_na;
346 	struct netmap_kring *kring, *mkring;
347 	int i;
348 	enum txrx t;
349 
350 	ND("%p: onoff %d", na, onoff);
351 	if (onoff) {
352 		if (pna == NULL) {
353 			/* parent left netmap mode, fatal */
354 			D("%s: internal error", na->name);
355 			return ENXIO;
356 		}
357 		for_rx_tx(t) {
358 			if (mna->flags & nm_txrx2flag(t)) {
359 				for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
360 					kring = &NMR(pna, t)[i];
361 					mkring = &na->rx_rings[i];
362 					netmap_monitor_add(mkring, kring, zmon);
363 				}
364 			}
365 		}
366 		na->na_flags |= NAF_NETMAP_ON;
367 	} else {
368 		if (pna == NULL) {
369 			D("%s: parent left netmap mode, nothing to restore", na->name);
370 			return 0;
371 		}
372 		na->na_flags &= ~NAF_NETMAP_ON;
373 		for_rx_tx(t) {
374 			if (mna->flags & nm_txrx2flag(t)) {
375 				for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
376 					kring = &NMR(pna, t)[i];
377 					mkring = &na->rx_rings[i];
378 					netmap_monitor_del(mkring, kring);
379 				}
380 			}
381 		}
382 	}
383 	return 0;
384 }
385 
386 /*
387  ****************************************************************
388  * functions specific for zero-copy monitors
389  ****************************************************************
390  */
391 
392 /*
393  * Common function for both zero-copy tx and rx nm_sync()
394  * callbacks
395  */
396 static int
397 netmap_zmon_parent_sync(struct netmap_kring *kring, int flags, enum txrx tx)
398 {
399 	struct netmap_kring *mkring = kring->monitors[0];
400 	struct netmap_ring *ring = kring->ring, *mring;
401 	int error = 0;
402 	int rel_slots, free_slots, busy, sent = 0;
403 	u_int beg, end, i;
404 	u_int lim = kring->nkr_num_slots - 1,
405 	      mlim; // = mkring->nkr_num_slots - 1;
406 
407 	if (mkring == NULL) {
408 		RD(5, "NULL monitor on %s", kring->name);
409 		return 0;
410 	}
411 	mring = mkring->ring;
412 	mlim = mkring->nkr_num_slots - 1;
413 
414 	/* get the relased slots (rel_slots) */
415 	if (tx == NR_TX) {
416 		beg = kring->nr_hwtail;
417 		error = kring->mon_sync(kring, flags);
418 		if (error)
419 			return error;
420 		end = kring->nr_hwtail;
421 	} else { /* NR_RX */
422 		beg = kring->nr_hwcur;
423 		end = kring->rhead;
424 	}
425 
426 	rel_slots = end - beg;
427 	if (rel_slots < 0)
428 		rel_slots += kring->nkr_num_slots;
429 
430 	if (!rel_slots) {
431 		/* no released slots, but we still need
432 		 * to call rxsync if this is a rx ring
433 		 */
434 		goto out_rxsync;
435 	}
436 
437 	/* we need to lock the monitor receive ring, since it
438 	 * is the target of bot tx and rx traffic from the monitored
439 	 * adapter
440 	 */
441 	mtx_lock(&mkring->q_lock);
442 	/* get the free slots available on the monitor ring */
443 	i = mkring->nr_hwtail;
444 	busy = i - mkring->nr_hwcur;
445 	if (busy < 0)
446 		busy += mkring->nkr_num_slots;
447 	free_slots = mlim - busy;
448 
449 	if (!free_slots)
450 		goto out;
451 
452 	/* swap min(free_slots, rel_slots) slots */
453 	if (free_slots < rel_slots) {
454 		beg += (rel_slots - free_slots);
455 		if (beg >= kring->nkr_num_slots)
456 			beg -= kring->nkr_num_slots;
457 		rel_slots = free_slots;
458 	}
459 
460 	sent = rel_slots;
461 	for ( ; rel_slots; rel_slots--) {
462 		struct netmap_slot *s = &ring->slot[beg];
463 		struct netmap_slot *ms = &mring->slot[i];
464 		uint32_t tmp;
465 
466 		tmp = ms->buf_idx;
467 		ms->buf_idx = s->buf_idx;
468 		s->buf_idx = tmp;
469 		ND(5, "beg %d buf_idx %d", beg, tmp);
470 
471 		tmp = ms->len;
472 		ms->len = s->len;
473 		s->len = tmp;
474 
475 		s->flags |= NS_BUF_CHANGED;
476 
477 		beg = nm_next(beg, lim);
478 		i = nm_next(i, mlim);
479 
480 	}
481 	mb();
482 	mkring->nr_hwtail = i;
483 
484 out:
485 	mtx_unlock(&mkring->q_lock);
486 
487 	if (sent) {
488 		/* notify the new frames to the monitor */
489 		mkring->nm_notify(mkring, 0);
490 	}
491 
492 out_rxsync:
493 	if (tx == NR_RX)
494 		error = kring->mon_sync(kring, flags);
495 
496 	return error;
497 }
498 
499 /* callback used to replace the nm_sync callback in the monitored tx rings */
500 static int
501 netmap_zmon_parent_txsync(struct netmap_kring *kring, int flags)
502 {
503         ND("%s %x", kring->name, flags);
504         return netmap_zmon_parent_sync(kring, flags, NR_TX);
505 }
506 
507 /* callback used to replace the nm_sync callback in the monitored rx rings */
508 static int
509 netmap_zmon_parent_rxsync(struct netmap_kring *kring, int flags)
510 {
511         ND("%s %x", kring->name, flags);
512         return netmap_zmon_parent_sync(kring, flags, NR_RX);
513 }
514 
515 
516 static int
517 netmap_zmon_reg(struct netmap_adapter *na, int onoff)
518 {
519 	return netmap_monitor_reg_common(na, onoff, 1 /* zcopy */);
520 }
521 
522 /* nm_dtor callback for monitors */
523 static void
524 netmap_zmon_dtor(struct netmap_adapter *na)
525 {
526 	struct netmap_monitor_adapter *mna =
527 		(struct netmap_monitor_adapter *)na;
528 	struct netmap_priv_d *priv = &mna->priv;
529 	struct netmap_adapter *pna = priv->np_na;
530 
531 	netmap_adapter_put(pna);
532 }
533 
534 /*
535  ****************************************************************
536  * functions specific for copy monitors
537  ****************************************************************
538  */
539 
540 static void
541 netmap_monitor_parent_sync(struct netmap_kring *kring, u_int first_new, int new_slots)
542 {
543 	u_int j;
544 
545 	for (j = 0; j < kring->n_monitors; j++) {
546 		struct netmap_kring *mkring = kring->monitors[j];
547 		u_int i, mlim, beg;
548 		int free_slots, busy, sent = 0, m;
549 		u_int lim = kring->nkr_num_slots - 1;
550 		struct netmap_ring *ring = kring->ring, *mring = mkring->ring;
551 		u_int max_len = NETMAP_BUF_SIZE(mkring->na);
552 
553 		mlim = mkring->nkr_num_slots - 1;
554 
555 		/* we need to lock the monitor receive ring, since it
556 		 * is the target of bot tx and rx traffic from the monitored
557 		 * adapter
558 		 */
559 		mtx_lock(&mkring->q_lock);
560 		/* get the free slots available on the monitor ring */
561 		i = mkring->nr_hwtail;
562 		busy = i - mkring->nr_hwcur;
563 		if (busy < 0)
564 			busy += mkring->nkr_num_slots;
565 		free_slots = mlim - busy;
566 
567 		if (!free_slots)
568 			goto out;
569 
570 		/* copy min(free_slots, new_slots) slots */
571 		m = new_slots;
572 		beg = first_new;
573 		if (free_slots < m) {
574 			beg += (m - free_slots);
575 			if (beg >= kring->nkr_num_slots)
576 				beg -= kring->nkr_num_slots;
577 			m = free_slots;
578 		}
579 
580 		for ( ; m; m--) {
581 			struct netmap_slot *s = &ring->slot[beg];
582 			struct netmap_slot *ms = &mring->slot[i];
583 			u_int copy_len = s->len;
584 			char *src = NMB(kring->na, s),
585 			     *dst = NMB(mkring->na, ms);
586 
587 			if (unlikely(copy_len > max_len)) {
588 				RD(5, "%s->%s: truncating %d to %d", kring->name,
589 						mkring->name, copy_len, max_len);
590 				copy_len = max_len;
591 			}
592 
593 			memcpy(dst, src, copy_len);
594 			ms->len = copy_len;
595 			sent++;
596 
597 			beg = nm_next(beg, lim);
598 			i = nm_next(i, mlim);
599 		}
600 		mb();
601 		mkring->nr_hwtail = i;
602 	out:
603 		mtx_unlock(&mkring->q_lock);
604 
605 		if (sent) {
606 			/* notify the new frames to the monitor */
607 			mkring->nm_notify(mkring, 0);
608 		}
609 	}
610 }
611 
612 /* callback used to replace the nm_sync callback in the monitored tx rings */
613 static int
614 netmap_monitor_parent_txsync(struct netmap_kring *kring, int flags)
615 {
616 	u_int first_new;
617 	int new_slots;
618 
619 	/* get the new slots */
620 	first_new = kring->nr_hwcur;
621         new_slots = kring->rhead - first_new;
622         if (new_slots < 0)
623                 new_slots += kring->nkr_num_slots;
624 	if (new_slots)
625 		netmap_monitor_parent_sync(kring, first_new, new_slots);
626 	return kring->mon_sync(kring, flags);
627 }
628 
629 /* callback used to replace the nm_sync callback in the monitored rx rings */
630 static int
631 netmap_monitor_parent_rxsync(struct netmap_kring *kring, int flags)
632 {
633 	u_int first_new;
634 	int new_slots, error;
635 
636 	/* get the new slots */
637 	error =  kring->mon_sync(kring, flags);
638 	if (error)
639 		return error;
640 	first_new = kring->mon_tail;
641         new_slots = kring->nr_hwtail - first_new;
642         if (new_slots < 0)
643                 new_slots += kring->nkr_num_slots;
644 	if (new_slots)
645 		netmap_monitor_parent_sync(kring, first_new, new_slots);
646 	kring->mon_tail = kring->nr_hwtail;
647 	return 0;
648 }
649 
650 /* callback used to replace the nm_notify() callback in the monitored rx rings */
651 static int
652 netmap_monitor_parent_notify(struct netmap_kring *kring, int flags)
653 {
654 	ND(5, "%s %x", kring->name, flags);
655 	/* ?xsync callbacks have tryget called by their callers
656 	 * (NIOCREGIF and poll()), but here we have to call it
657 	 * by ourself
658 	 */
659 	if (nm_kr_tryget(kring))
660 		goto out;
661 	netmap_monitor_parent_rxsync(kring, NAF_FORCE_READ);
662 	nm_kr_put(kring);
663 out:
664         return kring->mon_notify(kring, flags);
665 }
666 
667 
668 static int
669 netmap_monitor_reg(struct netmap_adapter *na, int onoff)
670 {
671 	return netmap_monitor_reg_common(na, onoff, 0 /* no zcopy */);
672 }
673 
674 static void
675 netmap_monitor_dtor(struct netmap_adapter *na)
676 {
677 	struct netmap_monitor_adapter *mna =
678 		(struct netmap_monitor_adapter *)na;
679 	struct netmap_priv_d *priv = &mna->priv;
680 	struct netmap_adapter *pna = priv->np_na;
681 
682 	netmap_adapter_put(pna);
683 }
684 
685 
686 /* check if nmr is a request for a monitor adapter that we can satisfy */
687 int
688 netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na, int create)
689 {
690 	struct nmreq pnmr;
691 	struct netmap_adapter *pna; /* parent adapter */
692 	struct netmap_monitor_adapter *mna;
693 	int i, error;
694 	enum txrx t;
695 	int zcopy = (nmr->nr_flags & NR_ZCOPY_MON);
696 	char monsuff[10] = "";
697 
698 	if ((nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) {
699 		ND("not a monitor");
700 		return 0;
701 	}
702 	/* this is a request for a monitor adapter */
703 
704 	D("flags %x", nmr->nr_flags);
705 
706 	mna = malloc(sizeof(*mna), M_DEVBUF, M_NOWAIT | M_ZERO);
707 	if (mna == NULL) {
708 		D("memory error");
709 		return ENOMEM;
710 	}
711 
712 	/* first, try to find the adapter that we want to monitor
713 	 * We use the same nmr, after we have turned off the monitor flags.
714 	 * In this way we can potentially monitor everything netmap understands,
715 	 * except other monitors.
716 	 */
717 	memcpy(&pnmr, nmr, sizeof(pnmr));
718 	pnmr.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX);
719 	error = netmap_get_na(&pnmr, &pna, create);
720 	if (error) {
721 		D("parent lookup failed: %d", error);
722 		return error;
723 	}
724 	D("found parent: %s", pna->name);
725 
726 	if (!nm_netmap_on(pna)) {
727 		/* parent not in netmap mode */
728 		/* XXX we can wait for the parent to enter netmap mode,
729 		 * by intercepting its nm_register callback (2014-03-16)
730 		 */
731 		D("%s not in netmap mode", pna->name);
732 		error = EINVAL;
733 		goto put_out;
734 	}
735 
736 	/* grab all the rings we need in the parent */
737 	mna->priv.np_na = pna;
738 	error = netmap_interp_ringid(&mna->priv, nmr->nr_ringid, nmr->nr_flags);
739 	if (error) {
740 		D("ringid error");
741 		goto put_out;
742 	}
743 	if (mna->priv.np_qlast[NR_TX] - mna->priv.np_qfirst[NR_TX] == 1) {
744 		snprintf(monsuff, 10, "-%d", mna->priv.np_qfirst[NR_TX]);
745 	}
746 	snprintf(mna->up.name, sizeof(mna->up.name), "%s%s/%s%s%s", pna->name,
747 			monsuff,
748 			zcopy ? "z" : "",
749 			(nmr->nr_flags & NR_MONITOR_RX) ? "r" : "",
750 			(nmr->nr_flags & NR_MONITOR_TX) ? "t" : "");
751 
752 	if (zcopy) {
753 		/* zero copy monitors need exclusive access to the monitored rings */
754 		for_rx_tx(t) {
755 			if (! (nmr->nr_flags & nm_txrx2flag(t)))
756 				continue;
757 			for (i = mna->priv.np_qfirst[t]; i < mna->priv.np_qlast[t]; i++) {
758 				struct netmap_kring *kring = &NMR(pna, t)[i];
759 				if (kring->n_monitors > 0) {
760 					error = EBUSY;
761 					D("ring %s already monitored by %s", kring->name,
762 							kring->monitors[0]->name);
763 					goto put_out;
764 				}
765 			}
766 		}
767 		mna->up.nm_register = netmap_zmon_reg;
768 		mna->up.nm_dtor = netmap_zmon_dtor;
769 		/* to have zero copy, we need to use the same memory allocator
770 		 * as the monitored port
771 		 */
772 		mna->up.nm_mem = pna->nm_mem;
773 		mna->up.na_lut = pna->na_lut;
774 	} else {
775 		/* normal monitors are incompatible with zero copy ones */
776 		for_rx_tx(t) {
777 			if (! (nmr->nr_flags & nm_txrx2flag(t)))
778 				continue;
779 			for (i = mna->priv.np_qfirst[t]; i < mna->priv.np_qlast[t]; i++) {
780 				struct netmap_kring *kring = &NMR(pna, t)[i];
781 				if (kring->n_monitors > 0 &&
782 				    kring->monitors[0]->na->nm_register == netmap_zmon_reg)
783 				{
784 					error = EBUSY;
785 					D("ring busy");
786 					goto put_out;
787 				}
788 			}
789 		}
790 		mna->up.nm_rxsync = netmap_monitor_rxsync;
791 		mna->up.nm_register = netmap_monitor_reg;
792 		mna->up.nm_dtor = netmap_monitor_dtor;
793 	}
794 
795 	/* the monitor supports the host rings iff the parent does */
796 	mna->up.na_flags = (pna->na_flags & NAF_HOST_RINGS);
797 	/* a do-nothing txsync: monitors cannot be used to inject packets */
798 	mna->up.nm_txsync = netmap_monitor_txsync;
799 	mna->up.nm_rxsync = netmap_monitor_rxsync;
800 	mna->up.nm_krings_create = netmap_monitor_krings_create;
801 	mna->up.nm_krings_delete = netmap_monitor_krings_delete;
802 	mna->up.num_tx_rings = 1; // XXX we don't need it, but field can't be zero
803 	/* we set the number of our rx_rings to be max(num_rx_rings, num_rx_rings)
804 	 * in the parent
805 	 */
806 	mna->up.num_rx_rings = pna->num_rx_rings;
807 	if (pna->num_tx_rings > pna->num_rx_rings)
808 		mna->up.num_rx_rings = pna->num_tx_rings;
809 	/* by default, the number of slots is the same as in
810 	 * the parent rings, but the user may ask for a different
811 	 * number
812 	 */
813 	mna->up.num_tx_desc = nmr->nr_tx_slots;
814 	nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc,
815 			1, NM_MONITOR_MAXSLOTS, NULL);
816 	mna->up.num_rx_desc = nmr->nr_rx_slots;
817 	nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc,
818 			1, NM_MONITOR_MAXSLOTS, NULL);
819 	error = netmap_attach_common(&mna->up);
820 	if (error) {
821 		D("attach_common error");
822 		goto put_out;
823 	}
824 
825 	/* remember the traffic directions we have to monitor */
826 	mna->flags = (nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX));
827 
828 	*na = &mna->up;
829 	netmap_adapter_get(*na);
830 
831 	/* write the configuration back */
832 	nmr->nr_tx_rings = mna->up.num_tx_rings;
833 	nmr->nr_rx_rings = mna->up.num_rx_rings;
834 	nmr->nr_tx_slots = mna->up.num_tx_desc;
835 	nmr->nr_rx_slots = mna->up.num_rx_desc;
836 
837 	/* keep the reference to the parent */
838 	D("monitor ok");
839 
840 	return 0;
841 
842 put_out:
843 	netmap_adapter_put(pna);
844 	free(mna, M_DEVBUF);
845 	return error;
846 }
847 
848 
849 #endif /* WITH_MONITOR */
850