Chapter 16. Network Drivers, Part 1: Data Structures

image with no caption

Network devices, or interfaces, transmit and receive data packets that are driven by the network subsystem (Corbet et al., 2005). In this chapter, we’ll examine the data structures used to manage these devices: ifnet, ifmedia, and mbuf. You’ll then learn about Message Signaled Interrupts, which are an alternative to traditional interrupts and are commonly used by network devices.

Note

To keep things simple, we’ll examine only Ethernet drivers. Also, I won’t provide a discussion on general networking concepts.

Network Interface Structures

An ifnet structure is the kernel’s representation of an individual network interface. It is defined in the <net/if_var.h> header as follows:

struct ifnet {
        void    *if_softc;              /* Driver private data.         */
        void    *if_l2com;              /* Protocol bits.               */
        struct  vnet *if_vnet;          /* Network stack instance.      */
        TAILQ_ENTRY(ifnet) if_link;     /* ifnet linkage.               */
        char    if_xname[IFNAMSIZ];     /* External name.               */
        const char *if_dname;           /* Driver name.                 */
        int     if_dunit;       /* Unit number or IF_DUNIT_NONE.        */
        u_int   if_refcount;            /* Reference count.             */

        /*
         * Linked list containing every address associated with
         * this interface.
         */
        struct  ifaddrhead if_addrhead;

        int     if_pcount;      /* Number of promiscuous listeners.     */
        struct  carp_if *if_carp;       /* CARP interface.              */
        struct  bpf_if *if_bpf;         /* Packet filter.               */
        u_short if_index;       /* Numeric abbreviation for interface.  */
        short   if_timer;       /* Time until if_watchdog is called.    */
        struct  ifvlantrunk *if_vlantrunk; /* 802.1Q data.              */
        int     if_flags;       /* Flags (e.g., up, down, broadcast).   */
        int     if_capabilities;/* Interface features and capabilities. */
        int     if_capenable;   /* Enabled features and capabilities.   */
        void    *if_linkmib;            /* Link specific MIB data.      */
        size_t  if_linkmiblen;          /* Length of above.             */
        struct  if_data if_data;        /* Interface information.       */
        struct  ifmultihead if_multiaddrs; /* Multicast addresses.      */
        int     if_amcount;     /* Number of multicast requests.        */

        /* Interface methods.                                           */
        int     (*if_output)
                (struct ifnet *, struct mbuf *, struct sockaddr *,
                    struct route *);
        void    (*if_input)
                (struct ifnet *, struct mbuf *);
        void    (*if_start)
                (struct ifnet *);
        int     (*if_ioctl)
                (struct ifnet *, u_long, caddr_t);
        void    (*if_watchdog)
                (struct ifnet *);
        void    (*if_init)
                (void *);
        int     (*if_resolvemulti)
                (struct ifnet *, struct sockaddr **, struct sockaddr *);
        void    (*if_qflush)
                (struct ifnet *);
        int     (*if_transmit)
                (struct ifnet *, struct mbuf *);
        void    (*if_reassign)
                (struct ifnet *, struct vnet *, char *);

        struct  vnet *if_home_vnet;     /* Where we originate from.     */
        struct  ifaddr *if_addr;        /* Link level address.          */
        void    *if_llsoftc;            /* Link level softc.            */
        int     if_drv_flags;           /* Driver managed status flags. */
        struct  ifaltq if_snd;        /* Output queue, includes altq. */
        const u_int8_t *if_broadcastaddr; /* Link level broadcast addr. */
        void    *if_bridge;             /* Bridge glue.                 */
        struct  label *if_label;        /* Interface MAC label.         */

        /* Only used by IPv6.                                           */
        struct  ifprefixhead if_prefixhead;
        void    *if_afdata[AF_MAX];
        int     if_afdata_initialized;
        struct  rwlock if_afdata_lock;
        struct  task if_linktask;
        struct  mtx if_addr_mtx;

        LIST_ENTRY(ifnet) if_clones;    /* Clone interfaces.            */
        TAILQ_HEAD(, ifg_list) if_groups; /* Linked list of groups.     */
        void    *if_pf_kif;             /* pf(4) glue.                  */
        void    *if_lagg;               /* lagg(4) glue.                */
        u_char  if_alloctype;           /* Type (e.g., Ethernet).       */

        /* Spare fields.                                                */
        char    if_cspare[3];           /* Spare characters.            */
        char    *if_description;        /* Interface description.       */
        void    *if_pspare[7];          /* Spare pointers.              */
        int     if_ispare[4];           /* Spare integers.              */
};

I’ll demonstrate how struct ifnet is used in Hello, world! in Hello, world!. For now, let’s look at its method fields.

The if_init field identifies the interface’s init routine. Init routines are called to initialize their interface.

The if_ioctl field identifies the interface’s ioctl routine. Characteristically, ioctl routines are used to configure their interface (for example, for setting the maximum transmission unit).

The if_input field identifies the interface’s input routine. An interface sends an interrupt whenever it receives a packet. Its driver-defined interrupt handler then calls its input routine to process the packet. Note that this is a departure from the norm. Input routines are called by a driver, while the other routines are called by the network stack. The if_input field generally points to a link layer routine (for example, ether_input) rather than a driver-defined routine.

Note

Obviously, link layer routines are kernel defined. Method fields that expect a link layer routine should be defined by an *ifattach function (such as ether_ifattach), not directly by a driver. *ifattach functions are described in Network Interface Structure Management Routines in Network Interface Structure Management Routines.

The if_output field identifies the interface’s output routine. Output routines are called by the network stack to prepare an upper-layer packet for transmission. Every output routine ends by calling its interface’s transmit routine. If an interface lacks a transmit routine, its start routine is called instead. Typically, when a network driver defines a transmit routine, its start routine is undefined, and vice versa. The if_output field generally points to a link layer routine (for example, ether_output) rather than a driver-defined routine.

The if_start field identifies the interface’s start routine. Before I describe start routines, it’s important to discuss send queues. Send queues are filled by output routines. Start routines remove one packet from their send queue and deposit it in their interface’s transmit ring. They repeat this process until the send queue is empty or the transmit ring is full. Transmit rings are simply ring buffers used for transmission. Network interfaces use ring buffers for transmission and reception.

The if_transmit field identifies the interface’s transmit routine. Transmit routines are an alternative to start routines. Transmit routines maintain their own send queues. That is, they forego the predefined send queue, and output routines push packets directly to them. Transmit routines can maintain multiple send queues, which makes them ideal for interfaces with multiple transmit rings.

The if_qflush field identifies the interface’s qflush routine. Qflush routines are called to flush the send queues of transmit routines. Every transmit routine must have a corresponding qflush routine.

The if_resolvemulti field identifies the interface’s resolvemulti routine. Resolvemulti routines are called to resolve a network layer address into a link layer address when registering a multicast address with their interface. The if_resolvemulti field generally points to a link layer routine (for example, ether_resolvemulti) rather than a driver-defined routine.

The if_reassign field identifies the interface’s reassign routine. Reassign routines are called before their interface is moved to another virtual network stack (vnet). They perform any tasks necessary before the move. The if_reassign field generally points to a link layer routine (for example, ether_reassign) rather than a driver-defined routine.

The if_watchdog field is deprecated and must not be defined. In FreeBSD version 9, if_watchdog will be removed.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.146.65.212