14bf50f18SLuigi Rizzo /* 24bf50f18SLuigi Rizzo * Copyright (C) 2014 Giuseppe Lettieri. All rights reserved. 34bf50f18SLuigi Rizzo * 44bf50f18SLuigi Rizzo * Redistribution and use in source and binary forms, with or without 54bf50f18SLuigi Rizzo * modification, are permitted provided that the following conditions 64bf50f18SLuigi Rizzo * are met: 74bf50f18SLuigi Rizzo * 1. Redistributions of source code must retain the above copyright 84bf50f18SLuigi Rizzo * notice, this list of conditions and the following disclaimer. 94bf50f18SLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 104bf50f18SLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 114bf50f18SLuigi Rizzo * documentation and/or other materials provided with the distribution. 124bf50f18SLuigi Rizzo * 134bf50f18SLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 144bf50f18SLuigi Rizzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 154bf50f18SLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 164bf50f18SLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 174bf50f18SLuigi Rizzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 184bf50f18SLuigi Rizzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 194bf50f18SLuigi Rizzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 204bf50f18SLuigi Rizzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 214bf50f18SLuigi Rizzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 224bf50f18SLuigi Rizzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 234bf50f18SLuigi Rizzo * SUCH DAMAGE. 244bf50f18SLuigi Rizzo */ 254bf50f18SLuigi Rizzo 264bf50f18SLuigi Rizzo /* 274bf50f18SLuigi Rizzo * $FreeBSD$ 284bf50f18SLuigi Rizzo * 294bf50f18SLuigi Rizzo * Monitors 304bf50f18SLuigi Rizzo * 314bf50f18SLuigi Rizzo * netmap monitors can be used to do zero-copy monitoring of network traffic 324bf50f18SLuigi Rizzo * on another adapter, when the latter adapter is working in netmap mode. 334bf50f18SLuigi Rizzo * 344bf50f18SLuigi Rizzo * Monitors offer to userspace the same interface as any other netmap port, 354bf50f18SLuigi Rizzo * with as many pairs of netmap rings as the monitored adapter. 364bf50f18SLuigi Rizzo * However, only the rx rings are actually used. Each monitor rx ring receives 374bf50f18SLuigi Rizzo * the traffic transiting on both the tx and rx corresponding rings in the 384bf50f18SLuigi Rizzo * monitored adapter. During registration, the user can choose if she wants 394bf50f18SLuigi Rizzo * to intercept tx only, rx only, or both tx and rx traffic. 404bf50f18SLuigi Rizzo * 414bf50f18SLuigi Rizzo * The monitor only sees the frames after they have been consumed in the 424bf50f18SLuigi Rizzo * monitored adapter: 434bf50f18SLuigi Rizzo * 444bf50f18SLuigi Rizzo * - For tx traffic, this is after the slots containing the frames have been 454bf50f18SLuigi Rizzo * marked as free. Note that this may happen at a considerably delay after 464bf50f18SLuigi Rizzo * frame transmission, since freeing of slots is often done lazily. 474bf50f18SLuigi Rizzo * 484bf50f18SLuigi Rizzo * - For rx traffic, this is after the consumer on the monitored adapter 494bf50f18SLuigi Rizzo * has released them. In most cases, the consumer is a userspace 504bf50f18SLuigi Rizzo * application which may have modified the frame contents. 514bf50f18SLuigi Rizzo * 524bf50f18SLuigi Rizzo * If the monitor is not able to cope with the stream of frames, excess traffic 534bf50f18SLuigi Rizzo * will be dropped. 544bf50f18SLuigi Rizzo * 554bf50f18SLuigi Rizzo * Each ring can be monitored by at most one monitor. This may change in the 564bf50f18SLuigi Rizzo * future, if we implement monitor chaining. 574bf50f18SLuigi Rizzo * 584bf50f18SLuigi Rizzo */ 594bf50f18SLuigi Rizzo 604bf50f18SLuigi Rizzo 614bf50f18SLuigi Rizzo #if defined(__FreeBSD__) 624bf50f18SLuigi Rizzo #include <sys/cdefs.h> /* prerequisite */ 634bf50f18SLuigi Rizzo 644bf50f18SLuigi Rizzo #include <sys/types.h> 654bf50f18SLuigi Rizzo #include <sys/errno.h> 664bf50f18SLuigi Rizzo #include <sys/param.h> /* defines used in kernel.h */ 674bf50f18SLuigi Rizzo #include <sys/kernel.h> /* types used in module initialization */ 684bf50f18SLuigi Rizzo #include <sys/malloc.h> 694bf50f18SLuigi Rizzo #include <sys/poll.h> 704bf50f18SLuigi Rizzo #include <sys/lock.h> 714bf50f18SLuigi Rizzo #include <sys/rwlock.h> 724bf50f18SLuigi Rizzo #include <sys/selinfo.h> 734bf50f18SLuigi Rizzo #include <sys/sysctl.h> 744bf50f18SLuigi Rizzo #include <sys/socket.h> /* sockaddrs */ 754bf50f18SLuigi Rizzo #include <net/if.h> 764bf50f18SLuigi Rizzo #include <net/if_var.h> 774bf50f18SLuigi Rizzo #include <machine/bus.h> /* bus_dmamap_* */ 784bf50f18SLuigi Rizzo #include <sys/refcount.h> 794bf50f18SLuigi Rizzo 804bf50f18SLuigi Rizzo 814bf50f18SLuigi Rizzo #elif defined(linux) 824bf50f18SLuigi Rizzo 834bf50f18SLuigi Rizzo #include "bsd_glue.h" 844bf50f18SLuigi Rizzo 854bf50f18SLuigi Rizzo #elif defined(__APPLE__) 864bf50f18SLuigi Rizzo 874bf50f18SLuigi Rizzo #warning OSX support is only partial 884bf50f18SLuigi Rizzo #include "osx_glue.h" 894bf50f18SLuigi Rizzo 904bf50f18SLuigi Rizzo #else 914bf50f18SLuigi Rizzo 924bf50f18SLuigi Rizzo #error Unsupported platform 934bf50f18SLuigi Rizzo 944bf50f18SLuigi Rizzo #endif /* unsupported */ 954bf50f18SLuigi Rizzo 964bf50f18SLuigi Rizzo /* 974bf50f18SLuigi Rizzo * common headers 984bf50f18SLuigi Rizzo */ 994bf50f18SLuigi Rizzo 1004bf50f18SLuigi Rizzo #include <net/netmap.h> 1014bf50f18SLuigi Rizzo #include <dev/netmap/netmap_kern.h> 1024bf50f18SLuigi Rizzo #include <dev/netmap/netmap_mem2.h> 1034bf50f18SLuigi Rizzo 1044bf50f18SLuigi Rizzo #ifdef WITH_MONITOR 1054bf50f18SLuigi Rizzo 1064bf50f18SLuigi Rizzo #define NM_MONITOR_MAXSLOTS 4096 1074bf50f18SLuigi Rizzo 1084bf50f18SLuigi Rizzo /* monitor works by replacing the nm_sync callbacks in the monitored rings. 1094bf50f18SLuigi Rizzo * The actions to be performed are the same on both tx and rx rings, so we 1104bf50f18SLuigi Rizzo * have collected them here 1114bf50f18SLuigi Rizzo */ 1124bf50f18SLuigi Rizzo static int 1134bf50f18SLuigi Rizzo netmap_monitor_parent_sync(struct netmap_kring *kring, int flags, u_int* ringptr) 1144bf50f18SLuigi Rizzo { 1154bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna = kring->monitor; 1164bf50f18SLuigi Rizzo struct netmap_kring *mkring = &mna->up.rx_rings[kring->ring_id]; 1174bf50f18SLuigi Rizzo struct netmap_ring *ring = kring->ring, *mring = mkring->ring; 1184bf50f18SLuigi Rizzo int error; 1194bf50f18SLuigi Rizzo int rel_slots, free_slots, busy; 1204bf50f18SLuigi Rizzo u_int beg, end, i; 1214bf50f18SLuigi Rizzo u_int lim = kring->nkr_num_slots - 1, 1224bf50f18SLuigi Rizzo mlim = mkring->nkr_num_slots - 1; 1234bf50f18SLuigi Rizzo 1244bf50f18SLuigi Rizzo /* get the relased slots (rel_slots) */ 1254bf50f18SLuigi Rizzo beg = *ringptr; 1264bf50f18SLuigi Rizzo error = kring->save_sync(kring, flags); 1274bf50f18SLuigi Rizzo if (error) 1284bf50f18SLuigi Rizzo return error; 1294bf50f18SLuigi Rizzo end = *ringptr; 1304bf50f18SLuigi Rizzo rel_slots = end - beg; 1314bf50f18SLuigi Rizzo if (rel_slots < 0) 1324bf50f18SLuigi Rizzo rel_slots += kring->nkr_num_slots; 1334bf50f18SLuigi Rizzo 1344bf50f18SLuigi Rizzo if (!rel_slots) { 1354bf50f18SLuigi Rizzo return 0; 1364bf50f18SLuigi Rizzo } 1374bf50f18SLuigi Rizzo 1384bf50f18SLuigi Rizzo /* we need to lock the monitor receive ring, since it 1394bf50f18SLuigi Rizzo * is the target of bot tx and rx traffic from the monitored 1404bf50f18SLuigi Rizzo * adapter 1414bf50f18SLuigi Rizzo */ 1424bf50f18SLuigi Rizzo mtx_lock(&mkring->q_lock); 1434bf50f18SLuigi Rizzo /* get the free slots available on the monitor ring */ 1444bf50f18SLuigi Rizzo i = mkring->nr_hwtail; 1454bf50f18SLuigi Rizzo busy = i - mkring->nr_hwcur; 1464bf50f18SLuigi Rizzo if (busy < 0) 1474bf50f18SLuigi Rizzo busy += mkring->nkr_num_slots; 1484bf50f18SLuigi Rizzo free_slots = mlim - busy; 1494bf50f18SLuigi Rizzo 1504bf50f18SLuigi Rizzo if (!free_slots) { 1514bf50f18SLuigi Rizzo mtx_unlock(&mkring->q_lock); 1524bf50f18SLuigi Rizzo return 0; 1534bf50f18SLuigi Rizzo } 1544bf50f18SLuigi Rizzo 1554bf50f18SLuigi Rizzo /* swap min(free_slots, rel_slots) slots */ 1564bf50f18SLuigi Rizzo if (free_slots < rel_slots) { 1574bf50f18SLuigi Rizzo beg += (rel_slots - free_slots); 1584bf50f18SLuigi Rizzo if (beg > lim) 1594bf50f18SLuigi Rizzo beg = 0; 1604bf50f18SLuigi Rizzo rel_slots = free_slots; 1614bf50f18SLuigi Rizzo } 1624bf50f18SLuigi Rizzo 1634bf50f18SLuigi Rizzo for ( ; rel_slots; rel_slots--) { 1644bf50f18SLuigi Rizzo struct netmap_slot *s = &ring->slot[beg]; 1654bf50f18SLuigi Rizzo struct netmap_slot *ms = &mring->slot[i]; 1664bf50f18SLuigi Rizzo uint32_t tmp; 1674bf50f18SLuigi Rizzo 1684bf50f18SLuigi Rizzo tmp = ms->buf_idx; 1694bf50f18SLuigi Rizzo ms->buf_idx = s->buf_idx; 1704bf50f18SLuigi Rizzo s->buf_idx = tmp; 1714bf50f18SLuigi Rizzo 1724bf50f18SLuigi Rizzo tmp = ms->len; 1734bf50f18SLuigi Rizzo ms->len = s->len; 1744bf50f18SLuigi Rizzo s->len = tmp; 1754bf50f18SLuigi Rizzo 1764bf50f18SLuigi Rizzo s->flags |= NS_BUF_CHANGED; 1774bf50f18SLuigi Rizzo 1784bf50f18SLuigi Rizzo beg = nm_next(beg, lim); 1794bf50f18SLuigi Rizzo i = nm_next(i, mlim); 1804bf50f18SLuigi Rizzo 1814bf50f18SLuigi Rizzo } 182*ad15cc59SLuigi Rizzo mb(); 1834bf50f18SLuigi Rizzo mkring->nr_hwtail = i; 1844bf50f18SLuigi Rizzo 1854bf50f18SLuigi Rizzo mtx_unlock(&mkring->q_lock); 1864bf50f18SLuigi Rizzo /* notify the new frames to the monitor */ 1874bf50f18SLuigi Rizzo mna->up.nm_notify(&mna->up, mkring->ring_id, NR_RX, 0); 1884bf50f18SLuigi Rizzo return 0; 1894bf50f18SLuigi Rizzo } 1904bf50f18SLuigi Rizzo 1914bf50f18SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored tx rings */ 1924bf50f18SLuigi Rizzo static int 1934bf50f18SLuigi Rizzo netmap_monitor_parent_txsync(struct netmap_kring *kring, int flags) 1944bf50f18SLuigi Rizzo { 1954bf50f18SLuigi Rizzo ND("%s %x", kring->name, flags); 1964bf50f18SLuigi Rizzo return netmap_monitor_parent_sync(kring, flags, &kring->nr_hwtail); 1974bf50f18SLuigi Rizzo } 1984bf50f18SLuigi Rizzo 1994bf50f18SLuigi Rizzo /* callback used to replace the nm_sync callback in the monitored rx rings */ 2004bf50f18SLuigi Rizzo static int 2014bf50f18SLuigi Rizzo netmap_monitor_parent_rxsync(struct netmap_kring *kring, int flags) 2024bf50f18SLuigi Rizzo { 2034bf50f18SLuigi Rizzo ND("%s %x", kring->name, flags); 2044bf50f18SLuigi Rizzo return netmap_monitor_parent_sync(kring, flags, &kring->rcur); 2054bf50f18SLuigi Rizzo } 2064bf50f18SLuigi Rizzo 2074bf50f18SLuigi Rizzo /* nm_sync callback for the monitor's own tx rings. 2084bf50f18SLuigi Rizzo * This makes no sense and always returns error 2094bf50f18SLuigi Rizzo */ 2104bf50f18SLuigi Rizzo static int 2114bf50f18SLuigi Rizzo netmap_monitor_txsync(struct netmap_kring *kring, int flags) 2124bf50f18SLuigi Rizzo { 2134bf50f18SLuigi Rizzo D("%s %x", kring->name, flags); 2144bf50f18SLuigi Rizzo return EIO; 2154bf50f18SLuigi Rizzo } 2164bf50f18SLuigi Rizzo 2174bf50f18SLuigi Rizzo /* nm_sync callback for the monitor's own rx rings. 2184bf50f18SLuigi Rizzo * Note that the lock in netmap_monitor_parent_sync only protects 2194bf50f18SLuigi Rizzo * writers among themselves. Synchronization between writers 2204bf50f18SLuigi Rizzo * (i.e., netmap_monitor_parent_txsync and netmap_monitor_parent_rxsync) 2214bf50f18SLuigi Rizzo * and readers (i.e., netmap_monitor_rxsync) relies on memory barriers. 2224bf50f18SLuigi Rizzo */ 2234bf50f18SLuigi Rizzo static int 2244bf50f18SLuigi Rizzo netmap_monitor_rxsync(struct netmap_kring *kring, int flags) 2254bf50f18SLuigi Rizzo { 2264bf50f18SLuigi Rizzo ND("%s %x", kring->name, flags); 2274bf50f18SLuigi Rizzo kring->nr_hwcur = kring->rcur; 228*ad15cc59SLuigi Rizzo mb(); 2294bf50f18SLuigi Rizzo nm_rxsync_finalize(kring); 2304bf50f18SLuigi Rizzo return 0; 2314bf50f18SLuigi Rizzo } 2324bf50f18SLuigi Rizzo 2334bf50f18SLuigi Rizzo /* nm_krings_create callbacks for monitors. 2344bf50f18SLuigi Rizzo * We could use the default netmap_hw_krings_monitor, but 2354bf50f18SLuigi Rizzo * we don't need the mbq. 2364bf50f18SLuigi Rizzo */ 2374bf50f18SLuigi Rizzo static int 2384bf50f18SLuigi Rizzo netmap_monitor_krings_create(struct netmap_adapter *na) 2394bf50f18SLuigi Rizzo { 2404bf50f18SLuigi Rizzo return netmap_krings_create(na, 0); 2414bf50f18SLuigi Rizzo } 2424bf50f18SLuigi Rizzo 2434bf50f18SLuigi Rizzo 2444bf50f18SLuigi Rizzo /* nm_register callback for monitors. 2454bf50f18SLuigi Rizzo * 2464bf50f18SLuigi Rizzo * On registration, replace the nm_sync callbacks in the monitored 2474bf50f18SLuigi Rizzo * rings with our own, saving the previous ones in the monitored 2484bf50f18SLuigi Rizzo * rings themselves, where they are used by netmap_monitor_parent_sync. 2494bf50f18SLuigi Rizzo * 2504bf50f18SLuigi Rizzo * On de-registration, restore the original callbacks. We need to 2514bf50f18SLuigi Rizzo * stop traffic while we are doing this, since the monitored adapter may 2524bf50f18SLuigi Rizzo * have already started executing a netmap_monitor_parent_sync 2534bf50f18SLuigi Rizzo * and may not like the kring->save_sync pointer to become NULL. 2544bf50f18SLuigi Rizzo */ 2554bf50f18SLuigi Rizzo static int 2564bf50f18SLuigi Rizzo netmap_monitor_reg(struct netmap_adapter *na, int onoff) 2574bf50f18SLuigi Rizzo { 2584bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna = 2594bf50f18SLuigi Rizzo (struct netmap_monitor_adapter *)na; 2604bf50f18SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 2614bf50f18SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 2624bf50f18SLuigi Rizzo struct netmap_kring *kring; 2634bf50f18SLuigi Rizzo int i; 2644bf50f18SLuigi Rizzo 2654bf50f18SLuigi Rizzo ND("%p: onoff %d", na, onoff); 2664bf50f18SLuigi Rizzo if (onoff) { 2674bf50f18SLuigi Rizzo if (!nm_netmap_on(pna)) { 2684bf50f18SLuigi Rizzo /* parent left netmap mode, fatal */ 2694bf50f18SLuigi Rizzo return ENXIO; 2704bf50f18SLuigi Rizzo } 2714bf50f18SLuigi Rizzo if (mna->flags & NR_MONITOR_TX) { 2724bf50f18SLuigi Rizzo for (i = priv->np_txqfirst; i < priv->np_txqlast; i++) { 2734bf50f18SLuigi Rizzo kring = &pna->tx_rings[i]; 2744bf50f18SLuigi Rizzo kring->save_sync = kring->nm_sync; 2754bf50f18SLuigi Rizzo kring->nm_sync = netmap_monitor_parent_txsync; 2764bf50f18SLuigi Rizzo } 2774bf50f18SLuigi Rizzo } 2784bf50f18SLuigi Rizzo if (mna->flags & NR_MONITOR_RX) { 2794bf50f18SLuigi Rizzo for (i = priv->np_rxqfirst; i < priv->np_rxqlast; i++) { 2804bf50f18SLuigi Rizzo kring = &pna->rx_rings[i]; 2814bf50f18SLuigi Rizzo kring->save_sync = kring->nm_sync; 2824bf50f18SLuigi Rizzo kring->nm_sync = netmap_monitor_parent_rxsync; 2834bf50f18SLuigi Rizzo } 2844bf50f18SLuigi Rizzo } 2854bf50f18SLuigi Rizzo na->na_flags |= NAF_NETMAP_ON; 2864bf50f18SLuigi Rizzo } else { 2874bf50f18SLuigi Rizzo if (!nm_netmap_on(pna)) { 2884bf50f18SLuigi Rizzo /* parent left netmap mode, nothing to restore */ 2894bf50f18SLuigi Rizzo return 0; 2904bf50f18SLuigi Rizzo } 2914bf50f18SLuigi Rizzo na->na_flags &= ~NAF_NETMAP_ON; 2924bf50f18SLuigi Rizzo if (mna->flags & NR_MONITOR_TX) { 2934bf50f18SLuigi Rizzo for (i = priv->np_txqfirst; i < priv->np_txqlast; i++) { 2944bf50f18SLuigi Rizzo netmap_set_txring(pna, i, 1 /* stopped */); 2954bf50f18SLuigi Rizzo kring = &pna->tx_rings[i]; 2964bf50f18SLuigi Rizzo kring->nm_sync = kring->save_sync; 2974bf50f18SLuigi Rizzo kring->save_sync = NULL; 2984bf50f18SLuigi Rizzo netmap_set_txring(pna, i, 0 /* enabled */); 2994bf50f18SLuigi Rizzo } 3004bf50f18SLuigi Rizzo } 3014bf50f18SLuigi Rizzo if (mna->flags & NR_MONITOR_RX) { 3024bf50f18SLuigi Rizzo for (i = priv->np_rxqfirst; i < priv->np_rxqlast; i++) { 3034bf50f18SLuigi Rizzo netmap_set_rxring(pna, i, 1 /* stopped */); 3044bf50f18SLuigi Rizzo kring = &pna->rx_rings[i]; 3054bf50f18SLuigi Rizzo kring->nm_sync = kring->save_sync; 3064bf50f18SLuigi Rizzo kring->save_sync = NULL; 3074bf50f18SLuigi Rizzo netmap_set_rxring(pna, i, 0 /* enabled */); 3084bf50f18SLuigi Rizzo } 3094bf50f18SLuigi Rizzo } 3104bf50f18SLuigi Rizzo } 3114bf50f18SLuigi Rizzo return 0; 3124bf50f18SLuigi Rizzo } 3134bf50f18SLuigi Rizzo /* nm_krings_delete callback for monitors */ 3144bf50f18SLuigi Rizzo static void 3154bf50f18SLuigi Rizzo netmap_monitor_krings_delete(struct netmap_adapter *na) 3164bf50f18SLuigi Rizzo { 3174bf50f18SLuigi Rizzo netmap_krings_delete(na); 3184bf50f18SLuigi Rizzo } 3194bf50f18SLuigi Rizzo 3204bf50f18SLuigi Rizzo 3214bf50f18SLuigi Rizzo /* nm_dtor callback for monitors */ 3224bf50f18SLuigi Rizzo static void 3234bf50f18SLuigi Rizzo netmap_monitor_dtor(struct netmap_adapter *na) 3244bf50f18SLuigi Rizzo { 3254bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna = 3264bf50f18SLuigi Rizzo (struct netmap_monitor_adapter *)na; 3274bf50f18SLuigi Rizzo struct netmap_priv_d *priv = &mna->priv; 3284bf50f18SLuigi Rizzo struct netmap_adapter *pna = priv->np_na; 3294bf50f18SLuigi Rizzo int i; 3304bf50f18SLuigi Rizzo 3314bf50f18SLuigi Rizzo ND("%p", na); 3324bf50f18SLuigi Rizzo if (nm_netmap_on(pna)) { 3334bf50f18SLuigi Rizzo /* parent still in netmap mode, mark its krings as free */ 3344bf50f18SLuigi Rizzo if (mna->flags & NR_MONITOR_TX) { 3354bf50f18SLuigi Rizzo for (i = priv->np_txqfirst; i < priv->np_txqlast; i++) { 3364bf50f18SLuigi Rizzo pna->tx_rings[i].monitor = NULL; 3374bf50f18SLuigi Rizzo } 3384bf50f18SLuigi Rizzo } 3394bf50f18SLuigi Rizzo if (mna->flags & NR_MONITOR_RX) { 3404bf50f18SLuigi Rizzo for (i = priv->np_rxqfirst; i < priv->np_rxqlast; i++) { 3414bf50f18SLuigi Rizzo pna->rx_rings[i].monitor = NULL; 3424bf50f18SLuigi Rizzo } 3434bf50f18SLuigi Rizzo } 3444bf50f18SLuigi Rizzo } 3454bf50f18SLuigi Rizzo netmap_adapter_put(pna); 3464bf50f18SLuigi Rizzo } 3474bf50f18SLuigi Rizzo 3484bf50f18SLuigi Rizzo 3494bf50f18SLuigi Rizzo /* check if nmr is a request for a monitor adapter that we can satisfy */ 3504bf50f18SLuigi Rizzo int 3514bf50f18SLuigi Rizzo netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na, int create) 3524bf50f18SLuigi Rizzo { 3534bf50f18SLuigi Rizzo struct nmreq pnmr; 3544bf50f18SLuigi Rizzo struct netmap_adapter *pna; /* parent adapter */ 3554bf50f18SLuigi Rizzo struct netmap_monitor_adapter *mna; 3564bf50f18SLuigi Rizzo int i, error; 3574bf50f18SLuigi Rizzo 3584bf50f18SLuigi Rizzo if ((nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) { 3594bf50f18SLuigi Rizzo ND("not a monitor"); 3604bf50f18SLuigi Rizzo return 0; 3614bf50f18SLuigi Rizzo } 3624bf50f18SLuigi Rizzo /* this is a request for a monitor adapter */ 3634bf50f18SLuigi Rizzo 3644bf50f18SLuigi Rizzo D("flags %x", nmr->nr_flags); 3654bf50f18SLuigi Rizzo 3664bf50f18SLuigi Rizzo mna = malloc(sizeof(*mna), M_DEVBUF, M_NOWAIT | M_ZERO); 3674bf50f18SLuigi Rizzo if (mna == NULL) { 3684bf50f18SLuigi Rizzo D("memory error"); 3694bf50f18SLuigi Rizzo return ENOMEM; 3704bf50f18SLuigi Rizzo } 3714bf50f18SLuigi Rizzo 3724bf50f18SLuigi Rizzo /* first, try to find the adapter that we want to monitor 3734bf50f18SLuigi Rizzo * We use the same nmr, after we have turned off the monitor flags. 3744bf50f18SLuigi Rizzo * In this way we can potentially monitor everything netmap understands, 3754bf50f18SLuigi Rizzo * except other monitors. 3764bf50f18SLuigi Rizzo */ 3774bf50f18SLuigi Rizzo memcpy(&pnmr, nmr, sizeof(pnmr)); 3784bf50f18SLuigi Rizzo pnmr.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX); 3794bf50f18SLuigi Rizzo error = netmap_get_na(&pnmr, &pna, create); 3804bf50f18SLuigi Rizzo if (error) { 3814bf50f18SLuigi Rizzo D("parent lookup failed: %d", error); 3824bf50f18SLuigi Rizzo return error; 3834bf50f18SLuigi Rizzo } 3844bf50f18SLuigi Rizzo D("found parent: %s", pna->name); 3854bf50f18SLuigi Rizzo 3864bf50f18SLuigi Rizzo if (!nm_netmap_on(pna)) { 3874bf50f18SLuigi Rizzo /* parent not in netmap mode */ 3884bf50f18SLuigi Rizzo /* XXX we can wait for the parent to enter netmap mode, 3894bf50f18SLuigi Rizzo * by intercepting its nm_register callback (2014-03-16) 3904bf50f18SLuigi Rizzo */ 3914bf50f18SLuigi Rizzo D("%s not in netmap mode", pna->name); 3924bf50f18SLuigi Rizzo error = EINVAL; 3934bf50f18SLuigi Rizzo goto put_out; 3944bf50f18SLuigi Rizzo } 3954bf50f18SLuigi Rizzo 3964bf50f18SLuigi Rizzo /* grab all the rings we need in the parent */ 3974bf50f18SLuigi Rizzo mna->priv.np_na = pna; 3984bf50f18SLuigi Rizzo error = netmap_interp_ringid(&mna->priv, nmr->nr_ringid, nmr->nr_flags); 3994bf50f18SLuigi Rizzo if (error) { 4004bf50f18SLuigi Rizzo D("ringid error"); 4014bf50f18SLuigi Rizzo goto put_out; 4024bf50f18SLuigi Rizzo } 4034bf50f18SLuigi Rizzo if (nmr->nr_flags & NR_MONITOR_TX) { 4044bf50f18SLuigi Rizzo for (i = mna->priv.np_txqfirst; i < mna->priv.np_txqlast; i++) { 4054bf50f18SLuigi Rizzo struct netmap_kring *kring = &pna->tx_rings[i]; 4064bf50f18SLuigi Rizzo if (kring->monitor) { 4074bf50f18SLuigi Rizzo error = EBUSY; 4084bf50f18SLuigi Rizzo D("ring busy"); 4094bf50f18SLuigi Rizzo goto release_out; 4104bf50f18SLuigi Rizzo } 4114bf50f18SLuigi Rizzo kring->monitor = mna; 4124bf50f18SLuigi Rizzo } 4134bf50f18SLuigi Rizzo } 4144bf50f18SLuigi Rizzo if (nmr->nr_flags & NR_MONITOR_RX) { 4154bf50f18SLuigi Rizzo for (i = mna->priv.np_rxqfirst; i < mna->priv.np_rxqlast; i++) { 4164bf50f18SLuigi Rizzo struct netmap_kring *kring = &pna->rx_rings[i]; 4174bf50f18SLuigi Rizzo if (kring->monitor) { 4184bf50f18SLuigi Rizzo error = EBUSY; 4194bf50f18SLuigi Rizzo D("ring busy"); 4204bf50f18SLuigi Rizzo goto release_out; 4214bf50f18SLuigi Rizzo } 4224bf50f18SLuigi Rizzo kring->monitor = mna; 4234bf50f18SLuigi Rizzo } 4244bf50f18SLuigi Rizzo } 4254bf50f18SLuigi Rizzo 4264bf50f18SLuigi Rizzo snprintf(mna->up.name, sizeof(mna->up.name), "mon:%s", pna->name); 4274bf50f18SLuigi Rizzo 4284bf50f18SLuigi Rizzo /* the monitor supports the host rings iff the parent does */ 4294bf50f18SLuigi Rizzo mna->up.na_flags = (pna->na_flags & NAF_HOST_RINGS); 4304bf50f18SLuigi Rizzo mna->up.nm_txsync = netmap_monitor_txsync; 4314bf50f18SLuigi Rizzo mna->up.nm_rxsync = netmap_monitor_rxsync; 4324bf50f18SLuigi Rizzo mna->up.nm_register = netmap_monitor_reg; 4334bf50f18SLuigi Rizzo mna->up.nm_dtor = netmap_monitor_dtor; 4344bf50f18SLuigi Rizzo mna->up.nm_krings_create = netmap_monitor_krings_create; 4354bf50f18SLuigi Rizzo mna->up.nm_krings_delete = netmap_monitor_krings_delete; 4364bf50f18SLuigi Rizzo mna->up.nm_mem = pna->nm_mem; 4374bf50f18SLuigi Rizzo mna->up.na_lut = pna->na_lut; 4384bf50f18SLuigi Rizzo mna->up.na_lut_objtotal = pna->na_lut_objtotal; 4394bf50f18SLuigi Rizzo mna->up.na_lut_objsize = pna->na_lut_objsize; 4404bf50f18SLuigi Rizzo 4414bf50f18SLuigi Rizzo mna->up.num_tx_rings = 1; // XXX we don't need it, but field can't be zero 4424bf50f18SLuigi Rizzo /* we set the number of our rx_rings to be max(num_rx_rings, num_rx_rings) 4434bf50f18SLuigi Rizzo * in the parent 4444bf50f18SLuigi Rizzo */ 4454bf50f18SLuigi Rizzo mna->up.num_rx_rings = pna->num_rx_rings; 4464bf50f18SLuigi Rizzo if (pna->num_tx_rings > pna->num_rx_rings) 4474bf50f18SLuigi Rizzo mna->up.num_rx_rings = pna->num_tx_rings; 4484bf50f18SLuigi Rizzo /* by default, the number of slots is the same as in 4494bf50f18SLuigi Rizzo * the parent rings, but the user may ask for a different 4504bf50f18SLuigi Rizzo * number 4514bf50f18SLuigi Rizzo */ 4524bf50f18SLuigi Rizzo mna->up.num_tx_desc = nmr->nr_tx_slots; 4534bf50f18SLuigi Rizzo nm_bound_var(&mna->up.num_tx_desc, pna->num_tx_desc, 4544bf50f18SLuigi Rizzo 1, NM_MONITOR_MAXSLOTS, NULL); 4554bf50f18SLuigi Rizzo mna->up.num_rx_desc = nmr->nr_rx_slots; 4564bf50f18SLuigi Rizzo nm_bound_var(&mna->up.num_rx_desc, pna->num_rx_desc, 4574bf50f18SLuigi Rizzo 1, NM_MONITOR_MAXSLOTS, NULL); 4584bf50f18SLuigi Rizzo error = netmap_attach_common(&mna->up); 4594bf50f18SLuigi Rizzo if (error) { 4604bf50f18SLuigi Rizzo D("attach_common error"); 4614bf50f18SLuigi Rizzo goto release_out; 4624bf50f18SLuigi Rizzo } 4634bf50f18SLuigi Rizzo 4644bf50f18SLuigi Rizzo /* remember the traffic directions we have to monitor */ 4654bf50f18SLuigi Rizzo mna->flags = (nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)); 4664bf50f18SLuigi Rizzo 4674bf50f18SLuigi Rizzo *na = &mna->up; 4684bf50f18SLuigi Rizzo netmap_adapter_get(*na); 4694bf50f18SLuigi Rizzo 4704bf50f18SLuigi Rizzo /* write the configuration back */ 4714bf50f18SLuigi Rizzo nmr->nr_tx_rings = mna->up.num_tx_rings; 4724bf50f18SLuigi Rizzo nmr->nr_rx_rings = mna->up.num_rx_rings; 4734bf50f18SLuigi Rizzo nmr->nr_tx_slots = mna->up.num_tx_desc; 4744bf50f18SLuigi Rizzo nmr->nr_rx_slots = mna->up.num_rx_desc; 4754bf50f18SLuigi Rizzo 4764bf50f18SLuigi Rizzo /* keep the reference to the parent */ 4774bf50f18SLuigi Rizzo D("monitor ok"); 4784bf50f18SLuigi Rizzo 4794bf50f18SLuigi Rizzo return 0; 4804bf50f18SLuigi Rizzo 4814bf50f18SLuigi Rizzo release_out: 4824bf50f18SLuigi Rizzo D("monitor error"); 4834bf50f18SLuigi Rizzo for (i = mna->priv.np_txqfirst; i < mna->priv.np_txqlast; i++) { 4844bf50f18SLuigi Rizzo if (pna->tx_rings[i].monitor == mna) 4854bf50f18SLuigi Rizzo pna->tx_rings[i].monitor = NULL; 4864bf50f18SLuigi Rizzo } 4874bf50f18SLuigi Rizzo for (i = mna->priv.np_rxqfirst; i < mna->priv.np_rxqlast; i++) { 4884bf50f18SLuigi Rizzo if (pna->rx_rings[i].monitor == mna) 4894bf50f18SLuigi Rizzo pna->rx_rings[i].monitor = NULL; 4904bf50f18SLuigi Rizzo } 4914bf50f18SLuigi Rizzo put_out: 4924bf50f18SLuigi Rizzo netmap_adapter_put(pna); 4934bf50f18SLuigi Rizzo free(mna, M_DEVBUF); 4944bf50f18SLuigi Rizzo return error; 4954bf50f18SLuigi Rizzo } 4964bf50f18SLuigi Rizzo 4974bf50f18SLuigi Rizzo 4984bf50f18SLuigi Rizzo #endif /* WITH_MONITOR */ 499