1718cf2ccSPedro F. Giffuni /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
437e3a6d3SLuigi Rizzo * Copyright (C) 2011-2014 Matteo Landi
537e3a6d3SLuigi Rizzo * Copyright (C) 2011-2016 Luigi Rizzo
637e3a6d3SLuigi Rizzo * Copyright (C) 2011-2016 Giuseppe Lettieri
737e3a6d3SLuigi Rizzo * Copyright (C) 2011-2016 Vincenzo Maffione
837e3a6d3SLuigi Rizzo * All rights reserved.
968b8534bSLuigi Rizzo *
1068b8534bSLuigi Rizzo * Redistribution and use in source and binary forms, with or without
1168b8534bSLuigi Rizzo * modification, are permitted provided that the following conditions
1268b8534bSLuigi Rizzo * are met:
1368b8534bSLuigi Rizzo * 1. Redistributions of source code must retain the above copyright
1468b8534bSLuigi Rizzo * notice, this list of conditions and the following disclaimer.
1568b8534bSLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright
1668b8534bSLuigi Rizzo * notice, this list of conditions and the following disclaimer in the
1768b8534bSLuigi Rizzo * documentation and/or other materials provided with the distribution.
1868b8534bSLuigi Rizzo *
1968b8534bSLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2068b8534bSLuigi Rizzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2168b8534bSLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2268b8534bSLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2368b8534bSLuigi Rizzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2468b8534bSLuigi Rizzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2568b8534bSLuigi Rizzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2668b8534bSLuigi Rizzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2768b8534bSLuigi Rizzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2868b8534bSLuigi Rizzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2968b8534bSLuigi Rizzo * SUCH DAMAGE.
3068b8534bSLuigi Rizzo */
3168b8534bSLuigi Rizzo
32ce3ee1e7SLuigi Rizzo
3368b8534bSLuigi Rizzo /*
34f9790aebSLuigi Rizzo *
3568b8534bSLuigi Rizzo * This module supports memory mapped access to network devices,
3668b8534bSLuigi Rizzo * see netmap(4).
3768b8534bSLuigi Rizzo *
3868b8534bSLuigi Rizzo * The module uses a large, memory pool allocated by the kernel
3968b8534bSLuigi Rizzo * and accessible as mmapped memory by multiple userspace threads/processes.
4068b8534bSLuigi Rizzo * The memory pool contains packet buffers and "netmap rings",
4168b8534bSLuigi Rizzo * i.e. user-accessible copies of the interface's queues.
4268b8534bSLuigi Rizzo *
4368b8534bSLuigi Rizzo * Access to the network card works like this:
4468b8534bSLuigi Rizzo * 1. a process/thread issues one or more open() on /dev/netmap, to create
4568b8534bSLuigi Rizzo * select()able file descriptor on which events are reported.
4668b8534bSLuigi Rizzo * 2. on each descriptor, the process issues an ioctl() to identify
4768b8534bSLuigi Rizzo * the interface that should report events to the file descriptor.
4868b8534bSLuigi Rizzo * 3. on each descriptor, the process issues an mmap() request to
4968b8534bSLuigi Rizzo * map the shared memory region within the process' address space.
5068b8534bSLuigi Rizzo * The list of interesting queues is indicated by a location in
5168b8534bSLuigi Rizzo * the shared memory region.
5268b8534bSLuigi Rizzo * 4. using the functions in the netmap(4) userspace API, a process
5368b8534bSLuigi Rizzo * can look up the occupation state of a queue, access memory buffers,
5468b8534bSLuigi Rizzo * and retrieve received packets or enqueue packets to transmit.
5568b8534bSLuigi Rizzo * 5. using some ioctl()s the process can synchronize the userspace view
5668b8534bSLuigi Rizzo * of the queue with the actual status in the kernel. This includes both
5768b8534bSLuigi Rizzo * receiving the notification of new packets, and transmitting new
5868b8534bSLuigi Rizzo * packets on the output interface.
5968b8534bSLuigi Rizzo * 6. select() or poll() can be used to wait for events on individual
6068b8534bSLuigi Rizzo * transmit or receive queues (or all queues for a given interface).
61ce3ee1e7SLuigi Rizzo *
62ce3ee1e7SLuigi Rizzo
63ce3ee1e7SLuigi Rizzo SYNCHRONIZATION (USER)
64ce3ee1e7SLuigi Rizzo
65ce3ee1e7SLuigi Rizzo The netmap rings and data structures may be shared among multiple
66ce3ee1e7SLuigi Rizzo user threads or even independent processes.
67ce3ee1e7SLuigi Rizzo Any synchronization among those threads/processes is delegated
68ce3ee1e7SLuigi Rizzo to the threads themselves. Only one thread at a time can be in
69ce3ee1e7SLuigi Rizzo a system call on the same netmap ring. The OS does not enforce
70ce3ee1e7SLuigi Rizzo this and only guarantees against system crashes in case of
71ce3ee1e7SLuigi Rizzo invalid usage.
72ce3ee1e7SLuigi Rizzo
73ce3ee1e7SLuigi Rizzo LOCKING (INTERNAL)
74ce3ee1e7SLuigi Rizzo
75ce3ee1e7SLuigi Rizzo Within the kernel, access to the netmap rings is protected as follows:
76ce3ee1e7SLuigi Rizzo
77ce3ee1e7SLuigi Rizzo - a spinlock on each ring, to handle producer/consumer races on
78ce3ee1e7SLuigi Rizzo RX rings attached to the host stack (against multiple host
79ce3ee1e7SLuigi Rizzo threads writing from the host stack to the same ring),
80ce3ee1e7SLuigi Rizzo and on 'destination' rings attached to a VALE switch
81ce3ee1e7SLuigi Rizzo (i.e. RX rings in VALE ports, and TX rings in NIC/host ports)
82ce3ee1e7SLuigi Rizzo protecting multiple active senders for the same destination)
83ce3ee1e7SLuigi Rizzo
84ce3ee1e7SLuigi Rizzo - an atomic variable to guarantee that there is at most one
85ce3ee1e7SLuigi Rizzo instance of *_*xsync() on the ring at any time.
86ce3ee1e7SLuigi Rizzo For rings connected to user file
87ce3ee1e7SLuigi Rizzo descriptors, an atomic_test_and_set() protects this, and the
88ce3ee1e7SLuigi Rizzo lock on the ring is not actually used.
89ce3ee1e7SLuigi Rizzo For NIC RX rings connected to a VALE switch, an atomic_test_and_set()
90ce3ee1e7SLuigi Rizzo is also used to prevent multiple executions (the driver might indeed
91ce3ee1e7SLuigi Rizzo already guarantee this).
92ce3ee1e7SLuigi Rizzo For NIC TX rings connected to a VALE switch, the lock arbitrates
93ce3ee1e7SLuigi Rizzo access to the queue (both when allocating buffers and when pushing
94ce3ee1e7SLuigi Rizzo them out).
95ce3ee1e7SLuigi Rizzo
96ce3ee1e7SLuigi Rizzo - *xsync() should be protected against initializations of the card.
97ce3ee1e7SLuigi Rizzo On FreeBSD most devices have the reset routine protected by
98ce3ee1e7SLuigi Rizzo a RING lock (ixgbe, igb, em) or core lock (re). lem is missing
99ce3ee1e7SLuigi Rizzo the RING protection on rx_reset(), this should be added.
100ce3ee1e7SLuigi Rizzo
101ce3ee1e7SLuigi Rizzo On linux there is an external lock on the tx path, which probably
102ce3ee1e7SLuigi Rizzo also arbitrates access to the reset routine. XXX to be revised
103ce3ee1e7SLuigi Rizzo
104ce3ee1e7SLuigi Rizzo - a per-interface core_lock protecting access from the host stack
105ce3ee1e7SLuigi Rizzo while interfaces may be detached from netmap mode.
106ce3ee1e7SLuigi Rizzo XXX there should be no need for this lock if we detach the interfaces
107ce3ee1e7SLuigi Rizzo only while they are down.
108ce3ee1e7SLuigi Rizzo
109ce3ee1e7SLuigi Rizzo
110ce3ee1e7SLuigi Rizzo --- VALE SWITCH ---
111ce3ee1e7SLuigi Rizzo
112ce3ee1e7SLuigi Rizzo NMG_LOCK() serializes all modifications to switches and ports.
113ce3ee1e7SLuigi Rizzo A switch cannot be deleted until all ports are gone.
114ce3ee1e7SLuigi Rizzo
115ce3ee1e7SLuigi Rizzo For each switch, an SX lock (RWlock on linux) protects
116ce3ee1e7SLuigi Rizzo deletion of ports. When configuring or deleting a new port, the
117ce3ee1e7SLuigi Rizzo lock is acquired in exclusive mode (after holding NMG_LOCK).
118ce3ee1e7SLuigi Rizzo When forwarding, the lock is acquired in shared mode (without NMG_LOCK).
119ce3ee1e7SLuigi Rizzo The lock is held throughout the entire forwarding cycle,
120ce3ee1e7SLuigi Rizzo during which the thread may incur in a page fault.
121ce3ee1e7SLuigi Rizzo Hence it is important that sleepable shared locks are used.
122ce3ee1e7SLuigi Rizzo
123ce3ee1e7SLuigi Rizzo On the rx ring, the per-port lock is grabbed initially to reserve
124ce3ee1e7SLuigi Rizzo a number of slot in the ring, then the lock is released,
125ce3ee1e7SLuigi Rizzo packets are copied from source to destination, and then
126ce3ee1e7SLuigi Rizzo the lock is acquired again and the receive ring is updated.
127ce3ee1e7SLuigi Rizzo (A similar thing is done on the tx ring for NIC and host stack
128ce3ee1e7SLuigi Rizzo ports attached to the switch)
129ce3ee1e7SLuigi Rizzo
13068b8534bSLuigi Rizzo */
13168b8534bSLuigi Rizzo
1324bf50f18SLuigi Rizzo
1334bf50f18SLuigi Rizzo /* --- internals ----
1344bf50f18SLuigi Rizzo *
1354bf50f18SLuigi Rizzo * Roadmap to the code that implements the above.
1364bf50f18SLuigi Rizzo *
1374bf50f18SLuigi Rizzo * > 1. a process/thread issues one or more open() on /dev/netmap, to create
1384bf50f18SLuigi Rizzo * > select()able file descriptor on which events are reported.
1394bf50f18SLuigi Rizzo *
1404bf50f18SLuigi Rizzo * Internally, we allocate a netmap_priv_d structure, that will be
14137e3a6d3SLuigi Rizzo * initialized on ioctl(NIOCREGIF). There is one netmap_priv_d
14237e3a6d3SLuigi Rizzo * structure for each open().
1434bf50f18SLuigi Rizzo *
1444bf50f18SLuigi Rizzo * os-specific:
14537e3a6d3SLuigi Rizzo * FreeBSD: see netmap_open() (netmap_freebsd.c)
14637e3a6d3SLuigi Rizzo * linux: see linux_netmap_open() (netmap_linux.c)
1474bf50f18SLuigi Rizzo *
1484bf50f18SLuigi Rizzo * > 2. on each descriptor, the process issues an ioctl() to identify
1494bf50f18SLuigi Rizzo * > the interface that should report events to the file descriptor.
1504bf50f18SLuigi Rizzo *
1514bf50f18SLuigi Rizzo * Implemented by netmap_ioctl(), NIOCREGIF case, with nmr->nr_cmd==0.
1524bf50f18SLuigi Rizzo * Most important things happen in netmap_get_na() and
1534bf50f18SLuigi Rizzo * netmap_do_regif(), called from there. Additional details can be
1544bf50f18SLuigi Rizzo * found in the comments above those functions.
1554bf50f18SLuigi Rizzo *
1564bf50f18SLuigi Rizzo * In all cases, this action creates/takes-a-reference-to a
1574bf50f18SLuigi Rizzo * netmap_*_adapter describing the port, and allocates a netmap_if
1584bf50f18SLuigi Rizzo * and all necessary netmap rings, filling them with netmap buffers.
1594bf50f18SLuigi Rizzo *
1604bf50f18SLuigi Rizzo * In this phase, the sync callbacks for each ring are set (these are used
1614bf50f18SLuigi Rizzo * in steps 5 and 6 below). The callbacks depend on the type of adapter.
1624bf50f18SLuigi Rizzo * The adapter creation/initialization code puts them in the
1634bf50f18SLuigi Rizzo * netmap_adapter (fields na->nm_txsync and na->nm_rxsync). Then, they
1644bf50f18SLuigi Rizzo * are copied from there to the netmap_kring's during netmap_do_regif(), by
1654bf50f18SLuigi Rizzo * the nm_krings_create() callback. All the nm_krings_create callbacks
1664bf50f18SLuigi Rizzo * actually call netmap_krings_create() to perform this and the other
1674bf50f18SLuigi Rizzo * common stuff. netmap_krings_create() also takes care of the host rings,
1684bf50f18SLuigi Rizzo * if needed, by setting their sync callbacks appropriately.
1694bf50f18SLuigi Rizzo *
1704bf50f18SLuigi Rizzo * Additional actions depend on the kind of netmap_adapter that has been
1714bf50f18SLuigi Rizzo * registered:
1724bf50f18SLuigi Rizzo *
1734bf50f18SLuigi Rizzo * - netmap_hw_adapter: [netmap.c]
1744bf50f18SLuigi Rizzo * This is a system netdev/ifp with native netmap support.
1754bf50f18SLuigi Rizzo * The ifp is detached from the host stack by redirecting:
1764bf50f18SLuigi Rizzo * - transmissions (from the network stack) to netmap_transmit()
1774bf50f18SLuigi Rizzo * - receive notifications to the nm_notify() callback for
1784bf50f18SLuigi Rizzo * this adapter. The callback is normally netmap_notify(), unless
1794bf50f18SLuigi Rizzo * the ifp is attached to a bridge using bwrap, in which case it
1804bf50f18SLuigi Rizzo * is netmap_bwrap_intr_notify().
1814bf50f18SLuigi Rizzo *
1824bf50f18SLuigi Rizzo * - netmap_generic_adapter: [netmap_generic.c]
1834bf50f18SLuigi Rizzo * A system netdev/ifp without native netmap support.
1844bf50f18SLuigi Rizzo *
1854bf50f18SLuigi Rizzo * (the decision about native/non native support is taken in
1864bf50f18SLuigi Rizzo * netmap_get_hw_na(), called by netmap_get_na())
1874bf50f18SLuigi Rizzo *
1884bf50f18SLuigi Rizzo * - netmap_vp_adapter [netmap_vale.c]
1894bf50f18SLuigi Rizzo * Returned by netmap_get_bdg_na().
1904bf50f18SLuigi Rizzo * This is a persistent or ephemeral VALE port. Ephemeral ports
1914bf50f18SLuigi Rizzo * are created on the fly if they don't already exist, and are
1924bf50f18SLuigi Rizzo * always attached to a bridge.
193453130d9SPedro F. Giffuni * Persistent VALE ports must must be created separately, and i
1944bf50f18SLuigi Rizzo * then attached like normal NICs. The NIOCREGIF we are examining
19545c67e8fSVincenzo Maffione * will find them only if they had previously been created and
1964bf50f18SLuigi Rizzo * attached (see VALE_CTL below).
1974bf50f18SLuigi Rizzo *
1984bf50f18SLuigi Rizzo * - netmap_pipe_adapter [netmap_pipe.c]
1994bf50f18SLuigi Rizzo * Returned by netmap_get_pipe_na().
2004bf50f18SLuigi Rizzo * Both pipe ends are created, if they didn't already exist.
2014bf50f18SLuigi Rizzo *
2024bf50f18SLuigi Rizzo * - netmap_monitor_adapter [netmap_monitor.c]
2034bf50f18SLuigi Rizzo * Returned by netmap_get_monitor_na().
2044bf50f18SLuigi Rizzo * If successful, the nm_sync callbacks of the monitored adapter
2054bf50f18SLuigi Rizzo * will be intercepted by the returned monitor.
2064bf50f18SLuigi Rizzo *
2074bf50f18SLuigi Rizzo * - netmap_bwrap_adapter [netmap_vale.c]
2084bf50f18SLuigi Rizzo * Cannot be obtained in this way, see VALE_CTL below
2094bf50f18SLuigi Rizzo *
2104bf50f18SLuigi Rizzo *
2114bf50f18SLuigi Rizzo * os-specific:
2124bf50f18SLuigi Rizzo * linux: we first go through linux_netmap_ioctl() to
2134bf50f18SLuigi Rizzo * adapt the FreeBSD interface to the linux one.
2144bf50f18SLuigi Rizzo *
2154bf50f18SLuigi Rizzo *
2164bf50f18SLuigi Rizzo * > 3. on each descriptor, the process issues an mmap() request to
2174bf50f18SLuigi Rizzo * > map the shared memory region within the process' address space.
2184bf50f18SLuigi Rizzo * > The list of interesting queues is indicated by a location in
2194bf50f18SLuigi Rizzo * > the shared memory region.
2204bf50f18SLuigi Rizzo *
2214bf50f18SLuigi Rizzo * os-specific:
2224bf50f18SLuigi Rizzo * FreeBSD: netmap_mmap_single (netmap_freebsd.c).
2234bf50f18SLuigi Rizzo * linux: linux_netmap_mmap (netmap_linux.c).
2244bf50f18SLuigi Rizzo *
2254bf50f18SLuigi Rizzo * > 4. using the functions in the netmap(4) userspace API, a process
2264bf50f18SLuigi Rizzo * > can look up the occupation state of a queue, access memory buffers,
2274bf50f18SLuigi Rizzo * > and retrieve received packets or enqueue packets to transmit.
2284bf50f18SLuigi Rizzo *
2294bf50f18SLuigi Rizzo * these actions do not involve the kernel.
2304bf50f18SLuigi Rizzo *
2314bf50f18SLuigi Rizzo * > 5. using some ioctl()s the process can synchronize the userspace view
2324bf50f18SLuigi Rizzo * > of the queue with the actual status in the kernel. This includes both
2334bf50f18SLuigi Rizzo * > receiving the notification of new packets, and transmitting new
2344bf50f18SLuigi Rizzo * > packets on the output interface.
2354bf50f18SLuigi Rizzo *
2364bf50f18SLuigi Rizzo * These are implemented in netmap_ioctl(), NIOCTXSYNC and NIOCRXSYNC
2374bf50f18SLuigi Rizzo * cases. They invoke the nm_sync callbacks on the netmap_kring
2384bf50f18SLuigi Rizzo * structures, as initialized in step 2 and maybe later modified
2394bf50f18SLuigi Rizzo * by a monitor. Monitors, however, will always call the original
2404bf50f18SLuigi Rizzo * callback before doing anything else.
2414bf50f18SLuigi Rizzo *
2424bf50f18SLuigi Rizzo *
2434bf50f18SLuigi Rizzo * > 6. select() or poll() can be used to wait for events on individual
2444bf50f18SLuigi Rizzo * > transmit or receive queues (or all queues for a given interface).
2454bf50f18SLuigi Rizzo *
2464bf50f18SLuigi Rizzo * Implemented in netmap_poll(). This will call the same nm_sync()
2474bf50f18SLuigi Rizzo * callbacks as in step 5 above.
2484bf50f18SLuigi Rizzo *
2494bf50f18SLuigi Rizzo * os-specific:
2504bf50f18SLuigi Rizzo * linux: we first go through linux_netmap_poll() to adapt
2514bf50f18SLuigi Rizzo * the FreeBSD interface to the linux one.
2524bf50f18SLuigi Rizzo *
2534bf50f18SLuigi Rizzo *
2544bf50f18SLuigi Rizzo * ---- VALE_CTL -----
2554bf50f18SLuigi Rizzo *
2564bf50f18SLuigi Rizzo * VALE switches are controlled by issuing a NIOCREGIF with a non-null
2574bf50f18SLuigi Rizzo * nr_cmd in the nmreq structure. These subcommands are handled by
2584bf50f18SLuigi Rizzo * netmap_bdg_ctl() in netmap_vale.c. Persistent VALE ports are created
2594bf50f18SLuigi Rizzo * and destroyed by issuing the NETMAP_BDG_NEWIF and NETMAP_BDG_DELIF
2604bf50f18SLuigi Rizzo * subcommands, respectively.
2614bf50f18SLuigi Rizzo *
2624bf50f18SLuigi Rizzo * Any network interface known to the system (including a persistent VALE
2634bf50f18SLuigi Rizzo * port) can be attached to a VALE switch by issuing the
2642ff91c17SVincenzo Maffione * NETMAP_REQ_VALE_ATTACH command. After the attachment, persistent VALE ports
2654bf50f18SLuigi Rizzo * look exactly like ephemeral VALE ports (as created in step 2 above). The
2664bf50f18SLuigi Rizzo * attachment of other interfaces, instead, requires the creation of a
2674bf50f18SLuigi Rizzo * netmap_bwrap_adapter. Moreover, the attached interface must be put in
2684bf50f18SLuigi Rizzo * netmap mode. This may require the creation of a netmap_generic_adapter if
2694bf50f18SLuigi Rizzo * we have no native support for the interface, or if generic adapters have
2704bf50f18SLuigi Rizzo * been forced by sysctl.
2714bf50f18SLuigi Rizzo *
2724bf50f18SLuigi Rizzo * Both persistent VALE ports and bwraps are handled by netmap_get_bdg_na(),
2734bf50f18SLuigi Rizzo * called by nm_bdg_ctl_attach(), and discriminated by the nm_bdg_attach()
2744bf50f18SLuigi Rizzo * callback. In the case of the bwrap, the callback creates the
2754bf50f18SLuigi Rizzo * netmap_bwrap_adapter. The initialization of the bwrap is then
2764bf50f18SLuigi Rizzo * completed by calling netmap_do_regif() on it, in the nm_bdg_ctl()
2774bf50f18SLuigi Rizzo * callback (netmap_bwrap_bdg_ctl in netmap_vale.c).
2784bf50f18SLuigi Rizzo * A generic adapter for the wrapped ifp will be created if needed, when
2794bf50f18SLuigi Rizzo * netmap_get_bdg_na() calls netmap_get_hw_na().
2804bf50f18SLuigi Rizzo *
2814bf50f18SLuigi Rizzo *
2824bf50f18SLuigi Rizzo * ---- DATAPATHS -----
2834bf50f18SLuigi Rizzo *
2844bf50f18SLuigi Rizzo * -= SYSTEM DEVICE WITH NATIVE SUPPORT =-
2854bf50f18SLuigi Rizzo *
2864bf50f18SLuigi Rizzo * na == NA(ifp) == netmap_hw_adapter created in DEVICE_netmap_attach()
2874bf50f18SLuigi Rizzo *
2884bf50f18SLuigi Rizzo * - tx from netmap userspace:
2894bf50f18SLuigi Rizzo * concurrently:
2904bf50f18SLuigi Rizzo * 1) ioctl(NIOCTXSYNC)/netmap_poll() in process context
2914bf50f18SLuigi Rizzo * kring->nm_sync() == DEVICE_netmap_txsync()
2924bf50f18SLuigi Rizzo * 2) device interrupt handler
2934bf50f18SLuigi Rizzo * na->nm_notify() == netmap_notify()
2944bf50f18SLuigi Rizzo * - rx from netmap userspace:
2954bf50f18SLuigi Rizzo * concurrently:
2964bf50f18SLuigi Rizzo * 1) ioctl(NIOCRXSYNC)/netmap_poll() in process context
2974bf50f18SLuigi Rizzo * kring->nm_sync() == DEVICE_netmap_rxsync()
2984bf50f18SLuigi Rizzo * 2) device interrupt handler
2994bf50f18SLuigi Rizzo * na->nm_notify() == netmap_notify()
300847bf383SLuigi Rizzo * - rx from host stack
3014bf50f18SLuigi Rizzo * concurrently:
3024bf50f18SLuigi Rizzo * 1) host stack
3034bf50f18SLuigi Rizzo * netmap_transmit()
3044bf50f18SLuigi Rizzo * na->nm_notify == netmap_notify()
3054bf50f18SLuigi Rizzo * 2) ioctl(NIOCRXSYNC)/netmap_poll() in process context
30637e3a6d3SLuigi Rizzo * kring->nm_sync() == netmap_rxsync_from_host
3074bf50f18SLuigi Rizzo * netmap_rxsync_from_host(na, NULL, NULL)
3084bf50f18SLuigi Rizzo * - tx to host stack
3094bf50f18SLuigi Rizzo * ioctl(NIOCTXSYNC)/netmap_poll() in process context
31037e3a6d3SLuigi Rizzo * kring->nm_sync() == netmap_txsync_to_host
3114bf50f18SLuigi Rizzo * netmap_txsync_to_host(na)
31237e3a6d3SLuigi Rizzo * nm_os_send_up()
31337e3a6d3SLuigi Rizzo * FreeBSD: na->if_input() == ether_input()
3144bf50f18SLuigi Rizzo * linux: netif_rx() with NM_MAGIC_PRIORITY_RX
3154bf50f18SLuigi Rizzo *
3164bf50f18SLuigi Rizzo *
3174bf50f18SLuigi Rizzo * -= SYSTEM DEVICE WITH GENERIC SUPPORT =-
3184bf50f18SLuigi Rizzo *
319847bf383SLuigi Rizzo * na == NA(ifp) == generic_netmap_adapter created in generic_netmap_attach()
320847bf383SLuigi Rizzo *
321847bf383SLuigi Rizzo * - tx from netmap userspace:
322847bf383SLuigi Rizzo * concurrently:
323847bf383SLuigi Rizzo * 1) ioctl(NIOCTXSYNC)/netmap_poll() in process context
324847bf383SLuigi Rizzo * kring->nm_sync() == generic_netmap_txsync()
32537e3a6d3SLuigi Rizzo * nm_os_generic_xmit_frame()
326847bf383SLuigi Rizzo * linux: dev_queue_xmit() with NM_MAGIC_PRIORITY_TX
32737e3a6d3SLuigi Rizzo * ifp->ndo_start_xmit == generic_ndo_start_xmit()
32837e3a6d3SLuigi Rizzo * gna->save_start_xmit == orig. dev. start_xmit
329847bf383SLuigi Rizzo * FreeBSD: na->if_transmit() == orig. dev if_transmit
330847bf383SLuigi Rizzo * 2) generic_mbuf_destructor()
331847bf383SLuigi Rizzo * na->nm_notify() == netmap_notify()
332847bf383SLuigi Rizzo * - rx from netmap userspace:
333847bf383SLuigi Rizzo * 1) ioctl(NIOCRXSYNC)/netmap_poll() in process context
334847bf383SLuigi Rizzo * kring->nm_sync() == generic_netmap_rxsync()
335847bf383SLuigi Rizzo * mbq_safe_dequeue()
336847bf383SLuigi Rizzo * 2) device driver
337847bf383SLuigi Rizzo * generic_rx_handler()
338847bf383SLuigi Rizzo * mbq_safe_enqueue()
339847bf383SLuigi Rizzo * na->nm_notify() == netmap_notify()
34037e3a6d3SLuigi Rizzo * - rx from host stack
34137e3a6d3SLuigi Rizzo * FreeBSD: same as native
34237e3a6d3SLuigi Rizzo * Linux: same as native except:
343847bf383SLuigi Rizzo * 1) host stack
34437e3a6d3SLuigi Rizzo * dev_queue_xmit() without NM_MAGIC_PRIORITY_TX
34537e3a6d3SLuigi Rizzo * ifp->ndo_start_xmit == generic_ndo_start_xmit()
346847bf383SLuigi Rizzo * netmap_transmit()
347847bf383SLuigi Rizzo * na->nm_notify() == netmap_notify()
34837e3a6d3SLuigi Rizzo * - tx to host stack (same as native):
3494bf50f18SLuigi Rizzo *
3504bf50f18SLuigi Rizzo *
351847bf383SLuigi Rizzo * -= VALE =-
3524bf50f18SLuigi Rizzo *
353847bf383SLuigi Rizzo * INCOMING:
3544bf50f18SLuigi Rizzo *
355847bf383SLuigi Rizzo * - VALE ports:
356847bf383SLuigi Rizzo * ioctl(NIOCTXSYNC)/netmap_poll() in process context
357847bf383SLuigi Rizzo * kring->nm_sync() == netmap_vp_txsync()
3584bf50f18SLuigi Rizzo *
359847bf383SLuigi Rizzo * - system device with native support:
360847bf383SLuigi Rizzo * from cable:
361847bf383SLuigi Rizzo * interrupt
362847bf383SLuigi Rizzo * na->nm_notify() == netmap_bwrap_intr_notify(ring_nr != host ring)
363847bf383SLuigi Rizzo * kring->nm_sync() == DEVICE_netmap_rxsync()
364847bf383SLuigi Rizzo * netmap_vp_txsync()
365847bf383SLuigi Rizzo * kring->nm_sync() == DEVICE_netmap_rxsync()
366847bf383SLuigi Rizzo * from host stack:
367847bf383SLuigi Rizzo * netmap_transmit()
368847bf383SLuigi Rizzo * na->nm_notify() == netmap_bwrap_intr_notify(ring_nr == host ring)
36937e3a6d3SLuigi Rizzo * kring->nm_sync() == netmap_rxsync_from_host()
370847bf383SLuigi Rizzo * netmap_vp_txsync()
3714bf50f18SLuigi Rizzo *
372847bf383SLuigi Rizzo * - system device with generic support:
373847bf383SLuigi Rizzo * from device driver:
374847bf383SLuigi Rizzo * generic_rx_handler()
375847bf383SLuigi Rizzo * na->nm_notify() == netmap_bwrap_intr_notify(ring_nr != host ring)
376847bf383SLuigi Rizzo * kring->nm_sync() == generic_netmap_rxsync()
377847bf383SLuigi Rizzo * netmap_vp_txsync()
378847bf383SLuigi Rizzo * kring->nm_sync() == generic_netmap_rxsync()
379847bf383SLuigi Rizzo * from host stack:
380847bf383SLuigi Rizzo * netmap_transmit()
381847bf383SLuigi Rizzo * na->nm_notify() == netmap_bwrap_intr_notify(ring_nr == host ring)
38237e3a6d3SLuigi Rizzo * kring->nm_sync() == netmap_rxsync_from_host()
383847bf383SLuigi Rizzo * netmap_vp_txsync()
3844bf50f18SLuigi Rizzo *
385847bf383SLuigi Rizzo * (all cases) --> nm_bdg_flush()
386847bf383SLuigi Rizzo * dest_na->nm_notify() == (see below)
3874bf50f18SLuigi Rizzo *
388847bf383SLuigi Rizzo * OUTGOING:
3894bf50f18SLuigi Rizzo *
390847bf383SLuigi Rizzo * - VALE ports:
391847bf383SLuigi Rizzo * concurrently:
392c3e9b4dbSLuiz Otavio O Souza * 1) ioctl(NIOCRXSYNC)/netmap_poll() in process context
393847bf383SLuigi Rizzo * kring->nm_sync() == netmap_vp_rxsync()
394847bf383SLuigi Rizzo * 2) from nm_bdg_flush()
395847bf383SLuigi Rizzo * na->nm_notify() == netmap_notify()
3964bf50f18SLuigi Rizzo *
397847bf383SLuigi Rizzo * - system device with native support:
398847bf383SLuigi Rizzo * to cable:
399847bf383SLuigi Rizzo * na->nm_notify() == netmap_bwrap_notify()
400847bf383SLuigi Rizzo * netmap_vp_rxsync()
401847bf383SLuigi Rizzo * kring->nm_sync() == DEVICE_netmap_txsync()
402847bf383SLuigi Rizzo * netmap_vp_rxsync()
403847bf383SLuigi Rizzo * to host stack:
404847bf383SLuigi Rizzo * netmap_vp_rxsync()
40537e3a6d3SLuigi Rizzo * kring->nm_sync() == netmap_txsync_to_host
406847bf383SLuigi Rizzo * netmap_vp_rxsync_locked()
4074bf50f18SLuigi Rizzo *
408847bf383SLuigi Rizzo * - system device with generic adapter:
409847bf383SLuigi Rizzo * to device driver:
410847bf383SLuigi Rizzo * na->nm_notify() == netmap_bwrap_notify()
411847bf383SLuigi Rizzo * netmap_vp_rxsync()
412847bf383SLuigi Rizzo * kring->nm_sync() == generic_netmap_txsync()
413847bf383SLuigi Rizzo * netmap_vp_rxsync()
414847bf383SLuigi Rizzo * to host stack:
415847bf383SLuigi Rizzo * netmap_vp_rxsync()
41637e3a6d3SLuigi Rizzo * kring->nm_sync() == netmap_txsync_to_host
417847bf383SLuigi Rizzo * netmap_vp_rxsync()
4184bf50f18SLuigi Rizzo *
4194bf50f18SLuigi Rizzo */
4204bf50f18SLuigi Rizzo
421ce3ee1e7SLuigi Rizzo /*
422ce3ee1e7SLuigi Rizzo * OS-specific code that is used only within this file.
423ce3ee1e7SLuigi Rizzo * Other OS-specific code that must be accessed by drivers
424ce3ee1e7SLuigi Rizzo * is present in netmap_kern.h
425ce3ee1e7SLuigi Rizzo */
42601c7d25fSLuigi Rizzo
427ce3ee1e7SLuigi Rizzo #if defined(__FreeBSD__)
42868b8534bSLuigi Rizzo #include <sys/cdefs.h> /* prerequisite */
42968b8534bSLuigi Rizzo #include <sys/types.h>
43068b8534bSLuigi Rizzo #include <sys/errno.h>
43168b8534bSLuigi Rizzo #include <sys/param.h> /* defines used in kernel.h */
43268b8534bSLuigi Rizzo #include <sys/kernel.h> /* types used in module initialization */
433f9790aebSLuigi Rizzo #include <sys/conf.h> /* cdevsw struct, UID, GID */
43489e3fd52SLuigi Rizzo #include <sys/filio.h> /* FIONBIO */
43568b8534bSLuigi Rizzo #include <sys/sockio.h>
43668b8534bSLuigi Rizzo #include <sys/socketvar.h> /* struct socket */
43768b8534bSLuigi Rizzo #include <sys/malloc.h>
43868b8534bSLuigi Rizzo #include <sys/poll.h>
439a4470078SGleb Smirnoff #include <sys/proc.h>
44089f6b863SAttilio Rao #include <sys/rwlock.h>
44168b8534bSLuigi Rizzo #include <sys/socket.h> /* sockaddrs */
44268b8534bSLuigi Rizzo #include <sys/selinfo.h>
44368b8534bSLuigi Rizzo #include <sys/sysctl.h>
444339f59c0SGleb Smirnoff #include <sys/jail.h>
445a4470078SGleb Smirnoff #include <sys/epoch.h>
446339f59c0SGleb Smirnoff #include <net/vnet.h>
44768b8534bSLuigi Rizzo #include <net/if.h>
44876039bc8SGleb Smirnoff #include <net/if_var.h>
44968b8534bSLuigi Rizzo #include <net/bpf.h> /* BIOCIMMEDIATE */
45068b8534bSLuigi Rizzo #include <machine/bus.h> /* bus_dmamap_* */
451ce3ee1e7SLuigi Rizzo #include <sys/endian.h>
452ce3ee1e7SLuigi Rizzo #include <sys/refcount.h>
45389a9a5b5SVincenzo Maffione #include <net/ethernet.h> /* ETHER_BPF_MTAP */
45468b8534bSLuigi Rizzo
45568b8534bSLuigi Rizzo
456ce3ee1e7SLuigi Rizzo #elif defined(linux)
457ce3ee1e7SLuigi Rizzo
458ce3ee1e7SLuigi Rizzo #include "bsd_glue.h"
459ce3ee1e7SLuigi Rizzo
460ce3ee1e7SLuigi Rizzo #elif defined(__APPLE__)
461ce3ee1e7SLuigi Rizzo
462ce3ee1e7SLuigi Rizzo #warning OSX support is only partial
463ce3ee1e7SLuigi Rizzo #include "osx_glue.h"
464ce3ee1e7SLuigi Rizzo
46537e3a6d3SLuigi Rizzo #elif defined (_WIN32)
46637e3a6d3SLuigi Rizzo
46737e3a6d3SLuigi Rizzo #include "win_glue.h"
46837e3a6d3SLuigi Rizzo
469ce3ee1e7SLuigi Rizzo #else
470ce3ee1e7SLuigi Rizzo
471ce3ee1e7SLuigi Rizzo #error Unsupported platform
472ce3ee1e7SLuigi Rizzo
473ce3ee1e7SLuigi Rizzo #endif /* unsupported */
474ce3ee1e7SLuigi Rizzo
475ce3ee1e7SLuigi Rizzo /*
476ce3ee1e7SLuigi Rizzo * common headers
477ce3ee1e7SLuigi Rizzo */
4780b8ed8e0SLuigi Rizzo #include <net/netmap.h>
4790b8ed8e0SLuigi Rizzo #include <dev/netmap/netmap_kern.h>
480ce3ee1e7SLuigi Rizzo #include <dev/netmap/netmap_mem2.h>
4810b8ed8e0SLuigi Rizzo
482ce3ee1e7SLuigi Rizzo
4835819da83SLuigi Rizzo /* user-controlled variables */
4845819da83SLuigi Rizzo int netmap_verbose;
485b6e66be2SVincenzo Maffione #ifdef CONFIG_NETMAP_DEBUG
486b6e66be2SVincenzo Maffione int netmap_debug;
487b6e66be2SVincenzo Maffione #endif /* CONFIG_NETMAP_DEBUG */
4885819da83SLuigi Rizzo
4895819da83SLuigi Rizzo static int netmap_no_timestamp; /* don't timestamp on rxsync */
490c85cb1a0SLuigi Rizzo int netmap_no_pendintr = 1;
491f18be576SLuigi Rizzo int netmap_txsync_retry = 2;
492c3e9b4dbSLuiz Otavio O Souza static int netmap_fwd = 0; /* force transparent forwarding */
493f196ce38SLuigi Rizzo
494f9790aebSLuigi Rizzo /*
495f9790aebSLuigi Rizzo * netmap_admode selects the netmap mode to use.
496f9790aebSLuigi Rizzo * Invalid values are reset to NETMAP_ADMODE_BEST
497f9790aebSLuigi Rizzo */
498f9790aebSLuigi Rizzo enum { NETMAP_ADMODE_BEST = 0, /* use native, fallback to generic */
499f9790aebSLuigi Rizzo NETMAP_ADMODE_NATIVE, /* either native or none */
500f9790aebSLuigi Rizzo NETMAP_ADMODE_GENERIC, /* force generic */
501f9790aebSLuigi Rizzo NETMAP_ADMODE_LAST };
502f9790aebSLuigi Rizzo static int netmap_admode = NETMAP_ADMODE_BEST;
503f9790aebSLuigi Rizzo
50437e3a6d3SLuigi Rizzo /* netmap_generic_mit controls mitigation of RX notifications for
50537e3a6d3SLuigi Rizzo * the generic netmap adapter. The value is a time interval in
50637e3a6d3SLuigi Rizzo * nanoseconds. */
50737e3a6d3SLuigi Rizzo int netmap_generic_mit = 100*1000;
50837e3a6d3SLuigi Rizzo
50937e3a6d3SLuigi Rizzo /* We use by default netmap-aware qdiscs with generic netmap adapters,
51037e3a6d3SLuigi Rizzo * even if there can be a little performance hit with hardware NICs.
51137e3a6d3SLuigi Rizzo * However, using the qdisc is the safer approach, for two reasons:
51237e3a6d3SLuigi Rizzo * 1) it prevents non-fifo qdiscs to break the TX notification
51337e3a6d3SLuigi Rizzo * scheme, which is based on mbuf destructors when txqdisc is
51437e3a6d3SLuigi Rizzo * not used.
51537e3a6d3SLuigi Rizzo * 2) it makes it possible to transmit over software devices that
51637e3a6d3SLuigi Rizzo * change skb->dev, like bridge, veth, ...
51737e3a6d3SLuigi Rizzo *
51837e3a6d3SLuigi Rizzo * Anyway users looking for the best performance should
51937e3a6d3SLuigi Rizzo * use native adapters.
52037e3a6d3SLuigi Rizzo */
5214f80b14cSVincenzo Maffione #ifdef linux
52237e3a6d3SLuigi Rizzo int netmap_generic_txqdisc = 1;
5234f80b14cSVincenzo Maffione #endif
52437e3a6d3SLuigi Rizzo
52537e3a6d3SLuigi Rizzo /* Default number of slots and queues for generic adapters. */
52637e3a6d3SLuigi Rizzo int netmap_generic_ringsize = 1024;
52737e3a6d3SLuigi Rizzo int netmap_generic_rings = 1;
52837e3a6d3SLuigi Rizzo
5292a7db7a6SVincenzo Maffione /* Non-zero to enable checksum offloading in NIC drivers */
5302a7db7a6SVincenzo Maffione int netmap_generic_hwcsum = 0;
5312a7db7a6SVincenzo Maffione
53237e3a6d3SLuigi Rizzo /* Non-zero if ptnet devices are allowed to use virtio-net headers. */
53337e3a6d3SLuigi Rizzo int ptnet_vnet_hdr = 1;
53437e3a6d3SLuigi Rizzo
53537e3a6d3SLuigi Rizzo /*
53637e3a6d3SLuigi Rizzo * SYSCTL calls are grouped between SYSBEGIN and SYSEND to be emulated
53737e3a6d3SLuigi Rizzo * in some other operating systems
53837e3a6d3SLuigi Rizzo */
53937e3a6d3SLuigi Rizzo SYSBEGIN(main_init);
54037e3a6d3SLuigi Rizzo
54137e3a6d3SLuigi Rizzo SYSCTL_DECL(_dev_netmap);
5427029da5cSPawel Biernacki SYSCTL_NODE(_dev, OID_AUTO, netmap, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
5437029da5cSPawel Biernacki "Netmap args");
54437e3a6d3SLuigi Rizzo SYSCTL_INT(_dev_netmap, OID_AUTO, verbose,
54537e3a6d3SLuigi Rizzo CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode");
546b6e66be2SVincenzo Maffione #ifdef CONFIG_NETMAP_DEBUG
547b6e66be2SVincenzo Maffione SYSCTL_INT(_dev_netmap, OID_AUTO, debug,
548b6e66be2SVincenzo Maffione CTLFLAG_RW, &netmap_debug, 0, "Debug messages");
549b6e66be2SVincenzo Maffione #endif /* CONFIG_NETMAP_DEBUG */
55037e3a6d3SLuigi Rizzo SYSCTL_INT(_dev_netmap, OID_AUTO, no_timestamp,
55137e3a6d3SLuigi Rizzo CTLFLAG_RW, &netmap_no_timestamp, 0, "no_timestamp");
5524f80b14cSVincenzo Maffione SYSCTL_INT(_dev_netmap, OID_AUTO, no_pendintr, CTLFLAG_RW, &netmap_no_pendintr,
5534f80b14cSVincenzo Maffione 0, "Always look for new received packets.");
55437e3a6d3SLuigi Rizzo SYSCTL_INT(_dev_netmap, OID_AUTO, txsync_retry, CTLFLAG_RW,
55537e3a6d3SLuigi Rizzo &netmap_txsync_retry, 0, "Number of txsync loops in bridge's flush.");
556f9790aebSLuigi Rizzo
5574f80b14cSVincenzo Maffione SYSCTL_INT(_dev_netmap, OID_AUTO, fwd, CTLFLAG_RW, &netmap_fwd, 0,
5584f80b14cSVincenzo Maffione "Force NR_FORWARD mode");
5594f80b14cSVincenzo Maffione SYSCTL_INT(_dev_netmap, OID_AUTO, admode, CTLFLAG_RW, &netmap_admode, 0,
5604f80b14cSVincenzo Maffione "Adapter mode. 0 selects the best option available,"
5614f80b14cSVincenzo Maffione "1 forces native adapter, 2 forces emulated adapter");
5622a7db7a6SVincenzo Maffione SYSCTL_INT(_dev_netmap, OID_AUTO, generic_hwcsum, CTLFLAG_RW, &netmap_generic_hwcsum,
5632a7db7a6SVincenzo Maffione 0, "Hardware checksums. 0 to disable checksum generation by the NIC (default),"
5642a7db7a6SVincenzo Maffione "1 to enable checksum generation by the NIC");
5654f80b14cSVincenzo Maffione SYSCTL_INT(_dev_netmap, OID_AUTO, generic_mit, CTLFLAG_RW, &netmap_generic_mit,
5664f80b14cSVincenzo Maffione 0, "RX notification interval in nanoseconds");
5674f80b14cSVincenzo Maffione SYSCTL_INT(_dev_netmap, OID_AUTO, generic_ringsize, CTLFLAG_RW,
5684f80b14cSVincenzo Maffione &netmap_generic_ringsize, 0,
5694f80b14cSVincenzo Maffione "Number of per-ring slots for emulated netmap mode");
5704f80b14cSVincenzo Maffione SYSCTL_INT(_dev_netmap, OID_AUTO, generic_rings, CTLFLAG_RW,
5714f80b14cSVincenzo Maffione &netmap_generic_rings, 0,
5724f80b14cSVincenzo Maffione "Number of TX/RX queues for emulated netmap adapters");
5734f80b14cSVincenzo Maffione #ifdef linux
5744f80b14cSVincenzo Maffione SYSCTL_INT(_dev_netmap, OID_AUTO, generic_txqdisc, CTLFLAG_RW,
5754f80b14cSVincenzo Maffione &netmap_generic_txqdisc, 0, "Use qdisc for generic adapters");
5764f80b14cSVincenzo Maffione #endif
5774f80b14cSVincenzo Maffione SYSCTL_INT(_dev_netmap, OID_AUTO, ptnet_vnet_hdr, CTLFLAG_RW, &ptnet_vnet_hdr,
5784f80b14cSVincenzo Maffione 0, "Allow ptnet devices to use virtio-net headers");
57937e3a6d3SLuigi Rizzo
58037e3a6d3SLuigi Rizzo SYSEND;
581f196ce38SLuigi Rizzo
582ce3ee1e7SLuigi Rizzo NMG_LOCK_T netmap_global_lock;
583ce3ee1e7SLuigi Rizzo
58417885a7bSLuigi Rizzo /*
58517885a7bSLuigi Rizzo * mark the ring as stopped, and run through the locks
58617885a7bSLuigi Rizzo * to make sure other users get to see it.
58737e3a6d3SLuigi Rizzo * stopped must be either NR_KR_STOPPED (for unbounded stop)
58837e3a6d3SLuigi Rizzo * of NR_KR_LOCKED (brief stop for mutual exclusion purposes)
58917885a7bSLuigi Rizzo */
5904bf50f18SLuigi Rizzo static void
netmap_disable_ring(struct netmap_kring * kr,int stopped)59137e3a6d3SLuigi Rizzo netmap_disable_ring(struct netmap_kring *kr, int stopped)
592ce3ee1e7SLuigi Rizzo {
59337e3a6d3SLuigi Rizzo nm_kr_stop(kr, stopped);
59437e3a6d3SLuigi Rizzo // XXX check if nm_kr_stop is sufficient
595ce3ee1e7SLuigi Rizzo mtx_lock(&kr->q_lock);
596ce3ee1e7SLuigi Rizzo mtx_unlock(&kr->q_lock);
597ce3ee1e7SLuigi Rizzo nm_kr_put(kr);
598ce3ee1e7SLuigi Rizzo }
599ce3ee1e7SLuigi Rizzo
600847bf383SLuigi Rizzo /* stop or enable a single ring */
6014bf50f18SLuigi Rizzo void
netmap_set_ring(struct netmap_adapter * na,u_int ring_id,enum txrx t,int stopped)602847bf383SLuigi Rizzo netmap_set_ring(struct netmap_adapter *na, u_int ring_id, enum txrx t, int stopped)
6034bf50f18SLuigi Rizzo {
6044bf50f18SLuigi Rizzo if (stopped)
6052ff91c17SVincenzo Maffione netmap_disable_ring(NMR(na, t)[ring_id], stopped);
6064bf50f18SLuigi Rizzo else
6072ff91c17SVincenzo Maffione NMR(na, t)[ring_id]->nkr_stopped = 0;
6084bf50f18SLuigi Rizzo }
6094bf50f18SLuigi Rizzo
610f9790aebSLuigi Rizzo
61189cc2556SLuigi Rizzo /* stop or enable all the rings of na */
6124bf50f18SLuigi Rizzo void
netmap_set_all_rings(struct netmap_adapter * na,int stopped)6134bf50f18SLuigi Rizzo netmap_set_all_rings(struct netmap_adapter *na, int stopped)
614ce3ee1e7SLuigi Rizzo {
615ce3ee1e7SLuigi Rizzo int i;
616847bf383SLuigi Rizzo enum txrx t;
617ce3ee1e7SLuigi Rizzo
6184bf50f18SLuigi Rizzo if (!nm_netmap_on(na))
619ce3ee1e7SLuigi Rizzo return;
620ce3ee1e7SLuigi Rizzo
621bb714db6SVincenzo Maffione if (netmap_verbose) {
622bb714db6SVincenzo Maffione nm_prinf("%s: %sable all rings", na->name,
623bb714db6SVincenzo Maffione (stopped ? "dis" : "en"));
624bb714db6SVincenzo Maffione }
625847bf383SLuigi Rizzo for_rx_tx(t) {
626847bf383SLuigi Rizzo for (i = 0; i < netmap_real_rings(na, t); i++) {
627847bf383SLuigi Rizzo netmap_set_ring(na, i, t, stopped);
628ce3ee1e7SLuigi Rizzo }
629ce3ee1e7SLuigi Rizzo }
630ce3ee1e7SLuigi Rizzo }
631ce3ee1e7SLuigi Rizzo
63289cc2556SLuigi Rizzo /*
63389cc2556SLuigi Rizzo * Convenience function used in drivers. Waits for current txsync()s/rxsync()s
63489cc2556SLuigi Rizzo * to finish and prevents any new one from starting. Call this before turning
635ddb13598SKevin Lo * netmap mode off, or before removing the hardware rings (e.g., on module
63637e3a6d3SLuigi Rizzo * onload).
63789cc2556SLuigi Rizzo */
638f9790aebSLuigi Rizzo void
netmap_disable_all_rings(if_t ifp)639e330262fSJustin Hibbits netmap_disable_all_rings(if_t ifp)
640f9790aebSLuigi Rizzo {
64137e3a6d3SLuigi Rizzo if (NM_NA_VALID(ifp)) {
64255f0ad5fSVincenzo Maffione netmap_set_all_rings(NA(ifp), NM_KR_LOCKED);
64337e3a6d3SLuigi Rizzo }
644f9790aebSLuigi Rizzo }
645f9790aebSLuigi Rizzo
64689cc2556SLuigi Rizzo /*
64789cc2556SLuigi Rizzo * Convenience function used in drivers. Re-enables rxsync and txsync on the
64889cc2556SLuigi Rizzo * adapter's rings In linux drivers, this should be placed near each
64989cc2556SLuigi Rizzo * napi_enable().
65089cc2556SLuigi Rizzo */
651f9790aebSLuigi Rizzo void
netmap_enable_all_rings(if_t ifp)652e330262fSJustin Hibbits netmap_enable_all_rings(if_t ifp)
653f9790aebSLuigi Rizzo {
65437e3a6d3SLuigi Rizzo if (NM_NA_VALID(ifp)) {
6554bf50f18SLuigi Rizzo netmap_set_all_rings(NA(ifp), 0 /* enabled */);
656f9790aebSLuigi Rizzo }
65737e3a6d3SLuigi Rizzo }
658f9790aebSLuigi Rizzo
65937e3a6d3SLuigi Rizzo void
netmap_make_zombie(if_t ifp)660e330262fSJustin Hibbits netmap_make_zombie(if_t ifp)
66137e3a6d3SLuigi Rizzo {
66237e3a6d3SLuigi Rizzo if (NM_NA_VALID(ifp)) {
66337e3a6d3SLuigi Rizzo struct netmap_adapter *na = NA(ifp);
66437e3a6d3SLuigi Rizzo netmap_set_all_rings(na, NM_KR_LOCKED);
66537e3a6d3SLuigi Rizzo na->na_flags |= NAF_ZOMBIE;
66637e3a6d3SLuigi Rizzo netmap_set_all_rings(na, 0);
66737e3a6d3SLuigi Rizzo }
66837e3a6d3SLuigi Rizzo }
66937e3a6d3SLuigi Rizzo
67037e3a6d3SLuigi Rizzo void
netmap_undo_zombie(if_t ifp)671e330262fSJustin Hibbits netmap_undo_zombie(if_t ifp)
67237e3a6d3SLuigi Rizzo {
67337e3a6d3SLuigi Rizzo if (NM_NA_VALID(ifp)) {
67437e3a6d3SLuigi Rizzo struct netmap_adapter *na = NA(ifp);
67537e3a6d3SLuigi Rizzo if (na->na_flags & NAF_ZOMBIE) {
67637e3a6d3SLuigi Rizzo netmap_set_all_rings(na, NM_KR_LOCKED);
67737e3a6d3SLuigi Rizzo na->na_flags &= ~NAF_ZOMBIE;
67837e3a6d3SLuigi Rizzo netmap_set_all_rings(na, 0);
67937e3a6d3SLuigi Rizzo }
68037e3a6d3SLuigi Rizzo }
68137e3a6d3SLuigi Rizzo }
682f9790aebSLuigi Rizzo
683ce3ee1e7SLuigi Rizzo /*
684ce3ee1e7SLuigi Rizzo * generic bound_checking function
685ce3ee1e7SLuigi Rizzo */
686ce3ee1e7SLuigi Rizzo u_int
nm_bound_var(u_int * v,u_int dflt,u_int lo,u_int hi,const char * msg)687ce3ee1e7SLuigi Rizzo nm_bound_var(u_int *v, u_int dflt, u_int lo, u_int hi, const char *msg)
688ce3ee1e7SLuigi Rizzo {
689ce3ee1e7SLuigi Rizzo u_int oldv = *v;
690ce3ee1e7SLuigi Rizzo const char *op = NULL;
691ce3ee1e7SLuigi Rizzo
692ce3ee1e7SLuigi Rizzo if (dflt < lo)
693ce3ee1e7SLuigi Rizzo dflt = lo;
694ce3ee1e7SLuigi Rizzo if (dflt > hi)
695ce3ee1e7SLuigi Rizzo dflt = hi;
696ce3ee1e7SLuigi Rizzo if (oldv < lo) {
697ce3ee1e7SLuigi Rizzo *v = dflt;
698ce3ee1e7SLuigi Rizzo op = "Bump";
699ce3ee1e7SLuigi Rizzo } else if (oldv > hi) {
700ce3ee1e7SLuigi Rizzo *v = hi;
701ce3ee1e7SLuigi Rizzo op = "Clamp";
702ce3ee1e7SLuigi Rizzo }
703ce3ee1e7SLuigi Rizzo if (op && msg)
704b6e66be2SVincenzo Maffione nm_prinf("%s %s to %d (was %d)", op, msg, *v, oldv);
705ce3ee1e7SLuigi Rizzo return *v;
706ce3ee1e7SLuigi Rizzo }
707ce3ee1e7SLuigi Rizzo
708f9790aebSLuigi Rizzo
709ce3ee1e7SLuigi Rizzo /*
710ce3ee1e7SLuigi Rizzo * packet-dump function, user-supplied or static buffer.
711ce3ee1e7SLuigi Rizzo * The destination buffer must be at least 30+4*len
712ce3ee1e7SLuigi Rizzo */
713ce3ee1e7SLuigi Rizzo const char *
nm_dump_buf(char * p,int len,int lim,char * dst)714ce3ee1e7SLuigi Rizzo nm_dump_buf(char *p, int len, int lim, char *dst)
715ce3ee1e7SLuigi Rizzo {
716ce3ee1e7SLuigi Rizzo static char _dst[8192];
717ce3ee1e7SLuigi Rizzo int i, j, i0;
718ce3ee1e7SLuigi Rizzo static char hex[] ="0123456789abcdef";
719ce3ee1e7SLuigi Rizzo char *o; /* output position */
720ce3ee1e7SLuigi Rizzo
721ce3ee1e7SLuigi Rizzo #define P_HI(x) hex[((x) & 0xf0)>>4]
722ce3ee1e7SLuigi Rizzo #define P_LO(x) hex[((x) & 0xf)]
723ce3ee1e7SLuigi Rizzo #define P_C(x) ((x) >= 0x20 && (x) <= 0x7e ? (x) : '.')
724ce3ee1e7SLuigi Rizzo if (!dst)
725ce3ee1e7SLuigi Rizzo dst = _dst;
726ce3ee1e7SLuigi Rizzo if (lim <= 0 || lim > len)
727ce3ee1e7SLuigi Rizzo lim = len;
728ce3ee1e7SLuigi Rizzo o = dst;
729ce3ee1e7SLuigi Rizzo sprintf(o, "buf 0x%p len %d lim %d\n", p, len, lim);
730ce3ee1e7SLuigi Rizzo o += strlen(o);
731ce3ee1e7SLuigi Rizzo /* hexdump routine */
732ce3ee1e7SLuigi Rizzo for (i = 0; i < lim; ) {
733ce3ee1e7SLuigi Rizzo sprintf(o, "%5d: ", i);
734ce3ee1e7SLuigi Rizzo o += strlen(o);
735ce3ee1e7SLuigi Rizzo memset(o, ' ', 48);
736ce3ee1e7SLuigi Rizzo i0 = i;
737ce3ee1e7SLuigi Rizzo for (j=0; j < 16 && i < lim; i++, j++) {
738ce3ee1e7SLuigi Rizzo o[j*3] = P_HI(p[i]);
739ce3ee1e7SLuigi Rizzo o[j*3+1] = P_LO(p[i]);
740ce3ee1e7SLuigi Rizzo }
741ce3ee1e7SLuigi Rizzo i = i0;
742ce3ee1e7SLuigi Rizzo for (j=0; j < 16 && i < lim; i++, j++)
743ce3ee1e7SLuigi Rizzo o[j + 48] = P_C(p[i]);
744ce3ee1e7SLuigi Rizzo o[j+48] = '\n';
745ce3ee1e7SLuigi Rizzo o += j+49;
746ce3ee1e7SLuigi Rizzo }
747ce3ee1e7SLuigi Rizzo *o = '\0';
748ce3ee1e7SLuigi Rizzo #undef P_HI
749ce3ee1e7SLuigi Rizzo #undef P_LO
750ce3ee1e7SLuigi Rizzo #undef P_C
751ce3ee1e7SLuigi Rizzo return dst;
752ce3ee1e7SLuigi Rizzo }
753f196ce38SLuigi Rizzo
754f18be576SLuigi Rizzo
755ae10d1afSLuigi Rizzo /*
756ae10d1afSLuigi Rizzo * Fetch configuration from the device, to cope with dynamic
757ae10d1afSLuigi Rizzo * reconfigurations after loading the module.
758ae10d1afSLuigi Rizzo */
75989cc2556SLuigi Rizzo /* call with NMG_LOCK held */
760f9790aebSLuigi Rizzo int
netmap_update_config(struct netmap_adapter * na)761ae10d1afSLuigi Rizzo netmap_update_config(struct netmap_adapter *na)
762ae10d1afSLuigi Rizzo {
7632ff91c17SVincenzo Maffione struct nm_config_info info;
764ae10d1afSLuigi Rizzo
7654ad57c7aSVincenzo Maffione if (na->ifp && !nm_is_bwrap(na)) {
766e330262fSJustin Hibbits strlcpy(na->name, if_name(na->ifp), sizeof(na->name));
7674ad57c7aSVincenzo Maffione }
7684ad57c7aSVincenzo Maffione
7692ff91c17SVincenzo Maffione bzero(&info, sizeof(info));
7706641c68bSLuigi Rizzo if (na->nm_config == NULL ||
7712ff91c17SVincenzo Maffione na->nm_config(na, &info)) {
772ae10d1afSLuigi Rizzo /* take whatever we had at init time */
7732ff91c17SVincenzo Maffione info.num_tx_rings = na->num_tx_rings;
7742ff91c17SVincenzo Maffione info.num_tx_descs = na->num_tx_desc;
7752ff91c17SVincenzo Maffione info.num_rx_rings = na->num_rx_rings;
7762ff91c17SVincenzo Maffione info.num_rx_descs = na->num_rx_desc;
7772ff91c17SVincenzo Maffione info.rx_buf_maxsize = na->rx_buf_maxsize;
778ae10d1afSLuigi Rizzo }
779ae10d1afSLuigi Rizzo
7802ff91c17SVincenzo Maffione if (na->num_tx_rings == info.num_tx_rings &&
7812ff91c17SVincenzo Maffione na->num_tx_desc == info.num_tx_descs &&
7822ff91c17SVincenzo Maffione na->num_rx_rings == info.num_rx_rings &&
7832ff91c17SVincenzo Maffione na->num_rx_desc == info.num_rx_descs &&
7842ff91c17SVincenzo Maffione na->rx_buf_maxsize == info.rx_buf_maxsize)
785ae10d1afSLuigi Rizzo return 0; /* nothing changed */
786f9790aebSLuigi Rizzo if (na->active_fds == 0) {
7872ff91c17SVincenzo Maffione na->num_tx_rings = info.num_tx_rings;
7882ff91c17SVincenzo Maffione na->num_tx_desc = info.num_tx_descs;
7892ff91c17SVincenzo Maffione na->num_rx_rings = info.num_rx_rings;
7902ff91c17SVincenzo Maffione na->num_rx_desc = info.num_rx_descs;
7912ff91c17SVincenzo Maffione na->rx_buf_maxsize = info.rx_buf_maxsize;
792b6e66be2SVincenzo Maffione if (netmap_verbose)
793b6e66be2SVincenzo Maffione nm_prinf("configuration changed for %s: txring %d x %d, "
794cfa866f6SMatt Macy "rxring %d x %d, rxbufsz %d",
795cfa866f6SMatt Macy na->name, na->num_tx_rings, na->num_tx_desc,
796cfa866f6SMatt Macy na->num_rx_rings, na->num_rx_desc, na->rx_buf_maxsize);
797ae10d1afSLuigi Rizzo return 0;
798ae10d1afSLuigi Rizzo }
799b6e66be2SVincenzo Maffione nm_prerr("WARNING: configuration changed for %s while active: "
8002ff91c17SVincenzo Maffione "txring %d x %d, rxring %d x %d, rxbufsz %d",
8012ff91c17SVincenzo Maffione na->name, info.num_tx_rings, info.num_tx_descs,
8022ff91c17SVincenzo Maffione info.num_rx_rings, info.num_rx_descs,
8032ff91c17SVincenzo Maffione info.rx_buf_maxsize);
804ae10d1afSLuigi Rizzo return 1;
805ae10d1afSLuigi Rizzo }
806ae10d1afSLuigi Rizzo
80737e3a6d3SLuigi Rizzo /* nm_sync callbacks for the host rings */
80837e3a6d3SLuigi Rizzo static int netmap_txsync_to_host(struct netmap_kring *kring, int flags);
80937e3a6d3SLuigi Rizzo static int netmap_rxsync_from_host(struct netmap_kring *kring, int flags);
810f0ea3689SLuigi Rizzo
811a6d768d8SVincenzo Maffione static int
netmap_default_bufcfg(struct netmap_kring * kring,uint64_t target)812a6d768d8SVincenzo Maffione netmap_default_bufcfg(struct netmap_kring *kring, uint64_t target)
813a6d768d8SVincenzo Maffione {
814a6d768d8SVincenzo Maffione kring->hwbuf_len = target;
815a6d768d8SVincenzo Maffione kring->buf_align = 0; /* no alignment */
816a6d768d8SVincenzo Maffione return 0;
817a6d768d8SVincenzo Maffione }
818a6d768d8SVincenzo Maffione
819f0ea3689SLuigi Rizzo /* create the krings array and initialize the fields common to all adapters.
820f0ea3689SLuigi Rizzo * The array layout is this:
821f0ea3689SLuigi Rizzo *
822f0ea3689SLuigi Rizzo * +----------+
823f0ea3689SLuigi Rizzo * na->tx_rings ----->| | \
824f0ea3689SLuigi Rizzo * | | } na->num_tx_ring
825f0ea3689SLuigi Rizzo * | | /
826f0ea3689SLuigi Rizzo * +----------+
827f0ea3689SLuigi Rizzo * | | host tx kring
828f0ea3689SLuigi Rizzo * na->rx_rings ----> +----------+
829f0ea3689SLuigi Rizzo * | | \
830f0ea3689SLuigi Rizzo * | | } na->num_rx_rings
831f0ea3689SLuigi Rizzo * | | /
832f0ea3689SLuigi Rizzo * +----------+
833f0ea3689SLuigi Rizzo * | | host rx kring
834f0ea3689SLuigi Rizzo * +----------+
835f0ea3689SLuigi Rizzo * na->tailroom ----->| | \
836f0ea3689SLuigi Rizzo * | | } tailroom bytes
837f0ea3689SLuigi Rizzo * | | /
838f0ea3689SLuigi Rizzo * +----------+
839f0ea3689SLuigi Rizzo *
840f0ea3689SLuigi Rizzo * Note: for compatibility, host krings are created even when not needed.
841f0ea3689SLuigi Rizzo * The tailroom space is currently used by vale ports for allocating leases.
842f0ea3689SLuigi Rizzo */
84389cc2556SLuigi Rizzo /* call with NMG_LOCK held */
844f9790aebSLuigi Rizzo int
netmap_krings_create(struct netmap_adapter * na,u_int tailroom)845f0ea3689SLuigi Rizzo netmap_krings_create(struct netmap_adapter *na, u_int tailroom)
846f9790aebSLuigi Rizzo {
847f9790aebSLuigi Rizzo u_int i, len, ndesc;
848f9790aebSLuigi Rizzo struct netmap_kring *kring;
849847bf383SLuigi Rizzo u_int n[NR_TXRX];
850847bf383SLuigi Rizzo enum txrx t;
85119c4ec08SVincenzo Maffione int err = 0;
852f9790aebSLuigi Rizzo
853c3e9b4dbSLuiz Otavio O Souza if (na->tx_rings != NULL) {
854b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_ON)
855b6e66be2SVincenzo Maffione nm_prerr("warning: krings were already created");
856c3e9b4dbSLuiz Otavio O Souza return 0;
857c3e9b4dbSLuiz Otavio O Souza }
858c3e9b4dbSLuiz Otavio O Souza
859f0ea3689SLuigi Rizzo /* account for the (possibly fake) host rings */
8602a7db7a6SVincenzo Maffione n[NR_TX] = netmap_all_rings(na, NR_TX);
8612a7db7a6SVincenzo Maffione n[NR_RX] = netmap_all_rings(na, NR_RX);
862f0ea3689SLuigi Rizzo
8632ff91c17SVincenzo Maffione len = (n[NR_TX] + n[NR_RX]) *
8642ff91c17SVincenzo Maffione (sizeof(struct netmap_kring) + sizeof(struct netmap_kring *))
8652ff91c17SVincenzo Maffione + tailroom;
866f9790aebSLuigi Rizzo
867c3e9b4dbSLuiz Otavio O Souza na->tx_rings = nm_os_malloc((size_t)len);
868f9790aebSLuigi Rizzo if (na->tx_rings == NULL) {
869b6e66be2SVincenzo Maffione nm_prerr("Cannot allocate krings");
870f9790aebSLuigi Rizzo return ENOMEM;
871f9790aebSLuigi Rizzo }
872847bf383SLuigi Rizzo na->rx_rings = na->tx_rings + n[NR_TX];
8732ff91c17SVincenzo Maffione na->tailroom = na->rx_rings + n[NR_RX];
8742ff91c17SVincenzo Maffione
8752ff91c17SVincenzo Maffione /* link the krings in the krings array */
8762ff91c17SVincenzo Maffione kring = (struct netmap_kring *)((char *)na->tailroom + tailroom);
8772ff91c17SVincenzo Maffione for (i = 0; i < n[NR_TX] + n[NR_RX]; i++) {
8782ff91c17SVincenzo Maffione na->tx_rings[i] = kring;
8792ff91c17SVincenzo Maffione kring++;
8802ff91c17SVincenzo Maffione }
881f9790aebSLuigi Rizzo
88217885a7bSLuigi Rizzo /*
88317885a7bSLuigi Rizzo * All fields in krings are 0 except the one initialized below.
88417885a7bSLuigi Rizzo * but better be explicit on important kring fields.
88517885a7bSLuigi Rizzo */
886847bf383SLuigi Rizzo for_rx_tx(t) {
887847bf383SLuigi Rizzo ndesc = nma_get_ndesc(na, t);
888847bf383SLuigi Rizzo for (i = 0; i < n[t]; i++) {
8892ff91c17SVincenzo Maffione kring = NMR(na, t)[i];
890f9790aebSLuigi Rizzo bzero(kring, sizeof(*kring));
8912ff91c17SVincenzo Maffione kring->notify_na = na;
89217885a7bSLuigi Rizzo kring->ring_id = i;
893847bf383SLuigi Rizzo kring->tx = t;
894f9790aebSLuigi Rizzo kring->nkr_num_slots = ndesc;
89537e3a6d3SLuigi Rizzo kring->nr_mode = NKR_NETMAP_OFF;
89637e3a6d3SLuigi Rizzo kring->nr_pending_mode = NKR_NETMAP_OFF;
897847bf383SLuigi Rizzo if (i < nma_get_nrings(na, t)) {
898847bf383SLuigi Rizzo kring->nm_sync = (t == NR_TX ? na->nm_txsync : na->nm_rxsync);
899a6d768d8SVincenzo Maffione kring->nm_bufcfg = na->nm_bufcfg;
900a6d768d8SVincenzo Maffione if (kring->nm_bufcfg == NULL)
901a6d768d8SVincenzo Maffione kring->nm_bufcfg = netmap_default_bufcfg;
90237e3a6d3SLuigi Rizzo } else {
9032ff91c17SVincenzo Maffione if (!(na->na_flags & NAF_HOST_RINGS))
9042ff91c17SVincenzo Maffione kring->nr_kflags |= NKR_FAKERING;
905847bf383SLuigi Rizzo kring->nm_sync = (t == NR_TX ?
90637e3a6d3SLuigi Rizzo netmap_txsync_to_host:
90737e3a6d3SLuigi Rizzo netmap_rxsync_from_host);
908a6d768d8SVincenzo Maffione kring->nm_bufcfg = netmap_default_bufcfg;
909f0ea3689SLuigi Rizzo }
910847bf383SLuigi Rizzo kring->nm_notify = na->nm_notify;
911847bf383SLuigi Rizzo kring->rhead = kring->rcur = kring->nr_hwcur = 0;
912f9790aebSLuigi Rizzo /*
91317885a7bSLuigi Rizzo * IMPORTANT: Always keep one slot empty.
914f9790aebSLuigi Rizzo */
915847bf383SLuigi Rizzo kring->rtail = kring->nr_hwtail = (t == NR_TX ? ndesc - 1 : 0);
916847bf383SLuigi Rizzo snprintf(kring->name, sizeof(kring->name) - 1, "%s %s%d", na->name,
917847bf383SLuigi Rizzo nm_txrx2str(t), i);
91875f4f3edSVincenzo Maffione nm_prdis("ktx %s h %d c %d t %d",
919f0ea3689SLuigi Rizzo kring->name, kring->rhead, kring->rcur, kring->rtail);
92019c4ec08SVincenzo Maffione err = nm_os_selinfo_init(&kring->si, kring->name);
92119c4ec08SVincenzo Maffione if (err) {
92219c4ec08SVincenzo Maffione netmap_krings_delete(na);
92319c4ec08SVincenzo Maffione return err;
92419c4ec08SVincenzo Maffione }
925847bf383SLuigi Rizzo mtx_init(&kring->q_lock, (t == NR_TX ? "nm_txq_lock" : "nm_rxq_lock"), NULL, MTX_DEF);
92619c4ec08SVincenzo Maffione kring->na = na; /* setting this field marks the mutex as initialized */
927f9790aebSLuigi Rizzo }
92819c4ec08SVincenzo Maffione err = nm_os_selinfo_init(&na->si[t], na->name);
92919c4ec08SVincenzo Maffione if (err) {
93019c4ec08SVincenzo Maffione netmap_krings_delete(na);
93119c4ec08SVincenzo Maffione return err;
932f0ea3689SLuigi Rizzo }
93319c4ec08SVincenzo Maffione }
934f9790aebSLuigi Rizzo
935f9790aebSLuigi Rizzo return 0;
936f9790aebSLuigi Rizzo }
937f9790aebSLuigi Rizzo
938f9790aebSLuigi Rizzo
939f0ea3689SLuigi Rizzo /* undo the actions performed by netmap_krings_create */
94089cc2556SLuigi Rizzo /* call with NMG_LOCK held */
941f9790aebSLuigi Rizzo void
netmap_krings_delete(struct netmap_adapter * na)942f9790aebSLuigi Rizzo netmap_krings_delete(struct netmap_adapter *na)
943f9790aebSLuigi Rizzo {
9442ff91c17SVincenzo Maffione struct netmap_kring **kring = na->tx_rings;
945847bf383SLuigi Rizzo enum txrx t;
946847bf383SLuigi Rizzo
947c3e9b4dbSLuiz Otavio O Souza if (na->tx_rings == NULL) {
948b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_ON)
949b6e66be2SVincenzo Maffione nm_prerr("warning: krings were already deleted");
950c3e9b4dbSLuiz Otavio O Souza return;
951c3e9b4dbSLuiz Otavio O Souza }
952c3e9b4dbSLuiz Otavio O Souza
953847bf383SLuigi Rizzo for_rx_tx(t)
95437e3a6d3SLuigi Rizzo nm_os_selinfo_uninit(&na->si[t]);
955f9790aebSLuigi Rizzo
956f0ea3689SLuigi Rizzo /* we rely on the krings layout described above */
957f0ea3689SLuigi Rizzo for ( ; kring != na->tailroom; kring++) {
95819c4ec08SVincenzo Maffione if ((*kring)->na != NULL)
9592ff91c17SVincenzo Maffione mtx_destroy(&(*kring)->q_lock);
9602ff91c17SVincenzo Maffione nm_os_selinfo_uninit(&(*kring)->si);
961f9790aebSLuigi Rizzo }
962c3e9b4dbSLuiz Otavio O Souza nm_os_free(na->tx_rings);
963f9790aebSLuigi Rizzo na->tx_rings = na->rx_rings = na->tailroom = NULL;
964f9790aebSLuigi Rizzo }
965f9790aebSLuigi Rizzo
966f9790aebSLuigi Rizzo
96717885a7bSLuigi Rizzo /*
96817885a7bSLuigi Rizzo * Destructor for NIC ports. They also have an mbuf queue
96917885a7bSLuigi Rizzo * on the rings connected to the host so we need to purge
97017885a7bSLuigi Rizzo * them first.
97117885a7bSLuigi Rizzo */
97289cc2556SLuigi Rizzo /* call with NMG_LOCK held */
97337e3a6d3SLuigi Rizzo void
netmap_hw_krings_delete(struct netmap_adapter * na)97417885a7bSLuigi Rizzo netmap_hw_krings_delete(struct netmap_adapter *na)
97517885a7bSLuigi Rizzo {
9762a7db7a6SVincenzo Maffione u_int lim = netmap_real_rings(na, NR_RX), i;
97717885a7bSLuigi Rizzo
9782a7db7a6SVincenzo Maffione for (i = nma_get_nrings(na, NR_RX); i < lim; i++) {
9792a7db7a6SVincenzo Maffione struct mbq *q = &NMR(na, NR_RX)[i]->rx_queue;
98075f4f3edSVincenzo Maffione nm_prdis("destroy sw mbq with len %d", mbq_len(q));
98117885a7bSLuigi Rizzo mbq_purge(q);
98237e3a6d3SLuigi Rizzo mbq_safe_fini(q);
9832a7db7a6SVincenzo Maffione }
98417885a7bSLuigi Rizzo netmap_krings_delete(na);
98517885a7bSLuigi Rizzo }
98617885a7bSLuigi Rizzo
987a6d768d8SVincenzo Maffione void
netmap_mem_restore(struct netmap_adapter * na)988a6d768d8SVincenzo Maffione netmap_mem_restore(struct netmap_adapter *na)
9894f80b14cSVincenzo Maffione {
990a6d768d8SVincenzo Maffione if (na->nm_mem_prev) {
9914f80b14cSVincenzo Maffione netmap_mem_put(na->nm_mem);
9924f80b14cSVincenzo Maffione na->nm_mem = na->nm_mem_prev;
9934f80b14cSVincenzo Maffione na->nm_mem_prev = NULL;
9944f80b14cSVincenzo Maffione }
9954f80b14cSVincenzo Maffione }
996f9790aebSLuigi Rizzo
997a6d768d8SVincenzo Maffione static void
netmap_mem_drop(struct netmap_adapter * na)998a6d768d8SVincenzo Maffione netmap_mem_drop(struct netmap_adapter *na)
999a6d768d8SVincenzo Maffione {
100009a18933SVincenzo Maffione netmap_mem_deref(na->nm_mem, na);
100109a18933SVincenzo Maffione
100209a18933SVincenzo Maffione if (na->active_fds <= 0) {
100345c67e8fSVincenzo Maffione /* if the native allocator had been overridden on regif,
1004a6d768d8SVincenzo Maffione * restore it now and drop the temporary one
1005a6d768d8SVincenzo Maffione */
1006a6d768d8SVincenzo Maffione netmap_mem_restore(na);
1007a6d768d8SVincenzo Maffione }
1008a6d768d8SVincenzo Maffione }
1009a6d768d8SVincenzo Maffione
101098399ab0SVincenzo Maffione static void
netmap_update_hostrings_mode(struct netmap_adapter * na)101198399ab0SVincenzo Maffione netmap_update_hostrings_mode(struct netmap_adapter *na)
101298399ab0SVincenzo Maffione {
101398399ab0SVincenzo Maffione enum txrx t;
101498399ab0SVincenzo Maffione struct netmap_kring *kring;
101598399ab0SVincenzo Maffione int i;
101698399ab0SVincenzo Maffione
101798399ab0SVincenzo Maffione for_rx_tx(t) {
101898399ab0SVincenzo Maffione for (i = nma_get_nrings(na, t);
101998399ab0SVincenzo Maffione i < netmap_real_rings(na, t); i++) {
102098399ab0SVincenzo Maffione kring = NMR(na, t)[i];
102198399ab0SVincenzo Maffione kring->nr_mode = kring->nr_pending_mode;
102298399ab0SVincenzo Maffione }
102398399ab0SVincenzo Maffione }
102498399ab0SVincenzo Maffione }
102598399ab0SVincenzo Maffione
102668b8534bSLuigi Rizzo /*
1027847bf383SLuigi Rizzo * Undo everything that was done in netmap_do_regif(). In particular,
1028847bf383SLuigi Rizzo * call nm_register(ifp,0) to stop netmap mode on the interface and
10294bf50f18SLuigi Rizzo * revert to normal operation.
103068b8534bSLuigi Rizzo */
1031ce3ee1e7SLuigi Rizzo /* call with NMG_LOCK held */
1032847bf383SLuigi Rizzo static void netmap_unset_ringid(struct netmap_priv_d *);
103337e3a6d3SLuigi Rizzo static void netmap_krings_put(struct netmap_priv_d *);
103437e3a6d3SLuigi Rizzo void
netmap_do_unregif(struct netmap_priv_d * priv)1035847bf383SLuigi Rizzo netmap_do_unregif(struct netmap_priv_d *priv)
103668b8534bSLuigi Rizzo {
1037f9790aebSLuigi Rizzo struct netmap_adapter *na = priv->np_na;
103868b8534bSLuigi Rizzo
1039ce3ee1e7SLuigi Rizzo NMG_LOCK_ASSERT();
1040f9790aebSLuigi Rizzo na->active_fds--;
104137e3a6d3SLuigi Rizzo /* unset nr_pending_mode and possibly release exclusive mode */
104237e3a6d3SLuigi Rizzo netmap_krings_put(priv);
1043847bf383SLuigi Rizzo
1044847bf383SLuigi Rizzo #ifdef WITH_MONITOR
104537e3a6d3SLuigi Rizzo /* XXX check whether we have to do something with monitor
104637e3a6d3SLuigi Rizzo * when rings change nr_mode. */
104737e3a6d3SLuigi Rizzo if (na->active_fds <= 0) {
1048847bf383SLuigi Rizzo /* walk through all the rings and tell any monitor
1049847bf383SLuigi Rizzo * that the port is going to exit netmap mode
1050847bf383SLuigi Rizzo */
1051847bf383SLuigi Rizzo netmap_monitor_stop(na);
105237e3a6d3SLuigi Rizzo }
1053847bf383SLuigi Rizzo #endif
105437e3a6d3SLuigi Rizzo
105537e3a6d3SLuigi Rizzo if (na->active_fds <= 0 || nm_kring_pending(priv)) {
105698399ab0SVincenzo Maffione netmap_set_all_rings(na, NM_KR_LOCKED);
105737e3a6d3SLuigi Rizzo na->nm_register(na, 0);
105898399ab0SVincenzo Maffione netmap_set_all_rings(na, 0);
105937e3a6d3SLuigi Rizzo }
106037e3a6d3SLuigi Rizzo
106137e3a6d3SLuigi Rizzo /* delete rings and buffers that are no longer needed */
106237e3a6d3SLuigi Rizzo netmap_mem_rings_delete(na);
106337e3a6d3SLuigi Rizzo
106437e3a6d3SLuigi Rizzo if (na->active_fds <= 0) { /* last instance */
106568b8534bSLuigi Rizzo /*
106637e3a6d3SLuigi Rizzo * (TO CHECK) We enter here
1067f18be576SLuigi Rizzo * when the last reference to this file descriptor goes
1068f18be576SLuigi Rizzo * away. This means we cannot have any pending poll()
1069f18be576SLuigi Rizzo * or interrupt routine operating on the structure.
1070ce3ee1e7SLuigi Rizzo * XXX The file may be closed in a thread while
1071ce3ee1e7SLuigi Rizzo * another thread is using it.
1072ce3ee1e7SLuigi Rizzo * Linux keeps the file opened until the last reference
1073ce3ee1e7SLuigi Rizzo * by any outstanding ioctl/poll or mmap is gone.
1074ce3ee1e7SLuigi Rizzo * FreeBSD does not track mmap()s (but we do) and
1075ce3ee1e7SLuigi Rizzo * wakes up any sleeping poll(). Need to check what
1076ce3ee1e7SLuigi Rizzo * happens if the close() occurs while a concurrent
1077ce3ee1e7SLuigi Rizzo * syscall is running.
107868b8534bSLuigi Rizzo */
1079b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_ON)
1080b6e66be2SVincenzo Maffione nm_prinf("deleting last instance for %s", na->name);
108137e3a6d3SLuigi Rizzo
108237e3a6d3SLuigi Rizzo if (nm_netmap_on(na)) {
1083b6e66be2SVincenzo Maffione nm_prerr("BUG: netmap on while going to delete the krings");
108437e3a6d3SLuigi Rizzo }
108537e3a6d3SLuigi Rizzo
1086f9790aebSLuigi Rizzo na->nm_krings_delete(na);
1087d12354a5SVincenzo Maffione
1088d12354a5SVincenzo Maffione /* restore the default number of host tx and rx rings */
1089253b2ec1SVincenzo Maffione if (na->na_flags & NAF_HOST_RINGS) {
1090d12354a5SVincenzo Maffione na->num_host_tx_rings = 1;
1091d12354a5SVincenzo Maffione na->num_host_rx_rings = 1;
1092253b2ec1SVincenzo Maffione } else {
1093253b2ec1SVincenzo Maffione na->num_host_tx_rings = 0;
1094253b2ec1SVincenzo Maffione na->num_host_rx_rings = 0;
1095253b2ec1SVincenzo Maffione }
109668b8534bSLuigi Rizzo }
109737e3a6d3SLuigi Rizzo
109845c67e8fSVincenzo Maffione /* possibly decrement counter of tx_si/rx_si users */
1099847bf383SLuigi Rizzo netmap_unset_ringid(priv);
1100f9790aebSLuigi Rizzo /* delete the nifp */
1101847bf383SLuigi Rizzo netmap_mem_if_delete(na, priv->np_nifp);
1102847bf383SLuigi Rizzo /* drop the allocator */
11034f80b14cSVincenzo Maffione netmap_mem_drop(na);
1104847bf383SLuigi Rizzo /* mark the priv as unregistered */
1105847bf383SLuigi Rizzo priv->np_na = NULL;
1106847bf383SLuigi Rizzo priv->np_nifp = NULL;
11075819da83SLuigi Rizzo }
110868b8534bSLuigi Rizzo
110937e3a6d3SLuigi Rizzo struct netmap_priv_d*
netmap_priv_new(void)111037e3a6d3SLuigi Rizzo netmap_priv_new(void)
111137e3a6d3SLuigi Rizzo {
111237e3a6d3SLuigi Rizzo struct netmap_priv_d *priv;
111337e3a6d3SLuigi Rizzo
1114c3e9b4dbSLuiz Otavio O Souza priv = nm_os_malloc(sizeof(struct netmap_priv_d));
111537e3a6d3SLuigi Rizzo if (priv == NULL)
111637e3a6d3SLuigi Rizzo return NULL;
111737e3a6d3SLuigi Rizzo priv->np_refs = 1;
111837e3a6d3SLuigi Rizzo nm_os_get_module();
111937e3a6d3SLuigi Rizzo return priv;
112037e3a6d3SLuigi Rizzo }
112137e3a6d3SLuigi Rizzo
1122ce3ee1e7SLuigi Rizzo /*
11238fd44c93SLuigi Rizzo * Destructor of the netmap_priv_d, called when the fd is closed
11248fd44c93SLuigi Rizzo * Action: undo all the things done by NIOCREGIF,
11258fd44c93SLuigi Rizzo * On FreeBSD we need to track whether there are active mmap()s,
11268fd44c93SLuigi Rizzo * and we use np_active_mmaps for that. On linux, the field is always 0.
11278fd44c93SLuigi Rizzo * Return: 1 if we can free priv, 0 otherwise.
112889cc2556SLuigi Rizzo *
1129ce3ee1e7SLuigi Rizzo */
113089cc2556SLuigi Rizzo /* call with NMG_LOCK held */
113137e3a6d3SLuigi Rizzo void
netmap_priv_delete(struct netmap_priv_d * priv)113237e3a6d3SLuigi Rizzo netmap_priv_delete(struct netmap_priv_d *priv)
1133ce3ee1e7SLuigi Rizzo {
1134f9790aebSLuigi Rizzo struct netmap_adapter *na = priv->np_na;
1135ce3ee1e7SLuigi Rizzo
1136847adfb7SLuigi Rizzo /* number of active references to this fd */
11378fd44c93SLuigi Rizzo if (--priv->np_refs > 0) {
113837e3a6d3SLuigi Rizzo return;
1139ce3ee1e7SLuigi Rizzo }
114037e3a6d3SLuigi Rizzo nm_os_put_module();
114137e3a6d3SLuigi Rizzo if (na) {
1142847bf383SLuigi Rizzo netmap_do_unregif(priv);
114337e3a6d3SLuigi Rizzo }
114437e3a6d3SLuigi Rizzo netmap_unget_na(na, priv->np_ifp);
114537e3a6d3SLuigi Rizzo bzero(priv, sizeof(*priv)); /* for safety */
1146c3e9b4dbSLuiz Otavio O Souza nm_os_free(priv);
1147f196ce38SLuigi Rizzo }
11485819da83SLuigi Rizzo
1149f9790aebSLuigi Rizzo
115089cc2556SLuigi Rizzo /* call with NMG_LOCK *not* held */
1151f9790aebSLuigi Rizzo void
netmap_dtor(void * data)11525819da83SLuigi Rizzo netmap_dtor(void *data)
11535819da83SLuigi Rizzo {
11545819da83SLuigi Rizzo struct netmap_priv_d *priv = data;
11555819da83SLuigi Rizzo
1156ce3ee1e7SLuigi Rizzo NMG_LOCK();
115737e3a6d3SLuigi Rizzo netmap_priv_delete(priv);
1158ce3ee1e7SLuigi Rizzo NMG_UNLOCK();
1159ce3ee1e7SLuigi Rizzo }
116068b8534bSLuigi Rizzo
1161f18be576SLuigi Rizzo
116268b8534bSLuigi Rizzo /*
1163c3e9b4dbSLuiz Otavio O Souza * Handlers for synchronization of the rings from/to the host stack.
1164c3e9b4dbSLuiz Otavio O Souza * These are associated to a network interface and are just another
1165c3e9b4dbSLuiz Otavio O Souza * ring pair managed by userspace.
1166c3e9b4dbSLuiz Otavio O Souza *
1167c3e9b4dbSLuiz Otavio O Souza * Netmap also supports transparent forwarding (NS_FORWARD and NR_FORWARD
1168c3e9b4dbSLuiz Otavio O Souza * flags):
1169c3e9b4dbSLuiz Otavio O Souza *
1170c3e9b4dbSLuiz Otavio O Souza * - Before releasing buffers on hw RX rings, the application can mark
1171c3e9b4dbSLuiz Otavio O Souza * them with the NS_FORWARD flag. During the next RXSYNC or poll(), they
1172c3e9b4dbSLuiz Otavio O Souza * will be forwarded to the host stack, similarly to what happened if
1173c3e9b4dbSLuiz Otavio O Souza * the application moved them to the host TX ring.
1174c3e9b4dbSLuiz Otavio O Souza *
1175c3e9b4dbSLuiz Otavio O Souza * - Before releasing buffers on the host RX ring, the application can
1176c3e9b4dbSLuiz Otavio O Souza * mark them with the NS_FORWARD flag. During the next RXSYNC or poll(),
1177c3e9b4dbSLuiz Otavio O Souza * they will be forwarded to the hw TX rings, saving the application
1178c3e9b4dbSLuiz Otavio O Souza * from doing the same task in user-space.
1179c3e9b4dbSLuiz Otavio O Souza *
118045c67e8fSVincenzo Maffione * Transparent forwarding can be enabled per-ring, by setting the NR_FORWARD
1181c3e9b4dbSLuiz Otavio O Souza * flag, or globally with the netmap_fwd sysctl.
1182c3e9b4dbSLuiz Otavio O Souza *
1183091fd0abSLuigi Rizzo * The transfer NIC --> host is relatively easy, just encapsulate
1184091fd0abSLuigi Rizzo * into mbufs and we are done. The host --> NIC side is slightly
1185091fd0abSLuigi Rizzo * harder because there might not be room in the tx ring so it
1186091fd0abSLuigi Rizzo * might take a while before releasing the buffer.
1187091fd0abSLuigi Rizzo */
1188091fd0abSLuigi Rizzo
1189f18be576SLuigi Rizzo
1190091fd0abSLuigi Rizzo /*
1191c3e9b4dbSLuiz Otavio O Souza * Pass a whole queue of mbufs to the host stack as coming from 'dst'
119217885a7bSLuigi Rizzo * We do not need to lock because the queue is private.
1193c3e9b4dbSLuiz Otavio O Souza * After this call the queue is empty.
1194091fd0abSLuigi Rizzo */
1195091fd0abSLuigi Rizzo static void
netmap_send_up(if_t dst,struct mbq * q)1196e330262fSJustin Hibbits netmap_send_up(if_t dst, struct mbq *q)
1197091fd0abSLuigi Rizzo {
1198091fd0abSLuigi Rizzo struct mbuf *m;
119937e3a6d3SLuigi Rizzo struct mbuf *head = NULL, *prev = NULL;
1200b7d69138SVincenzo Maffione #ifdef __FreeBSD__
1201b7d69138SVincenzo Maffione struct epoch_tracker et;
1202091fd0abSLuigi Rizzo
1203a4470078SGleb Smirnoff NET_EPOCH_ENTER(et);
1204b7d69138SVincenzo Maffione #endif /* __FreeBSD__ */
1205c3e9b4dbSLuiz Otavio O Souza /* Send packets up, outside the lock; head/prev machinery
1206c3e9b4dbSLuiz Otavio O Souza * is only useful for Windows. */
1207f9790aebSLuigi Rizzo while ((m = mbq_dequeue(q)) != NULL) {
1208b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_HOST)
1209b6e66be2SVincenzo Maffione nm_prinf("sending up pkt %p size %d", m, MBUF_LEN(m));
121037e3a6d3SLuigi Rizzo prev = nm_os_send_up(dst, m, prev);
121137e3a6d3SLuigi Rizzo if (head == NULL)
121237e3a6d3SLuigi Rizzo head = prev;
1213091fd0abSLuigi Rizzo }
121437e3a6d3SLuigi Rizzo if (head)
121537e3a6d3SLuigi Rizzo nm_os_send_up(dst, NULL, head);
1216b7d69138SVincenzo Maffione #ifdef __FreeBSD__
1217a4470078SGleb Smirnoff NET_EPOCH_EXIT(et);
1218b7d69138SVincenzo Maffione #endif /* __FreeBSD__ */
121937e3a6d3SLuigi Rizzo mbq_fini(q);
1220091fd0abSLuigi Rizzo }
1221091fd0abSLuigi Rizzo
1222f18be576SLuigi Rizzo
1223091fd0abSLuigi Rizzo /*
1224c3e9b4dbSLuiz Otavio O Souza * Scan the buffers from hwcur to ring->head, and put a copy of those
1225c3e9b4dbSLuiz Otavio O Souza * marked NS_FORWARD (or all of them if forced) into a queue of mbufs.
1226c3e9b4dbSLuiz Otavio O Souza * Drop remaining packets in the unlikely event
122717885a7bSLuigi Rizzo * of an mbuf shortage.
1228091fd0abSLuigi Rizzo */
1229091fd0abSLuigi Rizzo static void
netmap_grab_packets(struct netmap_kring * kring,struct mbq * q,int force)1230091fd0abSLuigi Rizzo netmap_grab_packets(struct netmap_kring *kring, struct mbq *q, int force)
1231091fd0abSLuigi Rizzo {
123217885a7bSLuigi Rizzo u_int const lim = kring->nkr_num_slots - 1;
1233847bf383SLuigi Rizzo u_int const head = kring->rhead;
123417885a7bSLuigi Rizzo u_int n;
1235f9790aebSLuigi Rizzo struct netmap_adapter *na = kring->na;
1236091fd0abSLuigi Rizzo
123717885a7bSLuigi Rizzo for (n = kring->nr_hwcur; n != head; n = nm_next(n, lim)) {
123817885a7bSLuigi Rizzo struct mbuf *m;
1239091fd0abSLuigi Rizzo struct netmap_slot *slot = &kring->ring->slot[n];
1240091fd0abSLuigi Rizzo
1241091fd0abSLuigi Rizzo if ((slot->flags & NS_FORWARD) == 0 && !force)
1242091fd0abSLuigi Rizzo continue;
12434bf50f18SLuigi Rizzo if (slot->len < 14 || slot->len > NETMAP_BUF_SIZE(na)) {
124475f4f3edSVincenzo Maffione nm_prlim(5, "bad pkt at %d len %d", n, slot->len);
1245091fd0abSLuigi Rizzo continue;
1246091fd0abSLuigi Rizzo }
1247091fd0abSLuigi Rizzo slot->flags &= ~NS_FORWARD; // XXX needed ?
124817885a7bSLuigi Rizzo /* XXX TODO: adapt to the case of a multisegment packet */
12494bf50f18SLuigi Rizzo m = m_devget(NMB(na, slot), slot->len, 0, na->ifp, NULL);
1250091fd0abSLuigi Rizzo
1251091fd0abSLuigi Rizzo if (m == NULL)
1252091fd0abSLuigi Rizzo break;
1253f9790aebSLuigi Rizzo mbq_enqueue(q, m);
1254091fd0abSLuigi Rizzo }
1255091fd0abSLuigi Rizzo }
1256091fd0abSLuigi Rizzo
125737e3a6d3SLuigi Rizzo static inline int
_nm_may_forward(struct netmap_kring * kring)125837e3a6d3SLuigi Rizzo _nm_may_forward(struct netmap_kring *kring)
125937e3a6d3SLuigi Rizzo {
126037e3a6d3SLuigi Rizzo return ((netmap_fwd || kring->ring->flags & NR_FORWARD) &&
126137e3a6d3SLuigi Rizzo kring->na->na_flags & NAF_HOST_RINGS &&
126237e3a6d3SLuigi Rizzo kring->tx == NR_RX);
126337e3a6d3SLuigi Rizzo }
126437e3a6d3SLuigi Rizzo
126537e3a6d3SLuigi Rizzo static inline int
nm_may_forward_up(struct netmap_kring * kring)126637e3a6d3SLuigi Rizzo nm_may_forward_up(struct netmap_kring *kring)
126737e3a6d3SLuigi Rizzo {
126837e3a6d3SLuigi Rizzo return _nm_may_forward(kring) &&
126937e3a6d3SLuigi Rizzo kring->ring_id != kring->na->num_rx_rings;
127037e3a6d3SLuigi Rizzo }
127137e3a6d3SLuigi Rizzo
127237e3a6d3SLuigi Rizzo static inline int
nm_may_forward_down(struct netmap_kring * kring,int sync_flags)1273c3e9b4dbSLuiz Otavio O Souza nm_may_forward_down(struct netmap_kring *kring, int sync_flags)
127437e3a6d3SLuigi Rizzo {
127537e3a6d3SLuigi Rizzo return _nm_may_forward(kring) &&
1276c3e9b4dbSLuiz Otavio O Souza (sync_flags & NAF_CAN_FORWARD_DOWN) &&
127737e3a6d3SLuigi Rizzo kring->ring_id == kring->na->num_rx_rings;
127837e3a6d3SLuigi Rizzo }
1279f18be576SLuigi Rizzo
1280091fd0abSLuigi Rizzo /*
128117885a7bSLuigi Rizzo * Send to the NIC rings packets marked NS_FORWARD between
1282c3e9b4dbSLuiz Otavio O Souza * kring->nr_hwcur and kring->rhead.
1283c3e9b4dbSLuiz Otavio O Souza * Called under kring->rx_queue.lock on the sw rx ring.
1284c3e9b4dbSLuiz Otavio O Souza *
1285c3e9b4dbSLuiz Otavio O Souza * It can only be called if the user opened all the TX hw rings,
1286c3e9b4dbSLuiz Otavio O Souza * see NAF_CAN_FORWARD_DOWN flag.
1287c3e9b4dbSLuiz Otavio O Souza * We can touch the TX netmap rings (slots, head and cur) since
1288c3e9b4dbSLuiz Otavio O Souza * we are in poll/ioctl system call context, and the application
1289c3e9b4dbSLuiz Otavio O Souza * is not supposed to touch the ring (using a different thread)
1290c3e9b4dbSLuiz Otavio O Souza * during the execution of the system call.
1291091fd0abSLuigi Rizzo */
129217885a7bSLuigi Rizzo static u_int
netmap_sw_to_nic(struct netmap_adapter * na)1293091fd0abSLuigi Rizzo netmap_sw_to_nic(struct netmap_adapter *na)
1294091fd0abSLuigi Rizzo {
12952ff91c17SVincenzo Maffione struct netmap_kring *kring = na->rx_rings[na->num_rx_rings];
129617885a7bSLuigi Rizzo struct netmap_slot *rxslot = kring->ring->slot;
129717885a7bSLuigi Rizzo u_int i, rxcur = kring->nr_hwcur;
129817885a7bSLuigi Rizzo u_int const head = kring->rhead;
129917885a7bSLuigi Rizzo u_int const src_lim = kring->nkr_num_slots - 1;
130017885a7bSLuigi Rizzo u_int sent = 0;
1301ce3ee1e7SLuigi Rizzo
130217885a7bSLuigi Rizzo /* scan rings to find space, then fill as much as possible */
130317885a7bSLuigi Rizzo for (i = 0; i < na->num_tx_rings; i++) {
13042ff91c17SVincenzo Maffione struct netmap_kring *kdst = na->tx_rings[i];
130517885a7bSLuigi Rizzo struct netmap_ring *rdst = kdst->ring;
130617885a7bSLuigi Rizzo u_int const dst_lim = kdst->nkr_num_slots - 1;
1307ce3ee1e7SLuigi Rizzo
130817885a7bSLuigi Rizzo /* XXX do we trust ring or kring->rcur,rtail ? */
130917885a7bSLuigi Rizzo for (; rxcur != head && !nm_ring_empty(rdst);
131017885a7bSLuigi Rizzo rxcur = nm_next(rxcur, src_lim) ) {
1311091fd0abSLuigi Rizzo struct netmap_slot *src, *dst, tmp;
131237e3a6d3SLuigi Rizzo u_int dst_head = rdst->head;
131317885a7bSLuigi Rizzo
131417885a7bSLuigi Rizzo src = &rxslot[rxcur];
131517885a7bSLuigi Rizzo if ((src->flags & NS_FORWARD) == 0 && !netmap_fwd)
131617885a7bSLuigi Rizzo continue;
131717885a7bSLuigi Rizzo
131817885a7bSLuigi Rizzo sent++;
131917885a7bSLuigi Rizzo
132037e3a6d3SLuigi Rizzo dst = &rdst->slot[dst_head];
132117885a7bSLuigi Rizzo
1322091fd0abSLuigi Rizzo tmp = *src;
132317885a7bSLuigi Rizzo
1324091fd0abSLuigi Rizzo src->buf_idx = dst->buf_idx;
1325091fd0abSLuigi Rizzo src->flags = NS_BUF_CHANGED;
1326091fd0abSLuigi Rizzo
1327091fd0abSLuigi Rizzo dst->buf_idx = tmp.buf_idx;
1328091fd0abSLuigi Rizzo dst->len = tmp.len;
1329091fd0abSLuigi Rizzo dst->flags = NS_BUF_CHANGED;
1330091fd0abSLuigi Rizzo
133137e3a6d3SLuigi Rizzo rdst->head = rdst->cur = nm_next(dst_head, dst_lim);
1332091fd0abSLuigi Rizzo }
1333c3e9b4dbSLuiz Otavio O Souza /* if (sent) XXX txsync ? it would be just an optimization */
1334091fd0abSLuigi Rizzo }
133517885a7bSLuigi Rizzo return sent;
1336091fd0abSLuigi Rizzo }
1337091fd0abSLuigi Rizzo
1338f18be576SLuigi Rizzo
1339091fd0abSLuigi Rizzo /*
1340ce3ee1e7SLuigi Rizzo * netmap_txsync_to_host() passes packets up. We are called from a
134102ad4083SLuigi Rizzo * system call in user process context, and the only contention
134202ad4083SLuigi Rizzo * can be among multiple user threads erroneously calling
1343091fd0abSLuigi Rizzo * this routine concurrently.
134468b8534bSLuigi Rizzo */
134537e3a6d3SLuigi Rizzo static int
netmap_txsync_to_host(struct netmap_kring * kring,int flags)134637e3a6d3SLuigi Rizzo netmap_txsync_to_host(struct netmap_kring *kring, int flags)
134768b8534bSLuigi Rizzo {
134837e3a6d3SLuigi Rizzo struct netmap_adapter *na = kring->na;
134917885a7bSLuigi Rizzo u_int const lim = kring->nkr_num_slots - 1;
1350f0ea3689SLuigi Rizzo u_int const head = kring->rhead;
1351f9790aebSLuigi Rizzo struct mbq q;
135268b8534bSLuigi Rizzo
135317885a7bSLuigi Rizzo /* Take packets from hwcur to head and pass them up.
1354c3e9b4dbSLuiz Otavio O Souza * Force hwcur = head since netmap_grab_packets() stops at head
135568b8534bSLuigi Rizzo */
1356f9790aebSLuigi Rizzo mbq_init(&q);
135717885a7bSLuigi Rizzo netmap_grab_packets(kring, &q, 1 /* force */);
135875f4f3edSVincenzo Maffione nm_prdis("have %d pkts in queue", mbq_len(&q));
135917885a7bSLuigi Rizzo kring->nr_hwcur = head;
136017885a7bSLuigi Rizzo kring->nr_hwtail = head + lim;
136117885a7bSLuigi Rizzo if (kring->nr_hwtail > lim)
136217885a7bSLuigi Rizzo kring->nr_hwtail -= lim + 1;
136368b8534bSLuigi Rizzo
1364f9790aebSLuigi Rizzo netmap_send_up(na->ifp, &q);
136537e3a6d3SLuigi Rizzo return 0;
1366f18be576SLuigi Rizzo }
1367f18be576SLuigi Rizzo
1368f18be576SLuigi Rizzo
136968b8534bSLuigi Rizzo /*
137002ad4083SLuigi Rizzo * rxsync backend for packets coming from the host stack.
137117885a7bSLuigi Rizzo * They have been put in kring->rx_queue by netmap_transmit().
137217885a7bSLuigi Rizzo * We protect access to the kring using kring->rx_queue.lock
137302ad4083SLuigi Rizzo *
1374c3e9b4dbSLuiz Otavio O Souza * also moves to the nic hw rings any packet the user has marked
1375c3e9b4dbSLuiz Otavio O Souza * for transparent-mode forwarding, then sets the NR_FORWARD
1376c3e9b4dbSLuiz Otavio O Souza * flag in the kring to let the caller push them out
137768b8534bSLuigi Rizzo */
13788fd44c93SLuigi Rizzo static int
netmap_rxsync_from_host(struct netmap_kring * kring,int flags)137937e3a6d3SLuigi Rizzo netmap_rxsync_from_host(struct netmap_kring *kring, int flags)
138068b8534bSLuigi Rizzo {
138137e3a6d3SLuigi Rizzo struct netmap_adapter *na = kring->na;
138268b8534bSLuigi Rizzo struct netmap_ring *ring = kring->ring;
138317885a7bSLuigi Rizzo u_int nm_i, n;
138417885a7bSLuigi Rizzo u_int const lim = kring->nkr_num_slots - 1;
1385f0ea3689SLuigi Rizzo u_int const head = kring->rhead;
138617885a7bSLuigi Rizzo int ret = 0;
1387847bf383SLuigi Rizzo struct mbq *q = &kring->rx_queue, fq;
138868b8534bSLuigi Rizzo
1389847bf383SLuigi Rizzo mbq_init(&fq); /* fq holds packets to be freed */
1390847bf383SLuigi Rizzo
1391997b054cSLuigi Rizzo mbq_lock(q);
139217885a7bSLuigi Rizzo
139317885a7bSLuigi Rizzo /* First part: import newly received packets */
139417885a7bSLuigi Rizzo n = mbq_len(q);
139517885a7bSLuigi Rizzo if (n) { /* grab packets from the queue */
139617885a7bSLuigi Rizzo struct mbuf *m;
139717885a7bSLuigi Rizzo uint32_t stop_i;
139817885a7bSLuigi Rizzo
139917885a7bSLuigi Rizzo nm_i = kring->nr_hwtail;
1400c3e9b4dbSLuiz Otavio O Souza stop_i = nm_prev(kring->nr_hwcur, lim);
140117885a7bSLuigi Rizzo while ( nm_i != stop_i && (m = mbq_dequeue(q)) != NULL ) {
140217885a7bSLuigi Rizzo int len = MBUF_LEN(m);
140317885a7bSLuigi Rizzo struct netmap_slot *slot = &ring->slot[nm_i];
140417885a7bSLuigi Rizzo
14054bf50f18SLuigi Rizzo m_copydata(m, 0, len, NMB(na, slot));
140675f4f3edSVincenzo Maffione nm_prdis("nm %d len %d", nm_i, len);
1407b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_HOST)
1408b6e66be2SVincenzo Maffione nm_prinf("%s", nm_dump_buf(NMB(na, slot),len, 128, NULL));
140917885a7bSLuigi Rizzo
141017885a7bSLuigi Rizzo slot->len = len;
14114f80b14cSVincenzo Maffione slot->flags = 0;
141217885a7bSLuigi Rizzo nm_i = nm_next(nm_i, lim);
1413847bf383SLuigi Rizzo mbq_enqueue(&fq, m);
141464ae02c3SLuigi Rizzo }
141517885a7bSLuigi Rizzo kring->nr_hwtail = nm_i;
141664ae02c3SLuigi Rizzo }
141717885a7bSLuigi Rizzo
141817885a7bSLuigi Rizzo /*
141917885a7bSLuigi Rizzo * Second part: skip past packets that userspace has released.
142017885a7bSLuigi Rizzo */
142117885a7bSLuigi Rizzo nm_i = kring->nr_hwcur;
142217885a7bSLuigi Rizzo if (nm_i != head) { /* something was released */
1423c3e9b4dbSLuiz Otavio O Souza if (nm_may_forward_down(kring, flags)) {
142417885a7bSLuigi Rizzo ret = netmap_sw_to_nic(na);
142537e3a6d3SLuigi Rizzo if (ret > 0) {
142637e3a6d3SLuigi Rizzo kring->nr_kflags |= NR_FORWARD;
142737e3a6d3SLuigi Rizzo ret = 0;
142837e3a6d3SLuigi Rizzo }
142937e3a6d3SLuigi Rizzo }
143017885a7bSLuigi Rizzo kring->nr_hwcur = head;
143164ae02c3SLuigi Rizzo }
143217885a7bSLuigi Rizzo
1433997b054cSLuigi Rizzo mbq_unlock(q);
1434847bf383SLuigi Rizzo
1435847bf383SLuigi Rizzo mbq_purge(&fq);
143637e3a6d3SLuigi Rizzo mbq_fini(&fq);
1437847bf383SLuigi Rizzo
143817885a7bSLuigi Rizzo return ret;
143968b8534bSLuigi Rizzo }
144068b8534bSLuigi Rizzo
144168b8534bSLuigi Rizzo
1442f9790aebSLuigi Rizzo /* Get a netmap adapter for the port.
1443f9790aebSLuigi Rizzo *
1444f9790aebSLuigi Rizzo * If it is possible to satisfy the request, return 0
1445f9790aebSLuigi Rizzo * with *na containing the netmap adapter found.
1446f9790aebSLuigi Rizzo * Otherwise return an error code, with *na containing NULL.
1447f9790aebSLuigi Rizzo *
1448f9790aebSLuigi Rizzo * When the port is attached to a bridge, we always return
1449f9790aebSLuigi Rizzo * EBUSY.
1450f9790aebSLuigi Rizzo * Otherwise, if the port is already bound to a file descriptor,
1451f9790aebSLuigi Rizzo * then we unconditionally return the existing adapter into *na.
1452f9790aebSLuigi Rizzo * In all the other cases, we return (into *na) either native,
1453f9790aebSLuigi Rizzo * generic or NULL, according to the following table:
1454f9790aebSLuigi Rizzo *
1455f9790aebSLuigi Rizzo * native_support
1456f9790aebSLuigi Rizzo * active_fds dev.netmap.admode YES NO
1457f9790aebSLuigi Rizzo * -------------------------------------------------------
1458f9790aebSLuigi Rizzo * >0 * NA(ifp) NA(ifp)
1459f9790aebSLuigi Rizzo *
1460f9790aebSLuigi Rizzo * 0 NETMAP_ADMODE_BEST NATIVE GENERIC
1461f9790aebSLuigi Rizzo * 0 NETMAP_ADMODE_NATIVE NATIVE NULL
1462f9790aebSLuigi Rizzo * 0 NETMAP_ADMODE_GENERIC GENERIC GENERIC
1463f9790aebSLuigi Rizzo *
1464f9790aebSLuigi Rizzo */
146537e3a6d3SLuigi Rizzo static void netmap_hw_dtor(struct netmap_adapter *); /* needed by NM_IS_NATIVE() */
1466f9790aebSLuigi Rizzo int
netmap_get_hw_na(if_t ifp,struct netmap_mem_d * nmd,struct netmap_adapter ** na)1467e330262fSJustin Hibbits netmap_get_hw_na(if_t ifp, struct netmap_mem_d *nmd, struct netmap_adapter **na)
1468f9790aebSLuigi Rizzo {
1469f9790aebSLuigi Rizzo /* generic support */
1470f9790aebSLuigi Rizzo int i = netmap_admode; /* Take a snapshot. */
1471f9790aebSLuigi Rizzo struct netmap_adapter *prev_na;
1472847bf383SLuigi Rizzo int error = 0;
1473f9790aebSLuigi Rizzo
1474f9790aebSLuigi Rizzo *na = NULL; /* default */
1475f9790aebSLuigi Rizzo
1476f9790aebSLuigi Rizzo /* reset in case of invalid value */
1477f9790aebSLuigi Rizzo if (i < NETMAP_ADMODE_BEST || i >= NETMAP_ADMODE_LAST)
1478f9790aebSLuigi Rizzo i = netmap_admode = NETMAP_ADMODE_BEST;
1479f9790aebSLuigi Rizzo
148037e3a6d3SLuigi Rizzo if (NM_NA_VALID(ifp)) {
14814bf50f18SLuigi Rizzo prev_na = NA(ifp);
1482f9790aebSLuigi Rizzo /* If an adapter already exists, return it if
1483f9790aebSLuigi Rizzo * there are active file descriptors or if
1484f9790aebSLuigi Rizzo * netmap is not forced to use generic
1485f9790aebSLuigi Rizzo * adapters.
1486f9790aebSLuigi Rizzo */
14874bf50f18SLuigi Rizzo if (NETMAP_OWNED_BY_ANY(prev_na)
14884bf50f18SLuigi Rizzo || i != NETMAP_ADMODE_GENERIC
14894bf50f18SLuigi Rizzo || prev_na->na_flags & NAF_FORCE_NATIVE
14904bf50f18SLuigi Rizzo #ifdef WITH_PIPES
14914bf50f18SLuigi Rizzo /* ugly, but we cannot allow an adapter switch
14924bf50f18SLuigi Rizzo * if some pipe is referring to this one
14934bf50f18SLuigi Rizzo */
14944bf50f18SLuigi Rizzo || prev_na->na_next_pipe > 0
14954bf50f18SLuigi Rizzo #endif
14964bf50f18SLuigi Rizzo ) {
14974bf50f18SLuigi Rizzo *na = prev_na;
1498c3e9b4dbSLuiz Otavio O Souza goto assign_mem;
1499f9790aebSLuigi Rizzo }
1500f9790aebSLuigi Rizzo }
1501f9790aebSLuigi Rizzo
1502f9790aebSLuigi Rizzo /* If there isn't native support and netmap is not allowed
1503f9790aebSLuigi Rizzo * to use generic adapters, we cannot satisfy the request.
1504f9790aebSLuigi Rizzo */
150537e3a6d3SLuigi Rizzo if (!NM_IS_NATIVE(ifp) && i == NETMAP_ADMODE_NATIVE)
1506f2637526SLuigi Rizzo return EOPNOTSUPP;
1507f9790aebSLuigi Rizzo
1508f9790aebSLuigi Rizzo /* Otherwise, create a generic adapter and return it,
1509f9790aebSLuigi Rizzo * saving the previously used netmap adapter, if any.
1510f9790aebSLuigi Rizzo *
1511f9790aebSLuigi Rizzo * Note that here 'prev_na', if not NULL, MUST be a
1512f9790aebSLuigi Rizzo * native adapter, and CANNOT be a generic one. This is
1513f9790aebSLuigi Rizzo * true because generic adapters are created on demand, and
1514f9790aebSLuigi Rizzo * destroyed when not used anymore. Therefore, if the adapter
1515f9790aebSLuigi Rizzo * currently attached to an interface 'ifp' is generic, it
1516f9790aebSLuigi Rizzo * must be that
1517f9790aebSLuigi Rizzo * (NA(ifp)->active_fds > 0 || NETMAP_OWNED_BY_KERN(NA(ifp))).
1518f9790aebSLuigi Rizzo * Consequently, if NA(ifp) is generic, we will enter one of
1519f9790aebSLuigi Rizzo * the branches above. This ensures that we never override
1520f9790aebSLuigi Rizzo * a generic adapter with another generic adapter.
1521f9790aebSLuigi Rizzo */
1522f9790aebSLuigi Rizzo error = generic_netmap_attach(ifp);
1523f9790aebSLuigi Rizzo if (error)
1524f9790aebSLuigi Rizzo return error;
1525f9790aebSLuigi Rizzo
1526f9790aebSLuigi Rizzo *na = NA(ifp);
1527c3e9b4dbSLuiz Otavio O Souza
1528c3e9b4dbSLuiz Otavio O Souza assign_mem:
1529c3e9b4dbSLuiz Otavio O Souza if (nmd != NULL && !((*na)->na_flags & NAF_MEM_OWNER) &&
1530c3e9b4dbSLuiz Otavio O Souza (*na)->active_fds == 0 && ((*na)->nm_mem != nmd)) {
15314f80b14cSVincenzo Maffione (*na)->nm_mem_prev = (*na)->nm_mem;
1532c3e9b4dbSLuiz Otavio O Souza (*na)->nm_mem = netmap_mem_get(nmd);
1533f9790aebSLuigi Rizzo }
1534f9790aebSLuigi Rizzo
1535c3e9b4dbSLuiz Otavio O Souza return 0;
1536c3e9b4dbSLuiz Otavio O Souza }
1537f9790aebSLuigi Rizzo
153868b8534bSLuigi Rizzo /*
1539ce3ee1e7SLuigi Rizzo * MUST BE CALLED UNDER NMG_LOCK()
1540ce3ee1e7SLuigi Rizzo *
1541f2637526SLuigi Rizzo * Get a refcounted reference to a netmap adapter attached
15422ff91c17SVincenzo Maffione * to the interface specified by req.
1543ce3ee1e7SLuigi Rizzo * This is always called in the execution of an ioctl().
1544ce3ee1e7SLuigi Rizzo *
1545f2637526SLuigi Rizzo * Return ENXIO if the interface specified by the request does
1546f2637526SLuigi Rizzo * not exist, ENOTSUP if netmap is not supported by the interface,
1547f2637526SLuigi Rizzo * EBUSY if the interface is already attached to a bridge,
1548f2637526SLuigi Rizzo * EINVAL if parameters are invalid, ENOMEM if needed resources
1549f2637526SLuigi Rizzo * could not be allocated.
1550f2637526SLuigi Rizzo * If successful, hold a reference to the netmap adapter.
1551f18be576SLuigi Rizzo *
15522ff91c17SVincenzo Maffione * If the interface specified by req is a system one, also keep
155337e3a6d3SLuigi Rizzo * a reference to it and return a valid *ifp.
155468b8534bSLuigi Rizzo */
1555f9790aebSLuigi Rizzo int
netmap_get_na(struct nmreq_header * hdr,struct netmap_adapter ** na,if_t * ifp,struct netmap_mem_d * nmd,int create)15562ff91c17SVincenzo Maffione netmap_get_na(struct nmreq_header *hdr,
1557e330262fSJustin Hibbits struct netmap_adapter **na, if_t *ifp,
15582ff91c17SVincenzo Maffione struct netmap_mem_d *nmd, int create)
155968b8534bSLuigi Rizzo {
1560cfa866f6SMatt Macy struct nmreq_register *req = (struct nmreq_register *)(uintptr_t)hdr->nr_body;
1561f9790aebSLuigi Rizzo int error = 0;
1562f0ea3689SLuigi Rizzo struct netmap_adapter *ret = NULL;
1563c3e9b4dbSLuiz Otavio O Souza int nmd_ref = 0;
1564f9790aebSLuigi Rizzo
1565f9790aebSLuigi Rizzo *na = NULL; /* default return value */
156637e3a6d3SLuigi Rizzo *ifp = NULL;
1567f196ce38SLuigi Rizzo
15682ff91c17SVincenzo Maffione if (hdr->nr_reqtype != NETMAP_REQ_REGISTER) {
15692ff91c17SVincenzo Maffione return EINVAL;
15702ff91c17SVincenzo Maffione }
15712ff91c17SVincenzo Maffione
15722ff91c17SVincenzo Maffione if (req->nr_mode == NR_REG_PIPE_MASTER ||
15732ff91c17SVincenzo Maffione req->nr_mode == NR_REG_PIPE_SLAVE) {
15742ff91c17SVincenzo Maffione /* Do not accept deprecated pipe modes. */
1575b6e66be2SVincenzo Maffione nm_prerr("Deprecated pipe nr_mode, use xx{yy or xx}yy syntax");
15762ff91c17SVincenzo Maffione return EINVAL;
15772ff91c17SVincenzo Maffione }
15782ff91c17SVincenzo Maffione
1579ce3ee1e7SLuigi Rizzo NMG_LOCK_ASSERT();
1580ce3ee1e7SLuigi Rizzo
1581c3e9b4dbSLuiz Otavio O Souza /* if the request contain a memid, try to find the
1582c3e9b4dbSLuiz Otavio O Souza * corresponding memory region
1583c3e9b4dbSLuiz Otavio O Souza */
15842ff91c17SVincenzo Maffione if (nmd == NULL && req->nr_mem_id) {
15852ff91c17SVincenzo Maffione nmd = netmap_mem_find(req->nr_mem_id);
1586c3e9b4dbSLuiz Otavio O Souza if (nmd == NULL)
1587c3e9b4dbSLuiz Otavio O Souza return EINVAL;
1588c3e9b4dbSLuiz Otavio O Souza /* keep the rereference */
1589c3e9b4dbSLuiz Otavio O Souza nmd_ref = 1;
1590c3e9b4dbSLuiz Otavio O Souza }
1591c3e9b4dbSLuiz Otavio O Souza
159237e3a6d3SLuigi Rizzo /* We cascade through all possible types of netmap adapter.
15934bf50f18SLuigi Rizzo * All netmap_get_*_na() functions return an error and an na,
15944bf50f18SLuigi Rizzo * with the following combinations:
15954bf50f18SLuigi Rizzo *
15964bf50f18SLuigi Rizzo * error na
15974bf50f18SLuigi Rizzo * 0 NULL type doesn't match
15984bf50f18SLuigi Rizzo * !0 NULL type matches, but na creation/lookup failed
15994bf50f18SLuigi Rizzo * 0 !NULL type matches and na created/found
16004bf50f18SLuigi Rizzo * !0 !NULL impossible
16014bf50f18SLuigi Rizzo */
1602b6e66be2SVincenzo Maffione error = netmap_get_null_na(hdr, na, nmd, create);
160337e3a6d3SLuigi Rizzo if (error || *na != NULL)
1604c3e9b4dbSLuiz Otavio O Souza goto out;
160537e3a6d3SLuigi Rizzo
16064bf50f18SLuigi Rizzo /* try to see if this is a monitor port */
16072ff91c17SVincenzo Maffione error = netmap_get_monitor_na(hdr, na, nmd, create);
16084bf50f18SLuigi Rizzo if (error || *na != NULL)
1609c3e9b4dbSLuiz Otavio O Souza goto out;
16104bf50f18SLuigi Rizzo
16114bf50f18SLuigi Rizzo /* try to see if this is a pipe port */
16122ff91c17SVincenzo Maffione error = netmap_get_pipe_na(hdr, na, nmd, create);
1613f0ea3689SLuigi Rizzo if (error || *na != NULL)
1614c3e9b4dbSLuiz Otavio O Souza goto out;
1615ce3ee1e7SLuigi Rizzo
1616a6d768d8SVincenzo Maffione /* try to see if this is a vale port */
16172a7db7a6SVincenzo Maffione error = netmap_get_vale_na(hdr, na, nmd, create);
1618f0ea3689SLuigi Rizzo if (error)
1619c3e9b4dbSLuiz Otavio O Souza goto out;
1620f0ea3689SLuigi Rizzo
1621f0ea3689SLuigi Rizzo if (*na != NULL) /* valid match in netmap_get_bdg_na() */
1622847bf383SLuigi Rizzo goto out;
1623f0ea3689SLuigi Rizzo
162489cc2556SLuigi Rizzo /*
162589cc2556SLuigi Rizzo * This must be a hardware na, lookup the name in the system.
162689cc2556SLuigi Rizzo * Note that by hardware we actually mean "it shows up in ifconfig".
162789cc2556SLuigi Rizzo * This may still be a tap, a veth/epair, or even a
162889cc2556SLuigi Rizzo * persistent VALE port.
162989cc2556SLuigi Rizzo */
16302ff91c17SVincenzo Maffione *ifp = ifunit_ref(hdr->nr_name);
163137e3a6d3SLuigi Rizzo if (*ifp == NULL) {
1632c3e9b4dbSLuiz Otavio O Souza error = ENXIO;
1633c3e9b4dbSLuiz Otavio O Souza goto out;
1634f196ce38SLuigi Rizzo }
1635ce3ee1e7SLuigi Rizzo
1636c3e9b4dbSLuiz Otavio O Souza error = netmap_get_hw_na(*ifp, nmd, &ret);
1637f9790aebSLuigi Rizzo if (error)
1638f9790aebSLuigi Rizzo goto out;
1639f18be576SLuigi Rizzo
1640f9790aebSLuigi Rizzo *na = ret;
1641f9790aebSLuigi Rizzo netmap_adapter_get(ret);
1642f0ea3689SLuigi Rizzo
1643d12354a5SVincenzo Maffione /*
164445c67e8fSVincenzo Maffione * if the adapter supports the host rings and it is not already open,
1645d12354a5SVincenzo Maffione * try to set the number of host rings as requested by the user
1646d12354a5SVincenzo Maffione */
1647d12354a5SVincenzo Maffione if (((*na)->na_flags & NAF_HOST_RINGS) && (*na)->active_fds == 0) {
1648d12354a5SVincenzo Maffione if (req->nr_host_tx_rings)
1649d12354a5SVincenzo Maffione (*na)->num_host_tx_rings = req->nr_host_tx_rings;
1650d12354a5SVincenzo Maffione if (req->nr_host_rx_rings)
1651d12354a5SVincenzo Maffione (*na)->num_host_rx_rings = req->nr_host_rx_rings;
1652d12354a5SVincenzo Maffione }
1653d12354a5SVincenzo Maffione nm_prdis("%s: host tx %d rx %u", (*na)->name, (*na)->num_host_tx_rings,
1654d12354a5SVincenzo Maffione (*na)->num_host_rx_rings);
1655d12354a5SVincenzo Maffione
1656f9790aebSLuigi Rizzo out:
165737e3a6d3SLuigi Rizzo if (error) {
165837e3a6d3SLuigi Rizzo if (ret)
1659f0ea3689SLuigi Rizzo netmap_adapter_put(ret);
166037e3a6d3SLuigi Rizzo if (*ifp) {
166137e3a6d3SLuigi Rizzo if_rele(*ifp);
166237e3a6d3SLuigi Rizzo *ifp = NULL;
166337e3a6d3SLuigi Rizzo }
166437e3a6d3SLuigi Rizzo }
1665c3e9b4dbSLuiz Otavio O Souza if (nmd_ref)
1666c3e9b4dbSLuiz Otavio O Souza netmap_mem_put(nmd);
1667f18be576SLuigi Rizzo
16685ab0d24dSLuigi Rizzo return error;
16695ab0d24dSLuigi Rizzo }
1670ce3ee1e7SLuigi Rizzo
167137e3a6d3SLuigi Rizzo /* undo netmap_get_na() */
167237e3a6d3SLuigi Rizzo void
netmap_unget_na(struct netmap_adapter * na,if_t ifp)1673e330262fSJustin Hibbits netmap_unget_na(struct netmap_adapter *na, if_t ifp)
167437e3a6d3SLuigi Rizzo {
167537e3a6d3SLuigi Rizzo if (ifp)
167637e3a6d3SLuigi Rizzo if_rele(ifp);
167737e3a6d3SLuigi Rizzo if (na)
167837e3a6d3SLuigi Rizzo netmap_adapter_put(na);
167937e3a6d3SLuigi Rizzo }
168037e3a6d3SLuigi Rizzo
168137e3a6d3SLuigi Rizzo
168237e3a6d3SLuigi Rizzo #define NM_FAIL_ON(t) do { \
168337e3a6d3SLuigi Rizzo if (unlikely(t)) { \
168475f4f3edSVincenzo Maffione nm_prlim(5, "%s: fail '" #t "' " \
168537e3a6d3SLuigi Rizzo "h %d c %d t %d " \
168637e3a6d3SLuigi Rizzo "rh %d rc %d rt %d " \
168737e3a6d3SLuigi Rizzo "hc %d ht %d", \
168837e3a6d3SLuigi Rizzo kring->name, \
168937e3a6d3SLuigi Rizzo head, cur, ring->tail, \
169037e3a6d3SLuigi Rizzo kring->rhead, kring->rcur, kring->rtail, \
169137e3a6d3SLuigi Rizzo kring->nr_hwcur, kring->nr_hwtail); \
169237e3a6d3SLuigi Rizzo return kring->nkr_num_slots; \
169337e3a6d3SLuigi Rizzo } \
169437e3a6d3SLuigi Rizzo } while (0)
1695ce3ee1e7SLuigi Rizzo
1696f9790aebSLuigi Rizzo /*
1697f9790aebSLuigi Rizzo * validate parameters on entry for *_txsync()
1698f9790aebSLuigi Rizzo * Returns ring->cur if ok, or something >= kring->nkr_num_slots
169917885a7bSLuigi Rizzo * in case of error.
1700f9790aebSLuigi Rizzo *
170117885a7bSLuigi Rizzo * rhead, rcur and rtail=hwtail are stored from previous round.
170217885a7bSLuigi Rizzo * hwcur is the next packet to send to the ring.
1703f9790aebSLuigi Rizzo *
170417885a7bSLuigi Rizzo * We want
170517885a7bSLuigi Rizzo * hwcur <= *rhead <= head <= cur <= tail = *rtail <= hwtail
1706f9790aebSLuigi Rizzo *
170717885a7bSLuigi Rizzo * hwcur, rhead, rtail and hwtail are reliable
1708f9790aebSLuigi Rizzo */
170937e3a6d3SLuigi Rizzo u_int
nm_txsync_prologue(struct netmap_kring * kring,struct netmap_ring * ring)171037e3a6d3SLuigi Rizzo nm_txsync_prologue(struct netmap_kring *kring, struct netmap_ring *ring)
1711f9790aebSLuigi Rizzo {
171256c438fcSMark Johnston u_int head = NM_ACCESS_ONCE(ring->head);
171356c438fcSMark Johnston u_int cur = NM_ACCESS_ONCE(ring->cur);
1714f9790aebSLuigi Rizzo u_int n = kring->nkr_num_slots;
1715ce3ee1e7SLuigi Rizzo
171675f4f3edSVincenzo Maffione nm_prdis(5, "%s kcur %d ktail %d head %d cur %d tail %d",
171717885a7bSLuigi Rizzo kring->name,
171817885a7bSLuigi Rizzo kring->nr_hwcur, kring->nr_hwtail,
171917885a7bSLuigi Rizzo ring->head, ring->cur, ring->tail);
172017885a7bSLuigi Rizzo #if 1 /* kernel sanity checks; but we can trust the kring. */
172137e3a6d3SLuigi Rizzo NM_FAIL_ON(kring->nr_hwcur >= n || kring->rhead >= n ||
172237e3a6d3SLuigi Rizzo kring->rtail >= n || kring->nr_hwtail >= n);
1723f9790aebSLuigi Rizzo #endif /* kernel sanity checks */
172417885a7bSLuigi Rizzo /*
172537e3a6d3SLuigi Rizzo * user sanity checks. We only use head,
172637e3a6d3SLuigi Rizzo * A, B, ... are possible positions for head:
172717885a7bSLuigi Rizzo *
172837e3a6d3SLuigi Rizzo * 0 A rhead B rtail C n-1
172937e3a6d3SLuigi Rizzo * 0 D rtail E rhead F n-1
173017885a7bSLuigi Rizzo *
173117885a7bSLuigi Rizzo * B, F, D are valid. A, C, E are wrong
173217885a7bSLuigi Rizzo */
173317885a7bSLuigi Rizzo if (kring->rtail >= kring->rhead) {
173417885a7bSLuigi Rizzo /* want rhead <= head <= rtail */
173537e3a6d3SLuigi Rizzo NM_FAIL_ON(head < kring->rhead || head > kring->rtail);
173617885a7bSLuigi Rizzo /* and also head <= cur <= rtail */
173737e3a6d3SLuigi Rizzo NM_FAIL_ON(cur < head || cur > kring->rtail);
173817885a7bSLuigi Rizzo } else { /* here rtail < rhead */
173917885a7bSLuigi Rizzo /* we need head outside rtail .. rhead */
174037e3a6d3SLuigi Rizzo NM_FAIL_ON(head > kring->rtail && head < kring->rhead);
174117885a7bSLuigi Rizzo
174217885a7bSLuigi Rizzo /* two cases now: head <= rtail or head >= rhead */
174317885a7bSLuigi Rizzo if (head <= kring->rtail) {
174417885a7bSLuigi Rizzo /* want head <= cur <= rtail */
174537e3a6d3SLuigi Rizzo NM_FAIL_ON(cur < head || cur > kring->rtail);
174617885a7bSLuigi Rizzo } else { /* head >= rhead */
174717885a7bSLuigi Rizzo /* cur must be outside rtail..head */
174837e3a6d3SLuigi Rizzo NM_FAIL_ON(cur > kring->rtail && cur < head);
1749f18be576SLuigi Rizzo }
1750f9790aebSLuigi Rizzo }
175117885a7bSLuigi Rizzo if (ring->tail != kring->rtail) {
175275f4f3edSVincenzo Maffione nm_prlim(5, "%s tail overwritten was %d need %d", kring->name,
175317885a7bSLuigi Rizzo ring->tail, kring->rtail);
175417885a7bSLuigi Rizzo ring->tail = kring->rtail;
175517885a7bSLuigi Rizzo }
175617885a7bSLuigi Rizzo kring->rhead = head;
175717885a7bSLuigi Rizzo kring->rcur = cur;
175817885a7bSLuigi Rizzo return head;
175968b8534bSLuigi Rizzo }
176068b8534bSLuigi Rizzo
176168b8534bSLuigi Rizzo
176268b8534bSLuigi Rizzo /*
1763f9790aebSLuigi Rizzo * validate parameters on entry for *_rxsync()
176417885a7bSLuigi Rizzo * Returns ring->head if ok, kring->nkr_num_slots on error.
1765f9790aebSLuigi Rizzo *
176617885a7bSLuigi Rizzo * For a valid configuration,
176717885a7bSLuigi Rizzo * hwcur <= head <= cur <= tail <= hwtail
1768f9790aebSLuigi Rizzo *
176917885a7bSLuigi Rizzo * We only consider head and cur.
177017885a7bSLuigi Rizzo * hwcur and hwtail are reliable.
1771f9790aebSLuigi Rizzo *
1772f9790aebSLuigi Rizzo */
177337e3a6d3SLuigi Rizzo u_int
nm_rxsync_prologue(struct netmap_kring * kring,struct netmap_ring * ring)177437e3a6d3SLuigi Rizzo nm_rxsync_prologue(struct netmap_kring *kring, struct netmap_ring *ring)
1775f9790aebSLuigi Rizzo {
177617885a7bSLuigi Rizzo uint32_t const n = kring->nkr_num_slots;
177717885a7bSLuigi Rizzo uint32_t head, cur;
1778f9790aebSLuigi Rizzo
177975f4f3edSVincenzo Maffione nm_prdis(5,"%s kc %d kt %d h %d c %d t %d",
178017885a7bSLuigi Rizzo kring->name,
178117885a7bSLuigi Rizzo kring->nr_hwcur, kring->nr_hwtail,
178217885a7bSLuigi Rizzo ring->head, ring->cur, ring->tail);
178317885a7bSLuigi Rizzo /*
178417885a7bSLuigi Rizzo * Before storing the new values, we should check they do not
178517885a7bSLuigi Rizzo * move backwards. However:
178617885a7bSLuigi Rizzo * - head is not an issue because the previous value is hwcur;
178717885a7bSLuigi Rizzo * - cur could in principle go back, however it does not matter
178817885a7bSLuigi Rizzo * because we are processing a brand new rxsync()
178917885a7bSLuigi Rizzo */
179056c438fcSMark Johnston cur = kring->rcur = NM_ACCESS_ONCE(ring->cur);
179156c438fcSMark Johnston head = kring->rhead = NM_ACCESS_ONCE(ring->head);
1792f9790aebSLuigi Rizzo #if 1 /* kernel sanity checks */
179337e3a6d3SLuigi Rizzo NM_FAIL_ON(kring->nr_hwcur >= n || kring->nr_hwtail >= n);
1794f9790aebSLuigi Rizzo #endif /* kernel sanity checks */
1795f9790aebSLuigi Rizzo /* user sanity checks */
179617885a7bSLuigi Rizzo if (kring->nr_hwtail >= kring->nr_hwcur) {
179717885a7bSLuigi Rizzo /* want hwcur <= rhead <= hwtail */
179837e3a6d3SLuigi Rizzo NM_FAIL_ON(head < kring->nr_hwcur || head > kring->nr_hwtail);
179917885a7bSLuigi Rizzo /* and also rhead <= rcur <= hwtail */
180037e3a6d3SLuigi Rizzo NM_FAIL_ON(cur < head || cur > kring->nr_hwtail);
1801f9790aebSLuigi Rizzo } else {
180217885a7bSLuigi Rizzo /* we need rhead outside hwtail..hwcur */
180337e3a6d3SLuigi Rizzo NM_FAIL_ON(head < kring->nr_hwcur && head > kring->nr_hwtail);
180417885a7bSLuigi Rizzo /* two cases now: head <= hwtail or head >= hwcur */
180517885a7bSLuigi Rizzo if (head <= kring->nr_hwtail) {
180617885a7bSLuigi Rizzo /* want head <= cur <= hwtail */
180737e3a6d3SLuigi Rizzo NM_FAIL_ON(cur < head || cur > kring->nr_hwtail);
180817885a7bSLuigi Rizzo } else {
180917885a7bSLuigi Rizzo /* cur must be outside hwtail..head */
181037e3a6d3SLuigi Rizzo NM_FAIL_ON(cur < head && cur > kring->nr_hwtail);
1811f9790aebSLuigi Rizzo }
1812f9790aebSLuigi Rizzo }
181317885a7bSLuigi Rizzo if (ring->tail != kring->rtail) {
181475f4f3edSVincenzo Maffione nm_prlim(5, "%s tail overwritten was %d need %d",
181517885a7bSLuigi Rizzo kring->name,
181617885a7bSLuigi Rizzo ring->tail, kring->rtail);
181717885a7bSLuigi Rizzo ring->tail = kring->rtail;
181817885a7bSLuigi Rizzo }
181917885a7bSLuigi Rizzo return head;
1820f9790aebSLuigi Rizzo }
1821f9790aebSLuigi Rizzo
182217885a7bSLuigi Rizzo
1823f9790aebSLuigi Rizzo /*
182468b8534bSLuigi Rizzo * Error routine called when txsync/rxsync detects an error.
182517885a7bSLuigi Rizzo * Can't do much more than resetting head = cur = hwcur, tail = hwtail
182668b8534bSLuigi Rizzo * Return 1 on reinit.
1827506cc70cSLuigi Rizzo *
1828506cc70cSLuigi Rizzo * This routine is only called by the upper half of the kernel.
1829506cc70cSLuigi Rizzo * It only reads hwcur (which is changed only by the upper half, too)
183017885a7bSLuigi Rizzo * and hwtail (which may be changed by the lower half, but only on
1831506cc70cSLuigi Rizzo * a tx ring and only to increase it, so any error will be recovered
1832506cc70cSLuigi Rizzo * on the next call). For the above, we don't strictly need to call
1833506cc70cSLuigi Rizzo * it under lock.
183468b8534bSLuigi Rizzo */
183568b8534bSLuigi Rizzo int
netmap_ring_reinit(struct netmap_kring * kring)183668b8534bSLuigi Rizzo netmap_ring_reinit(struct netmap_kring *kring)
183768b8534bSLuigi Rizzo {
183868b8534bSLuigi Rizzo struct netmap_ring *ring = kring->ring;
183968b8534bSLuigi Rizzo u_int i, lim = kring->nkr_num_slots - 1;
184068b8534bSLuigi Rizzo int errors = 0;
184168b8534bSLuigi Rizzo
1842ce3ee1e7SLuigi Rizzo // XXX KASSERT nm_kr_tryget
184375f4f3edSVincenzo Maffione nm_prlim(10, "called for %s", kring->name);
184417885a7bSLuigi Rizzo // XXX probably wrong to trust userspace
184517885a7bSLuigi Rizzo kring->rhead = ring->head;
184617885a7bSLuigi Rizzo kring->rcur = ring->cur;
184717885a7bSLuigi Rizzo kring->rtail = ring->tail;
184817885a7bSLuigi Rizzo
184968b8534bSLuigi Rizzo if (ring->cur > lim)
185068b8534bSLuigi Rizzo errors++;
185117885a7bSLuigi Rizzo if (ring->head > lim)
185217885a7bSLuigi Rizzo errors++;
185317885a7bSLuigi Rizzo if (ring->tail > lim)
185417885a7bSLuigi Rizzo errors++;
185568b8534bSLuigi Rizzo for (i = 0; i <= lim; i++) {
185668b8534bSLuigi Rizzo u_int idx = ring->slot[i].buf_idx;
185768b8534bSLuigi Rizzo u_int len = ring->slot[i].len;
1858847bf383SLuigi Rizzo if (idx < 2 || idx >= kring->na->na_lut.objtotal) {
185975f4f3edSVincenzo Maffione nm_prlim(5, "bad index at slot %d idx %d len %d ", i, idx, len);
186068b8534bSLuigi Rizzo ring->slot[i].buf_idx = 0;
186168b8534bSLuigi Rizzo ring->slot[i].len = 0;
18624bf50f18SLuigi Rizzo } else if (len > NETMAP_BUF_SIZE(kring->na)) {
186368b8534bSLuigi Rizzo ring->slot[i].len = 0;
186475f4f3edSVincenzo Maffione nm_prlim(5, "bad len at slot %d idx %d len %d", i, idx, len);
186568b8534bSLuigi Rizzo }
186668b8534bSLuigi Rizzo }
186768b8534bSLuigi Rizzo if (errors) {
186875f4f3edSVincenzo Maffione nm_prlim(10, "total %d errors", errors);
186975f4f3edSVincenzo Maffione nm_prlim(10, "%s reinit, cur %d -> %d tail %d -> %d",
187017885a7bSLuigi Rizzo kring->name,
187168b8534bSLuigi Rizzo ring->cur, kring->nr_hwcur,
187217885a7bSLuigi Rizzo ring->tail, kring->nr_hwtail);
187317885a7bSLuigi Rizzo ring->head = kring->rhead = kring->nr_hwcur;
187417885a7bSLuigi Rizzo ring->cur = kring->rcur = kring->nr_hwcur;
187517885a7bSLuigi Rizzo ring->tail = kring->rtail = kring->nr_hwtail;
187668b8534bSLuigi Rizzo }
187768b8534bSLuigi Rizzo return (errors ? 1 : 0);
187868b8534bSLuigi Rizzo }
187968b8534bSLuigi Rizzo
18804bf50f18SLuigi Rizzo /* interpret the ringid and flags fields of an nmreq, by translating them
18814bf50f18SLuigi Rizzo * into a pair of intervals of ring indices:
18824bf50f18SLuigi Rizzo *
18834bf50f18SLuigi Rizzo * [priv->np_txqfirst, priv->np_txqlast) and
18844bf50f18SLuigi Rizzo * [priv->np_rxqfirst, priv->np_rxqlast)
18854bf50f18SLuigi Rizzo *
188668b8534bSLuigi Rizzo */
18874bf50f18SLuigi Rizzo int
netmap_interp_ringid(struct netmap_priv_d * priv,struct nmreq_header * hdr)1888ee0005f1SVincenzo Maffione netmap_interp_ringid(struct netmap_priv_d *priv, struct nmreq_header *hdr)
188968b8534bSLuigi Rizzo {
1890f9790aebSLuigi Rizzo struct netmap_adapter *na = priv->np_na;
1891ee0005f1SVincenzo Maffione struct nmreq_register *reg = (struct nmreq_register *)hdr->nr_body;
189237e3a6d3SLuigi Rizzo int excluded_direction[] = { NR_TX_RINGS_ONLY, NR_RX_RINGS_ONLY };
1893847bf383SLuigi Rizzo enum txrx t;
18942ff91c17SVincenzo Maffione u_int j;
1895ee0005f1SVincenzo Maffione u_int nr_flags = reg->nr_flags, nr_mode = reg->nr_mode,
1896ee0005f1SVincenzo Maffione nr_ringid = reg->nr_ringid;
189768b8534bSLuigi Rizzo
189837e3a6d3SLuigi Rizzo for_rx_tx(t) {
18992ff91c17SVincenzo Maffione if (nr_flags & excluded_direction[t]) {
190037e3a6d3SLuigi Rizzo priv->np_qfirst[t] = priv->np_qlast[t] = 0;
190137e3a6d3SLuigi Rizzo continue;
190237e3a6d3SLuigi Rizzo }
19032ff91c17SVincenzo Maffione switch (nr_mode) {
1904f0ea3689SLuigi Rizzo case NR_REG_ALL_NIC:
1905b6e66be2SVincenzo Maffione case NR_REG_NULL:
1906847bf383SLuigi Rizzo priv->np_qfirst[t] = 0;
1907847bf383SLuigi Rizzo priv->np_qlast[t] = nma_get_nrings(na, t);
190875f4f3edSVincenzo Maffione nm_prdis("ALL/PIPE: %s %d %d", nm_txrx2str(t),
190937e3a6d3SLuigi Rizzo priv->np_qfirst[t], priv->np_qlast[t]);
1910f0ea3689SLuigi Rizzo break;
1911f0ea3689SLuigi Rizzo case NR_REG_SW:
1912f0ea3689SLuigi Rizzo case NR_REG_NIC_SW:
1913f0ea3689SLuigi Rizzo if (!(na->na_flags & NAF_HOST_RINGS)) {
1914b6e66be2SVincenzo Maffione nm_prerr("host rings not supported");
1915f0ea3689SLuigi Rizzo return EINVAL;
1916f0ea3689SLuigi Rizzo }
19172ff91c17SVincenzo Maffione priv->np_qfirst[t] = (nr_mode == NR_REG_SW ?
1918847bf383SLuigi Rizzo nma_get_nrings(na, t) : 0);
19192a7db7a6SVincenzo Maffione priv->np_qlast[t] = netmap_all_rings(na, t);
192075f4f3edSVincenzo Maffione nm_prdis("%s: %s %d %d", nr_mode == NR_REG_SW ? "SW" : "NIC+SW",
192137e3a6d3SLuigi Rizzo nm_txrx2str(t),
192237e3a6d3SLuigi Rizzo priv->np_qfirst[t], priv->np_qlast[t]);
1923f0ea3689SLuigi Rizzo break;
1924f0ea3689SLuigi Rizzo case NR_REG_ONE_NIC:
19252ff91c17SVincenzo Maffione if (nr_ringid >= na->num_tx_rings &&
19262ff91c17SVincenzo Maffione nr_ringid >= na->num_rx_rings) {
1927b6e66be2SVincenzo Maffione nm_prerr("invalid ring id %d", nr_ringid);
1928f0ea3689SLuigi Rizzo return EINVAL;
1929f0ea3689SLuigi Rizzo }
1930f0ea3689SLuigi Rizzo /* if not enough rings, use the first one */
19312ff91c17SVincenzo Maffione j = nr_ringid;
1932847bf383SLuigi Rizzo if (j >= nma_get_nrings(na, t))
1933f0ea3689SLuigi Rizzo j = 0;
1934847bf383SLuigi Rizzo priv->np_qfirst[t] = j;
1935847bf383SLuigi Rizzo priv->np_qlast[t] = j + 1;
193675f4f3edSVincenzo Maffione nm_prdis("ONE_NIC: %s %d %d", nm_txrx2str(t),
193737e3a6d3SLuigi Rizzo priv->np_qfirst[t], priv->np_qlast[t]);
1938f0ea3689SLuigi Rizzo break;
1939d12354a5SVincenzo Maffione case NR_REG_ONE_SW:
1940d12354a5SVincenzo Maffione if (!(na->na_flags & NAF_HOST_RINGS)) {
1941d12354a5SVincenzo Maffione nm_prerr("host rings not supported");
1942d12354a5SVincenzo Maffione return EINVAL;
1943d12354a5SVincenzo Maffione }
1944d12354a5SVincenzo Maffione if (nr_ringid >= na->num_host_tx_rings &&
1945d12354a5SVincenzo Maffione nr_ringid >= na->num_host_rx_rings) {
1946d12354a5SVincenzo Maffione nm_prerr("invalid ring id %d", nr_ringid);
1947d12354a5SVincenzo Maffione return EINVAL;
1948d12354a5SVincenzo Maffione }
1949d12354a5SVincenzo Maffione /* if not enough rings, use the first one */
1950d12354a5SVincenzo Maffione j = nr_ringid;
1951d12354a5SVincenzo Maffione if (j >= nma_get_host_nrings(na, t))
1952d12354a5SVincenzo Maffione j = 0;
1953d12354a5SVincenzo Maffione priv->np_qfirst[t] = nma_get_nrings(na, t) + j;
1954d12354a5SVincenzo Maffione priv->np_qlast[t] = nma_get_nrings(na, t) + j + 1;
1955d12354a5SVincenzo Maffione nm_prdis("ONE_SW: %s %d %d", nm_txrx2str(t),
1956d12354a5SVincenzo Maffione priv->np_qfirst[t], priv->np_qlast[t]);
1957d12354a5SVincenzo Maffione break;
1958f0ea3689SLuigi Rizzo default:
1959b6e66be2SVincenzo Maffione nm_prerr("invalid regif type %d", nr_mode);
1960f0ea3689SLuigi Rizzo return EINVAL;
196168b8534bSLuigi Rizzo }
196237e3a6d3SLuigi Rizzo }
1963b6e66be2SVincenzo Maffione priv->np_flags = nr_flags;
19644bf50f18SLuigi Rizzo
1965c3e9b4dbSLuiz Otavio O Souza /* Allow transparent forwarding mode in the host --> nic
1966c3e9b4dbSLuiz Otavio O Souza * direction only if all the TX hw rings have been opened. */
1967c3e9b4dbSLuiz Otavio O Souza if (priv->np_qfirst[NR_TX] == 0 &&
1968c3e9b4dbSLuiz Otavio O Souza priv->np_qlast[NR_TX] >= na->num_tx_rings) {
1969c3e9b4dbSLuiz Otavio O Souza priv->np_sync_flags |= NAF_CAN_FORWARD_DOWN;
1970c3e9b4dbSLuiz Otavio O Souza }
1971c3e9b4dbSLuiz Otavio O Souza
1972ae10d1afSLuigi Rizzo if (netmap_verbose) {
1973b6e66be2SVincenzo Maffione nm_prinf("%s: tx [%d,%d) rx [%d,%d) id %d",
19744bf50f18SLuigi Rizzo na->name,
1975847bf383SLuigi Rizzo priv->np_qfirst[NR_TX],
1976847bf383SLuigi Rizzo priv->np_qlast[NR_TX],
1977847bf383SLuigi Rizzo priv->np_qfirst[NR_RX],
1978847bf383SLuigi Rizzo priv->np_qlast[NR_RX],
19792ff91c17SVincenzo Maffione nr_ringid);
1980ae10d1afSLuigi Rizzo }
198168b8534bSLuigi Rizzo return 0;
198268b8534bSLuigi Rizzo }
198368b8534bSLuigi Rizzo
19844bf50f18SLuigi Rizzo
19854bf50f18SLuigi Rizzo /*
19864bf50f18SLuigi Rizzo * Set the ring ID. For devices with a single queue, a request
19874bf50f18SLuigi Rizzo * for all rings is the same as a single ring.
19884bf50f18SLuigi Rizzo */
19894bf50f18SLuigi Rizzo static int
netmap_set_ringid(struct netmap_priv_d * priv,struct nmreq_header * hdr)1990ee0005f1SVincenzo Maffione netmap_set_ringid(struct netmap_priv_d *priv, struct nmreq_header *hdr)
19914bf50f18SLuigi Rizzo {
19924bf50f18SLuigi Rizzo struct netmap_adapter *na = priv->np_na;
1993ee0005f1SVincenzo Maffione struct nmreq_register *reg = (struct nmreq_register *)hdr->nr_body;
19944bf50f18SLuigi Rizzo int error;
1995847bf383SLuigi Rizzo enum txrx t;
19964bf50f18SLuigi Rizzo
1997ee0005f1SVincenzo Maffione error = netmap_interp_ringid(priv, hdr);
19984bf50f18SLuigi Rizzo if (error) {
19994bf50f18SLuigi Rizzo return error;
20004bf50f18SLuigi Rizzo }
20014bf50f18SLuigi Rizzo
2002ee0005f1SVincenzo Maffione priv->np_txpoll = (reg->nr_flags & NR_NO_TX_POLL) ? 0 : 1;
20034bf50f18SLuigi Rizzo
20044bf50f18SLuigi Rizzo /* optimization: count the users registered for more than
20054bf50f18SLuigi Rizzo * one ring, which are the ones sleeping on the global queue.
20064bf50f18SLuigi Rizzo * The default netmap_notify() callback will then
20074bf50f18SLuigi Rizzo * avoid signaling the global queue if nobody is using it
20084bf50f18SLuigi Rizzo */
2009847bf383SLuigi Rizzo for_rx_tx(t) {
2010847bf383SLuigi Rizzo if (nm_si_user(priv, t))
2011847bf383SLuigi Rizzo na->si_users[t]++;
2012847bf383SLuigi Rizzo }
20134bf50f18SLuigi Rizzo return 0;
20144bf50f18SLuigi Rizzo }
20154bf50f18SLuigi Rizzo
2016847bf383SLuigi Rizzo static void
netmap_unset_ringid(struct netmap_priv_d * priv)2017847bf383SLuigi Rizzo netmap_unset_ringid(struct netmap_priv_d *priv)
2018847bf383SLuigi Rizzo {
2019847bf383SLuigi Rizzo struct netmap_adapter *na = priv->np_na;
2020847bf383SLuigi Rizzo enum txrx t;
2021847bf383SLuigi Rizzo
2022847bf383SLuigi Rizzo for_rx_tx(t) {
2023847bf383SLuigi Rizzo if (nm_si_user(priv, t))
2024847bf383SLuigi Rizzo na->si_users[t]--;
2025847bf383SLuigi Rizzo priv->np_qfirst[t] = priv->np_qlast[t] = 0;
2026847bf383SLuigi Rizzo }
2027847bf383SLuigi Rizzo priv->np_flags = 0;
2028847bf383SLuigi Rizzo priv->np_txpoll = 0;
2029b6e66be2SVincenzo Maffione priv->np_kloop_state = 0;
2030847bf383SLuigi Rizzo }
2031847bf383SLuigi Rizzo
2032ee0005f1SVincenzo Maffione #define within_sel(p_, t_, i_) \
2033ee0005f1SVincenzo Maffione ((i_) < (p_)->np_qlast[(t_)])
2034ee0005f1SVincenzo Maffione #define nonempty_sel(p_, t_) \
2035ee0005f1SVincenzo Maffione (within_sel((p_), (t_), (p_)->np_qfirst[(t_)]))
2036ee0005f1SVincenzo Maffione #define foreach_selected_ring(p_, t_, i_, kring_) \
2037ee0005f1SVincenzo Maffione for ((t_) = nonempty_sel((p_), NR_RX) ? NR_RX : NR_TX, \
2038ee0005f1SVincenzo Maffione (i_) = (p_)->np_qfirst[(t_)]; \
2039ee0005f1SVincenzo Maffione (t_ == NR_RX || \
2040ee0005f1SVincenzo Maffione (t == NR_TX && within_sel((p_), (t_), (i_)))) && \
2041ee0005f1SVincenzo Maffione ((kring_) = NMR((p_)->np_na, (t_))[(i_)]); \
2042ee0005f1SVincenzo Maffione (i_) = within_sel((p_), (t_), (i_) + 1) ? (i_) + 1 : \
2043ee0005f1SVincenzo Maffione (++(t_) < NR_TXRX ? (p_)->np_qfirst[(t_)] : (i_)))
2044ee0005f1SVincenzo Maffione
2045847bf383SLuigi Rizzo
204637e3a6d3SLuigi Rizzo /* Set the nr_pending_mode for the requested rings.
204737e3a6d3SLuigi Rizzo * If requested, also try to get exclusive access to the rings, provided
204837e3a6d3SLuigi Rizzo * the rings we want to bind are not exclusively owned by a previous bind.
2049847bf383SLuigi Rizzo */
2050847bf383SLuigi Rizzo static int
netmap_krings_get(struct netmap_priv_d * priv)205137e3a6d3SLuigi Rizzo netmap_krings_get(struct netmap_priv_d *priv)
2052847bf383SLuigi Rizzo {
2053847bf383SLuigi Rizzo struct netmap_adapter *na = priv->np_na;
2054847bf383SLuigi Rizzo u_int i;
2055847bf383SLuigi Rizzo struct netmap_kring *kring;
2056847bf383SLuigi Rizzo int excl = (priv->np_flags & NR_EXCLUSIVE);
2057847bf383SLuigi Rizzo enum txrx t;
2058847bf383SLuigi Rizzo
2059b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_ON)
2060b6e66be2SVincenzo Maffione nm_prinf("%s: grabbing tx [%d, %d) rx [%d, %d)",
2061847bf383SLuigi Rizzo na->name,
2062847bf383SLuigi Rizzo priv->np_qfirst[NR_TX],
2063847bf383SLuigi Rizzo priv->np_qlast[NR_TX],
2064847bf383SLuigi Rizzo priv->np_qfirst[NR_RX],
2065847bf383SLuigi Rizzo priv->np_qlast[NR_RX]);
2066847bf383SLuigi Rizzo
2067847bf383SLuigi Rizzo /* first round: check that all the requested rings
206845c67e8fSVincenzo Maffione * are neither already exclusively owned, nor we
2069847bf383SLuigi Rizzo * want exclusive ownership when they are already in use
2070847bf383SLuigi Rizzo */
2071ee0005f1SVincenzo Maffione foreach_selected_ring(priv, t, i, kring) {
2072847bf383SLuigi Rizzo if ((kring->nr_kflags & NKR_EXCLUSIVE) ||
2073847bf383SLuigi Rizzo (kring->users && excl))
2074847bf383SLuigi Rizzo {
207575f4f3edSVincenzo Maffione nm_prdis("ring %s busy", kring->name);
2076847bf383SLuigi Rizzo return EBUSY;
2077847bf383SLuigi Rizzo }
2078847bf383SLuigi Rizzo }
2079847bf383SLuigi Rizzo
208037e3a6d3SLuigi Rizzo /* second round: increment usage count (possibly marking them
208137e3a6d3SLuigi Rizzo * as exclusive) and set the nr_pending_mode
2082847bf383SLuigi Rizzo */
2083ee0005f1SVincenzo Maffione foreach_selected_ring(priv, t, i, kring) {
2084847bf383SLuigi Rizzo kring->users++;
2085847bf383SLuigi Rizzo if (excl)
2086847bf383SLuigi Rizzo kring->nr_kflags |= NKR_EXCLUSIVE;
208737e3a6d3SLuigi Rizzo kring->nr_pending_mode = NKR_NETMAP_ON;
2088847bf383SLuigi Rizzo }
2089847bf383SLuigi Rizzo
2090847bf383SLuigi Rizzo return 0;
2091847bf383SLuigi Rizzo
2092847bf383SLuigi Rizzo }
2093847bf383SLuigi Rizzo
209437e3a6d3SLuigi Rizzo /* Undo netmap_krings_get(). This is done by clearing the exclusive mode
209537e3a6d3SLuigi Rizzo * if was asked on regif, and unset the nr_pending_mode if we are the
209637e3a6d3SLuigi Rizzo * last users of the involved rings. */
2097847bf383SLuigi Rizzo static void
netmap_krings_put(struct netmap_priv_d * priv)209837e3a6d3SLuigi Rizzo netmap_krings_put(struct netmap_priv_d *priv)
2099847bf383SLuigi Rizzo {
2100847bf383SLuigi Rizzo u_int i;
2101847bf383SLuigi Rizzo struct netmap_kring *kring;
2102847bf383SLuigi Rizzo int excl = (priv->np_flags & NR_EXCLUSIVE);
2103847bf383SLuigi Rizzo enum txrx t;
2104847bf383SLuigi Rizzo
210575f4f3edSVincenzo Maffione nm_prdis("%s: releasing tx [%d, %d) rx [%d, %d)",
2106847bf383SLuigi Rizzo na->name,
2107847bf383SLuigi Rizzo priv->np_qfirst[NR_TX],
2108847bf383SLuigi Rizzo priv->np_qlast[NR_TX],
2109847bf383SLuigi Rizzo priv->np_qfirst[NR_RX],
2110847bf383SLuigi Rizzo priv->np_qlast[MR_RX]);
2111847bf383SLuigi Rizzo
2112ee0005f1SVincenzo Maffione foreach_selected_ring(priv, t, i, kring) {
2113847bf383SLuigi Rizzo if (excl)
2114847bf383SLuigi Rizzo kring->nr_kflags &= ~NKR_EXCLUSIVE;
2115847bf383SLuigi Rizzo kring->users--;
211637e3a6d3SLuigi Rizzo if (kring->users == 0)
211737e3a6d3SLuigi Rizzo kring->nr_pending_mode = NKR_NETMAP_OFF;
2118847bf383SLuigi Rizzo }
2119847bf383SLuigi Rizzo }
2120847bf383SLuigi Rizzo
21212ff91c17SVincenzo Maffione static int
nm_priv_rx_enabled(struct netmap_priv_d * priv)21222ff91c17SVincenzo Maffione nm_priv_rx_enabled(struct netmap_priv_d *priv)
21232ff91c17SVincenzo Maffione {
21242ff91c17SVincenzo Maffione return (priv->np_qfirst[NR_RX] != priv->np_qlast[NR_RX]);
21252ff91c17SVincenzo Maffione }
21262ff91c17SVincenzo Maffione
2127b6e66be2SVincenzo Maffione /* Validate the CSB entries for both directions (atok and ktoa).
2128b6e66be2SVincenzo Maffione * To be called under NMG_LOCK(). */
2129b6e66be2SVincenzo Maffione static int
netmap_csb_validate(struct netmap_priv_d * priv,struct nmreq_opt_csb * csbo)2130b6e66be2SVincenzo Maffione netmap_csb_validate(struct netmap_priv_d *priv, struct nmreq_opt_csb *csbo)
2131b6e66be2SVincenzo Maffione {
2132b6e66be2SVincenzo Maffione struct nm_csb_atok *csb_atok_base =
2133b6e66be2SVincenzo Maffione (struct nm_csb_atok *)(uintptr_t)csbo->csb_atok;
2134b6e66be2SVincenzo Maffione struct nm_csb_ktoa *csb_ktoa_base =
2135b6e66be2SVincenzo Maffione (struct nm_csb_ktoa *)(uintptr_t)csbo->csb_ktoa;
2136b6e66be2SVincenzo Maffione enum txrx t;
2137b6e66be2SVincenzo Maffione int num_rings[NR_TXRX], tot_rings;
2138b6e66be2SVincenzo Maffione size_t entry_size[2];
2139b6e66be2SVincenzo Maffione void *csb_start[2];
2140b6e66be2SVincenzo Maffione int i;
2141b6e66be2SVincenzo Maffione
2142b6e66be2SVincenzo Maffione if (priv->np_kloop_state & NM_SYNC_KLOOP_RUNNING) {
2143b6e66be2SVincenzo Maffione nm_prerr("Cannot update CSB while kloop is running");
2144b6e66be2SVincenzo Maffione return EBUSY;
2145b6e66be2SVincenzo Maffione }
2146b6e66be2SVincenzo Maffione
2147b6e66be2SVincenzo Maffione tot_rings = 0;
2148b6e66be2SVincenzo Maffione for_rx_tx(t) {
2149b6e66be2SVincenzo Maffione num_rings[t] = priv->np_qlast[t] - priv->np_qfirst[t];
2150b6e66be2SVincenzo Maffione tot_rings += num_rings[t];
2151b6e66be2SVincenzo Maffione }
2152b6e66be2SVincenzo Maffione if (tot_rings <= 0)
2153b6e66be2SVincenzo Maffione return 0;
2154b6e66be2SVincenzo Maffione
2155b6e66be2SVincenzo Maffione if (!(priv->np_flags & NR_EXCLUSIVE)) {
2156b6e66be2SVincenzo Maffione nm_prerr("CSB mode requires NR_EXCLUSIVE");
2157b6e66be2SVincenzo Maffione return EINVAL;
2158b6e66be2SVincenzo Maffione }
2159b6e66be2SVincenzo Maffione
2160b6e66be2SVincenzo Maffione entry_size[0] = sizeof(*csb_atok_base);
2161b6e66be2SVincenzo Maffione entry_size[1] = sizeof(*csb_ktoa_base);
2162b6e66be2SVincenzo Maffione csb_start[0] = (void *)csb_atok_base;
2163b6e66be2SVincenzo Maffione csb_start[1] = (void *)csb_ktoa_base;
2164b6e66be2SVincenzo Maffione
2165b6e66be2SVincenzo Maffione for (i = 0; i < 2; i++) {
2166b6e66be2SVincenzo Maffione /* On Linux we could use access_ok() to simplify
2167b6e66be2SVincenzo Maffione * the validation. However, the advantage of
2168b6e66be2SVincenzo Maffione * this approach is that it works also on
2169b6e66be2SVincenzo Maffione * FreeBSD. */
2170b6e66be2SVincenzo Maffione size_t csb_size = tot_rings * entry_size[i];
2171b6e66be2SVincenzo Maffione void *tmp;
2172b6e66be2SVincenzo Maffione int err;
2173b6e66be2SVincenzo Maffione
2174b6e66be2SVincenzo Maffione if ((uintptr_t)csb_start[i] & (entry_size[i]-1)) {
2175b6e66be2SVincenzo Maffione nm_prerr("Unaligned CSB address");
2176b6e66be2SVincenzo Maffione return EINVAL;
2177b6e66be2SVincenzo Maffione }
2178b6e66be2SVincenzo Maffione
2179b6e66be2SVincenzo Maffione tmp = nm_os_malloc(csb_size);
2180b6e66be2SVincenzo Maffione if (!tmp)
2181b6e66be2SVincenzo Maffione return ENOMEM;
2182b6e66be2SVincenzo Maffione if (i == 0) {
2183b6e66be2SVincenzo Maffione /* Application --> kernel direction. */
2184b6e66be2SVincenzo Maffione err = copyin(csb_start[i], tmp, csb_size);
2185b6e66be2SVincenzo Maffione } else {
2186b6e66be2SVincenzo Maffione /* Kernel --> application direction. */
2187b6e66be2SVincenzo Maffione memset(tmp, 0, csb_size);
2188b6e66be2SVincenzo Maffione err = copyout(tmp, csb_start[i], csb_size);
2189b6e66be2SVincenzo Maffione }
2190b6e66be2SVincenzo Maffione nm_os_free(tmp);
2191b6e66be2SVincenzo Maffione if (err) {
2192b6e66be2SVincenzo Maffione nm_prerr("Invalid CSB address");
2193b6e66be2SVincenzo Maffione return err;
2194b6e66be2SVincenzo Maffione }
2195b6e66be2SVincenzo Maffione }
2196b6e66be2SVincenzo Maffione
2197b6e66be2SVincenzo Maffione priv->np_csb_atok_base = csb_atok_base;
2198b6e66be2SVincenzo Maffione priv->np_csb_ktoa_base = csb_ktoa_base;
2199b6e66be2SVincenzo Maffione
2200b6e66be2SVincenzo Maffione /* Initialize the CSB. */
2201b6e66be2SVincenzo Maffione for_rx_tx(t) {
2202b6e66be2SVincenzo Maffione for (i = 0; i < num_rings[t]; i++) {
2203b6e66be2SVincenzo Maffione struct netmap_kring *kring =
2204b6e66be2SVincenzo Maffione NMR(priv->np_na, t)[i + priv->np_qfirst[t]];
2205b6e66be2SVincenzo Maffione struct nm_csb_atok *csb_atok = csb_atok_base + i;
2206b6e66be2SVincenzo Maffione struct nm_csb_ktoa *csb_ktoa = csb_ktoa_base + i;
2207b6e66be2SVincenzo Maffione
2208b6e66be2SVincenzo Maffione if (t == NR_RX) {
2209b6e66be2SVincenzo Maffione csb_atok += num_rings[NR_TX];
2210b6e66be2SVincenzo Maffione csb_ktoa += num_rings[NR_TX];
2211b6e66be2SVincenzo Maffione }
2212b6e66be2SVincenzo Maffione
2213b6e66be2SVincenzo Maffione CSB_WRITE(csb_atok, head, kring->rhead);
2214b6e66be2SVincenzo Maffione CSB_WRITE(csb_atok, cur, kring->rcur);
2215b6e66be2SVincenzo Maffione CSB_WRITE(csb_atok, appl_need_kick, 1);
2216b6e66be2SVincenzo Maffione CSB_WRITE(csb_atok, sync_flags, 1);
2217b6e66be2SVincenzo Maffione CSB_WRITE(csb_ktoa, hwcur, kring->nr_hwcur);
2218b6e66be2SVincenzo Maffione CSB_WRITE(csb_ktoa, hwtail, kring->nr_hwtail);
2219b6e66be2SVincenzo Maffione CSB_WRITE(csb_ktoa, kern_need_kick, 1);
2220b6e66be2SVincenzo Maffione
2221b6e66be2SVincenzo Maffione nm_prinf("csb_init for kring %s: head %u, cur %u, "
2222b6e66be2SVincenzo Maffione "hwcur %u, hwtail %u", kring->name,
2223b6e66be2SVincenzo Maffione kring->rhead, kring->rcur, kring->nr_hwcur,
2224b6e66be2SVincenzo Maffione kring->nr_hwtail);
2225b6e66be2SVincenzo Maffione }
2226b6e66be2SVincenzo Maffione }
2227b6e66be2SVincenzo Maffione
2228b6e66be2SVincenzo Maffione return 0;
2229b6e66be2SVincenzo Maffione }
2230b6e66be2SVincenzo Maffione
223177a2baf5SVincenzo Maffione /* Ensure that the netmap adapter can support the given MTU.
223277a2baf5SVincenzo Maffione * @return EINVAL if the na cannot be set to mtu, 0 otherwise.
223377a2baf5SVincenzo Maffione */
223477a2baf5SVincenzo Maffione int
netmap_buf_size_validate(const struct netmap_adapter * na,unsigned mtu)223577a2baf5SVincenzo Maffione netmap_buf_size_validate(const struct netmap_adapter *na, unsigned mtu) {
223677a2baf5SVincenzo Maffione unsigned nbs = NETMAP_BUF_SIZE(na);
223777a2baf5SVincenzo Maffione
223877a2baf5SVincenzo Maffione if (mtu <= na->rx_buf_maxsize) {
223977a2baf5SVincenzo Maffione /* The MTU fits a single NIC slot. We only
224077a2baf5SVincenzo Maffione * Need to check that netmap buffers are
224177a2baf5SVincenzo Maffione * large enough to hold an MTU. NS_MOREFRAG
224277a2baf5SVincenzo Maffione * cannot be used in this case. */
224377a2baf5SVincenzo Maffione if (nbs < mtu) {
224477a2baf5SVincenzo Maffione nm_prerr("error: netmap buf size (%u) "
224577a2baf5SVincenzo Maffione "< device MTU (%u)", nbs, mtu);
224677a2baf5SVincenzo Maffione return EINVAL;
224777a2baf5SVincenzo Maffione }
224877a2baf5SVincenzo Maffione } else {
224977a2baf5SVincenzo Maffione /* More NIC slots may be needed to receive
225077a2baf5SVincenzo Maffione * or transmit a single packet. Check that
225177a2baf5SVincenzo Maffione * the adapter supports NS_MOREFRAG and that
225277a2baf5SVincenzo Maffione * netmap buffers are large enough to hold
225377a2baf5SVincenzo Maffione * the maximum per-slot size. */
225477a2baf5SVincenzo Maffione if (!(na->na_flags & NAF_MOREFRAG)) {
225577a2baf5SVincenzo Maffione nm_prerr("error: large MTU (%d) needed "
225677a2baf5SVincenzo Maffione "but %s does not support "
225777a2baf5SVincenzo Maffione "NS_MOREFRAG", mtu,
2258e330262fSJustin Hibbits if_name(na->ifp));
225977a2baf5SVincenzo Maffione return EINVAL;
226077a2baf5SVincenzo Maffione } else if (nbs < na->rx_buf_maxsize) {
226177a2baf5SVincenzo Maffione nm_prerr("error: using NS_MOREFRAG on "
226277a2baf5SVincenzo Maffione "%s requires netmap buf size "
2263e330262fSJustin Hibbits ">= %u", if_name(na->ifp),
226477a2baf5SVincenzo Maffione na->rx_buf_maxsize);
226577a2baf5SVincenzo Maffione return EINVAL;
226677a2baf5SVincenzo Maffione } else {
226777a2baf5SVincenzo Maffione nm_prinf("info: netmap application on "
226877a2baf5SVincenzo Maffione "%s needs to support "
226977a2baf5SVincenzo Maffione "NS_MOREFRAG "
227077a2baf5SVincenzo Maffione "(MTU=%u,netmap_buf_size=%u)",
2271e330262fSJustin Hibbits if_name(na->ifp), mtu, nbs);
227277a2baf5SVincenzo Maffione }
227377a2baf5SVincenzo Maffione }
227477a2baf5SVincenzo Maffione return 0;
227577a2baf5SVincenzo Maffione }
227677a2baf5SVincenzo Maffione
2277a6d768d8SVincenzo Maffione /* Handle the offset option, if present in the hdr.
2278a6d768d8SVincenzo Maffione * Returns 0 on success, or an error.
2279a6d768d8SVincenzo Maffione */
2280a6d768d8SVincenzo Maffione static int
netmap_offsets_init(struct netmap_priv_d * priv,struct nmreq_header * hdr)2281a6d768d8SVincenzo Maffione netmap_offsets_init(struct netmap_priv_d *priv, struct nmreq_header *hdr)
2282a6d768d8SVincenzo Maffione {
2283a6d768d8SVincenzo Maffione struct nmreq_opt_offsets *opt;
2284a6d768d8SVincenzo Maffione struct netmap_adapter *na = priv->np_na;
2285a6d768d8SVincenzo Maffione struct netmap_kring *kring;
2286a6d768d8SVincenzo Maffione uint64_t mask = 0, bits = 0, maxbits = sizeof(uint64_t) * 8,
2287a6d768d8SVincenzo Maffione max_offset = 0, initial_offset = 0, min_gap = 0;
2288a6d768d8SVincenzo Maffione u_int i;
2289a6d768d8SVincenzo Maffione enum txrx t;
2290a6d768d8SVincenzo Maffione int error = 0;
2291a6d768d8SVincenzo Maffione
2292a6d768d8SVincenzo Maffione opt = (struct nmreq_opt_offsets *)
2293a6d768d8SVincenzo Maffione nmreq_getoption(hdr, NETMAP_REQ_OPT_OFFSETS);
2294a6d768d8SVincenzo Maffione if (opt == NULL)
2295a6d768d8SVincenzo Maffione return 0;
2296a6d768d8SVincenzo Maffione
2297a6d768d8SVincenzo Maffione if (!(na->na_flags & NAF_OFFSETS)) {
2298a6d768d8SVincenzo Maffione if (netmap_verbose)
2299a6d768d8SVincenzo Maffione nm_prerr("%s does not support offsets",
2300a6d768d8SVincenzo Maffione na->name);
2301a6d768d8SVincenzo Maffione error = EOPNOTSUPP;
2302a6d768d8SVincenzo Maffione goto out;
2303a6d768d8SVincenzo Maffione }
2304a6d768d8SVincenzo Maffione
2305a6d768d8SVincenzo Maffione /* check sanity of the opt values */
2306a6d768d8SVincenzo Maffione max_offset = opt->nro_max_offset;
2307a6d768d8SVincenzo Maffione min_gap = opt->nro_min_gap;
2308a6d768d8SVincenzo Maffione initial_offset = opt->nro_initial_offset;
2309a6d768d8SVincenzo Maffione bits = opt->nro_offset_bits;
2310a6d768d8SVincenzo Maffione
2311a6d768d8SVincenzo Maffione if (bits > maxbits) {
2312a6d768d8SVincenzo Maffione if (netmap_verbose)
2313a6d768d8SVincenzo Maffione nm_prerr("bits: %llu too large (max %llu)",
2314a6d768d8SVincenzo Maffione (unsigned long long)bits,
2315a6d768d8SVincenzo Maffione (unsigned long long)maxbits);
2316a6d768d8SVincenzo Maffione error = EINVAL;
2317a6d768d8SVincenzo Maffione goto out;
2318a6d768d8SVincenzo Maffione }
2319a6d768d8SVincenzo Maffione /* we take bits == 0 as a request to use the entire field */
2320a6d768d8SVincenzo Maffione if (bits == 0 || bits == maxbits) {
2321a6d768d8SVincenzo Maffione /* shifting a type by sizeof(type) is undefined */
2322a6d768d8SVincenzo Maffione bits = maxbits;
2323a6d768d8SVincenzo Maffione mask = 0xffffffffffffffff;
2324a6d768d8SVincenzo Maffione } else {
2325a6d768d8SVincenzo Maffione mask = (1ULL << bits) - 1;
2326a6d768d8SVincenzo Maffione }
2327a6d768d8SVincenzo Maffione if (max_offset > NETMAP_BUF_SIZE(na)) {
2328a6d768d8SVincenzo Maffione if (netmap_verbose)
2329a6d768d8SVincenzo Maffione nm_prerr("max offset %llu > buf size %u",
2330a6d768d8SVincenzo Maffione (unsigned long long)max_offset, NETMAP_BUF_SIZE(na));
2331a6d768d8SVincenzo Maffione error = EINVAL;
2332a6d768d8SVincenzo Maffione goto out;
2333a6d768d8SVincenzo Maffione }
2334a6d768d8SVincenzo Maffione if ((max_offset & mask) != max_offset) {
2335a6d768d8SVincenzo Maffione if (netmap_verbose)
2336a6d768d8SVincenzo Maffione nm_prerr("max offset %llu to large for %llu bits",
2337a6d768d8SVincenzo Maffione (unsigned long long)max_offset,
2338a6d768d8SVincenzo Maffione (unsigned long long)bits);
2339a6d768d8SVincenzo Maffione error = EINVAL;
2340a6d768d8SVincenzo Maffione goto out;
2341a6d768d8SVincenzo Maffione }
2342a6d768d8SVincenzo Maffione if (initial_offset > max_offset) {
2343a6d768d8SVincenzo Maffione if (netmap_verbose)
2344a6d768d8SVincenzo Maffione nm_prerr("initial offset %llu > max offset %llu",
2345a6d768d8SVincenzo Maffione (unsigned long long)initial_offset,
2346a6d768d8SVincenzo Maffione (unsigned long long)max_offset);
2347a6d768d8SVincenzo Maffione error = EINVAL;
2348a6d768d8SVincenzo Maffione goto out;
2349a6d768d8SVincenzo Maffione }
2350a6d768d8SVincenzo Maffione
2351a6d768d8SVincenzo Maffione /* initialize the kring and ring fields. */
2352a6d768d8SVincenzo Maffione foreach_selected_ring(priv, t, i, kring) {
2353a6d768d8SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i];
2354a6d768d8SVincenzo Maffione struct netmap_ring *ring = kring->ring;
2355a6d768d8SVincenzo Maffione u_int j;
2356a6d768d8SVincenzo Maffione
2357a6d768d8SVincenzo Maffione /* it the ring is already in use we check that the
2358a6d768d8SVincenzo Maffione * new request is compatible with the existing one
2359a6d768d8SVincenzo Maffione */
2360a6d768d8SVincenzo Maffione if (kring->offset_mask) {
2361a6d768d8SVincenzo Maffione if ((kring->offset_mask & mask) != mask ||
2362a6d768d8SVincenzo Maffione kring->offset_max < max_offset) {
2363a6d768d8SVincenzo Maffione if (netmap_verbose)
2364a6d768d8SVincenzo Maffione nm_prinf("%s: cannot increase"
2365a6d768d8SVincenzo Maffione "offset mask and/or max"
2366a6d768d8SVincenzo Maffione "(current: mask=%llx,max=%llu",
2367a6d768d8SVincenzo Maffione kring->name,
2368a6d768d8SVincenzo Maffione (unsigned long long)kring->offset_mask,
2369a6d768d8SVincenzo Maffione (unsigned long long)kring->offset_max);
2370a6d768d8SVincenzo Maffione error = EBUSY;
2371a6d768d8SVincenzo Maffione goto out;
2372a6d768d8SVincenzo Maffione }
2373a6d768d8SVincenzo Maffione mask = kring->offset_mask;
2374a6d768d8SVincenzo Maffione max_offset = kring->offset_max;
2375a6d768d8SVincenzo Maffione } else {
2376a6d768d8SVincenzo Maffione kring->offset_mask = mask;
2377a6d768d8SVincenzo Maffione *(uint64_t *)(uintptr_t)&ring->offset_mask = mask;
2378a6d768d8SVincenzo Maffione kring->offset_max = max_offset;
2379a6d768d8SVincenzo Maffione kring->offset_gap = min_gap;
2380a6d768d8SVincenzo Maffione }
2381a6d768d8SVincenzo Maffione
2382a6d768d8SVincenzo Maffione /* if there is an initial offset, put it into
2383a6d768d8SVincenzo Maffione * all the slots
2384a6d768d8SVincenzo Maffione *
2385a6d768d8SVincenzo Maffione * Note: we cannot change the offsets if the
2386a6d768d8SVincenzo Maffione * ring is already in use.
2387a6d768d8SVincenzo Maffione */
2388a6d768d8SVincenzo Maffione if (!initial_offset || kring->users > 1)
2389a6d768d8SVincenzo Maffione continue;
2390a6d768d8SVincenzo Maffione
2391a6d768d8SVincenzo Maffione for (j = 0; j < kring->nkr_num_slots; j++) {
2392a6d768d8SVincenzo Maffione struct netmap_slot *slot = ring->slot + j;
2393a6d768d8SVincenzo Maffione
2394a6d768d8SVincenzo Maffione nm_write_offset(kring, slot, initial_offset);
2395a6d768d8SVincenzo Maffione }
2396a6d768d8SVincenzo Maffione }
2397a6d768d8SVincenzo Maffione
2398a6d768d8SVincenzo Maffione out:
2399a6d768d8SVincenzo Maffione opt->nro_opt.nro_status = error;
2400a6d768d8SVincenzo Maffione if (!error) {
2401a6d768d8SVincenzo Maffione opt->nro_max_offset = max_offset;
2402a6d768d8SVincenzo Maffione }
2403a6d768d8SVincenzo Maffione return error;
2404a6d768d8SVincenzo Maffione
2405a6d768d8SVincenzo Maffione }
2406a6d768d8SVincenzo Maffione
2407f4a54f43SVincenzo Maffione
2408f4a54f43SVincenzo Maffione /* set the hardware buffer length in each one of the newly opened rings
2409f4a54f43SVincenzo Maffione * (hwbuf_len field in the kring struct). The purpose it to select
2410f4a54f43SVincenzo Maffione * the maximum supported input buffer lenght that will not cause writes
2411f4a54f43SVincenzo Maffione * outside of the available space, even when offsets are in use.
2412f4a54f43SVincenzo Maffione */
2413a6d768d8SVincenzo Maffione static int
netmap_compute_buf_len(struct netmap_priv_d * priv)2414a6d768d8SVincenzo Maffione netmap_compute_buf_len(struct netmap_priv_d *priv)
2415a6d768d8SVincenzo Maffione {
2416a6d768d8SVincenzo Maffione enum txrx t;
2417a6d768d8SVincenzo Maffione u_int i;
2418a6d768d8SVincenzo Maffione struct netmap_kring *kring;
2419a6d768d8SVincenzo Maffione int error = 0;
2420a6d768d8SVincenzo Maffione unsigned mtu = 0;
2421a6d768d8SVincenzo Maffione struct netmap_adapter *na = priv->np_na;
2422f4a54f43SVincenzo Maffione uint64_t target;
2423a6d768d8SVincenzo Maffione
2424a6d768d8SVincenzo Maffione foreach_selected_ring(priv, t, i, kring) {
2425f4a54f43SVincenzo Maffione /* rings that are already active have their hwbuf_len
2426f4a54f43SVincenzo Maffione * already set and we cannot change it.
2427f4a54f43SVincenzo Maffione */
2428a6d768d8SVincenzo Maffione if (kring->users > 1)
2429a6d768d8SVincenzo Maffione continue;
2430a6d768d8SVincenzo Maffione
2431f4a54f43SVincenzo Maffione /* For netmap buffers which are not shared among several ring
2432f4a54f43SVincenzo Maffione * slots (the normal case), the available space is the buf size
2433f4a54f43SVincenzo Maffione * minus the max offset declared by the user at open time. If
2434f4a54f43SVincenzo Maffione * the user plans to have several slots pointing to different
2435f4a54f43SVincenzo Maffione * offsets into the same large buffer, she must also declare a
2436f4a54f43SVincenzo Maffione * "minimum gap" between two such consecutive offsets. In this
2437f4a54f43SVincenzo Maffione * case the user-declared 'offset_gap' is taken as the
2438f4a54f43SVincenzo Maffione * available space and offset_max is ignored.
2439f4a54f43SVincenzo Maffione */
2440f4a54f43SVincenzo Maffione
2441f4a54f43SVincenzo Maffione /* start with the normal case (unshared buffers) */
2442a6d768d8SVincenzo Maffione target = NETMAP_BUF_SIZE(kring->na) -
2443a6d768d8SVincenzo Maffione kring->offset_max;
2444f4a54f43SVincenzo Maffione /* if offset_gap is zero, the user does not intend to use
2445f4a54f43SVincenzo Maffione * shared buffers. In this case the minimum gap between
2446f4a54f43SVincenzo Maffione * two consective offsets into the same buffer can be
2447f4a54f43SVincenzo Maffione * assumed to be equal to the buffer size. In this way
2448f4a54f43SVincenzo Maffione * offset_gap always contains the available space ignoring
2449f4a54f43SVincenzo Maffione * offset_max. This may be used by drivers of NICs that
2450f4a54f43SVincenzo Maffione * are guaranteed to never write more than MTU bytes, even
2451f4a54f43SVincenzo Maffione * if the input buffer is larger: if the MTU is less
2452f4a54f43SVincenzo Maffione * than the target they can set hwbuf_len to offset_gap.
2453f4a54f43SVincenzo Maffione */
2454a6d768d8SVincenzo Maffione if (!kring->offset_gap)
2455a6d768d8SVincenzo Maffione kring->offset_gap =
2456a6d768d8SVincenzo Maffione NETMAP_BUF_SIZE(kring->na);
2457f4a54f43SVincenzo Maffione
2458a6d768d8SVincenzo Maffione if (kring->offset_gap < target)
2459a6d768d8SVincenzo Maffione target = kring->offset_gap;
2460a6d768d8SVincenzo Maffione error = kring->nm_bufcfg(kring, target);
2461a6d768d8SVincenzo Maffione if (error)
2462a6d768d8SVincenzo Maffione goto out;
2463a6d768d8SVincenzo Maffione
2464a6d768d8SVincenzo Maffione *(uint64_t *)(uintptr_t)&kring->ring->buf_align = kring->buf_align;
2465a6d768d8SVincenzo Maffione
2466a6d768d8SVincenzo Maffione if (mtu && t == NR_RX && kring->hwbuf_len < mtu) {
2467a6d768d8SVincenzo Maffione if (!(na->na_flags & NAF_MOREFRAG)) {
2468a6d768d8SVincenzo Maffione nm_prerr("error: large MTU (%d) needed "
2469a6d768d8SVincenzo Maffione "but %s does not support "
2470a6d768d8SVincenzo Maffione "NS_MOREFRAG", mtu,
2471a6d768d8SVincenzo Maffione na->name);
2472a6d768d8SVincenzo Maffione error = EINVAL;
2473a6d768d8SVincenzo Maffione goto out;
2474a6d768d8SVincenzo Maffione } else {
2475a6d768d8SVincenzo Maffione nm_prinf("info: netmap application on "
2476a6d768d8SVincenzo Maffione "%s needs to support "
2477a6d768d8SVincenzo Maffione "NS_MOREFRAG "
2478a6d768d8SVincenzo Maffione "(MTU=%u,buf_size=%llu)",
2479a6d768d8SVincenzo Maffione kring->name, mtu,
2480a6d768d8SVincenzo Maffione (unsigned long long)kring->hwbuf_len);
2481a6d768d8SVincenzo Maffione }
2482a6d768d8SVincenzo Maffione }
2483a6d768d8SVincenzo Maffione }
2484a6d768d8SVincenzo Maffione out:
2485a6d768d8SVincenzo Maffione return error;
2486a6d768d8SVincenzo Maffione }
248777a2baf5SVincenzo Maffione
2488f18be576SLuigi Rizzo /*
2489f18be576SLuigi Rizzo * possibly move the interface to netmap-mode.
2490f18be576SLuigi Rizzo * If success it returns a pointer to netmap_if, otherwise NULL.
2491ce3ee1e7SLuigi Rizzo * This must be called with NMG_LOCK held.
24924bf50f18SLuigi Rizzo *
24934bf50f18SLuigi Rizzo * The following na callbacks are called in the process:
24944bf50f18SLuigi Rizzo *
24954bf50f18SLuigi Rizzo * na->nm_config() [by netmap_update_config]
24964bf50f18SLuigi Rizzo * (get current number and size of rings)
24974bf50f18SLuigi Rizzo *
24984bf50f18SLuigi Rizzo * We have a generic one for linux (netmap_linux_config).
24994bf50f18SLuigi Rizzo * The bwrap has to override this, since it has to forward
25004bf50f18SLuigi Rizzo * the request to the wrapped adapter (netmap_bwrap_config).
25014bf50f18SLuigi Rizzo *
25024bf50f18SLuigi Rizzo *
2503847bf383SLuigi Rizzo * na->nm_krings_create()
25044bf50f18SLuigi Rizzo * (create and init the krings array)
25054bf50f18SLuigi Rizzo *
25064bf50f18SLuigi Rizzo * One of the following:
25074bf50f18SLuigi Rizzo *
25084bf50f18SLuigi Rizzo * * netmap_hw_krings_create, (hw ports)
25094bf50f18SLuigi Rizzo * creates the standard layout for the krings
25104bf50f18SLuigi Rizzo * and adds the mbq (used for the host rings).
25114bf50f18SLuigi Rizzo *
25124bf50f18SLuigi Rizzo * * netmap_vp_krings_create (VALE ports)
25134bf50f18SLuigi Rizzo * add leases and scratchpads
25144bf50f18SLuigi Rizzo *
25154bf50f18SLuigi Rizzo * * netmap_pipe_krings_create (pipes)
25164bf50f18SLuigi Rizzo * create the krings and rings of both ends and
25174bf50f18SLuigi Rizzo * cross-link them
25184bf50f18SLuigi Rizzo *
25194bf50f18SLuigi Rizzo * * netmap_monitor_krings_create (monitors)
25204bf50f18SLuigi Rizzo * avoid allocating the mbq
25214bf50f18SLuigi Rizzo *
25224bf50f18SLuigi Rizzo * * netmap_bwrap_krings_create (bwraps)
25234bf50f18SLuigi Rizzo * create both the brap krings array,
25244bf50f18SLuigi Rizzo * the krings array of the wrapped adapter, and
25254bf50f18SLuigi Rizzo * (if needed) the fake array for the host adapter
25264bf50f18SLuigi Rizzo *
25274bf50f18SLuigi Rizzo * na->nm_register(, 1)
25284bf50f18SLuigi Rizzo * (put the adapter in netmap mode)
25294bf50f18SLuigi Rizzo *
25304bf50f18SLuigi Rizzo * This may be one of the following:
25314bf50f18SLuigi Rizzo *
253237e3a6d3SLuigi Rizzo * * netmap_hw_reg (hw ports)
25334bf50f18SLuigi Rizzo * checks that the ifp is still there, then calls
25344bf50f18SLuigi Rizzo * the hardware specific callback;
25354bf50f18SLuigi Rizzo *
25364bf50f18SLuigi Rizzo * * netmap_vp_reg (VALE ports)
25374bf50f18SLuigi Rizzo * If the port is connected to a bridge,
25384bf50f18SLuigi Rizzo * set the NAF_NETMAP_ON flag under the
25394bf50f18SLuigi Rizzo * bridge write lock.
25404bf50f18SLuigi Rizzo *
25414bf50f18SLuigi Rizzo * * netmap_pipe_reg (pipes)
25424bf50f18SLuigi Rizzo * inform the other pipe end that it is no
2543453130d9SPedro F. Giffuni * longer responsible for the lifetime of this
25444bf50f18SLuigi Rizzo * pipe end
25454bf50f18SLuigi Rizzo *
25464bf50f18SLuigi Rizzo * * netmap_monitor_reg (monitors)
25474bf50f18SLuigi Rizzo * intercept the sync callbacks of the monitored
25484bf50f18SLuigi Rizzo * rings
25494bf50f18SLuigi Rizzo *
255037e3a6d3SLuigi Rizzo * * netmap_bwrap_reg (bwraps)
25514bf50f18SLuigi Rizzo * cross-link the bwrap and hwna rings,
25524bf50f18SLuigi Rizzo * forward the request to the hwna, override
25534bf50f18SLuigi Rizzo * the hwna notify callback (to get the frames
25544bf50f18SLuigi Rizzo * coming from outside go through the bridge).
25554bf50f18SLuigi Rizzo *
25564bf50f18SLuigi Rizzo *
2557f18be576SLuigi Rizzo */
2558847bf383SLuigi Rizzo int
netmap_do_regif(struct netmap_priv_d * priv,struct netmap_adapter * na,struct nmreq_header * hdr)2559f9790aebSLuigi Rizzo netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na,
2560ee0005f1SVincenzo Maffione struct nmreq_header *hdr)
2561f18be576SLuigi Rizzo {
2562f18be576SLuigi Rizzo struct netmap_if *nifp = NULL;
2563847bf383SLuigi Rizzo int error;
2564f18be576SLuigi Rizzo
2565ce3ee1e7SLuigi Rizzo NMG_LOCK_ASSERT();
2566f9790aebSLuigi Rizzo priv->np_na = na; /* store the reference */
2567847bf383SLuigi Rizzo error = netmap_mem_finalize(na->nm_mem, na);
2568ce3ee1e7SLuigi Rizzo if (error)
2569847bf383SLuigi Rizzo goto err;
2570847bf383SLuigi Rizzo
2571847bf383SLuigi Rizzo if (na->active_fds == 0) {
25722ff91c17SVincenzo Maffione
25732ff91c17SVincenzo Maffione /* cache the allocator info in the na */
25742ff91c17SVincenzo Maffione error = netmap_mem_get_lut(na->nm_mem, &na->na_lut);
25752ff91c17SVincenzo Maffione if (error)
25762ff91c17SVincenzo Maffione goto err_drop_mem;
257775f4f3edSVincenzo Maffione nm_prdis("lut %p bufs %u size %u", na->na_lut.lut, na->na_lut.objtotal,
25782ff91c17SVincenzo Maffione na->na_lut.objsize);
25792ff91c17SVincenzo Maffione
25802ff91c17SVincenzo Maffione /* ring configuration may have changed, fetch from the card */
25812ff91c17SVincenzo Maffione netmap_update_config(na);
2582cfa866f6SMatt Macy }
25832ff91c17SVincenzo Maffione
2584cfa866f6SMatt Macy /* compute the range of tx and rx rings to monitor */
2585ee0005f1SVincenzo Maffione error = netmap_set_ringid(priv, hdr);
2586cfa866f6SMatt Macy if (error)
2587cfa866f6SMatt Macy goto err_put_lut;
2588cfa866f6SMatt Macy
2589cfa866f6SMatt Macy if (na->active_fds == 0) {
2590847bf383SLuigi Rizzo /*
2591847bf383SLuigi Rizzo * If this is the first registration of the adapter,
25924f80b14cSVincenzo Maffione * perform sanity checks and create the in-kernel view
25934f80b14cSVincenzo Maffione * of the netmap rings (the netmap krings).
2594847bf383SLuigi Rizzo */
25952ff91c17SVincenzo Maffione if (na->ifp && nm_priv_rx_enabled(priv)) {
25964f80b14cSVincenzo Maffione /* This netmap adapter is attached to an ifnet. */
25974f80b14cSVincenzo Maffione unsigned mtu = nm_os_ifnet_mtu(na->ifp);
25984f80b14cSVincenzo Maffione
259975f4f3edSVincenzo Maffione nm_prdis("%s: mtu %d rx_buf_maxsize %d netmap_buf_size %d",
260077a2baf5SVincenzo Maffione na->name, mtu, na->rx_buf_maxsize, NETMAP_BUF_SIZE(na));
2601cfa866f6SMatt Macy
2602cfa866f6SMatt Macy if (na->rx_buf_maxsize == 0) {
2603b6e66be2SVincenzo Maffione nm_prerr("%s: error: rx_buf_maxsize == 0", na->name);
2604cfa866f6SMatt Macy error = EIO;
2605cfa866f6SMatt Macy goto err_drop_mem;
2606cfa866f6SMatt Macy }
26072ff91c17SVincenzo Maffione
260877a2baf5SVincenzo Maffione error = netmap_buf_size_validate(na, mtu);
260977a2baf5SVincenzo Maffione if (error)
26104f80b14cSVincenzo Maffione goto err_drop_mem;
26114f80b14cSVincenzo Maffione }
2612847bf383SLuigi Rizzo
2613847bf383SLuigi Rizzo /*
2614847bf383SLuigi Rizzo * Depending on the adapter, this may also create
2615847bf383SLuigi Rizzo * the netmap rings themselves
2616847bf383SLuigi Rizzo */
2617847bf383SLuigi Rizzo error = na->nm_krings_create(na);
2618847bf383SLuigi Rizzo if (error)
26192ff91c17SVincenzo Maffione goto err_put_lut;
2620847bf383SLuigi Rizzo
2621ce3ee1e7SLuigi Rizzo }
2622847bf383SLuigi Rizzo
262337e3a6d3SLuigi Rizzo /* now the krings must exist and we can check whether some
262437e3a6d3SLuigi Rizzo * previous bind has exclusive ownership on them, and set
262537e3a6d3SLuigi Rizzo * nr_pending_mode
2626847bf383SLuigi Rizzo */
262737e3a6d3SLuigi Rizzo error = netmap_krings_get(priv);
2628847bf383SLuigi Rizzo if (error)
262937e3a6d3SLuigi Rizzo goto err_del_krings;
263037e3a6d3SLuigi Rizzo
263137e3a6d3SLuigi Rizzo /* create all needed missing netmap rings */
263237e3a6d3SLuigi Rizzo error = netmap_mem_rings_create(na);
263337e3a6d3SLuigi Rizzo if (error)
263437e3a6d3SLuigi Rizzo goto err_rel_excl;
2635847bf383SLuigi Rizzo
2636a6d768d8SVincenzo Maffione /* initialize offsets if requested */
2637a6d768d8SVincenzo Maffione error = netmap_offsets_init(priv, hdr);
2638a6d768d8SVincenzo Maffione if (error)
2639a6d768d8SVincenzo Maffione goto err_rel_excl;
2640a6d768d8SVincenzo Maffione
264145c67e8fSVincenzo Maffione /* compute and validate the buf lengths */
2642a6d768d8SVincenzo Maffione error = netmap_compute_buf_len(priv);
2643a6d768d8SVincenzo Maffione if (error)
2644a6d768d8SVincenzo Maffione goto err_rel_excl;
2645a6d768d8SVincenzo Maffione
2646847bf383SLuigi Rizzo /* in all cases, create a new netmap if */
2647c3e9b4dbSLuiz Otavio O Souza nifp = netmap_mem_if_new(na, priv);
2648847bf383SLuigi Rizzo if (nifp == NULL) {
2649f18be576SLuigi Rizzo error = ENOMEM;
2650cfa866f6SMatt Macy goto err_rel_excl;
2651ce3ee1e7SLuigi Rizzo }
2652847bf383SLuigi Rizzo
265337e3a6d3SLuigi Rizzo if (nm_kring_pending(priv)) {
265437e3a6d3SLuigi Rizzo /* Some kring is switching mode, tell the adapter to
265537e3a6d3SLuigi Rizzo * react on this. */
265698399ab0SVincenzo Maffione netmap_set_all_rings(na, NM_KR_LOCKED);
265737e3a6d3SLuigi Rizzo error = na->nm_register(na, 1);
265898399ab0SVincenzo Maffione netmap_set_all_rings(na, 0);
265937e3a6d3SLuigi Rizzo if (error)
26602ff91c17SVincenzo Maffione goto err_del_if;
266137e3a6d3SLuigi Rizzo }
266237e3a6d3SLuigi Rizzo
266337e3a6d3SLuigi Rizzo /* Commit the reference. */
266437e3a6d3SLuigi Rizzo na->active_fds++;
266537e3a6d3SLuigi Rizzo
2666ce3ee1e7SLuigi Rizzo /*
2667847bf383SLuigi Rizzo * advertise that the interface is ready by setting np_nifp.
2668847bf383SLuigi Rizzo * The barrier is needed because readers (poll, *SYNC and mmap)
2669ce3ee1e7SLuigi Rizzo * check for priv->np_nifp != NULL without locking
2670ce3ee1e7SLuigi Rizzo */
2671847bf383SLuigi Rizzo mb(); /* make sure previous writes are visible to all CPUs */
2672ce3ee1e7SLuigi Rizzo priv->np_nifp = nifp;
2673847bf383SLuigi Rizzo
2674847bf383SLuigi Rizzo return 0;
2675847bf383SLuigi Rizzo
267637e3a6d3SLuigi Rizzo err_del_if:
2677847bf383SLuigi Rizzo netmap_mem_if_delete(na, nifp);
26784f80b14cSVincenzo Maffione err_rel_excl:
26794f80b14cSVincenzo Maffione netmap_krings_put(priv);
2680cfa866f6SMatt Macy netmap_mem_rings_delete(na);
2681847bf383SLuigi Rizzo err_del_krings:
2682847bf383SLuigi Rizzo if (na->active_fds == 0)
2683847bf383SLuigi Rizzo na->nm_krings_delete(na);
26842ff91c17SVincenzo Maffione err_put_lut:
26852ff91c17SVincenzo Maffione if (na->active_fds == 0)
26862ff91c17SVincenzo Maffione memset(&na->na_lut, 0, sizeof(na->na_lut));
2687847bf383SLuigi Rizzo err_drop_mem:
26884f80b14cSVincenzo Maffione netmap_mem_drop(na);
2689847bf383SLuigi Rizzo err:
2690847bf383SLuigi Rizzo priv->np_na = NULL;
2691847bf383SLuigi Rizzo return error;
2692ce3ee1e7SLuigi Rizzo }
2693847bf383SLuigi Rizzo
2694847bf383SLuigi Rizzo
2695847bf383SLuigi Rizzo /*
269637e3a6d3SLuigi Rizzo * update kring and ring at the end of rxsync/txsync.
2697847bf383SLuigi Rizzo */
2698847bf383SLuigi Rizzo static inline void
nm_sync_finalize(struct netmap_kring * kring)269937e3a6d3SLuigi Rizzo nm_sync_finalize(struct netmap_kring *kring)
2700847bf383SLuigi Rizzo {
270137e3a6d3SLuigi Rizzo /*
270237e3a6d3SLuigi Rizzo * Update ring tail to what the kernel knows
270337e3a6d3SLuigi Rizzo * After txsync: head/rhead/hwcur might be behind cur/rcur
270437e3a6d3SLuigi Rizzo * if no carrier.
270537e3a6d3SLuigi Rizzo */
2706847bf383SLuigi Rizzo kring->ring->tail = kring->rtail = kring->nr_hwtail;
2707847bf383SLuigi Rizzo
270875f4f3edSVincenzo Maffione nm_prdis(5, "%s now hwcur %d hwtail %d head %d cur %d tail %d",
2709847bf383SLuigi Rizzo kring->name, kring->nr_hwcur, kring->nr_hwtail,
2710847bf383SLuigi Rizzo kring->rhead, kring->rcur, kring->rtail);
2711847bf383SLuigi Rizzo }
2712847bf383SLuigi Rizzo
2713c3e9b4dbSLuiz Otavio O Souza /* set ring timestamp */
2714c3e9b4dbSLuiz Otavio O Souza static inline void
ring_timestamp_set(struct netmap_ring * ring)2715c3e9b4dbSLuiz Otavio O Souza ring_timestamp_set(struct netmap_ring *ring)
2716c3e9b4dbSLuiz Otavio O Souza {
2717c3e9b4dbSLuiz Otavio O Souza if (netmap_no_timestamp == 0 || ring->flags & NR_TIMESTAMP) {
2718c3e9b4dbSLuiz Otavio O Souza microtime(&ring->ts);
2719c3e9b4dbSLuiz Otavio O Souza }
2720c3e9b4dbSLuiz Otavio O Souza }
2721c3e9b4dbSLuiz Otavio O Souza
27222ff91c17SVincenzo Maffione static int nmreq_copyin(struct nmreq_header *, int);
27232ff91c17SVincenzo Maffione static int nmreq_copyout(struct nmreq_header *, int);
27242ff91c17SVincenzo Maffione static int nmreq_checkoptions(struct nmreq_header *);
2725c3e9b4dbSLuiz Otavio O Souza
272668b8534bSLuigi Rizzo /*
272768b8534bSLuigi Rizzo * ioctl(2) support for the "netmap" device.
272868b8534bSLuigi Rizzo *
272968b8534bSLuigi Rizzo * Following a list of accepted commands:
27302ff91c17SVincenzo Maffione * - NIOCCTRL device control API
27312ff91c17SVincenzo Maffione * - NIOCTXSYNC sync TX rings
27322ff91c17SVincenzo Maffione * - NIOCRXSYNC sync RX rings
273368b8534bSLuigi Rizzo * - SIOCGIFADDR just for convenience
27342ff91c17SVincenzo Maffione * - NIOCGINFO deprecated (legacy API)
27352ff91c17SVincenzo Maffione * - NIOCREGIF deprecated (legacy API)
273668b8534bSLuigi Rizzo *
273768b8534bSLuigi Rizzo * Return 0 on success, errno otherwise.
273868b8534bSLuigi Rizzo */
2739f9790aebSLuigi Rizzo int
netmap_ioctl(struct netmap_priv_d * priv,u_long cmd,caddr_t data,struct thread * td,int nr_body_is_user)27402ff91c17SVincenzo Maffione netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data,
27412ff91c17SVincenzo Maffione struct thread *td, int nr_body_is_user)
274268b8534bSLuigi Rizzo {
2743c3e9b4dbSLuiz Otavio O Souza struct mbq q; /* packets from RX hw queues to host stack */
2744ce3ee1e7SLuigi Rizzo struct netmap_adapter *na = NULL;
2745c3e9b4dbSLuiz Otavio O Souza struct netmap_mem_d *nmd = NULL;
2746e330262fSJustin Hibbits if_t ifp = NULL;
274737e3a6d3SLuigi Rizzo int error = 0;
2748f0ea3689SLuigi Rizzo u_int i, qfirst, qlast;
27492ff91c17SVincenzo Maffione struct netmap_kring **krings;
2750c3e9b4dbSLuiz Otavio O Souza int sync_flags;
2751847bf383SLuigi Rizzo enum txrx t;
275268b8534bSLuigi Rizzo
27532ff91c17SVincenzo Maffione switch (cmd) {
27542ff91c17SVincenzo Maffione case NIOCCTRL: {
27552ff91c17SVincenzo Maffione struct nmreq_header *hdr = (struct nmreq_header *)data;
27562ff91c17SVincenzo Maffione
27572ff91c17SVincenzo Maffione if (hdr->nr_version < NETMAP_MIN_API ||
27582ff91c17SVincenzo Maffione hdr->nr_version > NETMAP_MAX_API) {
2759b6e66be2SVincenzo Maffione nm_prerr("API mismatch: got %d need %d",
2760b6e66be2SVincenzo Maffione hdr->nr_version, NETMAP_API);
276117885a7bSLuigi Rizzo return EINVAL;
276217885a7bSLuigi Rizzo }
276368b8534bSLuigi Rizzo
27642ff91c17SVincenzo Maffione /* Make a kernel-space copy of the user-space nr_body.
276545c67e8fSVincenzo Maffione * For convenience, the nr_body pointer and the pointers
27662ff91c17SVincenzo Maffione * in the options list will be replaced with their
27672ff91c17SVincenzo Maffione * kernel-space counterparts. The original pointers are
27682ff91c17SVincenzo Maffione * saved internally and later restored by nmreq_copyout
27692ff91c17SVincenzo Maffione */
27702ff91c17SVincenzo Maffione error = nmreq_copyin(hdr, nr_body_is_user);
277137e3a6d3SLuigi Rizzo if (error) {
27722ff91c17SVincenzo Maffione return error;
2773ce3ee1e7SLuigi Rizzo }
2774ce3ee1e7SLuigi Rizzo
27752ff91c17SVincenzo Maffione /* Sanitize hdr->nr_name. */
27762ff91c17SVincenzo Maffione hdr->nr_name[sizeof(hdr->nr_name) - 1] = '\0';
277768b8534bSLuigi Rizzo
27782ff91c17SVincenzo Maffione switch (hdr->nr_reqtype) {
27792ff91c17SVincenzo Maffione case NETMAP_REQ_REGISTER: {
27802ff91c17SVincenzo Maffione struct nmreq_register *req =
2781cfa866f6SMatt Macy (struct nmreq_register *)(uintptr_t)hdr->nr_body;
2782b6e66be2SVincenzo Maffione struct netmap_if *nifp;
2783b6e66be2SVincenzo Maffione
27842ff91c17SVincenzo Maffione /* Protect access to priv from concurrent requests. */
2785ce3ee1e7SLuigi Rizzo NMG_LOCK();
2786ce3ee1e7SLuigi Rizzo do {
27872ff91c17SVincenzo Maffione struct nmreq_option *opt;
2788b6e66be2SVincenzo Maffione u_int memflags;
2789ce3ee1e7SLuigi Rizzo
2790847bf383SLuigi Rizzo if (priv->np_nifp != NULL) { /* thread already registered */
2791f0ea3689SLuigi Rizzo error = EBUSY;
2792506cc70cSLuigi Rizzo break;
2793506cc70cSLuigi Rizzo }
2794c3e9b4dbSLuiz Otavio O Souza
27952ff91c17SVincenzo Maffione #ifdef WITH_EXTMEM
2796253b2ec1SVincenzo Maffione opt = nmreq_getoption(hdr, NETMAP_REQ_OPT_EXTMEM);
27972ff91c17SVincenzo Maffione if (opt != NULL) {
27982ff91c17SVincenzo Maffione struct nmreq_opt_extmem *e =
27992ff91c17SVincenzo Maffione (struct nmreq_opt_extmem *)opt;
28002ff91c17SVincenzo Maffione
28012ff91c17SVincenzo Maffione nmd = netmap_mem_ext_create(e->nro_usrptr,
28022ff91c17SVincenzo Maffione &e->nro_info, &error);
28032ff91c17SVincenzo Maffione opt->nro_status = error;
28042ff91c17SVincenzo Maffione if (nmd == NULL)
28052ff91c17SVincenzo Maffione break;
28062ff91c17SVincenzo Maffione }
28072ff91c17SVincenzo Maffione #endif /* WITH_EXTMEM */
28082ff91c17SVincenzo Maffione
28092ff91c17SVincenzo Maffione if (nmd == NULL && req->nr_mem_id) {
2810c3e9b4dbSLuiz Otavio O Souza /* find the allocator and get a reference */
28112ff91c17SVincenzo Maffione nmd = netmap_mem_find(req->nr_mem_id);
2812c3e9b4dbSLuiz Otavio O Souza if (nmd == NULL) {
2813b6e66be2SVincenzo Maffione if (netmap_verbose) {
2814b6e66be2SVincenzo Maffione nm_prerr("%s: failed to find mem_id %u",
2815b6e66be2SVincenzo Maffione hdr->nr_name, req->nr_mem_id);
2816b6e66be2SVincenzo Maffione }
2817c3e9b4dbSLuiz Otavio O Souza error = EINVAL;
2818c3e9b4dbSLuiz Otavio O Souza break;
2819c3e9b4dbSLuiz Otavio O Souza }
2820c3e9b4dbSLuiz Otavio O Souza }
282168b8534bSLuigi Rizzo /* find the interface and a reference */
28222ff91c17SVincenzo Maffione error = netmap_get_na(hdr, &na, &ifp, nmd,
282337e3a6d3SLuigi Rizzo 1 /* create */); /* keep reference */
282468b8534bSLuigi Rizzo if (error)
2825ce3ee1e7SLuigi Rizzo break;
2826f9790aebSLuigi Rizzo if (NETMAP_OWNED_BY_KERN(na)) {
2827ce3ee1e7SLuigi Rizzo error = EBUSY;
2828ce3ee1e7SLuigi Rizzo break;
2829f196ce38SLuigi Rizzo }
283037e3a6d3SLuigi Rizzo
28312ff91c17SVincenzo Maffione if (na->virt_hdr_len && !(req->nr_flags & NR_ACCEPT_VNET_HDR)) {
2832b6e66be2SVincenzo Maffione nm_prerr("virt_hdr_len=%d, but application does "
2833b6e66be2SVincenzo Maffione "not accept it", na->virt_hdr_len);
283437e3a6d3SLuigi Rizzo error = EIO;
283537e3a6d3SLuigi Rizzo break;
283637e3a6d3SLuigi Rizzo }
283737e3a6d3SLuigi Rizzo
2838ee0005f1SVincenzo Maffione error = netmap_do_regif(priv, na, hdr);
2839847bf383SLuigi Rizzo if (error) { /* reg. failed, release priv and ref */
2840ce3ee1e7SLuigi Rizzo break;
284168b8534bSLuigi Rizzo }
2842b6e66be2SVincenzo Maffione
2843253b2ec1SVincenzo Maffione opt = nmreq_getoption(hdr, NETMAP_REQ_OPT_CSB);
2844b6e66be2SVincenzo Maffione if (opt != NULL) {
2845b6e66be2SVincenzo Maffione struct nmreq_opt_csb *csbo =
2846b6e66be2SVincenzo Maffione (struct nmreq_opt_csb *)opt;
2847b6e66be2SVincenzo Maffione error = netmap_csb_validate(priv, csbo);
2848b6e66be2SVincenzo Maffione opt->nro_status = error;
2849b6e66be2SVincenzo Maffione if (error) {
2850b6e66be2SVincenzo Maffione netmap_do_unregif(priv);
2851b6e66be2SVincenzo Maffione break;
2852b6e66be2SVincenzo Maffione }
2853b6e66be2SVincenzo Maffione }
2854b6e66be2SVincenzo Maffione
2855847bf383SLuigi Rizzo nifp = priv->np_nifp;
285668b8534bSLuigi Rizzo
285768b8534bSLuigi Rizzo /* return the offset of the netmap_if object */
28582ff91c17SVincenzo Maffione req->nr_rx_rings = na->num_rx_rings;
28592ff91c17SVincenzo Maffione req->nr_tx_rings = na->num_tx_rings;
28602ff91c17SVincenzo Maffione req->nr_rx_slots = na->num_rx_desc;
28612ff91c17SVincenzo Maffione req->nr_tx_slots = na->num_tx_desc;
2862d12354a5SVincenzo Maffione req->nr_host_tx_rings = na->num_host_tx_rings;
2863d12354a5SVincenzo Maffione req->nr_host_rx_rings = na->num_host_rx_rings;
28642ff91c17SVincenzo Maffione error = netmap_mem_get_info(na->nm_mem, &req->nr_memsize, &memflags,
28652ff91c17SVincenzo Maffione &req->nr_mem_id);
2866ce3ee1e7SLuigi Rizzo if (error) {
2867847bf383SLuigi Rizzo netmap_do_unregif(priv);
2868ce3ee1e7SLuigi Rizzo break;
2869ce3ee1e7SLuigi Rizzo }
2870ce3ee1e7SLuigi Rizzo if (memflags & NETMAP_MEM_PRIVATE) {
28713d819cb6SLuigi Rizzo *(uint32_t *)(uintptr_t)&nifp->ni_flags |= NI_PRIV_MEM;
2872ce3ee1e7SLuigi Rizzo }
2873847bf383SLuigi Rizzo for_rx_tx(t) {
2874847bf383SLuigi Rizzo priv->np_si[t] = nm_si_user(priv, t) ?
28752ff91c17SVincenzo Maffione &na->si[t] : &NMR(na, t)[priv->np_qfirst[t]]->si;
2876847bf383SLuigi Rizzo }
2877f0ea3689SLuigi Rizzo
28782ff91c17SVincenzo Maffione if (req->nr_extra_bufs) {
287937e3a6d3SLuigi Rizzo if (netmap_verbose)
2880b6e66be2SVincenzo Maffione nm_prinf("requested %d extra buffers",
28812ff91c17SVincenzo Maffione req->nr_extra_bufs);
28822ff91c17SVincenzo Maffione req->nr_extra_bufs = netmap_extra_alloc(na,
28832ff91c17SVincenzo Maffione &nifp->ni_bufs_head, req->nr_extra_bufs);
288437e3a6d3SLuigi Rizzo if (netmap_verbose)
2885b6e66be2SVincenzo Maffione nm_prinf("got %d extra buffers", req->nr_extra_bufs);
288698399ab0SVincenzo Maffione } else {
288798399ab0SVincenzo Maffione nifp->ni_bufs_head = 0;
2888f0ea3689SLuigi Rizzo }
28892ff91c17SVincenzo Maffione req->nr_offset = netmap_mem_if_offset(na->nm_mem, nifp);
28902ff91c17SVincenzo Maffione
28912ff91c17SVincenzo Maffione error = nmreq_checkoptions(hdr);
28922ff91c17SVincenzo Maffione if (error) {
28932ff91c17SVincenzo Maffione netmap_do_unregif(priv);
28942ff91c17SVincenzo Maffione break;
28952ff91c17SVincenzo Maffione }
289637e3a6d3SLuigi Rizzo
289737e3a6d3SLuigi Rizzo /* store ifp reference so that priv destructor may release it */
289837e3a6d3SLuigi Rizzo priv->np_ifp = ifp;
2899ce3ee1e7SLuigi Rizzo } while (0);
2900c3e9b4dbSLuiz Otavio O Souza if (error) {
2901c3e9b4dbSLuiz Otavio O Souza netmap_unget_na(na, ifp);
2902c3e9b4dbSLuiz Otavio O Souza }
2903c3e9b4dbSLuiz Otavio O Souza /* release the reference from netmap_mem_find() or
2904c3e9b4dbSLuiz Otavio O Souza * netmap_mem_ext_create()
2905c3e9b4dbSLuiz Otavio O Souza */
2906c3e9b4dbSLuiz Otavio O Souza if (nmd)
2907c3e9b4dbSLuiz Otavio O Souza netmap_mem_put(nmd);
2908ce3ee1e7SLuigi Rizzo NMG_UNLOCK();
290968b8534bSLuigi Rizzo break;
29102ff91c17SVincenzo Maffione }
29112ff91c17SVincenzo Maffione
29122ff91c17SVincenzo Maffione case NETMAP_REQ_PORT_INFO_GET: {
29132ff91c17SVincenzo Maffione struct nmreq_port_info_get *req =
2914cfa866f6SMatt Macy (struct nmreq_port_info_get *)(uintptr_t)hdr->nr_body;
29150ab5902eSVincenzo Maffione int nmd_ref = 0;
29162ff91c17SVincenzo Maffione
29172ff91c17SVincenzo Maffione NMG_LOCK();
29182ff91c17SVincenzo Maffione do {
29192ff91c17SVincenzo Maffione u_int memflags;
29202ff91c17SVincenzo Maffione
29212ff91c17SVincenzo Maffione if (hdr->nr_name[0] != '\0') {
29222ff91c17SVincenzo Maffione /* Build a nmreq_register out of the nmreq_port_info_get,
29232ff91c17SVincenzo Maffione * so that we can call netmap_get_na(). */
29242ff91c17SVincenzo Maffione struct nmreq_register regreq;
29252ff91c17SVincenzo Maffione bzero(®req, sizeof(regreq));
2926b6e66be2SVincenzo Maffione regreq.nr_mode = NR_REG_ALL_NIC;
29272ff91c17SVincenzo Maffione regreq.nr_tx_slots = req->nr_tx_slots;
29282ff91c17SVincenzo Maffione regreq.nr_rx_slots = req->nr_rx_slots;
29292ff91c17SVincenzo Maffione regreq.nr_tx_rings = req->nr_tx_rings;
29302ff91c17SVincenzo Maffione regreq.nr_rx_rings = req->nr_rx_rings;
2931d12354a5SVincenzo Maffione regreq.nr_host_tx_rings = req->nr_host_tx_rings;
2932d12354a5SVincenzo Maffione regreq.nr_host_rx_rings = req->nr_host_rx_rings;
29332ff91c17SVincenzo Maffione regreq.nr_mem_id = req->nr_mem_id;
29342ff91c17SVincenzo Maffione
29352ff91c17SVincenzo Maffione /* get a refcount */
29362ff91c17SVincenzo Maffione hdr->nr_reqtype = NETMAP_REQ_REGISTER;
2937cfa866f6SMatt Macy hdr->nr_body = (uintptr_t)®req;
29382ff91c17SVincenzo Maffione error = netmap_get_na(hdr, &na, &ifp, NULL, 1 /* create */);
29392ff91c17SVincenzo Maffione hdr->nr_reqtype = NETMAP_REQ_PORT_INFO_GET; /* reset type */
2940cfa866f6SMatt Macy hdr->nr_body = (uintptr_t)req; /* reset nr_body */
29412ff91c17SVincenzo Maffione if (error) {
29422ff91c17SVincenzo Maffione na = NULL;
29432ff91c17SVincenzo Maffione ifp = NULL;
29442ff91c17SVincenzo Maffione break;
29452ff91c17SVincenzo Maffione }
29462ff91c17SVincenzo Maffione nmd = na->nm_mem; /* get memory allocator */
29472ff91c17SVincenzo Maffione } else {
29482ff91c17SVincenzo Maffione nmd = netmap_mem_find(req->nr_mem_id ? req->nr_mem_id : 1);
29492ff91c17SVincenzo Maffione if (nmd == NULL) {
2950b6e66be2SVincenzo Maffione if (netmap_verbose)
2951b6e66be2SVincenzo Maffione nm_prerr("%s: failed to find mem_id %u",
2952b6e66be2SVincenzo Maffione hdr->nr_name,
2953b6e66be2SVincenzo Maffione req->nr_mem_id ? req->nr_mem_id : 1);
29542ff91c17SVincenzo Maffione error = EINVAL;
29552ff91c17SVincenzo Maffione break;
29562ff91c17SVincenzo Maffione }
29570ab5902eSVincenzo Maffione nmd_ref = 1;
29582ff91c17SVincenzo Maffione }
29592ff91c17SVincenzo Maffione
29602ff91c17SVincenzo Maffione error = netmap_mem_get_info(nmd, &req->nr_memsize, &memflags,
29612ff91c17SVincenzo Maffione &req->nr_mem_id);
29622ff91c17SVincenzo Maffione if (error)
29632ff91c17SVincenzo Maffione break;
29642ff91c17SVincenzo Maffione if (na == NULL) /* only memory info */
29652ff91c17SVincenzo Maffione break;
29662ff91c17SVincenzo Maffione netmap_update_config(na);
29672ff91c17SVincenzo Maffione req->nr_rx_rings = na->num_rx_rings;
29682ff91c17SVincenzo Maffione req->nr_tx_rings = na->num_tx_rings;
29692ff91c17SVincenzo Maffione req->nr_rx_slots = na->num_rx_desc;
29702ff91c17SVincenzo Maffione req->nr_tx_slots = na->num_tx_desc;
2971d12354a5SVincenzo Maffione req->nr_host_tx_rings = na->num_host_tx_rings;
2972d12354a5SVincenzo Maffione req->nr_host_rx_rings = na->num_host_rx_rings;
29732ff91c17SVincenzo Maffione } while (0);
29742ff91c17SVincenzo Maffione netmap_unget_na(na, ifp);
29750ab5902eSVincenzo Maffione if (nmd_ref)
29760ab5902eSVincenzo Maffione netmap_mem_put(nmd);
29772ff91c17SVincenzo Maffione NMG_UNLOCK();
29782ff91c17SVincenzo Maffione break;
29792ff91c17SVincenzo Maffione }
29802ff91c17SVincenzo Maffione #ifdef WITH_VALE
29812ff91c17SVincenzo Maffione case NETMAP_REQ_VALE_ATTACH: {
2982a6d768d8SVincenzo Maffione error = netmap_bdg_attach(hdr, NULL /* userspace request */);
29832ff91c17SVincenzo Maffione break;
29842ff91c17SVincenzo Maffione }
29852ff91c17SVincenzo Maffione
29862ff91c17SVincenzo Maffione case NETMAP_REQ_VALE_DETACH: {
2987a6d768d8SVincenzo Maffione error = netmap_bdg_detach(hdr, NULL /* userspace request */);
29882ff91c17SVincenzo Maffione break;
29892ff91c17SVincenzo Maffione }
29902ff91c17SVincenzo Maffione
29912ff91c17SVincenzo Maffione case NETMAP_REQ_PORT_HDR_SET: {
29922ff91c17SVincenzo Maffione struct nmreq_port_hdr *req =
2993cfa866f6SMatt Macy (struct nmreq_port_hdr *)(uintptr_t)hdr->nr_body;
29942ff91c17SVincenzo Maffione /* Build a nmreq_register out of the nmreq_port_hdr,
29952ff91c17SVincenzo Maffione * so that we can call netmap_get_bdg_na(). */
29962ff91c17SVincenzo Maffione struct nmreq_register regreq;
29972ff91c17SVincenzo Maffione bzero(®req, sizeof(regreq));
2998b6e66be2SVincenzo Maffione regreq.nr_mode = NR_REG_ALL_NIC;
2999b6e66be2SVincenzo Maffione
30002ff91c17SVincenzo Maffione /* For now we only support virtio-net headers, and only for
30012ff91c17SVincenzo Maffione * VALE ports, but this may change in future. Valid lengths
30022ff91c17SVincenzo Maffione * for the virtio-net header are 0 (no header), 10 and 12. */
30032ff91c17SVincenzo Maffione if (req->nr_hdr_len != 0 &&
30042ff91c17SVincenzo Maffione req->nr_hdr_len != sizeof(struct nm_vnet_hdr) &&
30052ff91c17SVincenzo Maffione req->nr_hdr_len != 12) {
3006b6e66be2SVincenzo Maffione if (netmap_verbose)
3007b6e66be2SVincenzo Maffione nm_prerr("invalid hdr_len %u", req->nr_hdr_len);
30082ff91c17SVincenzo Maffione error = EINVAL;
30092ff91c17SVincenzo Maffione break;
30102ff91c17SVincenzo Maffione }
30112ff91c17SVincenzo Maffione NMG_LOCK();
30122ff91c17SVincenzo Maffione hdr->nr_reqtype = NETMAP_REQ_REGISTER;
3013cfa866f6SMatt Macy hdr->nr_body = (uintptr_t)®req;
30142a7db7a6SVincenzo Maffione error = netmap_get_vale_na(hdr, &na, NULL, 0);
30152ff91c17SVincenzo Maffione hdr->nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
3016cfa866f6SMatt Macy hdr->nr_body = (uintptr_t)req;
30172ff91c17SVincenzo Maffione if (na && !error) {
30182ff91c17SVincenzo Maffione struct netmap_vp_adapter *vpna =
30192ff91c17SVincenzo Maffione (struct netmap_vp_adapter *)na;
30202ff91c17SVincenzo Maffione na->virt_hdr_len = req->nr_hdr_len;
30212ff91c17SVincenzo Maffione if (na->virt_hdr_len) {
30222ff91c17SVincenzo Maffione vpna->mfs = NETMAP_BUF_SIZE(na);
30232ff91c17SVincenzo Maffione }
3024b6e66be2SVincenzo Maffione if (netmap_verbose)
3025b6e66be2SVincenzo Maffione nm_prinf("Using vnet_hdr_len %d for %p", na->virt_hdr_len, na);
30262ff91c17SVincenzo Maffione netmap_adapter_put(na);
30272ff91c17SVincenzo Maffione } else if (!na) {
30282ff91c17SVincenzo Maffione error = ENXIO;
30292ff91c17SVincenzo Maffione }
30302ff91c17SVincenzo Maffione NMG_UNLOCK();
30312ff91c17SVincenzo Maffione break;
30322ff91c17SVincenzo Maffione }
30332ff91c17SVincenzo Maffione
30342ff91c17SVincenzo Maffione case NETMAP_REQ_PORT_HDR_GET: {
30352ff91c17SVincenzo Maffione /* Get vnet-header length for this netmap port */
30362ff91c17SVincenzo Maffione struct nmreq_port_hdr *req =
3037cfa866f6SMatt Macy (struct nmreq_port_hdr *)(uintptr_t)hdr->nr_body;
30382ff91c17SVincenzo Maffione /* Build a nmreq_register out of the nmreq_port_hdr,
30392ff91c17SVincenzo Maffione * so that we can call netmap_get_bdg_na(). */
30402ff91c17SVincenzo Maffione struct nmreq_register regreq;
3041e330262fSJustin Hibbits if_t ifp;
30422ff91c17SVincenzo Maffione
30432ff91c17SVincenzo Maffione bzero(®req, sizeof(regreq));
3044b6e66be2SVincenzo Maffione regreq.nr_mode = NR_REG_ALL_NIC;
30452ff91c17SVincenzo Maffione NMG_LOCK();
30462ff91c17SVincenzo Maffione hdr->nr_reqtype = NETMAP_REQ_REGISTER;
3047cfa866f6SMatt Macy hdr->nr_body = (uintptr_t)®req;
30482ff91c17SVincenzo Maffione error = netmap_get_na(hdr, &na, &ifp, NULL, 0);
30492ff91c17SVincenzo Maffione hdr->nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
3050cfa866f6SMatt Macy hdr->nr_body = (uintptr_t)req;
30512ff91c17SVincenzo Maffione if (na && !error) {
30522ff91c17SVincenzo Maffione req->nr_hdr_len = na->virt_hdr_len;
30532ff91c17SVincenzo Maffione }
30542ff91c17SVincenzo Maffione netmap_unget_na(na, ifp);
30552ff91c17SVincenzo Maffione NMG_UNLOCK();
30562ff91c17SVincenzo Maffione break;
30572ff91c17SVincenzo Maffione }
30582ff91c17SVincenzo Maffione
3059a6d768d8SVincenzo Maffione case NETMAP_REQ_VALE_LIST: {
3060a6d768d8SVincenzo Maffione error = netmap_vale_list(hdr);
3061a6d768d8SVincenzo Maffione break;
3062a6d768d8SVincenzo Maffione }
3063a6d768d8SVincenzo Maffione
30642ff91c17SVincenzo Maffione case NETMAP_REQ_VALE_NEWIF: {
30652ff91c17SVincenzo Maffione error = nm_vi_create(hdr);
30662ff91c17SVincenzo Maffione break;
30672ff91c17SVincenzo Maffione }
30682ff91c17SVincenzo Maffione
30692ff91c17SVincenzo Maffione case NETMAP_REQ_VALE_DELIF: {
30702ff91c17SVincenzo Maffione error = nm_vi_destroy(hdr->nr_name);
30712ff91c17SVincenzo Maffione break;
30722ff91c17SVincenzo Maffione }
3073a6d768d8SVincenzo Maffione #endif /* WITH_VALE */
30742ff91c17SVincenzo Maffione
30752ff91c17SVincenzo Maffione case NETMAP_REQ_VALE_POLLING_ENABLE:
30762ff91c17SVincenzo Maffione case NETMAP_REQ_VALE_POLLING_DISABLE: {
30772ff91c17SVincenzo Maffione error = nm_bdg_polling(hdr);
30782ff91c17SVincenzo Maffione break;
30792ff91c17SVincenzo Maffione }
30802ff91c17SVincenzo Maffione case NETMAP_REQ_POOLS_INFO_GET: {
3081b6e66be2SVincenzo Maffione /* Get information from the memory allocator used for
3082b6e66be2SVincenzo Maffione * hdr->nr_name. */
30832ff91c17SVincenzo Maffione struct nmreq_pools_info *req =
3084cfa866f6SMatt Macy (struct nmreq_pools_info *)(uintptr_t)hdr->nr_body;
30852ff91c17SVincenzo Maffione NMG_LOCK();
3086b6e66be2SVincenzo Maffione do {
3087b6e66be2SVincenzo Maffione /* Build a nmreq_register out of the nmreq_pools_info,
3088b6e66be2SVincenzo Maffione * so that we can call netmap_get_na(). */
3089b6e66be2SVincenzo Maffione struct nmreq_register regreq;
3090b6e66be2SVincenzo Maffione bzero(®req, sizeof(regreq));
3091b6e66be2SVincenzo Maffione regreq.nr_mem_id = req->nr_mem_id;
3092b6e66be2SVincenzo Maffione regreq.nr_mode = NR_REG_ALL_NIC;
3093b6e66be2SVincenzo Maffione
3094b6e66be2SVincenzo Maffione hdr->nr_reqtype = NETMAP_REQ_REGISTER;
3095b6e66be2SVincenzo Maffione hdr->nr_body = (uintptr_t)®req;
3096b6e66be2SVincenzo Maffione error = netmap_get_na(hdr, &na, &ifp, NULL, 1 /* create */);
3097b6e66be2SVincenzo Maffione hdr->nr_reqtype = NETMAP_REQ_POOLS_INFO_GET; /* reset type */
3098b6e66be2SVincenzo Maffione hdr->nr_body = (uintptr_t)req; /* reset nr_body */
3099b6e66be2SVincenzo Maffione if (error) {
3100b6e66be2SVincenzo Maffione na = NULL;
3101b6e66be2SVincenzo Maffione ifp = NULL;
3102b6e66be2SVincenzo Maffione break;
31032ff91c17SVincenzo Maffione }
3104b6e66be2SVincenzo Maffione nmd = na->nm_mem; /* grab the memory allocator */
3105b6e66be2SVincenzo Maffione if (nmd == NULL) {
3106b6e66be2SVincenzo Maffione error = EINVAL;
3107b6e66be2SVincenzo Maffione break;
3108b6e66be2SVincenzo Maffione }
3109b6e66be2SVincenzo Maffione
3110b6e66be2SVincenzo Maffione /* Finalize the memory allocator, get the pools
3111b6e66be2SVincenzo Maffione * information and release the allocator. */
3112b6e66be2SVincenzo Maffione error = netmap_mem_finalize(nmd, na);
3113b6e66be2SVincenzo Maffione if (error) {
3114b6e66be2SVincenzo Maffione break;
3115b6e66be2SVincenzo Maffione }
3116b6e66be2SVincenzo Maffione error = netmap_mem_pools_info_get(req, nmd);
3117b6e66be2SVincenzo Maffione netmap_mem_drop(na);
3118b6e66be2SVincenzo Maffione } while (0);
3119b6e66be2SVincenzo Maffione netmap_unget_na(na, ifp);
31202ff91c17SVincenzo Maffione NMG_UNLOCK();
31212ff91c17SVincenzo Maffione break;
31222ff91c17SVincenzo Maffione }
31232ff91c17SVincenzo Maffione
3124b6e66be2SVincenzo Maffione case NETMAP_REQ_CSB_ENABLE: {
3125b6e66be2SVincenzo Maffione struct nmreq_option *opt;
3126b6e66be2SVincenzo Maffione
3127253b2ec1SVincenzo Maffione opt = nmreq_getoption(hdr, NETMAP_REQ_OPT_CSB);
3128b6e66be2SVincenzo Maffione if (opt == NULL) {
3129b6e66be2SVincenzo Maffione error = EINVAL;
3130b6e66be2SVincenzo Maffione } else {
3131b6e66be2SVincenzo Maffione struct nmreq_opt_csb *csbo =
3132b6e66be2SVincenzo Maffione (struct nmreq_opt_csb *)opt;
3133b6e66be2SVincenzo Maffione NMG_LOCK();
3134b6e66be2SVincenzo Maffione error = netmap_csb_validate(priv, csbo);
3135b6e66be2SVincenzo Maffione NMG_UNLOCK();
3136b6e66be2SVincenzo Maffione opt->nro_status = error;
3137b6e66be2SVincenzo Maffione }
3138b6e66be2SVincenzo Maffione break;
3139b6e66be2SVincenzo Maffione }
3140b6e66be2SVincenzo Maffione
3141b6e66be2SVincenzo Maffione case NETMAP_REQ_SYNC_KLOOP_START: {
3142b6e66be2SVincenzo Maffione error = netmap_sync_kloop(priv, hdr);
3143b6e66be2SVincenzo Maffione break;
3144b6e66be2SVincenzo Maffione }
3145b6e66be2SVincenzo Maffione
3146b6e66be2SVincenzo Maffione case NETMAP_REQ_SYNC_KLOOP_STOP: {
3147b6e66be2SVincenzo Maffione error = netmap_sync_kloop_stop(priv);
3148b6e66be2SVincenzo Maffione break;
3149b6e66be2SVincenzo Maffione }
3150b6e66be2SVincenzo Maffione
31512ff91c17SVincenzo Maffione default: {
31522ff91c17SVincenzo Maffione error = EINVAL;
31532ff91c17SVincenzo Maffione break;
31542ff91c17SVincenzo Maffione }
31552ff91c17SVincenzo Maffione }
31562ff91c17SVincenzo Maffione /* Write back request body to userspace and reset the
31572ff91c17SVincenzo Maffione * user-space pointer. */
31582ff91c17SVincenzo Maffione error = nmreq_copyout(hdr, error);
31592ff91c17SVincenzo Maffione break;
31602ff91c17SVincenzo Maffione }
316168b8534bSLuigi Rizzo
316268b8534bSLuigi Rizzo case NIOCTXSYNC:
31632ff91c17SVincenzo Maffione case NIOCRXSYNC: {
3164b6e66be2SVincenzo Maffione if (unlikely(priv->np_nifp == NULL)) {
3165506cc70cSLuigi Rizzo error = ENXIO;
3166506cc70cSLuigi Rizzo break;
3167506cc70cSLuigi Rizzo }
31686641c68bSLuigi Rizzo mb(); /* make sure following reads are not from cache */
31698241616dSLuigi Rizzo
3170b6e66be2SVincenzo Maffione if (unlikely(priv->np_csb_atok_base)) {
3171b6e66be2SVincenzo Maffione nm_prerr("Invalid sync in CSB mode");
3172b6e66be2SVincenzo Maffione error = EBUSY;
31738241616dSLuigi Rizzo break;
31748241616dSLuigi Rizzo }
31758241616dSLuigi Rizzo
3176b6e66be2SVincenzo Maffione na = priv->np_na; /* we have a reference */
3177b6e66be2SVincenzo Maffione
3178c3e9b4dbSLuiz Otavio O Souza mbq_init(&q);
3179847bf383SLuigi Rizzo t = (cmd == NIOCTXSYNC ? NR_TX : NR_RX);
3180847bf383SLuigi Rizzo krings = NMR(na, t);
3181847bf383SLuigi Rizzo qfirst = priv->np_qfirst[t];
3182847bf383SLuigi Rizzo qlast = priv->np_qlast[t];
3183c3e9b4dbSLuiz Otavio O Souza sync_flags = priv->np_sync_flags;
318468b8534bSLuigi Rizzo
3185f0ea3689SLuigi Rizzo for (i = qfirst; i < qlast; i++) {
31862ff91c17SVincenzo Maffione struct netmap_kring *kring = krings[i];
318737e3a6d3SLuigi Rizzo struct netmap_ring *ring = kring->ring;
318837e3a6d3SLuigi Rizzo
318937e3a6d3SLuigi Rizzo if (unlikely(nm_kr_tryget(kring, 1, &error))) {
319037e3a6d3SLuigi Rizzo error = (error ? EIO : 0);
319137e3a6d3SLuigi Rizzo continue;
3192ce3ee1e7SLuigi Rizzo }
319337e3a6d3SLuigi Rizzo
319468b8534bSLuigi Rizzo if (cmd == NIOCTXSYNC) {
3195b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_TXSYNC)
3196b6e66be2SVincenzo Maffione nm_prinf("pre txsync ring %d cur %d hwcur %d",
319737e3a6d3SLuigi Rizzo i, ring->cur,
319868b8534bSLuigi Rizzo kring->nr_hwcur);
319937e3a6d3SLuigi Rizzo if (nm_txsync_prologue(kring, ring) >= kring->nkr_num_slots) {
320017885a7bSLuigi Rizzo netmap_ring_reinit(kring);
3201c3e9b4dbSLuiz Otavio O Souza } else if (kring->nm_sync(kring, sync_flags | NAF_FORCE_RECLAIM) == 0) {
320237e3a6d3SLuigi Rizzo nm_sync_finalize(kring);
320317885a7bSLuigi Rizzo }
3204b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_TXSYNC)
3205b6e66be2SVincenzo Maffione nm_prinf("post txsync ring %d cur %d hwcur %d",
320637e3a6d3SLuigi Rizzo i, ring->cur,
320768b8534bSLuigi Rizzo kring->nr_hwcur);
320868b8534bSLuigi Rizzo } else {
320937e3a6d3SLuigi Rizzo if (nm_rxsync_prologue(kring, ring) >= kring->nkr_num_slots) {
3210847bf383SLuigi Rizzo netmap_ring_reinit(kring);
3211c3e9b4dbSLuiz Otavio O Souza }
3212c3e9b4dbSLuiz Otavio O Souza if (nm_may_forward_up(kring)) {
3213c3e9b4dbSLuiz Otavio O Souza /* transparent forwarding, see netmap_poll() */
3214c3e9b4dbSLuiz Otavio O Souza netmap_grab_packets(kring, &q, netmap_fwd);
3215c3e9b4dbSLuiz Otavio O Souza }
3216c3e9b4dbSLuiz Otavio O Souza if (kring->nm_sync(kring, sync_flags | NAF_FORCE_READ) == 0) {
321737e3a6d3SLuigi Rizzo nm_sync_finalize(kring);
3218847bf383SLuigi Rizzo }
3219c3e9b4dbSLuiz Otavio O Souza ring_timestamp_set(ring);
322068b8534bSLuigi Rizzo }
3221ce3ee1e7SLuigi Rizzo nm_kr_put(kring);
322268b8534bSLuigi Rizzo }
322368b8534bSLuigi Rizzo
3224c3e9b4dbSLuiz Otavio O Souza if (mbq_peek(&q)) {
3225c3e9b4dbSLuiz Otavio O Souza netmap_send_up(na->ifp, &q);
3226c3e9b4dbSLuiz Otavio O Souza }
3227c3e9b4dbSLuiz Otavio O Souza
322868b8534bSLuigi Rizzo break;
322968b8534bSLuigi Rizzo }
3230f196ce38SLuigi Rizzo
32312ff91c17SVincenzo Maffione default: {
32322ff91c17SVincenzo Maffione return netmap_ioctl_legacy(priv, cmd, data, td);
32332ff91c17SVincenzo Maffione break;
32342ff91c17SVincenzo Maffione }
323568b8534bSLuigi Rizzo }
323668b8534bSLuigi Rizzo
323768b8534bSLuigi Rizzo return (error);
323868b8534bSLuigi Rizzo }
323968b8534bSLuigi Rizzo
32402ff91c17SVincenzo Maffione size_t
nmreq_size_by_type(uint16_t nr_reqtype)32412ff91c17SVincenzo Maffione nmreq_size_by_type(uint16_t nr_reqtype)
32422ff91c17SVincenzo Maffione {
32432ff91c17SVincenzo Maffione switch (nr_reqtype) {
32442ff91c17SVincenzo Maffione case NETMAP_REQ_REGISTER:
32452ff91c17SVincenzo Maffione return sizeof(struct nmreq_register);
32462ff91c17SVincenzo Maffione case NETMAP_REQ_PORT_INFO_GET:
32472ff91c17SVincenzo Maffione return sizeof(struct nmreq_port_info_get);
32482ff91c17SVincenzo Maffione case NETMAP_REQ_VALE_ATTACH:
32492ff91c17SVincenzo Maffione return sizeof(struct nmreq_vale_attach);
32502ff91c17SVincenzo Maffione case NETMAP_REQ_VALE_DETACH:
32512ff91c17SVincenzo Maffione return sizeof(struct nmreq_vale_detach);
32522ff91c17SVincenzo Maffione case NETMAP_REQ_VALE_LIST:
32532ff91c17SVincenzo Maffione return sizeof(struct nmreq_vale_list);
32542ff91c17SVincenzo Maffione case NETMAP_REQ_PORT_HDR_SET:
32552ff91c17SVincenzo Maffione case NETMAP_REQ_PORT_HDR_GET:
32562ff91c17SVincenzo Maffione return sizeof(struct nmreq_port_hdr);
32572ff91c17SVincenzo Maffione case NETMAP_REQ_VALE_NEWIF:
32582ff91c17SVincenzo Maffione return sizeof(struct nmreq_vale_newif);
32592ff91c17SVincenzo Maffione case NETMAP_REQ_VALE_DELIF:
3260b6e66be2SVincenzo Maffione case NETMAP_REQ_SYNC_KLOOP_STOP:
3261b6e66be2SVincenzo Maffione case NETMAP_REQ_CSB_ENABLE:
32622ff91c17SVincenzo Maffione return 0;
32632ff91c17SVincenzo Maffione case NETMAP_REQ_VALE_POLLING_ENABLE:
32642ff91c17SVincenzo Maffione case NETMAP_REQ_VALE_POLLING_DISABLE:
32652ff91c17SVincenzo Maffione return sizeof(struct nmreq_vale_polling);
32662ff91c17SVincenzo Maffione case NETMAP_REQ_POOLS_INFO_GET:
32672ff91c17SVincenzo Maffione return sizeof(struct nmreq_pools_info);
3268b6e66be2SVincenzo Maffione case NETMAP_REQ_SYNC_KLOOP_START:
3269b6e66be2SVincenzo Maffione return sizeof(struct nmreq_sync_kloop_start);
32702ff91c17SVincenzo Maffione }
32712ff91c17SVincenzo Maffione return 0;
32722ff91c17SVincenzo Maffione }
32732ff91c17SVincenzo Maffione
32742ff91c17SVincenzo Maffione static size_t
nmreq_opt_size_by_type(uint32_t nro_reqtype,uint64_t nro_size)3275b6e66be2SVincenzo Maffione nmreq_opt_size_by_type(uint32_t nro_reqtype, uint64_t nro_size)
32762ff91c17SVincenzo Maffione {
32772ff91c17SVincenzo Maffione size_t rv = sizeof(struct nmreq_option);
32782ff91c17SVincenzo Maffione #ifdef NETMAP_REQ_OPT_DEBUG
32792ff91c17SVincenzo Maffione if (nro_reqtype & NETMAP_REQ_OPT_DEBUG)
32802ff91c17SVincenzo Maffione return (nro_reqtype & ~NETMAP_REQ_OPT_DEBUG);
32812ff91c17SVincenzo Maffione #endif /* NETMAP_REQ_OPT_DEBUG */
32822ff91c17SVincenzo Maffione switch (nro_reqtype) {
32832ff91c17SVincenzo Maffione #ifdef WITH_EXTMEM
32842ff91c17SVincenzo Maffione case NETMAP_REQ_OPT_EXTMEM:
32852ff91c17SVincenzo Maffione rv = sizeof(struct nmreq_opt_extmem);
32862ff91c17SVincenzo Maffione break;
32872ff91c17SVincenzo Maffione #endif /* WITH_EXTMEM */
3288b6e66be2SVincenzo Maffione case NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS:
3289b6e66be2SVincenzo Maffione if (nro_size >= rv)
3290b6e66be2SVincenzo Maffione rv = nro_size;
3291b6e66be2SVincenzo Maffione break;
3292b6e66be2SVincenzo Maffione case NETMAP_REQ_OPT_CSB:
3293b6e66be2SVincenzo Maffione rv = sizeof(struct nmreq_opt_csb);
3294b6e66be2SVincenzo Maffione break;
32955faab778SVincenzo Maffione case NETMAP_REQ_OPT_SYNC_KLOOP_MODE:
32965faab778SVincenzo Maffione rv = sizeof(struct nmreq_opt_sync_kloop_mode);
32975faab778SVincenzo Maffione break;
3298a6d768d8SVincenzo Maffione case NETMAP_REQ_OPT_OFFSETS:
3299a6d768d8SVincenzo Maffione rv = sizeof(struct nmreq_opt_offsets);
3300a6d768d8SVincenzo Maffione break;
33012ff91c17SVincenzo Maffione }
33022ff91c17SVincenzo Maffione /* subtract the common header */
33032ff91c17SVincenzo Maffione return rv - sizeof(struct nmreq_option);
33042ff91c17SVincenzo Maffione }
33052ff91c17SVincenzo Maffione
3306253b2ec1SVincenzo Maffione /*
3307253b2ec1SVincenzo Maffione * nmreq_copyin: create an in-kernel version of the request.
3308253b2ec1SVincenzo Maffione *
3309253b2ec1SVincenzo Maffione * We build the following data structure:
3310253b2ec1SVincenzo Maffione *
3311253b2ec1SVincenzo Maffione * hdr -> +-------+ buf
3312253b2ec1SVincenzo Maffione * | | +---------------+
3313253b2ec1SVincenzo Maffione * +-------+ |usr body ptr |
3314253b2ec1SVincenzo Maffione * |options|-. +---------------+
3315253b2ec1SVincenzo Maffione * +-------+ | |usr options ptr|
3316253b2ec1SVincenzo Maffione * |body |--------->+---------------+
3317253b2ec1SVincenzo Maffione * +-------+ | | |
3318253b2ec1SVincenzo Maffione * | | copy of body |
3319253b2ec1SVincenzo Maffione * | | |
3320253b2ec1SVincenzo Maffione * | +---------------+
3321253b2ec1SVincenzo Maffione * | | NULL |
3322253b2ec1SVincenzo Maffione * | +---------------+
3323253b2ec1SVincenzo Maffione * | .---| |\
3324253b2ec1SVincenzo Maffione * | | +---------------+ |
3325253b2ec1SVincenzo Maffione * | .------| | |
3326253b2ec1SVincenzo Maffione * | | | +---------------+ \ option table
3327253b2ec1SVincenzo Maffione * | | | | ... | / indexed by option
3328253b2ec1SVincenzo Maffione * | | | +---------------+ | type
3329253b2ec1SVincenzo Maffione * | | | | | |
3330253b2ec1SVincenzo Maffione * | | | +---------------+/
3331253b2ec1SVincenzo Maffione * | | | |usr next ptr 1 |
3332253b2ec1SVincenzo Maffione * `-|----->+---------------+
3333253b2ec1SVincenzo Maffione * | | | copy of opt 1 |
3334253b2ec1SVincenzo Maffione * | | | |
3335253b2ec1SVincenzo Maffione * | | .-| nro_next |
3336253b2ec1SVincenzo Maffione * | | | +---------------+
3337253b2ec1SVincenzo Maffione * | | | |usr next ptr 2 |
3338253b2ec1SVincenzo Maffione * | `-`>+---------------+
3339253b2ec1SVincenzo Maffione * | | copy of opt 2 |
3340253b2ec1SVincenzo Maffione * | | |
3341253b2ec1SVincenzo Maffione * | .-| nro_next |
3342253b2ec1SVincenzo Maffione * | | +---------------+
3343253b2ec1SVincenzo Maffione * | | | |
3344253b2ec1SVincenzo Maffione * ~ ~ ~ ... ~
3345253b2ec1SVincenzo Maffione * | .-| |
3346253b2ec1SVincenzo Maffione * `----->+---------------+
3347253b2ec1SVincenzo Maffione * | |usr next ptr n |
3348253b2ec1SVincenzo Maffione * `>+---------------+
3349253b2ec1SVincenzo Maffione * | copy of opt n |
3350253b2ec1SVincenzo Maffione * | |
3351253b2ec1SVincenzo Maffione * | nro_next(NULL)|
3352253b2ec1SVincenzo Maffione * +---------------+
3353253b2ec1SVincenzo Maffione *
3354253b2ec1SVincenzo Maffione * The options and body fields of the hdr structure are overwritten
3355253b2ec1SVincenzo Maffione * with in-kernel valid pointers inside the buf. The original user
3356253b2ec1SVincenzo Maffione * pointers are saved in the buf and restored on copyout.
3357253b2ec1SVincenzo Maffione * The list of options is copied and the pointers adjusted. The
3358253b2ec1SVincenzo Maffione * original pointers are saved before the option they belonged.
3359253b2ec1SVincenzo Maffione *
336045c67e8fSVincenzo Maffione * The option table has an entry for every available option. Entries
3361253b2ec1SVincenzo Maffione * for options that have not been passed contain NULL.
3362253b2ec1SVincenzo Maffione *
3363253b2ec1SVincenzo Maffione */
3364253b2ec1SVincenzo Maffione
33652ff91c17SVincenzo Maffione int
nmreq_copyin(struct nmreq_header * hdr,int nr_body_is_user)33662ff91c17SVincenzo Maffione nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
33672ff91c17SVincenzo Maffione {
336839372991SVincenzo Maffione size_t rqsz, optsz, bufsz;
3369253b2ec1SVincenzo Maffione int error = 0;
33702ff91c17SVincenzo Maffione char *ker = NULL, *p;
3371e2a431a0SVincenzo Maffione struct nmreq_option **next, *src, **opt_tab, *opt;
33722ff91c17SVincenzo Maffione uint64_t *ptrs;
33732ff91c17SVincenzo Maffione
3374b6e66be2SVincenzo Maffione if (hdr->nr_reserved) {
3375b6e66be2SVincenzo Maffione if (netmap_verbose)
3376b6e66be2SVincenzo Maffione nm_prerr("nr_reserved must be zero");
33772ff91c17SVincenzo Maffione return EINVAL;
3378b6e66be2SVincenzo Maffione }
33792ff91c17SVincenzo Maffione
33802ff91c17SVincenzo Maffione if (!nr_body_is_user)
33812ff91c17SVincenzo Maffione return 0;
33822ff91c17SVincenzo Maffione
33832ff91c17SVincenzo Maffione hdr->nr_reserved = nr_body_is_user;
33842ff91c17SVincenzo Maffione
33852ff91c17SVincenzo Maffione /* compute the total size of the buffer */
33862ff91c17SVincenzo Maffione rqsz = nmreq_size_by_type(hdr->nr_reqtype);
33872ff91c17SVincenzo Maffione if (rqsz > NETMAP_REQ_MAXSIZE) {
33882ff91c17SVincenzo Maffione error = EMSGSIZE;
33892ff91c17SVincenzo Maffione goto out_err;
33902ff91c17SVincenzo Maffione }
3391cfa866f6SMatt Macy if ((rqsz && hdr->nr_body == (uintptr_t)NULL) ||
3392cfa866f6SMatt Macy (!rqsz && hdr->nr_body != (uintptr_t)NULL)) {
33932ff91c17SVincenzo Maffione /* Request body expected, but not found; or
33942ff91c17SVincenzo Maffione * request body found but unexpected. */
3395b6e66be2SVincenzo Maffione if (netmap_verbose)
3396b6e66be2SVincenzo Maffione nm_prerr("nr_body expected but not found, or vice versa");
33972ff91c17SVincenzo Maffione error = EINVAL;
33982ff91c17SVincenzo Maffione goto out_err;
33992ff91c17SVincenzo Maffione }
34002ff91c17SVincenzo Maffione
340139372991SVincenzo Maffione /*
340239372991SVincenzo Maffione * The buffer size must be large enough to store the request body,
340339372991SVincenzo Maffione * all the possible options and the additional user pointers
340439372991SVincenzo Maffione * (2+NETMAP_REQ_OPT_MAX). Note that the maximum size of body plus
340539372991SVincenzo Maffione * options can not exceed NETMAP_REQ_MAXSIZE;
3406253b2ec1SVincenzo Maffione */
340739372991SVincenzo Maffione bufsz = (2 + NETMAP_REQ_OPT_MAX) * sizeof(void *) + NETMAP_REQ_MAXSIZE +
340839372991SVincenzo Maffione NETMAP_REQ_OPT_MAX * sizeof(opt_tab);
34092ff91c17SVincenzo Maffione
34102ff91c17SVincenzo Maffione ker = nm_os_malloc(bufsz);
34112ff91c17SVincenzo Maffione if (ker == NULL) {
34122ff91c17SVincenzo Maffione error = ENOMEM;
34132ff91c17SVincenzo Maffione goto out_err;
34142ff91c17SVincenzo Maffione }
3415253b2ec1SVincenzo Maffione p = ker; /* write pointer into the buffer */
34162ff91c17SVincenzo Maffione
34172ff91c17SVincenzo Maffione /* make a copy of the user pointers */
34182ff91c17SVincenzo Maffione ptrs = (uint64_t*)p;
34192ff91c17SVincenzo Maffione *ptrs++ = hdr->nr_body;
34202ff91c17SVincenzo Maffione *ptrs++ = hdr->nr_options;
34212ff91c17SVincenzo Maffione p = (char *)ptrs;
34222ff91c17SVincenzo Maffione /* overwrite the user pointer with the in-kernel one */
3423cfa866f6SMatt Macy hdr->nr_body = (uintptr_t)p;
3424e2a431a0SVincenzo Maffione /* prepare the options-list pointers and temporarily terminate
3425e2a431a0SVincenzo Maffione * the in-kernel list, in case we have to jump to out_restore
3426e2a431a0SVincenzo Maffione */
3427e2a431a0SVincenzo Maffione next = (struct nmreq_option **)&hdr->nr_options;
3428e2a431a0SVincenzo Maffione src = *next;
3429e2a431a0SVincenzo Maffione hdr->nr_options = 0;
3430e2a431a0SVincenzo Maffione
3431e2a431a0SVincenzo Maffione /* copy the body */
3432e2a431a0SVincenzo Maffione error = copyin(*(void **)ker, p, rqsz);
3433e2a431a0SVincenzo Maffione if (error)
3434e2a431a0SVincenzo Maffione goto out_restore;
34352ff91c17SVincenzo Maffione p += rqsz;
3436253b2ec1SVincenzo Maffione /* start of the options table */
3437253b2ec1SVincenzo Maffione opt_tab = (struct nmreq_option **)p;
3438253b2ec1SVincenzo Maffione p += sizeof(opt_tab) * NETMAP_REQ_OPT_MAX;
34392ff91c17SVincenzo Maffione
34402ff91c17SVincenzo Maffione /* copy the options */
34412ff91c17SVincenzo Maffione while (src) {
3442e2a431a0SVincenzo Maffione struct nmreq_option *nsrc;
34432ff91c17SVincenzo Maffione
3444e2a431a0SVincenzo Maffione if (p - ker + sizeof(uint64_t*) + sizeof(*src) > bufsz) {
3445e2a431a0SVincenzo Maffione error = EMSGSIZE;
3446e2a431a0SVincenzo Maffione /* there might be a loop in the list: don't try to
3447e2a431a0SVincenzo Maffione * copyout the options
3448e2a431a0SVincenzo Maffione */
3449e2a431a0SVincenzo Maffione hdr->nr_options = 0;
3450e2a431a0SVincenzo Maffione goto out_restore;
3451e2a431a0SVincenzo Maffione }
34522ff91c17SVincenzo Maffione /* copy the option header */
34532ff91c17SVincenzo Maffione ptrs = (uint64_t *)p;
34542ff91c17SVincenzo Maffione opt = (struct nmreq_option *)(ptrs + 1);
34552ff91c17SVincenzo Maffione error = copyin(src, opt, sizeof(*src));
34562ff91c17SVincenzo Maffione if (error)
34572ff91c17SVincenzo Maffione goto out_restore;
345839372991SVincenzo Maffione rqsz += sizeof(*src);
3459e2a431a0SVincenzo Maffione p = (char *)(opt + 1);
3460e2a431a0SVincenzo Maffione
34612ff91c17SVincenzo Maffione /* make a copy of the user next pointer */
34622ff91c17SVincenzo Maffione *ptrs = opt->nro_next;
3463e2a431a0SVincenzo Maffione /* append the option to the in-kernel list */
34642ff91c17SVincenzo Maffione *next = opt;
3465e2a431a0SVincenzo Maffione /* temporarily teminate the in-kernel list, in case we have to
3466e2a431a0SVincenzo Maffione * jump to out_restore
34672ff91c17SVincenzo Maffione */
3468e2a431a0SVincenzo Maffione nsrc = (struct nmreq_option *)opt->nro_next;
3469e2a431a0SVincenzo Maffione opt->nro_next = 0;
3470e2a431a0SVincenzo Maffione
3471e2a431a0SVincenzo Maffione opt->nro_status = 0;
34722ff91c17SVincenzo Maffione
3473253b2ec1SVincenzo Maffione /* check for invalid types */
3474253b2ec1SVincenzo Maffione if (opt->nro_reqtype < 1) {
3475253b2ec1SVincenzo Maffione if (netmap_verbose)
3476253b2ec1SVincenzo Maffione nm_prinf("invalid option type: %u", opt->nro_reqtype);
3477253b2ec1SVincenzo Maffione opt->nro_status = EINVAL;
3478253b2ec1SVincenzo Maffione error = EINVAL;
3479e2a431a0SVincenzo Maffione goto out_restore;
3480253b2ec1SVincenzo Maffione }
3481253b2ec1SVincenzo Maffione
3482253b2ec1SVincenzo Maffione if (opt->nro_reqtype >= NETMAP_REQ_OPT_MAX) {
3483e2a431a0SVincenzo Maffione /* opt->nro_status will be set to EOPNOTSUPP */
3484253b2ec1SVincenzo Maffione goto next;
3485253b2ec1SVincenzo Maffione }
3486253b2ec1SVincenzo Maffione
3487253b2ec1SVincenzo Maffione /* if the type is valid, index the option in the table
3488253b2ec1SVincenzo Maffione * unless it is a duplicate.
3489253b2ec1SVincenzo Maffione */
3490253b2ec1SVincenzo Maffione if (opt_tab[opt->nro_reqtype] != NULL) {
3491253b2ec1SVincenzo Maffione if (netmap_verbose)
3492253b2ec1SVincenzo Maffione nm_prinf("duplicate option: %u", opt->nro_reqtype);
3493253b2ec1SVincenzo Maffione opt->nro_status = EINVAL;
3494253b2ec1SVincenzo Maffione opt_tab[opt->nro_reqtype]->nro_status = EINVAL;
3495253b2ec1SVincenzo Maffione error = EINVAL;
3496e2a431a0SVincenzo Maffione goto out_restore;
3497253b2ec1SVincenzo Maffione }
3498253b2ec1SVincenzo Maffione opt_tab[opt->nro_reqtype] = opt;
3499253b2ec1SVincenzo Maffione
35002ff91c17SVincenzo Maffione /* copy the option body */
3501b6e66be2SVincenzo Maffione optsz = nmreq_opt_size_by_type(opt->nro_reqtype,
3502b6e66be2SVincenzo Maffione opt->nro_size);
350339372991SVincenzo Maffione /* check optsz and nro_size to avoid for possible integer overflows of rqsz */
350439372991SVincenzo Maffione if ((optsz > NETMAP_REQ_MAXSIZE) || (opt->nro_size > NETMAP_REQ_MAXSIZE)
350539372991SVincenzo Maffione || (rqsz + optsz > NETMAP_REQ_MAXSIZE)
350639372991SVincenzo Maffione || (optsz > 0 && rqsz + optsz <= rqsz)) {
350739372991SVincenzo Maffione error = EMSGSIZE;
350839372991SVincenzo Maffione goto out_restore;
350939372991SVincenzo Maffione }
351039372991SVincenzo Maffione rqsz += optsz;
35112ff91c17SVincenzo Maffione if (optsz) {
35122ff91c17SVincenzo Maffione /* the option body follows the option header */
35132ff91c17SVincenzo Maffione error = copyin(src + 1, p, optsz);
35142ff91c17SVincenzo Maffione if (error)
35152ff91c17SVincenzo Maffione goto out_restore;
35162ff91c17SVincenzo Maffione p += optsz;
35172ff91c17SVincenzo Maffione }
35182ff91c17SVincenzo Maffione
3519253b2ec1SVincenzo Maffione next:
35202ff91c17SVincenzo Maffione /* move to next option */
35212ff91c17SVincenzo Maffione next = (struct nmreq_option **)&opt->nro_next;
3522e2a431a0SVincenzo Maffione src = nsrc;
35232ff91c17SVincenzo Maffione }
3524e2a431a0SVincenzo Maffione
3525e2a431a0SVincenzo Maffione /* initialize all the options as not supported. Recognized options
3526e2a431a0SVincenzo Maffione * will update their field.
3527e2a431a0SVincenzo Maffione */
3528e2a431a0SVincenzo Maffione for (src = (struct nmreq_option *)hdr->nr_options; src;
3529e2a431a0SVincenzo Maffione src = (struct nmreq_option *)src->nro_next) {
3530e2a431a0SVincenzo Maffione src->nro_status = EOPNOTSUPP;
3531e2a431a0SVincenzo Maffione }
3532e2a431a0SVincenzo Maffione return 0;
35332ff91c17SVincenzo Maffione
35342ff91c17SVincenzo Maffione out_restore:
3535e2a431a0SVincenzo Maffione nmreq_copyout(hdr, error);
35362ff91c17SVincenzo Maffione out_err:
35372ff91c17SVincenzo Maffione return error;
35382ff91c17SVincenzo Maffione }
35392ff91c17SVincenzo Maffione
35402ff91c17SVincenzo Maffione static int
nmreq_copyout(struct nmreq_header * hdr,int rerror)35412ff91c17SVincenzo Maffione nmreq_copyout(struct nmreq_header *hdr, int rerror)
35422ff91c17SVincenzo Maffione {
35432ff91c17SVincenzo Maffione struct nmreq_option *src, *dst;
3544cfa866f6SMatt Macy void *ker = (void *)(uintptr_t)hdr->nr_body, *bufstart;
35452ff91c17SVincenzo Maffione uint64_t *ptrs;
35462ff91c17SVincenzo Maffione size_t bodysz;
35472ff91c17SVincenzo Maffione int error;
35482ff91c17SVincenzo Maffione
35492ff91c17SVincenzo Maffione if (!hdr->nr_reserved)
35502ff91c17SVincenzo Maffione return rerror;
35512ff91c17SVincenzo Maffione
35522ff91c17SVincenzo Maffione /* restore the user pointers in the header */
35532ff91c17SVincenzo Maffione ptrs = (uint64_t *)ker - 2;
35542ff91c17SVincenzo Maffione bufstart = ptrs;
35552ff91c17SVincenzo Maffione hdr->nr_body = *ptrs++;
3556cfa866f6SMatt Macy src = (struct nmreq_option *)(uintptr_t)hdr->nr_options;
35572ff91c17SVincenzo Maffione hdr->nr_options = *ptrs;
35582ff91c17SVincenzo Maffione
35592ff91c17SVincenzo Maffione if (!rerror) {
35602ff91c17SVincenzo Maffione /* copy the body */
35612ff91c17SVincenzo Maffione bodysz = nmreq_size_by_type(hdr->nr_reqtype);
3562cfa866f6SMatt Macy error = copyout(ker, (void *)(uintptr_t)hdr->nr_body, bodysz);
35632ff91c17SVincenzo Maffione if (error) {
35642ff91c17SVincenzo Maffione rerror = error;
35652ff91c17SVincenzo Maffione goto out;
35662ff91c17SVincenzo Maffione }
35672ff91c17SVincenzo Maffione }
35682ff91c17SVincenzo Maffione
35692ff91c17SVincenzo Maffione /* copy the options */
3570cfa866f6SMatt Macy dst = (struct nmreq_option *)(uintptr_t)hdr->nr_options;
35712ff91c17SVincenzo Maffione while (src) {
35722ff91c17SVincenzo Maffione size_t optsz;
35732ff91c17SVincenzo Maffione uint64_t next;
35742ff91c17SVincenzo Maffione
35752ff91c17SVincenzo Maffione /* restore the user pointer */
35762ff91c17SVincenzo Maffione next = src->nro_next;
35772ff91c17SVincenzo Maffione ptrs = (uint64_t *)src - 1;
35782ff91c17SVincenzo Maffione src->nro_next = *ptrs;
35792ff91c17SVincenzo Maffione
35802ff91c17SVincenzo Maffione /* always copy the option header */
35812ff91c17SVincenzo Maffione error = copyout(src, dst, sizeof(*src));
35822ff91c17SVincenzo Maffione if (error) {
35832ff91c17SVincenzo Maffione rerror = error;
35842ff91c17SVincenzo Maffione goto out;
35852ff91c17SVincenzo Maffione }
35862ff91c17SVincenzo Maffione
35872ff91c17SVincenzo Maffione /* copy the option body only if there was no error */
35882ff91c17SVincenzo Maffione if (!rerror && !src->nro_status) {
3589b6e66be2SVincenzo Maffione optsz = nmreq_opt_size_by_type(src->nro_reqtype,
3590b6e66be2SVincenzo Maffione src->nro_size);
35912ff91c17SVincenzo Maffione if (optsz) {
35922ff91c17SVincenzo Maffione error = copyout(src + 1, dst + 1, optsz);
35932ff91c17SVincenzo Maffione if (error) {
35942ff91c17SVincenzo Maffione rerror = error;
35952ff91c17SVincenzo Maffione goto out;
35962ff91c17SVincenzo Maffione }
35972ff91c17SVincenzo Maffione }
35982ff91c17SVincenzo Maffione }
3599cfa866f6SMatt Macy src = (struct nmreq_option *)(uintptr_t)next;
3600cfa866f6SMatt Macy dst = (struct nmreq_option *)(uintptr_t)*ptrs;
36012ff91c17SVincenzo Maffione }
36022ff91c17SVincenzo Maffione
36032ff91c17SVincenzo Maffione
36042ff91c17SVincenzo Maffione out:
36052ff91c17SVincenzo Maffione hdr->nr_reserved = 0;
36062ff91c17SVincenzo Maffione nm_os_free(bufstart);
36072ff91c17SVincenzo Maffione return rerror;
36082ff91c17SVincenzo Maffione }
36092ff91c17SVincenzo Maffione
36102ff91c17SVincenzo Maffione struct nmreq_option *
nmreq_getoption(struct nmreq_header * hdr,uint16_t reqtype)3611253b2ec1SVincenzo Maffione nmreq_getoption(struct nmreq_header *hdr, uint16_t reqtype)
36122ff91c17SVincenzo Maffione {
3613253b2ec1SVincenzo Maffione struct nmreq_option **opt_tab;
3614253b2ec1SVincenzo Maffione
3615253b2ec1SVincenzo Maffione if (!hdr->nr_options)
36162ff91c17SVincenzo Maffione return NULL;
36172ff91c17SVincenzo Maffione
3618760fa2abSVincenzo Maffione opt_tab = (struct nmreq_option **)((uintptr_t)hdr->nr_options) -
3619760fa2abSVincenzo Maffione (NETMAP_REQ_OPT_MAX + 1);
3620253b2ec1SVincenzo Maffione return opt_tab[reqtype];
36212ff91c17SVincenzo Maffione }
36222ff91c17SVincenzo Maffione
36232ff91c17SVincenzo Maffione static int
nmreq_checkoptions(struct nmreq_header * hdr)36242ff91c17SVincenzo Maffione nmreq_checkoptions(struct nmreq_header *hdr)
36252ff91c17SVincenzo Maffione {
36262ff91c17SVincenzo Maffione struct nmreq_option *opt;
36272ff91c17SVincenzo Maffione /* return error if there is still any option
36282ff91c17SVincenzo Maffione * marked as not supported
36292ff91c17SVincenzo Maffione */
36302ff91c17SVincenzo Maffione
3631cfa866f6SMatt Macy for (opt = (struct nmreq_option *)(uintptr_t)hdr->nr_options; opt;
3632cfa866f6SMatt Macy opt = (struct nmreq_option *)(uintptr_t)opt->nro_next)
36332ff91c17SVincenzo Maffione if (opt->nro_status == EOPNOTSUPP)
36342ff91c17SVincenzo Maffione return EOPNOTSUPP;
36352ff91c17SVincenzo Maffione
36362ff91c17SVincenzo Maffione return 0;
36372ff91c17SVincenzo Maffione }
363868b8534bSLuigi Rizzo
363968b8534bSLuigi Rizzo /*
364068b8534bSLuigi Rizzo * select(2) and poll(2) handlers for the "netmap" device.
364168b8534bSLuigi Rizzo *
364268b8534bSLuigi Rizzo * Can be called for one or more queues.
364368b8534bSLuigi Rizzo * Return true the event mask corresponding to ready events.
36448c9874f5SVincenzo Maffione * If there are no ready events (and 'sr' is not NULL), do a
36458c9874f5SVincenzo Maffione * selrecord on either individual selinfo or on the global one.
364668b8534bSLuigi Rizzo * Device-dependent parts (locking and sync of tx/rx rings)
364768b8534bSLuigi Rizzo * are done through callbacks.
3648f196ce38SLuigi Rizzo *
364901c7d25fSLuigi Rizzo * On linux, arguments are really pwait, the poll table, and 'td' is struct file *
365001c7d25fSLuigi Rizzo * The first one is remapped to pwait as selrecord() uses the name as an
365101c7d25fSLuigi Rizzo * hidden argument.
365268b8534bSLuigi Rizzo */
3653f9790aebSLuigi Rizzo int
netmap_poll(struct netmap_priv_d * priv,int events,NM_SELRECORD_T * sr)365437e3a6d3SLuigi Rizzo netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr)
365568b8534bSLuigi Rizzo {
365668b8534bSLuigi Rizzo struct netmap_adapter *na;
365768b8534bSLuigi Rizzo struct netmap_kring *kring;
365837e3a6d3SLuigi Rizzo struct netmap_ring *ring;
3659b6e66be2SVincenzo Maffione u_int i, want[NR_TXRX], revents = 0;
3660b6e66be2SVincenzo Maffione NM_SELINFO_T *si[NR_TXRX];
3661847bf383SLuigi Rizzo #define want_tx want[NR_TX]
3662847bf383SLuigi Rizzo #define want_rx want[NR_RX]
3663c3e9b4dbSLuiz Otavio O Souza struct mbq q; /* packets from RX hw queues to host stack */
366401c7d25fSLuigi Rizzo
3665f9790aebSLuigi Rizzo /*
3666f9790aebSLuigi Rizzo * In order to avoid nested locks, we need to "double check"
3667f9790aebSLuigi Rizzo * txsync and rxsync if we decide to do a selrecord().
3668f9790aebSLuigi Rizzo * retry_tx (and retry_rx, later) prevent looping forever.
3669f9790aebSLuigi Rizzo */
367017885a7bSLuigi Rizzo int retry_tx = 1, retry_rx = 1;
3671ce3ee1e7SLuigi Rizzo
3672c3e9b4dbSLuiz Otavio O Souza /* Transparent mode: send_down is 1 if we have found some
3673c3e9b4dbSLuiz Otavio O Souza * packets to forward (host RX ring --> NIC) during the rx
3674c3e9b4dbSLuiz Otavio O Souza * scan and we have not sent them down to the NIC yet.
3675c3e9b4dbSLuiz Otavio O Souza * Transparent mode requires to bind all rings to a single
3676c3e9b4dbSLuiz Otavio O Souza * file descriptor.
3677f0ea3689SLuigi Rizzo */
367837e3a6d3SLuigi Rizzo int send_down = 0;
3679c3e9b4dbSLuiz Otavio O Souza int sync_flags = priv->np_sync_flags;
368037e3a6d3SLuigi Rizzo
368137e3a6d3SLuigi Rizzo mbq_init(&q);
368268b8534bSLuigi Rizzo
3683b6e66be2SVincenzo Maffione if (unlikely(priv->np_nifp == NULL)) {
36848241616dSLuigi Rizzo return POLLERR;
36858241616dSLuigi Rizzo }
3686847bf383SLuigi Rizzo mb(); /* make sure following reads are not from cache */
36878241616dSLuigi Rizzo
3688f9790aebSLuigi Rizzo na = priv->np_na;
3689f9790aebSLuigi Rizzo
3690b6e66be2SVincenzo Maffione if (unlikely(!nm_netmap_on(na)))
369168b8534bSLuigi Rizzo return POLLERR;
369268b8534bSLuigi Rizzo
3693b6e66be2SVincenzo Maffione if (unlikely(priv->np_csb_atok_base)) {
3694b6e66be2SVincenzo Maffione nm_prerr("Invalid poll in CSB mode");
3695b6e66be2SVincenzo Maffione return POLLERR;
3696b6e66be2SVincenzo Maffione }
3697b6e66be2SVincenzo Maffione
3698b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_ON)
3699b6e66be2SVincenzo Maffione nm_prinf("device %s events 0x%x", na->name, events);
370068b8534bSLuigi Rizzo want_tx = events & (POLLOUT | POLLWRNORM);
370168b8534bSLuigi Rizzo want_rx = events & (POLLIN | POLLRDNORM);
370268b8534bSLuigi Rizzo
370368b8534bSLuigi Rizzo /*
3704b6e66be2SVincenzo Maffione * If the card has more than one queue AND the file descriptor is
3705b6e66be2SVincenzo Maffione * bound to all of them, we sleep on the "global" selinfo, otherwise
3706b6e66be2SVincenzo Maffione * we sleep on individual selinfo (FreeBSD only allows two selinfo's
3707b6e66be2SVincenzo Maffione * per file descriptor).
3708ce3ee1e7SLuigi Rizzo * The interrupt routine in the driver wake one or the other
3709ce3ee1e7SLuigi Rizzo * (or both) depending on which clients are active.
371068b8534bSLuigi Rizzo *
371168b8534bSLuigi Rizzo * rxsync() is only called if we run out of buffers on a POLLIN.
371268b8534bSLuigi Rizzo * txsync() is called if we run out of buffers on POLLOUT, or
371368b8534bSLuigi Rizzo * there are pending packets to send. The latter can be disabled
371468b8534bSLuigi Rizzo * passing NETMAP_NO_TX_POLL in the NIOCREG call.
371568b8534bSLuigi Rizzo */
37165faab778SVincenzo Maffione si[NR_RX] = priv->np_si[NR_RX];
37175faab778SVincenzo Maffione si[NR_TX] = priv->np_si[NR_TX];
371864ae02c3SLuigi Rizzo
37194f80b14cSVincenzo Maffione #ifdef __FreeBSD__
372068b8534bSLuigi Rizzo /*
3721f9790aebSLuigi Rizzo * We start with a lock free round which is cheap if we have
3722f9790aebSLuigi Rizzo * slots available. If this fails, then lock and call the sync
37234f80b14cSVincenzo Maffione * routines. We can't do this on Linux, as the contract says
37244f80b14cSVincenzo Maffione * that we must call nm_os_selrecord() unconditionally.
372568b8534bSLuigi Rizzo */
372637e3a6d3SLuigi Rizzo if (want_tx) {
372758e18542SVincenzo Maffione const enum txrx t = NR_TX;
372858e18542SVincenzo Maffione for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
37292ff91c17SVincenzo Maffione kring = NMR(na, t)[i];
373058e18542SVincenzo Maffione if (kring->ring->cur != kring->ring->tail) {
373158e18542SVincenzo Maffione /* Some unseen TX space is available, so what
373258e18542SVincenzo Maffione * we don't need to run txsync. */
373337e3a6d3SLuigi Rizzo revents |= want[t];
373458e18542SVincenzo Maffione want[t] = 0;
373558e18542SVincenzo Maffione break;
373637e3a6d3SLuigi Rizzo }
373737e3a6d3SLuigi Rizzo }
373837e3a6d3SLuigi Rizzo }
373937e3a6d3SLuigi Rizzo if (want_rx) {
374058e18542SVincenzo Maffione const enum txrx t = NR_RX;
3741e1ed1fbdSVincenzo Maffione int rxsync_needed = 0;
3742e1ed1fbdSVincenzo Maffione
374337e3a6d3SLuigi Rizzo for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) {
37442ff91c17SVincenzo Maffione kring = NMR(na, t)[i];
374558e18542SVincenzo Maffione if (kring->ring->cur == kring->ring->tail
374658e18542SVincenzo Maffione || kring->rhead != kring->ring->head) {
374758e18542SVincenzo Maffione /* There are no unseen packets on this ring,
374858e18542SVincenzo Maffione * or there are some buffers to be returned
374958e18542SVincenzo Maffione * to the netmap port. We therefore go ahead
375058e18542SVincenzo Maffione * and run rxsync. */
3751e1ed1fbdSVincenzo Maffione rxsync_needed = 1;
3752e1ed1fbdSVincenzo Maffione break;
375337e3a6d3SLuigi Rizzo }
375437e3a6d3SLuigi Rizzo }
375558e18542SVincenzo Maffione if (!rxsync_needed) {
375658e18542SVincenzo Maffione revents |= want_rx;
375758e18542SVincenzo Maffione want_rx = 0;
375858e18542SVincenzo Maffione }
375937e3a6d3SLuigi Rizzo }
37604f80b14cSVincenzo Maffione #endif
37614f80b14cSVincenzo Maffione
37624f80b14cSVincenzo Maffione #ifdef linux
37634f80b14cSVincenzo Maffione /* The selrecord must be unconditional on linux. */
3764b6e66be2SVincenzo Maffione nm_os_selrecord(sr, si[NR_RX]);
3765b6e66be2SVincenzo Maffione nm_os_selrecord(sr, si[NR_TX]);
37664f80b14cSVincenzo Maffione #endif /* linux */
376768b8534bSLuigi Rizzo
376868b8534bSLuigi Rizzo /*
376917885a7bSLuigi Rizzo * If we want to push packets out (priv->np_txpoll) or
377017885a7bSLuigi Rizzo * want_tx is still set, we must issue txsync calls
377117885a7bSLuigi Rizzo * (on all rings, to avoid that the tx rings stall).
3772f9790aebSLuigi Rizzo * Fortunately, normal tx mode has np_txpoll set.
377368b8534bSLuigi Rizzo */
377468b8534bSLuigi Rizzo if (priv->np_txpoll || want_tx) {
377517885a7bSLuigi Rizzo /*
377617885a7bSLuigi Rizzo * The first round checks if anyone is ready, if not
377717885a7bSLuigi Rizzo * do a selrecord and another round to handle races.
377817885a7bSLuigi Rizzo * want_tx goes to 0 if any space is found, and is
377917885a7bSLuigi Rizzo * used to skip rings with no pending transmissions.
3780ce3ee1e7SLuigi Rizzo */
3781091fd0abSLuigi Rizzo flush_tx:
378237e3a6d3SLuigi Rizzo for (i = priv->np_qfirst[NR_TX]; i < priv->np_qlast[NR_TX]; i++) {
378317885a7bSLuigi Rizzo int found = 0;
378417885a7bSLuigi Rizzo
37852ff91c17SVincenzo Maffione kring = na->tx_rings[i];
378637e3a6d3SLuigi Rizzo ring = kring->ring;
378737e3a6d3SLuigi Rizzo
37884f80b14cSVincenzo Maffione /*
37894f80b14cSVincenzo Maffione * Don't try to txsync this TX ring if we already found some
37904f80b14cSVincenzo Maffione * space in some of the TX rings (want_tx == 0) and there are no
37914f80b14cSVincenzo Maffione * TX slots in this ring that need to be flushed to the NIC
37922ff91c17SVincenzo Maffione * (head == hwcur).
37934f80b14cSVincenzo Maffione */
37942ff91c17SVincenzo Maffione if (!send_down && !want_tx && ring->head == kring->nr_hwcur)
379568b8534bSLuigi Rizzo continue;
379637e3a6d3SLuigi Rizzo
379737e3a6d3SLuigi Rizzo if (nm_kr_tryget(kring, 1, &revents))
379817885a7bSLuigi Rizzo continue;
379937e3a6d3SLuigi Rizzo
380037e3a6d3SLuigi Rizzo if (nm_txsync_prologue(kring, ring) >= kring->nkr_num_slots) {
380117885a7bSLuigi Rizzo netmap_ring_reinit(kring);
380217885a7bSLuigi Rizzo revents |= POLLERR;
380317885a7bSLuigi Rizzo } else {
3804c3e9b4dbSLuiz Otavio O Souza if (kring->nm_sync(kring, sync_flags))
380568b8534bSLuigi Rizzo revents |= POLLERR;
3806847bf383SLuigi Rizzo else
380737e3a6d3SLuigi Rizzo nm_sync_finalize(kring);
380817885a7bSLuigi Rizzo }
380968b8534bSLuigi Rizzo
381017885a7bSLuigi Rizzo /*
381117885a7bSLuigi Rizzo * If we found new slots, notify potential
381217885a7bSLuigi Rizzo * listeners on the same ring.
381317885a7bSLuigi Rizzo * Since we just did a txsync, look at the copies
381417885a7bSLuigi Rizzo * of cur,tail in the kring.
3815f9790aebSLuigi Rizzo */
381617885a7bSLuigi Rizzo found = kring->rcur != kring->rtail;
381717885a7bSLuigi Rizzo nm_kr_put(kring);
381817885a7bSLuigi Rizzo if (found) { /* notify other listeners */
381968b8534bSLuigi Rizzo revents |= want_tx;
382068b8534bSLuigi Rizzo want_tx = 0;
38214f80b14cSVincenzo Maffione #ifndef linux
3822847bf383SLuigi Rizzo kring->nm_notify(kring, 0);
38234f80b14cSVincenzo Maffione #endif /* linux */
382468b8534bSLuigi Rizzo }
3825ce3ee1e7SLuigi Rizzo }
382637e3a6d3SLuigi Rizzo /* if there were any packet to forward we must have handled them by now */
382737e3a6d3SLuigi Rizzo send_down = 0;
382837e3a6d3SLuigi Rizzo if (want_tx && retry_tx && sr) {
38294f80b14cSVincenzo Maffione #ifndef linux
3830b6e66be2SVincenzo Maffione nm_os_selrecord(sr, si[NR_TX]);
38314f80b14cSVincenzo Maffione #endif /* !linux */
3832ce3ee1e7SLuigi Rizzo retry_tx = 0;
3833ce3ee1e7SLuigi Rizzo goto flush_tx;
383468b8534bSLuigi Rizzo }
383568b8534bSLuigi Rizzo }
383668b8534bSLuigi Rizzo
383768b8534bSLuigi Rizzo /*
383817885a7bSLuigi Rizzo * If want_rx is still set scan receive rings.
383968b8534bSLuigi Rizzo * Do it on all rings because otherwise we starve.
384068b8534bSLuigi Rizzo */
384168b8534bSLuigi Rizzo if (want_rx) {
384289cc2556SLuigi Rizzo /* two rounds here for race avoidance */
3843ce3ee1e7SLuigi Rizzo do_retry_rx:
3844847bf383SLuigi Rizzo for (i = priv->np_qfirst[NR_RX]; i < priv->np_qlast[NR_RX]; i++) {
384517885a7bSLuigi Rizzo int found = 0;
384617885a7bSLuigi Rizzo
38472ff91c17SVincenzo Maffione kring = na->rx_rings[i];
384837e3a6d3SLuigi Rizzo ring = kring->ring;
3849ce3ee1e7SLuigi Rizzo
385037e3a6d3SLuigi Rizzo if (unlikely(nm_kr_tryget(kring, 1, &revents)))
385117885a7bSLuigi Rizzo continue;
3852ce3ee1e7SLuigi Rizzo
385337e3a6d3SLuigi Rizzo if (nm_rxsync_prologue(kring, ring) >= kring->nkr_num_slots) {
3854847bf383SLuigi Rizzo netmap_ring_reinit(kring);
3855847bf383SLuigi Rizzo revents |= POLLERR;
3856847bf383SLuigi Rizzo }
3857847bf383SLuigi Rizzo /* now we can use kring->rcur, rtail */
3858847bf383SLuigi Rizzo
385917885a7bSLuigi Rizzo /*
3860c3e9b4dbSLuiz Otavio O Souza * transparent mode support: collect packets from
3861c3e9b4dbSLuiz Otavio O Souza * hw rxring(s) that have been released by the user
3862ce3ee1e7SLuigi Rizzo */
386337e3a6d3SLuigi Rizzo if (nm_may_forward_up(kring)) {
3864091fd0abSLuigi Rizzo netmap_grab_packets(kring, &q, netmap_fwd);
3865091fd0abSLuigi Rizzo }
386668b8534bSLuigi Rizzo
3867c3e9b4dbSLuiz Otavio O Souza /* Clear the NR_FORWARD flag anyway, it may be set by
3868c3e9b4dbSLuiz Otavio O Souza * the nm_sync() below only on for the host RX ring (see
3869c3e9b4dbSLuiz Otavio O Souza * netmap_rxsync_from_host()). */
387037e3a6d3SLuigi Rizzo kring->nr_kflags &= ~NR_FORWARD;
3871c3e9b4dbSLuiz Otavio O Souza if (kring->nm_sync(kring, sync_flags))
387268b8534bSLuigi Rizzo revents |= POLLERR;
3873847bf383SLuigi Rizzo else
387437e3a6d3SLuigi Rizzo nm_sync_finalize(kring);
3875c3e9b4dbSLuiz Otavio O Souza send_down |= (kring->nr_kflags & NR_FORWARD);
3876c3e9b4dbSLuiz Otavio O Souza ring_timestamp_set(ring);
387717885a7bSLuigi Rizzo found = kring->rcur != kring->rtail;
387817885a7bSLuigi Rizzo nm_kr_put(kring);
387917885a7bSLuigi Rizzo if (found) {
388068b8534bSLuigi Rizzo revents |= want_rx;
3881ce3ee1e7SLuigi Rizzo retry_rx = 0;
38824f80b14cSVincenzo Maffione #ifndef linux
3883847bf383SLuigi Rizzo kring->nm_notify(kring, 0);
38844f80b14cSVincenzo Maffione #endif /* linux */
388568b8534bSLuigi Rizzo }
388668b8534bSLuigi Rizzo }
388717885a7bSLuigi Rizzo
38884f80b14cSVincenzo Maffione #ifndef linux
388937e3a6d3SLuigi Rizzo if (retry_rx && sr) {
3890b6e66be2SVincenzo Maffione nm_os_selrecord(sr, si[NR_RX]);
389137e3a6d3SLuigi Rizzo }
38924f80b14cSVincenzo Maffione #endif /* !linux */
3893c3e9b4dbSLuiz Otavio O Souza if (send_down || retry_rx) {
389417885a7bSLuigi Rizzo retry_rx = 0;
389517885a7bSLuigi Rizzo if (send_down)
389617885a7bSLuigi Rizzo goto flush_tx; /* and retry_rx */
389717885a7bSLuigi Rizzo else
3898ce3ee1e7SLuigi Rizzo goto do_retry_rx;
3899ce3ee1e7SLuigi Rizzo }
390068b8534bSLuigi Rizzo }
3901091fd0abSLuigi Rizzo
390217885a7bSLuigi Rizzo /*
3903c3e9b4dbSLuiz Otavio O Souza * Transparent mode: released bufs (i.e. between kring->nr_hwcur and
3904c3e9b4dbSLuiz Otavio O Souza * ring->head) marked with NS_FORWARD on hw rx rings are passed up
3905c3e9b4dbSLuiz Otavio O Souza * to the host stack.
3906ce3ee1e7SLuigi Rizzo */
3907091fd0abSLuigi Rizzo
3908c3e9b4dbSLuiz Otavio O Souza if (mbq_peek(&q)) {
3909f9790aebSLuigi Rizzo netmap_send_up(na->ifp, &q);
391037e3a6d3SLuigi Rizzo }
391168b8534bSLuigi Rizzo
391268b8534bSLuigi Rizzo return (revents);
3913847bf383SLuigi Rizzo #undef want_tx
3914847bf383SLuigi Rizzo #undef want_rx
391568b8534bSLuigi Rizzo }
391668b8534bSLuigi Rizzo
39174f80b14cSVincenzo Maffione int
nma_intr_enable(struct netmap_adapter * na,int onoff)39184f80b14cSVincenzo Maffione nma_intr_enable(struct netmap_adapter *na, int onoff)
39194f80b14cSVincenzo Maffione {
39204f80b14cSVincenzo Maffione bool changed = false;
39214f80b14cSVincenzo Maffione enum txrx t;
39224f80b14cSVincenzo Maffione int i;
39234f80b14cSVincenzo Maffione
39244f80b14cSVincenzo Maffione for_rx_tx(t) {
39254f80b14cSVincenzo Maffione for (i = 0; i < nma_get_nrings(na, t); i++) {
39262ff91c17SVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i];
39274f80b14cSVincenzo Maffione int on = !(kring->nr_kflags & NKR_NOINTR);
39284f80b14cSVincenzo Maffione
39294f80b14cSVincenzo Maffione if (!!onoff != !!on) {
39304f80b14cSVincenzo Maffione changed = true;
39314f80b14cSVincenzo Maffione }
39324f80b14cSVincenzo Maffione if (onoff) {
39334f80b14cSVincenzo Maffione kring->nr_kflags &= ~NKR_NOINTR;
39344f80b14cSVincenzo Maffione } else {
39354f80b14cSVincenzo Maffione kring->nr_kflags |= NKR_NOINTR;
39364f80b14cSVincenzo Maffione }
39374f80b14cSVincenzo Maffione }
39384f80b14cSVincenzo Maffione }
39394f80b14cSVincenzo Maffione
39404f80b14cSVincenzo Maffione if (!changed) {
39414f80b14cSVincenzo Maffione return 0; /* nothing to do */
39424f80b14cSVincenzo Maffione }
39434f80b14cSVincenzo Maffione
39444f80b14cSVincenzo Maffione if (!na->nm_intr) {
3945b6e66be2SVincenzo Maffione nm_prerr("Cannot %s interrupts for %s", onoff ? "enable" : "disable",
39464f80b14cSVincenzo Maffione na->name);
39474f80b14cSVincenzo Maffione return -1;
39484f80b14cSVincenzo Maffione }
39494f80b14cSVincenzo Maffione
39504f80b14cSVincenzo Maffione na->nm_intr(na, onoff);
39514f80b14cSVincenzo Maffione
39524f80b14cSVincenzo Maffione return 0;
39534f80b14cSVincenzo Maffione }
39544f80b14cSVincenzo Maffione
395517885a7bSLuigi Rizzo
395617885a7bSLuigi Rizzo /*-------------------- driver support routines -------------------*/
395768b8534bSLuigi Rizzo
395889cc2556SLuigi Rizzo /* default notify callback */
3959f9790aebSLuigi Rizzo static int
netmap_notify(struct netmap_kring * kring,int flags)3960847bf383SLuigi Rizzo netmap_notify(struct netmap_kring *kring, int flags)
3961f9790aebSLuigi Rizzo {
39622ff91c17SVincenzo Maffione struct netmap_adapter *na = kring->notify_na;
3963847bf383SLuigi Rizzo enum txrx t = kring->tx;
3964f9790aebSLuigi Rizzo
396537e3a6d3SLuigi Rizzo nm_os_selwakeup(&kring->si);
396689cc2556SLuigi Rizzo /* optimization: avoid a wake up on the global
396789cc2556SLuigi Rizzo * queue if nobody has registered for more
396889cc2556SLuigi Rizzo * than one ring
396989cc2556SLuigi Rizzo */
3970847bf383SLuigi Rizzo if (na->si_users[t] > 0)
397137e3a6d3SLuigi Rizzo nm_os_selwakeup(&na->si[t]);
3972847bf383SLuigi Rizzo
397337e3a6d3SLuigi Rizzo return NM_IRQ_COMPLETED;
3974f9790aebSLuigi Rizzo }
3975f9790aebSLuigi Rizzo
397689cc2556SLuigi Rizzo /* called by all routines that create netmap_adapters.
397737e3a6d3SLuigi Rizzo * provide some defaults and get a reference to the
397837e3a6d3SLuigi Rizzo * memory allocator
397989cc2556SLuigi Rizzo */
3980f9790aebSLuigi Rizzo int
netmap_attach_common(struct netmap_adapter * na)3981f9790aebSLuigi Rizzo netmap_attach_common(struct netmap_adapter *na)
3982f9790aebSLuigi Rizzo {
39832ff91c17SVincenzo Maffione if (!na->rx_buf_maxsize) {
39842ff91c17SVincenzo Maffione /* Set a conservative default (larger is safer). */
39852ff91c17SVincenzo Maffione na->rx_buf_maxsize = PAGE_SIZE;
39862ff91c17SVincenzo Maffione }
39872ff91c17SVincenzo Maffione
398817885a7bSLuigi Rizzo #ifdef __FreeBSD__
398937e3a6d3SLuigi Rizzo if (na->na_flags & NAF_HOST_RINGS && na->ifp) {
3990e330262fSJustin Hibbits na->if_input = if_getinputfn(na->ifp); /* for netmap_send_up */
39914bf50f18SLuigi Rizzo }
39924f80b14cSVincenzo Maffione na->pdev = na; /* make sure netmap_mem_map() is called */
399337e3a6d3SLuigi Rizzo #endif /* __FreeBSD__ */
39942a7db7a6SVincenzo Maffione if (na->na_flags & NAF_HOST_RINGS) {
39952a7db7a6SVincenzo Maffione if (na->num_host_rx_rings == 0)
39962a7db7a6SVincenzo Maffione na->num_host_rx_rings = 1;
39972a7db7a6SVincenzo Maffione if (na->num_host_tx_rings == 0)
39982a7db7a6SVincenzo Maffione na->num_host_tx_rings = 1;
39992a7db7a6SVincenzo Maffione }
4000f9790aebSLuigi Rizzo if (na->nm_krings_create == NULL) {
400189cc2556SLuigi Rizzo /* we assume that we have been called by a driver,
400289cc2556SLuigi Rizzo * since other port types all provide their own
400389cc2556SLuigi Rizzo * nm_krings_create
400489cc2556SLuigi Rizzo */
4005f9790aebSLuigi Rizzo na->nm_krings_create = netmap_hw_krings_create;
400617885a7bSLuigi Rizzo na->nm_krings_delete = netmap_hw_krings_delete;
4007f9790aebSLuigi Rizzo }
4008f9790aebSLuigi Rizzo if (na->nm_notify == NULL)
4009f9790aebSLuigi Rizzo na->nm_notify = netmap_notify;
4010f9790aebSLuigi Rizzo na->active_fds = 0;
4011f9790aebSLuigi Rizzo
4012c3e9b4dbSLuiz Otavio O Souza if (na->nm_mem == NULL) {
4013*1bae9dc5SMark Johnston /* select an allocator based on IOMMU and NUMA affinity */
4014*1bae9dc5SMark Johnston na->nm_mem = netmap_mem_get_allocator(na);
4015c3e9b4dbSLuiz Otavio O Souza }
40164bf50f18SLuigi Rizzo if (na->nm_bdg_attach == NULL)
40174bf50f18SLuigi Rizzo /* no special nm_bdg_attach callback. On VALE
40184bf50f18SLuigi Rizzo * attach, we need to interpose a bwrap
40194bf50f18SLuigi Rizzo */
40202a7db7a6SVincenzo Maffione na->nm_bdg_attach = netmap_default_bdg_attach;
402137e3a6d3SLuigi Rizzo
4022f9790aebSLuigi Rizzo return 0;
4023f9790aebSLuigi Rizzo }
4024f9790aebSLuigi Rizzo
402537e3a6d3SLuigi Rizzo /* Wrapper for the register callback provided netmap-enabled
402637e3a6d3SLuigi Rizzo * hardware drivers.
402737e3a6d3SLuigi Rizzo * nm_iszombie(na) means that the driver module has been
40284bf50f18SLuigi Rizzo * unloaded, so we cannot call into it.
402937e3a6d3SLuigi Rizzo * nm_os_ifnet_lock() must guarantee mutual exclusion with
403037e3a6d3SLuigi Rizzo * module unloading.
40314bf50f18SLuigi Rizzo */
40324bf50f18SLuigi Rizzo static int
netmap_hw_reg(struct netmap_adapter * na,int onoff)403337e3a6d3SLuigi Rizzo netmap_hw_reg(struct netmap_adapter *na, int onoff)
40344bf50f18SLuigi Rizzo {
40354bf50f18SLuigi Rizzo struct netmap_hw_adapter *hwna =
40364bf50f18SLuigi Rizzo (struct netmap_hw_adapter*)na;
403737e3a6d3SLuigi Rizzo int error = 0;
40384bf50f18SLuigi Rizzo
403937e3a6d3SLuigi Rizzo nm_os_ifnet_lock();
40404bf50f18SLuigi Rizzo
404137e3a6d3SLuigi Rizzo if (nm_iszombie(na)) {
404237e3a6d3SLuigi Rizzo if (onoff) {
404337e3a6d3SLuigi Rizzo error = ENXIO;
404437e3a6d3SLuigi Rizzo } else if (na != NULL) {
404537e3a6d3SLuigi Rizzo na->na_flags &= ~NAF_NETMAP_ON;
404637e3a6d3SLuigi Rizzo }
404737e3a6d3SLuigi Rizzo goto out;
404837e3a6d3SLuigi Rizzo }
404937e3a6d3SLuigi Rizzo
405037e3a6d3SLuigi Rizzo error = hwna->nm_hw_register(na, onoff);
405137e3a6d3SLuigi Rizzo
405237e3a6d3SLuigi Rizzo out:
405337e3a6d3SLuigi Rizzo nm_os_ifnet_unlock();
405437e3a6d3SLuigi Rizzo
405537e3a6d3SLuigi Rizzo return error;
405637e3a6d3SLuigi Rizzo }
405737e3a6d3SLuigi Rizzo
405837e3a6d3SLuigi Rizzo static void
netmap_hw_dtor(struct netmap_adapter * na)405937e3a6d3SLuigi Rizzo netmap_hw_dtor(struct netmap_adapter *na)
406037e3a6d3SLuigi Rizzo {
40612a7db7a6SVincenzo Maffione if (na->ifp == NULL)
406237e3a6d3SLuigi Rizzo return;
406337e3a6d3SLuigi Rizzo
40642a7db7a6SVincenzo Maffione NM_DETACH_NA(na->ifp);
40654bf50f18SLuigi Rizzo }
40664bf50f18SLuigi Rizzo
4067f18be576SLuigi Rizzo
406868b8534bSLuigi Rizzo /*
4069c3e9b4dbSLuiz Otavio O Souza * Allocate a netmap_adapter object, and initialize it from the
407037e3a6d3SLuigi Rizzo * 'arg' passed by the driver on attach.
4071c3e9b4dbSLuiz Otavio O Souza * We allocate a block of memory of 'size' bytes, which has room
4072c3e9b4dbSLuiz Otavio O Souza * for struct netmap_adapter plus additional room private to
4073c3e9b4dbSLuiz Otavio O Souza * the caller.
407468b8534bSLuigi Rizzo * Return 0 on success, ENOMEM otherwise.
407568b8534bSLuigi Rizzo */
4076c3e9b4dbSLuiz Otavio O Souza int
netmap_attach_ext(struct netmap_adapter * arg,size_t size,int override_reg)40774f80b14cSVincenzo Maffione netmap_attach_ext(struct netmap_adapter *arg, size_t size, int override_reg)
407868b8534bSLuigi Rizzo {
4079f9790aebSLuigi Rizzo struct netmap_hw_adapter *hwna = NULL;
4080e330262fSJustin Hibbits if_t ifp = NULL;
408168b8534bSLuigi Rizzo
4082c3e9b4dbSLuiz Otavio O Souza if (size < sizeof(struct netmap_hw_adapter)) {
4083b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_ON)
4084b6e66be2SVincenzo Maffione nm_prerr("Invalid netmap adapter size %d", (int)size);
4085c3e9b4dbSLuiz Otavio O Souza return EINVAL;
4086c3e9b4dbSLuiz Otavio O Souza }
4087c3e9b4dbSLuiz Otavio O Souza
4088b6e66be2SVincenzo Maffione if (arg == NULL || arg->ifp == NULL) {
4089b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_ON)
4090b6e66be2SVincenzo Maffione nm_prerr("either arg or arg->ifp is NULL");
40912a7db7a6SVincenzo Maffione return EINVAL;
4092b6e66be2SVincenzo Maffione }
4093b6e66be2SVincenzo Maffione
4094b6e66be2SVincenzo Maffione if (arg->num_tx_rings == 0 || arg->num_rx_rings == 0) {
4095b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_ON)
4096b6e66be2SVincenzo Maffione nm_prerr("%s: invalid rings tx %d rx %d",
4097b6e66be2SVincenzo Maffione arg->name, arg->num_tx_rings, arg->num_rx_rings);
4098b6e66be2SVincenzo Maffione return EINVAL;
4099b6e66be2SVincenzo Maffione }
41004f80b14cSVincenzo Maffione
410137e3a6d3SLuigi Rizzo ifp = arg->ifp;
41022a7db7a6SVincenzo Maffione if (NM_NA_CLASH(ifp)) {
41034f80b14cSVincenzo Maffione /* If NA(ifp) is not null but there is no valid netmap
41044f80b14cSVincenzo Maffione * adapter it means that someone else is using the same
41054f80b14cSVincenzo Maffione * pointer (e.g. ax25_ptr on linux). This happens for
41064f80b14cSVincenzo Maffione * instance when also PF_RING is in use. */
4107b6e66be2SVincenzo Maffione nm_prerr("Error: netmap adapter hook is busy");
41084f80b14cSVincenzo Maffione return EBUSY;
41094f80b14cSVincenzo Maffione }
41104f80b14cSVincenzo Maffione
4111c3e9b4dbSLuiz Otavio O Souza hwna = nm_os_malloc(size);
4112f9790aebSLuigi Rizzo if (hwna == NULL)
4113ae10d1afSLuigi Rizzo goto fail;
4114f9790aebSLuigi Rizzo hwna->up = *arg;
4115847bf383SLuigi Rizzo hwna->up.na_flags |= NAF_HOST_RINGS | NAF_NATIVE;
4116e330262fSJustin Hibbits strlcpy(hwna->up.name, if_name(ifp), sizeof(hwna->up.name));
41174f80b14cSVincenzo Maffione if (override_reg) {
41184bf50f18SLuigi Rizzo hwna->nm_hw_register = hwna->up.nm_register;
411937e3a6d3SLuigi Rizzo hwna->up.nm_register = netmap_hw_reg;
41204f80b14cSVincenzo Maffione }
4121f9790aebSLuigi Rizzo if (netmap_attach_common(&hwna->up)) {
4122c3e9b4dbSLuiz Otavio O Souza nm_os_free(hwna);
4123f9790aebSLuigi Rizzo goto fail;
4124f9790aebSLuigi Rizzo }
4125f9790aebSLuigi Rizzo netmap_adapter_get(&hwna->up);
4126f9790aebSLuigi Rizzo
412737e3a6d3SLuigi Rizzo NM_ATTACH_NA(ifp, &hwna->up);
412837e3a6d3SLuigi Rizzo
41292a7db7a6SVincenzo Maffione nm_os_onattach(ifp);
41302a7db7a6SVincenzo Maffione
413137e3a6d3SLuigi Rizzo if (arg->nm_dtor == NULL) {
413237e3a6d3SLuigi Rizzo hwna->up.nm_dtor = netmap_hw_dtor;
413337e3a6d3SLuigi Rizzo }
4134f9790aebSLuigi Rizzo
41351ef2a881SVincenzo Maffione if_printf(ifp, "netmap queues/slots: TX %d/%d, RX %d/%d\n",
4136d82f9014SRui Paulo hwna->up.num_tx_rings, hwna->up.num_tx_desc,
4137d82f9014SRui Paulo hwna->up.num_rx_rings, hwna->up.num_rx_desc);
4138ae10d1afSLuigi Rizzo return 0;
413968b8534bSLuigi Rizzo
4140ae10d1afSLuigi Rizzo fail:
4141b6e66be2SVincenzo Maffione nm_prerr("fail, arg %p ifp %p na %p", arg, ifp, hwna);
4142f9790aebSLuigi Rizzo return (hwna ? EINVAL : ENOMEM);
414368b8534bSLuigi Rizzo }
414468b8534bSLuigi Rizzo
414568b8534bSLuigi Rizzo
414637e3a6d3SLuigi Rizzo int
netmap_attach(struct netmap_adapter * arg)414737e3a6d3SLuigi Rizzo netmap_attach(struct netmap_adapter *arg)
414837e3a6d3SLuigi Rizzo {
41494f80b14cSVincenzo Maffione return netmap_attach_ext(arg, sizeof(struct netmap_hw_adapter),
41504f80b14cSVincenzo Maffione 1 /* override nm_reg */);
415137e3a6d3SLuigi Rizzo }
415237e3a6d3SLuigi Rizzo
415337e3a6d3SLuigi Rizzo
4154f9790aebSLuigi Rizzo void
NM_DBG(netmap_adapter_get)4155f9790aebSLuigi Rizzo NM_DBG(netmap_adapter_get)(struct netmap_adapter *na)
4156f9790aebSLuigi Rizzo {
4157f9790aebSLuigi Rizzo if (!na) {
4158f9790aebSLuigi Rizzo return;
4159f9790aebSLuigi Rizzo }
4160f9790aebSLuigi Rizzo
4161f9790aebSLuigi Rizzo refcount_acquire(&na->na_refcount);
4162f9790aebSLuigi Rizzo }
4163f9790aebSLuigi Rizzo
4164f9790aebSLuigi Rizzo
4165f9790aebSLuigi Rizzo /* returns 1 iff the netmap_adapter is destroyed */
4166f9790aebSLuigi Rizzo int
NM_DBG(netmap_adapter_put)4167f9790aebSLuigi Rizzo NM_DBG(netmap_adapter_put)(struct netmap_adapter *na)
4168f9790aebSLuigi Rizzo {
4169f9790aebSLuigi Rizzo if (!na)
4170f9790aebSLuigi Rizzo return 1;
4171f9790aebSLuigi Rizzo
4172f9790aebSLuigi Rizzo if (!refcount_release(&na->na_refcount))
4173f9790aebSLuigi Rizzo return 0;
4174f9790aebSLuigi Rizzo
4175f9790aebSLuigi Rizzo if (na->nm_dtor)
4176f9790aebSLuigi Rizzo na->nm_dtor(na);
4177f9790aebSLuigi Rizzo
41784f80b14cSVincenzo Maffione if (na->tx_rings) { /* XXX should not happen */
4179b6e66be2SVincenzo Maffione if (netmap_debug & NM_DEBUG_ON)
4180b6e66be2SVincenzo Maffione nm_prerr("freeing leftover tx_rings");
41814f80b14cSVincenzo Maffione na->nm_krings_delete(na);
41824f80b14cSVincenzo Maffione }
41834f80b14cSVincenzo Maffione netmap_pipe_dealloc(na);
41844f80b14cSVincenzo Maffione if (na->nm_mem)
41854f80b14cSVincenzo Maffione netmap_mem_put(na->nm_mem);
41864f80b14cSVincenzo Maffione bzero(na, sizeof(*na));
41874f80b14cSVincenzo Maffione nm_os_free(na);
4188f9790aebSLuigi Rizzo
4189f9790aebSLuigi Rizzo return 1;
4190f9790aebSLuigi Rizzo }
4191f9790aebSLuigi Rizzo
419289cc2556SLuigi Rizzo /* nm_krings_create callback for all hardware native adapters */
4193f9790aebSLuigi Rizzo int
netmap_hw_krings_create(struct netmap_adapter * na)4194f9790aebSLuigi Rizzo netmap_hw_krings_create(struct netmap_adapter *na)
4195f9790aebSLuigi Rizzo {
4196f0ea3689SLuigi Rizzo int ret = netmap_krings_create(na, 0);
419717885a7bSLuigi Rizzo if (ret == 0) {
419817885a7bSLuigi Rizzo /* initialize the mbq for the sw rx ring */
41992a7db7a6SVincenzo Maffione u_int lim = netmap_real_rings(na, NR_RX), i;
42002a7db7a6SVincenzo Maffione for (i = na->num_rx_rings; i < lim; i++) {
42012a7db7a6SVincenzo Maffione mbq_safe_init(&NMR(na, NR_RX)[i]->rx_queue);
42022a7db7a6SVincenzo Maffione }
420375f4f3edSVincenzo Maffione nm_prdis("initialized sw rx queue %d", na->num_rx_rings);
420417885a7bSLuigi Rizzo }
420517885a7bSLuigi Rizzo return ret;
4206f9790aebSLuigi Rizzo }
4207f9790aebSLuigi Rizzo
4208f9790aebSLuigi Rizzo
4209f9790aebSLuigi Rizzo
421068b8534bSLuigi Rizzo /*
421189cc2556SLuigi Rizzo * Called on module unload by the netmap-enabled drivers
421268b8534bSLuigi Rizzo */
421368b8534bSLuigi Rizzo void
netmap_detach(if_t ifp)4214e330262fSJustin Hibbits netmap_detach(if_t ifp)
421568b8534bSLuigi Rizzo {
421698399ab0SVincenzo Maffione struct netmap_adapter *na;
421768b8534bSLuigi Rizzo
4218f9790aebSLuigi Rizzo NMG_LOCK();
421998399ab0SVincenzo Maffione
422098399ab0SVincenzo Maffione if (!NM_NA_VALID(ifp)) {
422198399ab0SVincenzo Maffione NMG_UNLOCK();
422298399ab0SVincenzo Maffione return;
422398399ab0SVincenzo Maffione }
422498399ab0SVincenzo Maffione
422598399ab0SVincenzo Maffione na = NA(ifp);
422637e3a6d3SLuigi Rizzo netmap_set_all_rings(na, NM_KR_LOCKED);
4227847bf383SLuigi Rizzo /*
4228847bf383SLuigi Rizzo * if the netmap adapter is not native, somebody
4229847bf383SLuigi Rizzo * changed it, so we can not release it here.
423037e3a6d3SLuigi Rizzo * The NAF_ZOMBIE flag will notify the new owner that
4231847bf383SLuigi Rizzo * the driver is gone.
4232847bf383SLuigi Rizzo */
42334f80b14cSVincenzo Maffione if (!(na->na_flags & NAF_NATIVE) || !netmap_adapter_put(na)) {
42344f80b14cSVincenzo Maffione na->na_flags |= NAF_ZOMBIE;
4235847bf383SLuigi Rizzo }
423637e3a6d3SLuigi Rizzo /* give active users a chance to notice that NAF_ZOMBIE has been
423737e3a6d3SLuigi Rizzo * turned on, so that they can stop and return an error to userspace.
423837e3a6d3SLuigi Rizzo * Note that this becomes a NOP if there are no active users and,
423937e3a6d3SLuigi Rizzo * therefore, the put() above has deleted the na, since now NA(ifp) is
424037e3a6d3SLuigi Rizzo * NULL.
424137e3a6d3SLuigi Rizzo */
4242f9790aebSLuigi Rizzo netmap_enable_all_rings(ifp);
4243f9790aebSLuigi Rizzo NMG_UNLOCK();
4244ae10d1afSLuigi Rizzo }
4245f18be576SLuigi Rizzo
4246f18be576SLuigi Rizzo
424768b8534bSLuigi Rizzo /*
424802ad4083SLuigi Rizzo * Intercept packets from the network stack and pass them
424902ad4083SLuigi Rizzo * to netmap as incoming packets on the 'software' ring.
425017885a7bSLuigi Rizzo *
425117885a7bSLuigi Rizzo * We only store packets in a bounded mbq and then copy them
425217885a7bSLuigi Rizzo * in the relevant rxsync routine.
425317885a7bSLuigi Rizzo *
4254ce3ee1e7SLuigi Rizzo * We rely on the OS to make sure that the ifp and na do not go
4255ce3ee1e7SLuigi Rizzo * away (typically the caller checks for IFF_DRV_RUNNING or the like).
4256ce3ee1e7SLuigi Rizzo * In nm_register() or whenever there is a reinitialization,
4257f9790aebSLuigi Rizzo * we make sure to make the mode change visible here.
425868b8534bSLuigi Rizzo */
425968b8534bSLuigi Rizzo int
netmap_transmit(if_t ifp,struct mbuf * m)4260e330262fSJustin Hibbits netmap_transmit(if_t ifp, struct mbuf *m)
426168b8534bSLuigi Rizzo {
426268b8534bSLuigi Rizzo struct netmap_adapter *na = NA(ifp);
426337e3a6d3SLuigi Rizzo struct netmap_kring *kring, *tx_kring;
426417885a7bSLuigi Rizzo u_int len = MBUF_LEN(m);
426517885a7bSLuigi Rizzo u_int error = ENOBUFS;
426637e3a6d3SLuigi Rizzo unsigned int txr;
426717885a7bSLuigi Rizzo struct mbq *q;
4268c3e9b4dbSLuiz Otavio O Souza int busy;
42692a7db7a6SVincenzo Maffione u_int i;
427068b8534bSLuigi Rizzo
42712a7db7a6SVincenzo Maffione i = MBUF_TXQ(m);
42722a7db7a6SVincenzo Maffione if (i >= na->num_host_rx_rings) {
42732a7db7a6SVincenzo Maffione i = i % na->num_host_rx_rings;
42742a7db7a6SVincenzo Maffione }
42752a7db7a6SVincenzo Maffione kring = NMR(na, NR_RX)[nma_get_nrings(na, NR_RX) + i];
42762a7db7a6SVincenzo Maffione
4277ce3ee1e7SLuigi Rizzo // XXX [Linux] we do not need this lock
4278ce3ee1e7SLuigi Rizzo // if we follow the down/configure/up protocol -gl
4279ce3ee1e7SLuigi Rizzo // mtx_lock(&na->core_lock);
428017885a7bSLuigi Rizzo
42814bf50f18SLuigi Rizzo if (!nm_netmap_on(na)) {
4282b6e66be2SVincenzo Maffione nm_prerr("%s not in netmap mode anymore", na->name);
4283ce3ee1e7SLuigi Rizzo error = ENXIO;
4284ce3ee1e7SLuigi Rizzo goto done;
4285ce3ee1e7SLuigi Rizzo }
4286ce3ee1e7SLuigi Rizzo
428737e3a6d3SLuigi Rizzo txr = MBUF_TXQ(m);
428837e3a6d3SLuigi Rizzo if (txr >= na->num_tx_rings) {
428937e3a6d3SLuigi Rizzo txr %= na->num_tx_rings;
429037e3a6d3SLuigi Rizzo }
42912ff91c17SVincenzo Maffione tx_kring = NMR(na, NR_TX)[txr];
429237e3a6d3SLuigi Rizzo
429337e3a6d3SLuigi Rizzo if (tx_kring->nr_mode == NKR_NETMAP_OFF) {
429437e3a6d3SLuigi Rizzo return MBUF_TRANSMIT(na, ifp, m);
429537e3a6d3SLuigi Rizzo }
429637e3a6d3SLuigi Rizzo
429717885a7bSLuigi Rizzo q = &kring->rx_queue;
429817885a7bSLuigi Rizzo
4299ce3ee1e7SLuigi Rizzo // XXX reconsider long packets if we handle fragments
43004bf50f18SLuigi Rizzo if (len > NETMAP_BUF_SIZE(na)) { /* too long for us */
4301b6e66be2SVincenzo Maffione nm_prerr("%s from_host, drop packet size %d > %d", na->name,
43024bf50f18SLuigi Rizzo len, NETMAP_BUF_SIZE(na));
4303ce3ee1e7SLuigi Rizzo goto done;
4304849bec0eSLuigi Rizzo }
430517885a7bSLuigi Rizzo
43062a7db7a6SVincenzo Maffione if (!netmap_generic_hwcsum) {
43072a7db7a6SVincenzo Maffione if (nm_os_mbuf_has_csum_offld(m)) {
430875f4f3edSVincenzo Maffione nm_prlim(1, "%s drop mbuf that needs checksum offload", na->name);
43092a7db7a6SVincenzo Maffione goto done;
43102a7db7a6SVincenzo Maffione }
43112a7db7a6SVincenzo Maffione }
43122a7db7a6SVincenzo Maffione
43132a7db7a6SVincenzo Maffione if (nm_os_mbuf_has_seg_offld(m)) {
431475f4f3edSVincenzo Maffione nm_prlim(1, "%s drop mbuf that needs generic segmentation offload", na->name);
431537e3a6d3SLuigi Rizzo goto done;
431637e3a6d3SLuigi Rizzo }
431737e3a6d3SLuigi Rizzo
431889a9a5b5SVincenzo Maffione #ifdef __FreeBSD__
431989a9a5b5SVincenzo Maffione ETHER_BPF_MTAP(ifp, m);
432089a9a5b5SVincenzo Maffione #endif /* __FreeBSD__ */
432189a9a5b5SVincenzo Maffione
4322c3e9b4dbSLuiz Otavio O Souza /* protect against netmap_rxsync_from_host(), netmap_sw_to_nic()
432317885a7bSLuigi Rizzo * and maybe other instances of netmap_transmit (the latter
432417885a7bSLuigi Rizzo * not possible on Linux).
4325c3e9b4dbSLuiz Otavio O Souza * We enqueue the mbuf only if we are sure there is going to be
4326c3e9b4dbSLuiz Otavio O Souza * enough room in the host RX ring, otherwise we drop it.
4327ce3ee1e7SLuigi Rizzo */
4328997b054cSLuigi Rizzo mbq_lock(q);
432917885a7bSLuigi Rizzo
4330c3e9b4dbSLuiz Otavio O Souza busy = kring->nr_hwtail - kring->nr_hwcur;
4331c3e9b4dbSLuiz Otavio O Souza if (busy < 0)
4332c3e9b4dbSLuiz Otavio O Souza busy += kring->nkr_num_slots;
4333c3e9b4dbSLuiz Otavio O Souza if (busy + mbq_len(q) >= kring->nkr_num_slots - 1) {
433475f4f3edSVincenzo Maffione nm_prlim(2, "%s full hwcur %d hwtail %d qlen %d", na->name,
4335c3e9b4dbSLuiz Otavio O Souza kring->nr_hwcur, kring->nr_hwtail, mbq_len(q));
4336ce3ee1e7SLuigi Rizzo } else {
433717885a7bSLuigi Rizzo mbq_enqueue(q, m);
433875f4f3edSVincenzo Maffione nm_prdis(2, "%s %d bufs in queue", na->name, mbq_len(q));
433917885a7bSLuigi Rizzo /* notify outside the lock */
434017885a7bSLuigi Rizzo m = NULL;
434168b8534bSLuigi Rizzo error = 0;
4342ce3ee1e7SLuigi Rizzo }
4343997b054cSLuigi Rizzo mbq_unlock(q);
4344ce3ee1e7SLuigi Rizzo
434568b8534bSLuigi Rizzo done:
4346df40e30cSMark Johnston if (m) {
4347df40e30cSMark Johnston if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
434868b8534bSLuigi Rizzo m_freem(m);
4349df40e30cSMark Johnston }
435017885a7bSLuigi Rizzo /* unconditionally wake up listeners */
4351847bf383SLuigi Rizzo kring->nm_notify(kring, 0);
435289cc2556SLuigi Rizzo /* this is normally netmap_notify(), but for nics
435389cc2556SLuigi Rizzo * connected to a bridge it is netmap_bwrap_intr_notify(),
435489cc2556SLuigi Rizzo * that possibly forwards the frames through the switch
435589cc2556SLuigi Rizzo */
435668b8534bSLuigi Rizzo
435768b8534bSLuigi Rizzo return (error);
435868b8534bSLuigi Rizzo }
435968b8534bSLuigi Rizzo
436068b8534bSLuigi Rizzo
436168b8534bSLuigi Rizzo /*
43627ba6ecf2SVincenzo Maffione * Reset function to be called by the driver routines when reinitializing
43637ba6ecf2SVincenzo Maffione * a hardware ring. The driver is in charge of locking to protect the kring
436455f0ad5fSVincenzo Maffione * while this operation is being performed. This is normally achieved by
436555f0ad5fSVincenzo Maffione * calling netmap_disable_all_rings() before triggering a reset.
43667ba6ecf2SVincenzo Maffione * If the kring is not in netmap mode, return NULL to inform the caller
43677ba6ecf2SVincenzo Maffione * that this is the case.
436855f0ad5fSVincenzo Maffione * If the kring is in netmap mode, set hwofs so that the netmap indices
436955f0ad5fSVincenzo Maffione * seen by userspace (head/cut/tail) do not change, although the internal
437055f0ad5fSVincenzo Maffione * NIC indices have been reset to 0.
43717ba6ecf2SVincenzo Maffione * In any case, adjust kring->nr_mode.
437268b8534bSLuigi Rizzo */
437368b8534bSLuigi Rizzo struct netmap_slot *
netmap_reset(struct netmap_adapter * na,enum txrx tx,u_int n,u_int new_cur)4374ce3ee1e7SLuigi Rizzo netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n,
437568b8534bSLuigi Rizzo u_int new_cur)
437668b8534bSLuigi Rizzo {
437768b8534bSLuigi Rizzo struct netmap_kring *kring;
437855f0ad5fSVincenzo Maffione u_int new_hwtail, new_hwofs;
437968b8534bSLuigi Rizzo
43804bf50f18SLuigi Rizzo if (!nm_native_on(na)) {
438175f4f3edSVincenzo Maffione nm_prdis("interface not in native netmap mode");
438268b8534bSLuigi Rizzo return NULL; /* nothing to reinitialize */
4383ce3ee1e7SLuigi Rizzo }
438468b8534bSLuigi Rizzo
438564ae02c3SLuigi Rizzo if (tx == NR_TX) {
43868241616dSLuigi Rizzo if (n >= na->num_tx_rings)
43878241616dSLuigi Rizzo return NULL;
43882ff91c17SVincenzo Maffione kring = na->tx_rings[n];
438955f0ad5fSVincenzo Maffione /*
439055f0ad5fSVincenzo Maffione * Set hwofs to rhead, so that slots[rhead] is mapped to
439155f0ad5fSVincenzo Maffione * the NIC internal slot 0, and thus the netmap buffer
439255f0ad5fSVincenzo Maffione * at rhead is the next to be transmitted. Transmissions
439355f0ad5fSVincenzo Maffione * that were pending before the reset are considered as
439455f0ad5fSVincenzo Maffione * sent, so that we can have hwcur = rhead. All the slots
439555f0ad5fSVincenzo Maffione * are now owned by the user, so we can also reinit hwtail.
439655f0ad5fSVincenzo Maffione */
439755f0ad5fSVincenzo Maffione new_hwofs = kring->rhead;
439855f0ad5fSVincenzo Maffione new_hwtail = nm_prev(kring->rhead, kring->nkr_num_slots - 1);
439964ae02c3SLuigi Rizzo } else {
44008241616dSLuigi Rizzo if (n >= na->num_rx_rings)
44018241616dSLuigi Rizzo return NULL;
44022ff91c17SVincenzo Maffione kring = na->rx_rings[n];
440355f0ad5fSVincenzo Maffione /*
440455f0ad5fSVincenzo Maffione * Set hwofs to hwtail, so that slots[hwtail] is mapped to
440555f0ad5fSVincenzo Maffione * the NIC internal slot 0, and thus the netmap buffer
440655f0ad5fSVincenzo Maffione * at hwtail is the next to be given to the NIC.
440755f0ad5fSVincenzo Maffione * Unread slots (the ones in [rhead,hwtail[) are owned by
440855f0ad5fSVincenzo Maffione * the user, and thus the caller cannot give them
440955f0ad5fSVincenzo Maffione * to the NIC right now.
441055f0ad5fSVincenzo Maffione */
441155f0ad5fSVincenzo Maffione new_hwofs = kring->nr_hwtail;
441255f0ad5fSVincenzo Maffione new_hwtail = kring->nr_hwtail;
44137ba6ecf2SVincenzo Maffione }
441437e3a6d3SLuigi Rizzo if (kring->nr_pending_mode == NKR_NETMAP_OFF) {
441537e3a6d3SLuigi Rizzo kring->nr_mode = NKR_NETMAP_OFF;
441637e3a6d3SLuigi Rizzo return NULL;
441737e3a6d3SLuigi Rizzo }
44187ba6ecf2SVincenzo Maffione if (netmap_verbose) {
441955f0ad5fSVincenzo Maffione nm_prinf("%s, hc %u->%u, ht %u->%u, ho %u->%u", kring->name,
442055f0ad5fSVincenzo Maffione kring->nr_hwcur, kring->rhead,
442155f0ad5fSVincenzo Maffione kring->nr_hwtail, new_hwtail,
442255f0ad5fSVincenzo Maffione kring->nkr_hwofs, new_hwofs);
442364ae02c3SLuigi Rizzo }
442455f0ad5fSVincenzo Maffione kring->nr_hwcur = kring->rhead;
442555f0ad5fSVincenzo Maffione kring->nr_hwtail = new_hwtail;
442655f0ad5fSVincenzo Maffione kring->nkr_hwofs = new_hwofs;
4427506cc70cSLuigi Rizzo
442868b8534bSLuigi Rizzo /*
4429ce3ee1e7SLuigi Rizzo * Wakeup on the individual and global selwait
4430506cc70cSLuigi Rizzo * We do the wakeup here, but the ring is not yet reconfigured.
4431506cc70cSLuigi Rizzo * However, we are under lock so there are no races.
443268b8534bSLuigi Rizzo */
443337e3a6d3SLuigi Rizzo kring->nr_mode = NKR_NETMAP_ON;
4434847bf383SLuigi Rizzo kring->nm_notify(kring, 0);
443568b8534bSLuigi Rizzo return kring->ring->slot;
443668b8534bSLuigi Rizzo }
443768b8534bSLuigi Rizzo
443868b8534bSLuigi Rizzo
4439ce3ee1e7SLuigi Rizzo /*
4440f9790aebSLuigi Rizzo * Dispatch rx/tx interrupts to the netmap rings.
4441ce3ee1e7SLuigi Rizzo *
4442ce3ee1e7SLuigi Rizzo * "work_done" is non-null on the RX path, NULL for the TX path.
4443ce3ee1e7SLuigi Rizzo * We rely on the OS to make sure that there is only one active
4444ce3ee1e7SLuigi Rizzo * instance per queue, and that there is appropriate locking.
4445849bec0eSLuigi Rizzo *
4446f9790aebSLuigi Rizzo * The 'notify' routine depends on what the ring is attached to.
4447f9790aebSLuigi Rizzo * - for a netmap file descriptor, do a selwakeup on the individual
4448f9790aebSLuigi Rizzo * waitqueue, plus one on the global one if needed
44494bf50f18SLuigi Rizzo * (see netmap_notify)
44504bf50f18SLuigi Rizzo * - for a nic connected to a switch, call the proper forwarding routine
44514bf50f18SLuigi Rizzo * (see netmap_bwrap_intr_notify)
4452f9790aebSLuigi Rizzo */
445337e3a6d3SLuigi Rizzo int
netmap_common_irq(struct netmap_adapter * na,u_int q,u_int * work_done)445437e3a6d3SLuigi Rizzo netmap_common_irq(struct netmap_adapter *na, u_int q, u_int *work_done)
4455f9790aebSLuigi Rizzo {
4456f9790aebSLuigi Rizzo struct netmap_kring *kring;
4457847bf383SLuigi Rizzo enum txrx t = (work_done ? NR_RX : NR_TX);
4458f9790aebSLuigi Rizzo
4459f9790aebSLuigi Rizzo q &= NETMAP_RING_MASK;
4460f9790aebSLuigi Rizzo
4461b6e66be2SVincenzo Maffione if (netmap_debug & (NM_DEBUG_RXINTR|NM_DEBUG_TXINTR)) {
4462b6e66be2SVincenzo Maffione nm_prlim(5, "received %s queue %d", work_done ? "RX" : "TX" , q);
4463f9790aebSLuigi Rizzo }
4464f9790aebSLuigi Rizzo
4465847bf383SLuigi Rizzo if (q >= nma_get_nrings(na, t))
446637e3a6d3SLuigi Rizzo return NM_IRQ_PASS; // not a physical queue
4467847bf383SLuigi Rizzo
44682ff91c17SVincenzo Maffione kring = NMR(na, t)[q];
4469847bf383SLuigi Rizzo
447037e3a6d3SLuigi Rizzo if (kring->nr_mode == NKR_NETMAP_OFF) {
447137e3a6d3SLuigi Rizzo return NM_IRQ_PASS;
447237e3a6d3SLuigi Rizzo }
447337e3a6d3SLuigi Rizzo
4474847bf383SLuigi Rizzo if (t == NR_RX) {
4475f9790aebSLuigi Rizzo kring->nr_kflags |= NKR_PENDINTR; // XXX atomic ?
4476f9790aebSLuigi Rizzo *work_done = 1; /* do not fire napi again */
4477f9790aebSLuigi Rizzo }
447837e3a6d3SLuigi Rizzo
447937e3a6d3SLuigi Rizzo return kring->nm_notify(kring, 0);
4480f9790aebSLuigi Rizzo }
4481f9790aebSLuigi Rizzo
448217885a7bSLuigi Rizzo
4483f9790aebSLuigi Rizzo /*
4484f9790aebSLuigi Rizzo * Default functions to handle rx/tx interrupts from a physical device.
4485f9790aebSLuigi Rizzo * "work_done" is non-null on the RX path, NULL for the TX path.
4486f9790aebSLuigi Rizzo *
448737e3a6d3SLuigi Rizzo * If the card is not in netmap mode, simply return NM_IRQ_PASS,
4488ce3ee1e7SLuigi Rizzo * so that the caller proceeds with regular processing.
448937e3a6d3SLuigi Rizzo * Otherwise call netmap_common_irq().
4490ce3ee1e7SLuigi Rizzo *
4491ce3ee1e7SLuigi Rizzo * If the card is connected to a netmap file descriptor,
4492ce3ee1e7SLuigi Rizzo * do a selwakeup on the individual queue, plus one on the global one
4493ce3ee1e7SLuigi Rizzo * if needed (multiqueue card _and_ there are multiqueue listeners),
449437e3a6d3SLuigi Rizzo * and return NR_IRQ_COMPLETED.
4495ce3ee1e7SLuigi Rizzo *
4496ce3ee1e7SLuigi Rizzo * Finally, if called on rx from an interface connected to a switch,
449737e3a6d3SLuigi Rizzo * calls the proper forwarding routine.
44981a26580eSLuigi Rizzo */
4499babc7c12SLuigi Rizzo int
netmap_rx_irq(if_t ifp,u_int q,u_int * work_done)4500e330262fSJustin Hibbits netmap_rx_irq(if_t ifp, u_int q, u_int *work_done)
45011a26580eSLuigi Rizzo {
45024bf50f18SLuigi Rizzo struct netmap_adapter *na = NA(ifp);
45034bf50f18SLuigi Rizzo
45044bf50f18SLuigi Rizzo /*
45054bf50f18SLuigi Rizzo * XXX emulated netmap mode sets NAF_SKIP_INTR so
45064bf50f18SLuigi Rizzo * we still use the regular driver even though the previous
45074bf50f18SLuigi Rizzo * check fails. It is unclear whether we should use
45084bf50f18SLuigi Rizzo * nm_native_on() here.
45094bf50f18SLuigi Rizzo */
45104bf50f18SLuigi Rizzo if (!nm_netmap_on(na))
451137e3a6d3SLuigi Rizzo return NM_IRQ_PASS;
4512849bec0eSLuigi Rizzo
45134bf50f18SLuigi Rizzo if (na->na_flags & NAF_SKIP_INTR) {
451475f4f3edSVincenzo Maffione nm_prdis("use regular interrupt");
451537e3a6d3SLuigi Rizzo return NM_IRQ_PASS;
45168241616dSLuigi Rizzo }
45178241616dSLuigi Rizzo
451837e3a6d3SLuigi Rizzo return netmap_common_irq(na, q, work_done);
45191a26580eSLuigi Rizzo }
45201a26580eSLuigi Rizzo
45212a7db7a6SVincenzo Maffione /* set/clear native flags and if_transmit/netdev_ops */
45222a7db7a6SVincenzo Maffione void
nm_set_native_flags(struct netmap_adapter * na)45232a7db7a6SVincenzo Maffione nm_set_native_flags(struct netmap_adapter *na)
45242a7db7a6SVincenzo Maffione {
4525e330262fSJustin Hibbits if_t ifp = na->ifp;
45262a7db7a6SVincenzo Maffione
45272a7db7a6SVincenzo Maffione /* We do the setup for intercepting packets only if we are the
45281d238b07SVincenzo Maffione * first user of this adapter. */
45292a7db7a6SVincenzo Maffione if (na->active_fds > 0) {
45302a7db7a6SVincenzo Maffione return;
45312a7db7a6SVincenzo Maffione }
45322a7db7a6SVincenzo Maffione
45332a7db7a6SVincenzo Maffione na->na_flags |= NAF_NETMAP_ON;
45342a7db7a6SVincenzo Maffione nm_os_onenter(ifp);
453598399ab0SVincenzo Maffione netmap_update_hostrings_mode(na);
45362a7db7a6SVincenzo Maffione }
45372a7db7a6SVincenzo Maffione
45382a7db7a6SVincenzo Maffione void
nm_clear_native_flags(struct netmap_adapter * na)45392a7db7a6SVincenzo Maffione nm_clear_native_flags(struct netmap_adapter *na)
45402a7db7a6SVincenzo Maffione {
4541e330262fSJustin Hibbits if_t ifp = na->ifp;
45422a7db7a6SVincenzo Maffione
45432a7db7a6SVincenzo Maffione /* We undo the setup for intercepting packets only if we are the
4544b6e66be2SVincenzo Maffione * last user of this adapter. */
45452a7db7a6SVincenzo Maffione if (na->active_fds > 0) {
45462a7db7a6SVincenzo Maffione return;
45472a7db7a6SVincenzo Maffione }
45482a7db7a6SVincenzo Maffione
454998399ab0SVincenzo Maffione netmap_update_hostrings_mode(na);
45502a7db7a6SVincenzo Maffione nm_os_onexit(ifp);
45512a7db7a6SVincenzo Maffione
45522a7db7a6SVincenzo Maffione na->na_flags &= ~NAF_NETMAP_ON;
45532a7db7a6SVincenzo Maffione }
45542a7db7a6SVincenzo Maffione
455575f4f3edSVincenzo Maffione void
netmap_krings_mode_commit(struct netmap_adapter * na,int onoff)455675f4f3edSVincenzo Maffione netmap_krings_mode_commit(struct netmap_adapter *na, int onoff)
455775f4f3edSVincenzo Maffione {
455875f4f3edSVincenzo Maffione enum txrx t;
455975f4f3edSVincenzo Maffione
456075f4f3edSVincenzo Maffione for_rx_tx(t) {
456175f4f3edSVincenzo Maffione int i;
456275f4f3edSVincenzo Maffione
456375f4f3edSVincenzo Maffione for (i = 0; i < netmap_real_rings(na, t); i++) {
456475f4f3edSVincenzo Maffione struct netmap_kring *kring = NMR(na, t)[i];
456575f4f3edSVincenzo Maffione
456675f4f3edSVincenzo Maffione if (onoff && nm_kring_pending_on(kring))
456775f4f3edSVincenzo Maffione kring->nr_mode = NKR_NETMAP_ON;
456875f4f3edSVincenzo Maffione else if (!onoff && nm_kring_pending_off(kring))
456975f4f3edSVincenzo Maffione kring->nr_mode = NKR_NETMAP_OFF;
457075f4f3edSVincenzo Maffione }
457175f4f3edSVincenzo Maffione }
457275f4f3edSVincenzo Maffione }
457375f4f3edSVincenzo Maffione
457401c7d25fSLuigi Rizzo /*
4575f9790aebSLuigi Rizzo * Module loader and unloader
4576f196ce38SLuigi Rizzo *
4577f9790aebSLuigi Rizzo * netmap_init() creates the /dev/netmap device and initializes
4578f9790aebSLuigi Rizzo * all global variables. Returns 0 on success, errno on failure
4579f9790aebSLuigi Rizzo * (but there is no chance)
4580f9790aebSLuigi Rizzo *
4581f9790aebSLuigi Rizzo * netmap_fini() destroys everything.
4582f196ce38SLuigi Rizzo */
4583babc7c12SLuigi Rizzo
4584babc7c12SLuigi Rizzo static struct cdev *netmap_dev; /* /dev/netmap character device. */
4585f9790aebSLuigi Rizzo extern struct cdevsw netmap_cdevsw;
4586babc7c12SLuigi Rizzo
458717885a7bSLuigi Rizzo
4588f9790aebSLuigi Rizzo void
netmap_fini(void)458968b8534bSLuigi Rizzo netmap_fini(void)
459068b8534bSLuigi Rizzo {
4591f9790aebSLuigi Rizzo if (netmap_dev)
459268b8534bSLuigi Rizzo destroy_dev(netmap_dev);
459337e3a6d3SLuigi Rizzo /* we assume that there are no longer netmap users */
459437e3a6d3SLuigi Rizzo nm_os_ifnet_fini();
459537e3a6d3SLuigi Rizzo netmap_uninit_bridges();
4596ce3ee1e7SLuigi Rizzo netmap_mem_fini();
4597ce3ee1e7SLuigi Rizzo NMG_LOCK_DESTROY();
4598b6e66be2SVincenzo Maffione nm_prinf("netmap: unloaded module.");
459968b8534bSLuigi Rizzo }
460068b8534bSLuigi Rizzo
460117885a7bSLuigi Rizzo
4602f9790aebSLuigi Rizzo int
netmap_init(void)4603f9790aebSLuigi Rizzo netmap_init(void)
460468b8534bSLuigi Rizzo {
4605f9790aebSLuigi Rizzo int error;
460668b8534bSLuigi Rizzo
4607f9790aebSLuigi Rizzo NMG_LOCK_INIT();
460868b8534bSLuigi Rizzo
4609f9790aebSLuigi Rizzo error = netmap_mem_init();
4610f9790aebSLuigi Rizzo if (error != 0)
4611f9790aebSLuigi Rizzo goto fail;
4612c929ca72SLuigi Rizzo /*
4613c929ca72SLuigi Rizzo * MAKEDEV_ETERNAL_KLD avoids an expensive check on syscalls
4614c929ca72SLuigi Rizzo * when the module is compiled in.
4615c929ca72SLuigi Rizzo * XXX could use make_dev_credv() to get error number
4616c929ca72SLuigi Rizzo */
46170e73f29aSLuigi Rizzo netmap_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD,
461811c0b69cSAdrian Chadd &netmap_cdevsw, 0, NULL, UID_ROOT, GID_WHEEL, 0600,
46190e73f29aSLuigi Rizzo "netmap");
4620f9790aebSLuigi Rizzo if (!netmap_dev)
4621f9790aebSLuigi Rizzo goto fail;
4622f9790aebSLuigi Rizzo
4623847bf383SLuigi Rizzo error = netmap_init_bridges();
4624847bf383SLuigi Rizzo if (error)
4625847bf383SLuigi Rizzo goto fail;
4626847bf383SLuigi Rizzo
46274bf50f18SLuigi Rizzo #ifdef __FreeBSD__
462837e3a6d3SLuigi Rizzo nm_os_vi_init_index();
46294bf50f18SLuigi Rizzo #endif
4630847bf383SLuigi Rizzo
463137e3a6d3SLuigi Rizzo error = nm_os_ifnet_init();
463237e3a6d3SLuigi Rizzo if (error)
463337e3a6d3SLuigi Rizzo goto fail;
463437e3a6d3SLuigi Rizzo
4635fef84509SMark Johnston #if !defined(__FreeBSD__) || defined(KLD_MODULE)
4636b6e66be2SVincenzo Maffione nm_prinf("netmap: loaded module");
4637fef84509SMark Johnston #endif
4638f9790aebSLuigi Rizzo return (0);
4639f9790aebSLuigi Rizzo fail:
464068b8534bSLuigi Rizzo netmap_fini();
4641f9790aebSLuigi Rizzo return (EINVAL); /* may be incorrect */
464268b8534bSLuigi Rizzo }
4643