- add netmap (FreeBSD header files need to be updated with this) - move prototype perl scripts to prototype/ folder - create basic structure for sipcap app (no code yet)
132 lines
4.9 KiB
Plaintext
132 lines
4.9 KiB
Plaintext
# $Id$
|
|
|
|
Adding netmap support to network device drivers
|
|
------------------------------------------------
|
|
|
|
Netmap requires some small modifications to device drivers
|
|
to support the new API. You will need to add small patches
|
|
in 3-4 places in the original source, and implement typically
|
|
5 new functions.
|
|
|
|
Device driver patches
|
|
------------------------
|
|
+ in the initial part of the source, after the device-specific
|
|
headers and prototypes have been declared, add the following
|
|
<pre>
|
|
+#if defined(DEV_NETMAP) || defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
|
|
+#include <dev/netmap/if_re_netmap.h>
|
|
+#endif /* !DEV_NETMAP */
|
|
</pre>
|
|
The place is typically ... in FreeBSD, and
|
|
... on Linux.
|
|
|
|
The header really contains the new functions that implement
|
|
the netmap API. Including them inline simplifies the building
|
|
as it does not require to insert additional dependencies in the
|
|
build system.
|
|
|
|
On FreeBSD DEV_NETMAP is sufficient to detect whether netmap extensions
|
|
should be compiled in, whereas CONFIG_NETMAP and CONFIG_NETMAP_MODULE
|
|
are the Linux equivalent.
|
|
|
|
If a driver is made of multiple source files, you will need to include
|
|
the additional header in all the (few) patched files, preferably using
|
|
a macro such as NETMAP_FOO_MAIN to indicate the file where the
|
|
new functions should be compiled in.
|
|
|
|
+ near the end of the attach routine, once the ifnet/net_device structure
|
|
has been filled and initialized, add
|
|
<pre>
|
|
+#ifdef DEV_NETMAP
|
|
+ foo_netmap_attach(adapter);
|
|
+#endif /* DEV_NETMAP */
|
|
</pre>
|
|
The argument is either the ifnet or the private device descriptor.
|
|
This is in foo_attach() on FreeBSD, and somewhere in the path of
|
|
XXX foo_open() in Linux
|
|
|
|
+ near the code called on device removal, add
|
|
<pre>
|
|
+#ifdef DEV_NETMAP
|
|
+ netmap_detach(ifp);
|
|
+#endif /* DEV_NETMAP */
|
|
</pre>
|
|
|
|
+ after the tx/rx rings have been initialized, add a patch like this:
|
|
<pre>
|
|
+#ifdef DEV_NETMAP
|
|
+ foo_netmap_config(priv);
|
|
+#endif /* DEV_NETMAP */
|
|
</pre>
|
|
The argument is typically the private device descriptor, or even
|
|
the struct ifnet/net_device.
|
|
|
|
+ in the interrupt dispatch routines, something like
|
|
<pre>
|
|
+#ifdef DEV_NETMAP
|
|
+ int dummy;
|
|
+ if (netmap_rx_irq(adapter->netdev, rx_ring->queue_index, &dummy))
|
|
+ return true;
|
|
+#endif /* DEV_NETMAP */
|
|
...
|
|
+#ifdef DEV_NETMAP
|
|
+ if (netmap_tx_irq(adapter->netdev, tx_ring->queue_index))
|
|
+ return true; /* seems to be ignored */
|
|
+#endif /* DEV_NETMAP */
|
|
</pre>
|
|
to skip the normal processing and instead wake up the process in
|
|
charge of doing I/O
|
|
|
|
New functions
|
|
----------------
|
|
The new functions serve to register the netmap-enabled device driver,
|
|
support the enable/disable of netmap mode, attach netmap buffers to the
|
|
NIC rings, and finally implement the handlers (*_txsync(), *_rxsync())
|
|
called by the system calls.
|
|
|
|
* foo_netmap_attach()
|
|
This is a relatively mechanical function. The purpose is to fetch from
|
|
the device descriptor information on the number of rings and buffers,
|
|
the way locks are used, and invoke netmap_attach().
|
|
|
|
* foo_netmap_config()
|
|
This function is in charge of (over)writing the NIC rings with
|
|
pointers to the netmap buffers. Although this is device dependent,
|
|
we can often ignore the locking issue and expect that the locking is
|
|
already taken care of by the caller.
|
|
|
|
foo_netmap_config() only needs to run if the card is in netmap mode.
|
|
A quick way to check is to call netmap_ring_init() on one of the rings,
|
|
if the function returns NULL we can immediately exit.
|
|
Otherwise, we should run a couple of nested loops (on the rings,
|
|
and then on the buffers) to fill the NIC descriptors with the
|
|
addresses of the (preallocated) netmap buffers.
|
|
|
|
For the TX rings this can even be a no-op because these rings are
|
|
typically uninitialized, and the pointers can be overridden in the
|
|
txsync() routine.
|
|
|
|
For the receive ring, the operation is more critical because the
|
|
buffers should be available by the time the NIC is enabled.
|
|
|
|
Note that the device driver typically maintains head and tail pointers
|
|
to indicate which buffers are used. It might be convenient to retain
|
|
these indexes because may of the support routines, watchdogs etc.
|
|
depends on their values.
|
|
|
|
We should note that, especially on the receive ring, there might be
|
|
an offset between the indexes used in the netmap ring and those used
|
|
in the NIC ring (which might even be non-contiguous).
|
|
|
|
* foo_netmap_reg()
|
|
support entering/exiting of netmap mode. Typically, lock, stop the device,
|
|
set/clear the netmap flag, and restart the device.
|
|
An unfortunate side effect of stopping and restarting the device is that
|
|
in many drivers the link is reinitialized, causing long delays for the
|
|
speed negotiations and spanning tree setup.
|
|
|
|
|
|
* foo_netmap_txsync()
|
|
|
|
* foo_netmap_rxsync()
|