iPXE
Defines | Functions | Variables
netfront.c File Reference

Xen netfront driver. More...

#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <ipxe/netdevice.h>
#include <ipxe/ethernet.h>
#include <ipxe/if_ether.h>
#include <ipxe/malloc.h>
#include <ipxe/base16.h>
#include <ipxe/xen.h>
#include <ipxe/xenstore.h>
#include <ipxe/xenbus.h>
#include <ipxe/xengrant.h>
#include <ipxe/xenevent.h>
#include "netfront.h"

Go to the source code of this file.

Defines

#define EIO_NETIF_RSP_ERROR   __einfo_error ( EINFO_EIO_NETIF_RSP_ERROR )
#define EINFO_EIO_NETIF_RSP_ERROR
#define EIO_NETIF_RSP_DROPPED   __einfo_error ( EINFO_EIO_NETIF_RSP_DROPPED )
#define EINFO_EIO_NETIF_RSP_DROPPED
#define EIO_NETIF_RSP(status)

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static int netfront_reset (struct netfront_nic *netfront)
 Reset device.
static int netfront_read_mac (struct netfront_nic *netfront, void *hw_addr)
 Fetch MAC address.
static int netfront_write_num (struct netfront_nic *netfront, const char *subkey, unsigned long num)
 Write XenStore numeric value.
static int netfront_write_flag (struct netfront_nic *netfront, const char *subkey)
 Write XenStore flag value.
static int netfront_rm (struct netfront_nic *netfront, const char *subkey)
 Delete XenStore value.
static int netfront_create_event (struct netfront_nic *netfront)
 Create event channel.
static int netfront_send_event (struct netfront_nic *netfront)
 Send event.
static void netfront_destroy_event (struct netfront_nic *netfront)
 Destroy event channel.
static int netfront_create_ring (struct netfront_nic *netfront, struct netfront_ring *ring)
 Create descriptor ring.
static int netfront_push (struct netfront_nic *netfront, struct netfront_ring *ring, struct io_buffer *iobuf, uint16_t *id, grant_ref_t *ref)
 Add buffer to descriptor ring.
static struct io_buffernetfront_pull (struct netfront_nic *netfront, struct netfront_ring *ring, unsigned int id)
 Remove buffer from descriptor ring.
static void netfront_destroy_ring (struct netfront_nic *netfront, struct netfront_ring *ring, void(*discard)(struct io_buffer *))
 Destroy descriptor ring.
static void netfront_refill_rx (struct net_device *netdev)
 Refill receive descriptor ring.
static int netfront_open (struct net_device *netdev)
 Open network device.
static void netfront_close (struct net_device *netdev)
 Close network device.
static int netfront_transmit (struct net_device *netdev, struct io_buffer *iobuf)
 Transmit packet.
static void netfront_poll_tx (struct net_device *netdev)
 Poll for completed packets.
static void netfront_poll_rx (struct net_device *netdev)
 Poll for received packets.
static void netfront_poll (struct net_device *netdev)
 Poll for completed and received packets.
static int netfront_probe (struct xen_device *xendev)
 Probe Xen device.
static void netfront_remove (struct xen_device *xendev)
 Remove Xen device.

Variables

static struct net_device_operations netfront_operations
 Network device operations.
struct xen_driver netfront_driver __xen_driver
 Xen netfront driver.

Detailed Description

Xen netfront driver.

Definition in file netfront.c.


Define Documentation

Definition at line 48 of file netfront.c.

Value:
__einfo_uniqify ( EINFO_EIO, -NETIF_RSP_ERROR,                  \
                          "Unspecified network error" )

Definition at line 50 of file netfront.c.

Definition at line 53 of file netfront.c.

Value:
__einfo_uniqify ( EINFO_EIO, -NETIF_RSP_DROPPED,                \
                          "Packet dropped" )

Definition at line 55 of file netfront.c.

#define EIO_NETIF_RSP (   status)
Value:

Definition at line 58 of file netfront.c.

Referenced by netfront_poll_rx(), and netfront_poll_tx().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static int netfront_reset ( struct netfront_nic *  netfront) [static]

Reset device.

Parameters:
netfrontNetfront device
Return values:
rcReturn status code

Definition at line 75 of file netfront.c.

References DBGC, xen_device::key, rc, state, strerror(), xenbus_backend_state(), xenbus_backend_wait(), xenbus_set_state(), XenbusStateClosed, XenbusStateInitialising, and XenbusStateInitWait.

Referenced by netfront_close(), netfront_open(), and netfront_probe().

                                                            {
        struct xen_device *xendev = netfront->xendev;
        int state;
        int rc;

        /* Get current backend state */
        if ( ( state = xenbus_backend_state ( xendev ) ) < 0 ) {
                rc = state;
                DBGC ( netfront, "NETFRONT %s could not read backend state: "
                       "%s\n", xendev->key, strerror ( rc ) );
                return rc;
        }

        /* If the backend is not already in InitWait, then mark
         * frontend as Closed to shut down the backend.
         */
        if ( state != XenbusStateInitWait ) {

                /* Set state to Closed */
                xenbus_set_state ( xendev, XenbusStateClosed );

                /* Wait for backend to reach Closed */
                if ( ( rc = xenbus_backend_wait ( xendev,
                                                  XenbusStateClosed ) ) != 0 ) {
                        DBGC ( netfront, "NETFRONT %s backend did not reach "
                               "Closed: %s\n", xendev->key, strerror ( rc ) );
                        return rc;
                }
        }

        /* Reset state to Initialising */
        xenbus_set_state ( xendev, XenbusStateInitialising );

        /* Wait for backend to reach InitWait */
        if ( ( rc = xenbus_backend_wait ( xendev, XenbusStateInitWait ) ) != 0){
                DBGC ( netfront, "NETFRONT %s backend did not reach InitWait: "
                       "%s\n", xendev->key, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int netfront_read_mac ( struct netfront_nic *  netfront,
void *  hw_addr 
) [static]

Fetch MAC address.

Parameters:
netfrontNetfront device
hw_addrHardware address to fill in
Return values:
rcReturn status code

Definition at line 125 of file netfront.c.

References DBGC, DBGC2, ETH_ALEN, free, hex_decode(), xen_device::key, len, mac, NULL, rc, strerror(), xen_device::xen, and xenstore_read().

Referenced by netfront_probe().

                                                                              {
        struct xen_device *xendev = netfront->xendev;
        struct xen_hypervisor *xen = xendev->xen;
        char *mac;
        int len;
        int rc;

        /* Fetch MAC address */
        if ( ( rc = xenstore_read ( xen, &mac, xendev->key, "mac", NULL ) )!=0){
                DBGC ( netfront, "NETFRONT %s could not read MAC address: %s\n",
                       xendev->key, strerror ( rc ) );
                goto err_xenstore_read;
        }
        DBGC2 ( netfront, "NETFRONT %s has MAC address \"%s\"\n",
                xendev->key, mac );

        /* Decode MAC address */
        len = hex_decode ( ':', mac, hw_addr, ETH_ALEN );
        if ( len < 0 ) {
                rc = len;
                DBGC ( netfront, "NETFRONT %s could not decode MAC address "
                       "\"%s\": %s\n", xendev->key, mac, strerror ( rc ) );
                goto err_decode;
        }

        /* Success */
        rc = 0;

 err_decode:
        free ( mac );
 err_xenstore_read:
        return rc;
}
static int netfront_write_num ( struct netfront_nic *  netfront,
const char *  subkey,
unsigned long  num 
) [static]

Write XenStore numeric value.

Parameters:
netfrontNetfront device
subkeySubkey
numNumeric value
Return values:
rcReturn status code

Definition at line 167 of file netfront.c.

References DBGC, xen_device::key, NULL, rc, strerror(), xen_device::xen, and xenstore_write_num().

Referenced by netfront_create_event(), netfront_create_ring(), and netfront_write_flag().

                                                                        {
        struct xen_device *xendev = netfront->xendev;
        struct xen_hypervisor *xen = xendev->xen;
        int rc;

        /* Write value */
        if ( ( rc = xenstore_write_num ( xen, num, xendev->key, subkey,
                                         NULL ) ) != 0 ) {
                DBGC ( netfront, "NETFRONT %s could not set %s=\"%ld\": %s\n",
                       xendev->key, subkey, num, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int netfront_write_flag ( struct netfront_nic *  netfront,
const char *  subkey 
) [static]

Write XenStore flag value.

Parameters:
netfrontNetfront device
subkeySubkey
numNumeric value
Return values:
rcReturn status code

Definition at line 192 of file netfront.c.

References netfront_write_num().

Referenced by netfront_open().

                                                      {

        return netfront_write_num ( netfront, subkey, 1 );
}
static int netfront_rm ( struct netfront_nic *  netfront,
const char *  subkey 
) [static]

Delete XenStore value.

Parameters:
netfrontNetfront device
subkeySubkey
Return values:
rcReturn status code

Definition at line 205 of file netfront.c.

References DBGC, xen_device::key, NULL, rc, strerror(), xen_device::xen, and xenstore_rm().

Referenced by netfront_close(), netfront_create_event(), netfront_create_ring(), netfront_destroy_event(), netfront_destroy_ring(), and netfront_open().

                                                                             {
        struct xen_device *xendev = netfront->xendev;
        struct xen_hypervisor *xen = xendev->xen;
        int rc;

        /* Remove value */
        if ( ( rc = xenstore_rm ( xen, xendev->key, subkey, NULL ) ) != 0 ) {
                DBGC ( netfront, "NETFRONT %s could not delete %s: %s\n",
                       xendev->key, subkey, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int netfront_create_event ( struct netfront_nic *  netfront) [static]

Create event channel.

Parameters:
netfrontNetfront device
Return values:
rcReturn status code

Definition at line 233 of file netfront.c.

References xen_device::backend_id, DBGC, evtchn_alloc_unbound::dom, DOMID_SELF, EXEN, xen_device::key, netfront_rm(), netfront_write_num(), evtchn_alloc_unbound::port, evtchn_close::port, rc, evtchn_alloc_unbound::remote_dom, strerror(), and xen_device::xen.

Referenced by netfront_open().

                                                                   {
        struct xen_device *xendev = netfront->xendev;
        struct xen_hypervisor *xen = xendev->xen;
        struct evtchn_alloc_unbound alloc_unbound;
        struct evtchn_close close;
        int xenrc;
        int rc;

        /* Allocate event */
        alloc_unbound.dom = DOMID_SELF;
        alloc_unbound.remote_dom = xendev->backend_id;
        if ( ( xenrc = xenevent_alloc_unbound ( xen, &alloc_unbound ) ) != 0 ) {
                rc = -EXEN ( xenrc );
                DBGC ( netfront, "NETFRONT %s could not allocate event: %s\n",
                       xendev->key, strerror ( rc ) );
                goto err_alloc_unbound;
        }
        netfront->event.port = alloc_unbound.port;

        /* Publish event channel */
        if ( ( rc = netfront_write_num ( netfront, "event-channel",
                                         netfront->event.port ) ) != 0 )
                goto err_write_num;

        DBGC ( netfront, "NETFRONT %s event-channel=\"%d\"\n",
               xendev->key, netfront->event.port );
        return 0;

        netfront_rm ( netfront, "event-channel" );
 err_write_num:
        close.port = netfront->event.port;
        xenevent_close ( xen, &close );
 err_alloc_unbound:
        return rc;
}
static int netfront_send_event ( struct netfront_nic *  netfront) [inline, static]

Send event.

Parameters:
netfrontNetfront device
Return values:
rcReturn status code

Definition at line 276 of file netfront.c.

References DBGC, EXEN, xen_device::key, rc, strerror(), and xen_device::xen.

Referenced by netfront_refill_rx(), and netfront_transmit().

                                                      {
        struct xen_device *xendev = netfront->xendev;
        struct xen_hypervisor *xen = xendev->xen;
        int xenrc;
        int rc;

        /* Send event */
        if ( ( xenrc = xenevent_send ( xen, &netfront->event ) ) != 0 ) {
                rc = -EXEN ( xenrc );
                DBGC ( netfront, "NETFRONT %s could not send event: %s\n",
                       xendev->key, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static void netfront_destroy_event ( struct netfront_nic *  netfront) [static]

Destroy event channel.

Parameters:
netfrontNetfront device

Definition at line 298 of file netfront.c.

References netfront_rm(), evtchn_close::port, and xen_device::xen.

Referenced by netfront_close(), and netfront_open().

                                                                     {
        struct xen_device *xendev = netfront->xendev;
        struct xen_hypervisor *xen = xendev->xen;
        struct evtchn_close close;

        /* Unpublish event channel */
        netfront_rm ( netfront, "event-channel" );

        /* Close event channel */
        close.port = netfront->event.port;
        xenevent_close ( xen, &close );
}
static int netfront_create_ring ( struct netfront_nic *  netfront,
struct netfront_ring ring 
) [static]

Create descriptor ring.

Parameters:
netfrontNetfront device
ringDescriptor ring
Return values:
rcReturn status code

Definition at line 325 of file netfront.c.

References assert, xen_device::backend_id, netfront_ring::count, DBGC, ENOMEM, free_dma(), netfront_ring::id_cons, netfront_ring::id_prod, netfront_ring::ids, netfront_ring::iobufs, xen_device::key, malloc_dma(), netfront_rm(), netfront_write_num(), NULL, PAGE_SIZE, netfront_ring::raw, rc, netfront_ring::ref, netfront_ring::ref_key, netfront_ring::sring, strerror(), virt_to_phys(), and xen_device::xen.

Referenced by netfront_open().

                                                               {
        struct xen_device *xendev = netfront->xendev;
        struct xen_hypervisor *xen = xendev->xen;
        unsigned int i;
        int rc;

        /* Initialise buffer ID ring */
        for ( i = 0 ; i < ring->count ; i++ ) {
                ring->ids[i] = i;
                assert ( ring->iobufs[i] == NULL );
        }
        ring->id_prod = 0;
        ring->id_cons = 0;

        /* Allocate and initialise shared ring */
        ring->sring.raw = malloc_dma ( PAGE_SIZE, PAGE_SIZE );
        if ( ! ring->sring.raw ) {
                rc = -ENOMEM;
                goto err_alloc;
        }

        /* Grant access to shared ring */
        if ( ( rc = xengrant_permit_access ( xen, ring->ref, xendev->backend_id,
                                             0, ring->sring.raw ) ) != 0 ) {
                DBGC ( netfront, "NETFRONT %s could not permit access to "
                       "%#08lx: %s\n", xendev->key,
                       virt_to_phys ( ring->sring.raw ), strerror ( rc ) );
                goto err_permit_access;
        }

        /* Publish shared ring reference */
        if ( ( rc = netfront_write_num ( netfront, ring->ref_key,
                                         ring->ref ) ) != 0 )
                goto err_write_num;

        DBGC ( netfront, "NETFRONT %s %s=\"%d\" [%08lx,%08lx)\n",
               xendev->key, ring->ref_key, ring->ref,
               virt_to_phys ( ring->sring.raw ),
               ( virt_to_phys ( ring->sring.raw ) + PAGE_SIZE ) );
        return 0;

        netfront_rm ( netfront, ring->ref_key );
 err_write_num:
        xengrant_invalidate ( xen, ring->ref );
 err_permit_access:
        free_dma ( ring->sring.raw, PAGE_SIZE );
 err_alloc:
        return rc;
}
static int netfront_push ( struct netfront_nic *  netfront,
struct netfront_ring ring,
struct io_buffer iobuf,
uint16_t id,
grant_ref_t ref 
) [static]

Add buffer to descriptor ring.

Parameters:
netfrontNetfront device
ringDescriptor ring
iobufI/O buffer
idBuffer ID to fill in
refGrant reference to fill in
Return values:
rcReturn status code

The caller is responsible for ensuring that there is space in the ring.

Definition at line 389 of file netfront.c.

References assert, xen_device::backend_id, netfront_ring::count, io_buffer::data, DBGC, netfront_ring::id_prod, netfront_ring::ids, netfront_ring::iobufs, xen_device::key, NULL, rc, netfront_ring::refs, strerror(), virt_to_phys(), and xen_device::xen.

Referenced by netfront_refill_rx(), and netfront_transmit().

                                                            {
        struct xen_device *xendev = netfront->xendev;
        struct xen_hypervisor *xen = xendev->xen;
        unsigned int next_id;
        unsigned int next_ref;
        int rc;

        /* Sanity check */
        assert ( ! netfront_ring_is_full ( ring ) );

        /* Allocate buffer ID */
        next_id = ring->ids[ ring->id_prod & ( ring->count - 1 ) ];
        next_ref = ring->refs[next_id];

        /* Grant access to I/O buffer page.  I/O buffers are naturally
         * aligned, so we never need to worry about crossing a page
         * boundary.
         */
        if ( ( rc = xengrant_permit_access ( xen, next_ref, xendev->backend_id,
                                             0, iobuf->data ) ) != 0 ) {
                DBGC ( netfront, "NETFRONT %s could not permit access to "
                       "%#08lx: %s\n", xendev->key,
                       virt_to_phys ( iobuf->data ), strerror ( rc ) );
                return rc;
        }

        /* Store I/O buffer */
        assert ( ring->iobufs[next_id] == NULL );
        ring->iobufs[next_id] = iobuf;

        /* Consume buffer ID */
        ring->id_prod++;

        /* Return buffer ID and grant reference */
        *id = next_id;
        *ref = next_ref;

        return 0;
}
static struct io_buffer* netfront_pull ( struct netfront_nic *  netfront,
struct netfront_ring ring,
unsigned int  id 
) [static, read]

Remove buffer from descriptor ring.

Parameters:
netfrontNetfront device
ringDescriptor ring
idBuffer ID
Return values:
iobufI/O buffer

Definition at line 439 of file netfront.c.

References assert, netfront_ring::count, count, id, netfront_ring::id_cons, netfront_ring::ids, netfront_ring::iobufs, NULL, netfront_ring::refs, and xen_device::xen.

Referenced by netfront_destroy_ring(), netfront_poll_rx(), and netfront_poll_tx().

                                                            {
        struct xen_device *xendev = netfront->xendev;
        struct xen_hypervisor *xen = xendev->xen;
        struct io_buffer *iobuf;

        /* Sanity check */
        assert ( id < ring->count );

        /* Revoke access from I/O buffer page */
        xengrant_invalidate ( xen, ring->refs[id] );

        /* Retrieve I/O buffer */
        iobuf = ring->iobufs[id];
        assert ( iobuf != NULL );
        ring->iobufs[id] = NULL;

        /* Free buffer ID */
        ring->ids[ ( ring->id_cons++ ) & ( ring->count - 1 ) ] = id;

        return iobuf;
}
static void netfront_destroy_ring ( struct netfront_nic *  netfront,
struct netfront_ring ring,
void(*)(struct io_buffer *)  discard 
) [static]

Destroy descriptor ring.

Parameters:
netfrontNetfront device
ringDescriptor ring
discardMethod used to discard outstanding buffer, or NULL

Definition at line 470 of file netfront.c.

References netfront_ring::count, free_dma(), id, netfront_ring::id_cons, netfront_ring::ids, netfront_pull(), netfront_rm(), NULL, PAGE_SIZE, netfront_ring::raw, netfront_ring::ref, netfront_ring::ref_key, netfront_ring::sring, and xen_device::xen.

Referenced by netfront_close(), and netfront_open().

                                                                               {
        struct xen_device *xendev = netfront->xendev;
        struct xen_hypervisor *xen = xendev->xen;
        struct io_buffer *iobuf;
        unsigned int id;

        /* Flush any outstanding buffers */
        while ( ! netfront_ring_is_empty ( ring ) ) {
                id = ring->ids[ ring->id_cons & ( ring->count - 1 ) ];
                iobuf = netfront_pull ( netfront, ring, id );
                if ( discard )
                        discard ( iobuf );
        }

        /* Unpublish shared ring reference */
        netfront_rm ( netfront, ring->ref_key );

        /* Revoke access from shared ring */
        xengrant_invalidate ( xen, ring->ref );

        /* Free page */
        free_dma ( ring->sring.raw, PAGE_SIZE );
        ring->sring.raw = NULL;
}
static void netfront_refill_rx ( struct net_device netdev) [static]

Refill receive descriptor ring.

Parameters:
netdevNetwork device

Definition at line 509 of file netfront.c.

References alloc_iob(), io_buffer::data, DBGC2, netif_rx_request::gref, netif_rx_request::id, iob_tailroom(), xen_device::key, netdev_rx_err(), netfront_push(), NETFRONT_RX_FILL, netfront_send_event(), notify, PAGE_SIZE, net_device::priv, rc, request, RING_GET_REQUEST, RING_PUSH_REQUESTS_AND_CHECK_NOTIFY, and virt_to_phys().

Referenced by netfront_open(), and netfront_poll().

                                                             {
        struct netfront_nic *netfront = netdev->priv;
        struct xen_device *xendev = netfront->xendev;
        struct io_buffer *iobuf;
        struct netif_rx_request *request;
        unsigned int refilled = 0;
        int notify;
        int rc;

        /* Refill ring */
        while ( netfront_ring_fill ( &netfront->rx ) < NETFRONT_RX_FILL ) {

                /* Allocate I/O buffer */
                iobuf = alloc_iob ( PAGE_SIZE );
                if ( ! iobuf ) {
                        /* Wait for next refill */
                        break;
                }

                /* Add to descriptor ring */
                request = RING_GET_REQUEST ( &netfront->rx_fring,
                                             netfront->rx_fring.req_prod_pvt );
                if ( ( rc = netfront_push ( netfront, &netfront->rx,
                                            iobuf, &request->id,
                                            &request->gref ) ) != 0 ) {
                        netdev_rx_err ( netdev, iobuf, rc );
                        break;
                }
                DBGC2 ( netfront, "NETFRONT %s RX id %d ref %d is %#08lx+%zx\n",
                        xendev->key, request->id, request->gref,
                        virt_to_phys ( iobuf->data ), iob_tailroom ( iobuf ) );

                /* Move to next descriptor */
                netfront->rx_fring.req_prod_pvt++;
                refilled++;

        }

        /* Push new descriptors and notify backend if applicable */
        if ( refilled ) {
                RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->rx_fring,
                                                      notify );
                if ( notify )
                        netfront_send_event ( netfront );
        }
}
static int netfront_open ( struct net_device netdev) [static]

Open network device.

Parameters:
netdevNetwork device
Return values:
rcReturn status code

Definition at line 562 of file netfront.c.

References assert, DBGC, FRONT_RING_INIT, xen_device::key, netdev_link_up(), netfront_create_event(), netfront_create_ring(), netfront_destroy_event(), netfront_destroy_ring(), netfront_refill_rx(), netfront_reset(), netfront_rm(), netfront_write_flag(), NULL, PAGE_SIZE, net_device::priv, rc, RING_SIZE, SHARED_RING_INIT, strerror(), xenbus_backend_wait(), xenbus_set_state(), and XenbusStateConnected.

                                                       {
        struct netfront_nic *netfront = netdev->priv;
        struct xen_device *xendev = netfront->xendev;
        int rc;

        /* Ensure device is in a suitable initial state */
        if ( ( rc = netfront_reset ( netfront ) ) != 0 )
                goto err_reset;

        /* Create transmit descriptor ring */
        if ( ( rc = netfront_create_ring ( netfront, &netfront->tx ) ) != 0 )
                goto err_create_tx;
        SHARED_RING_INIT ( netfront->tx_sring );
        FRONT_RING_INIT ( &netfront->tx_fring, netfront->tx_sring, PAGE_SIZE );
        assert ( RING_SIZE ( &netfront->tx_fring ) >= netfront->tx.count );

        /* Create receive descriptor ring */
        if ( ( rc = netfront_create_ring ( netfront, &netfront->rx ) ) != 0 )
                goto err_create_rx;
        SHARED_RING_INIT ( netfront->rx_sring );
        FRONT_RING_INIT ( &netfront->rx_fring, netfront->rx_sring, PAGE_SIZE );
        assert ( RING_SIZE ( &netfront->rx_fring ) >= netfront->rx.count );

        /* Create event channel */
        if ( ( rc = netfront_create_event ( netfront ) ) != 0 )
                goto err_create_event;

        /* "Request" the rx-copy feature.  Current versions of
         * xen_netback.ko will fail silently if this parameter is not
         * present.
         */
        if ( ( rc = netfront_write_flag ( netfront, "request-rx-copy" ) ) != 0 )
                goto err_request_rx_copy;

        /* Disable checksum offload, since we will always do the work anyway */
        if ( ( rc = netfront_write_flag ( netfront,
                                          "feature-no-csum-offload" ) ) != 0 )
                goto err_feature_no_csum_offload;

        /* Inform backend that we will send notifications for RX requests */
        if ( ( rc = netfront_write_flag ( netfront,
                                          "feature-rx-notify" ) ) != 0 )
                goto err_feature_rx_notify;

        /* Set state to Connected */
        if ( ( rc = xenbus_set_state ( xendev, XenbusStateConnected ) ) != 0 ) {
                DBGC ( netfront, "NETFRONT %s could not set state=\"%d\": %s\n",
                       xendev->key, XenbusStateConnected, strerror ( rc ) );
                goto err_set_state;
        }

        /* Wait for backend to connect */
        if ( ( rc = xenbus_backend_wait ( xendev, XenbusStateConnected ) ) !=0){
                DBGC ( netfront, "NETFRONT %s could not connect to backend: "
                       "%s\n", xendev->key, strerror ( rc ) );
                goto err_backend_wait;
        }

        /* Refill receive descriptor ring */
        netfront_refill_rx ( netdev );

        /* Set link up */
        netdev_link_up ( netdev );

        return 0;

 err_backend_wait:
        netfront_reset ( netfront );
 err_set_state:
        netfront_rm ( netfront, "feature-rx-notify" );
 err_feature_rx_notify:
        netfront_rm ( netfront, "feature-no-csum-offload" );
 err_feature_no_csum_offload:
        netfront_rm ( netfront, "request-rx-copy" );
 err_request_rx_copy:
        netfront_destroy_event ( netfront );
 err_create_event:
        netfront_destroy_ring ( netfront, &netfront->rx, NULL );
 err_create_rx:
        netfront_destroy_ring ( netfront, &netfront->tx, NULL );
 err_create_tx:
 err_reset:
        return rc;
}
static void netfront_close ( struct net_device netdev) [static]

Close network device.

Parameters:
netdevNetwork device

Definition at line 652 of file netfront.c.

References DBGC, free_iob(), xen_device::key, netdev_link_down(), netdev_link_err(), netfront_destroy_event(), netfront_destroy_ring(), netfront_reset(), netfront_rm(), NULL, net_device::priv, rc, and strerror().

                                                         {
        struct netfront_nic *netfront = netdev->priv;
        struct xen_device *xendev = netfront->xendev;
        int rc;

        /* Reset devic, thereby ensuring that grant references are no
         * longer in use, etc.
         */
        if ( ( rc = netfront_reset ( netfront ) ) != 0 ) {
                DBGC ( netfront, "NETFRONT %s could not disconnect from "
                       "backend: %s\n", xendev->key, strerror ( rc ) );
                /* Things will probably go _very_ badly wrong if this
                 * happens, since it means the backend may still write
                 * to the outstanding RX buffers that we are about to
                 * free.  The best we can do is report the error via
                 * the link status, but there's a good chance the
                 * machine will crash soon.
                 */
                netdev_link_err ( netdev, rc );
        } else {
                netdev_link_down ( netdev );
        }

        /* Delete flags */
        netfront_rm ( netfront, "feature-rx-notify" );
        netfront_rm ( netfront, "feature-no-csum-offload" );
        netfront_rm ( netfront, "request-rx-copy" );

        /* Destroy event channel */
        netfront_destroy_event ( netfront );

        /* Destroy receive descriptor ring, freeing any outstanding
         * I/O buffers.
         */
        netfront_destroy_ring ( netfront, &netfront->rx, free_iob );

        /* Destroy transmit descriptor ring.  Leave any outstanding
         * I/O buffers to be freed by netdev_tx_flush().
         */
        netfront_destroy_ring ( netfront, &netfront->tx, NULL );
}
static int netfront_transmit ( struct net_device netdev,
struct io_buffer iobuf 
) [static]

Transmit packet.

Parameters:
netdevNetwork device
iobufI/O buffer
Return values:
rcReturn status code

Definition at line 701 of file netfront.c.

References io_buffer::data, DBGC, DBGC2, ENOBUFS, netif_tx_request::flags, netif_tx_request::gref, netif_tx_request::id, iob_len(), xen_device::key, netfront_push(), netfront_send_event(), NETTXF_data_validated, notify, netif_tx_request::offset, PAGE_SIZE, net_device::priv, rc, request, RING_GET_REQUEST, RING_PUSH_REQUESTS_AND_CHECK_NOTIFY, netif_tx_request::size, and virt_to_phys().

                                                         {
        struct netfront_nic *netfront = netdev->priv;
        struct xen_device *xendev = netfront->xendev;
        struct netif_tx_request *request;
        int notify;
        int rc;

        /* Check that we have space in the ring */
        if ( netfront_ring_is_full ( &netfront->tx ) ) {
                DBGC ( netfront, "NETFRONT %s out of transmit descriptors\n",
                       xendev->key );
                return -ENOBUFS;
        }

        /* Add to descriptor ring */
        request = RING_GET_REQUEST ( &netfront->tx_fring,
                                     netfront->tx_fring.req_prod_pvt );
        if ( ( rc = netfront_push ( netfront, &netfront->tx, iobuf,
                                    &request->id, &request->gref ) ) != 0 ) {
                return rc;
        }
        request->offset = ( virt_to_phys ( iobuf->data ) & ( PAGE_SIZE - 1 ) );
        request->flags = NETTXF_data_validated;
        request->size = iob_len ( iobuf );
        DBGC2 ( netfront, "NETFRONT %s TX id %d ref %d is %#08lx+%zx\n",
                xendev->key, request->id, request->gref,
                virt_to_phys ( iobuf->data ), iob_len ( iobuf ) );

        /* Consume descriptor */
        netfront->tx_fring.req_prod_pvt++;

        /* Push new descriptor and notify backend if applicable */
        RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->tx_fring, notify );
        if ( notify )
                netfront_send_event ( netfront );

        return 0;
}
static void netfront_poll_tx ( struct net_device netdev) [static]

Poll for completed packets.

Parameters:
netdevNetwork device

Definition at line 746 of file netfront.c.

References DBGC2, EIO_NETIF_RSP, netif_tx_response::id, xen_device::key, netdev_tx_complete(), netdev_tx_complete_err(), netfront_pull(), NETIF_RSP_OKAY, net_device::priv, rc, RING_GET_RESPONSE, RING_HAS_UNCONSUMED_RESPONSES, status, netif_tx_response::status, and strerror().

Referenced by netfront_poll().

                                                           {
        struct netfront_nic *netfront = netdev->priv;
        struct xen_device *xendev = netfront->xendev;
        struct netif_tx_response *response;
        struct io_buffer *iobuf;
        unsigned int status;
        int rc;

        /* Consume any unconsumed responses */
        while ( RING_HAS_UNCONSUMED_RESPONSES ( &netfront->tx_fring ) ) {

                /* Get next response */
                response = RING_GET_RESPONSE ( &netfront->tx_fring,
                                               netfront->tx_fring.rsp_cons++ );

                /* Retrieve from descriptor ring */
                iobuf = netfront_pull ( netfront, &netfront->tx, response->id );
                status = response->status;
                if ( status == NETIF_RSP_OKAY ) {
                        DBGC2 ( netfront, "NETFRONT %s TX id %d complete\n",
                                xendev->key, response->id );
                        netdev_tx_complete ( netdev, iobuf );
                } else {
                        rc = -EIO_NETIF_RSP ( status );
                        DBGC2 ( netfront, "NETFRONT %s TX id %d error %d: %s\n",
                                xendev->key, response->id, status,
                                strerror ( rc ) );
                        netdev_tx_complete_err ( netdev, iobuf, rc );
                }
        }
}
static void netfront_poll_rx ( struct net_device netdev) [static]

Poll for received packets.

Parameters:
netdevNetwork device

Definition at line 783 of file netfront.c.

References io_buffer::data, DBGC2, EIO_NETIF_RSP, netif_rx_response::id, iob_put, iob_reserve, xen_device::key, len, netdev_rx(), netdev_rx_err(), netfront_pull(), netif_rx_response::offset, net_device::priv, rc, RING_GET_RESPONSE, RING_HAS_UNCONSUMED_RESPONSES, status, netif_rx_response::status, strerror(), and virt_to_phys().

Referenced by netfront_poll().

                                                           {
        struct netfront_nic *netfront = netdev->priv;
        struct xen_device *xendev = netfront->xendev;
        struct netif_rx_response *response;
        struct io_buffer *iobuf;
        int status;
        size_t len;
        int rc;

        /* Consume any unconsumed responses */
        while ( RING_HAS_UNCONSUMED_RESPONSES ( &netfront->rx_fring ) ) {

                /* Get next response */
                response = RING_GET_RESPONSE ( &netfront->rx_fring,
                                               netfront->rx_fring.rsp_cons++ );

                /* Retrieve from descriptor ring */
                iobuf = netfront_pull ( netfront, &netfront->rx, response->id );
                status = response->status;
                if ( status >= 0 ) {
                        len = status;
                        iob_reserve ( iobuf, response->offset );
                        iob_put ( iobuf, len );
                        DBGC2 ( netfront, "NETFRONT %s RX id %d complete "
                                "%#08lx+%zx\n", xendev->key, response->id,
                                virt_to_phys ( iobuf->data ), len );
                        netdev_rx ( netdev, iobuf );
                } else {
                        rc = -EIO_NETIF_RSP ( status );
                        DBGC2 ( netfront, "NETFRONT %s RX id %d error %d: %s\n",
                                xendev->key, response->id, status,
                                strerror ( rc ) );
                        netdev_rx_err ( netdev, iobuf, rc );
                }
        }
}
static void netfront_poll ( struct net_device netdev) [static]

Poll for completed and received packets.

Parameters:
netdevNetwork device

Definition at line 825 of file netfront.c.

References netfront_poll_rx(), netfront_poll_tx(), and netfront_refill_rx().

                                                        {

        /* Poll for TX completions */
        netfront_poll_tx ( netdev );

        /* Poll for RX completions */
        netfront_poll_rx ( netdev );

        /* Refill RX descriptor ring */
        netfront_refill_rx ( netdev );
}
static int netfront_probe ( struct xen_device xendev) [static]

Probe Xen device.

Parameters:
xendevXen device
Return values:
rcReturn status code

Definition at line 858 of file netfront.c.

References alloc_etherdev(), xen_device::backend, xen_device::backend_id, DBGC, xen_device::dev, net_device::dev, ENOMEM, net_device::hw_addr, xen_device::key, netdev, netdev_init(), netdev_link_down(), netdev_nullify(), netdev_put(), NETFRONT_NUM_RX_DESC, NETFRONT_NUM_TX_DESC, netfront_read_mac(), NETFRONT_REF_COUNT, NETFRONT_REF_RX_BASE, NETFRONT_REF_RX_RING, NETFRONT_REF_TX_BASE, NETFRONT_REF_TX_RING, netfront_reset(), net_device::priv, rc, register_netdev(), strerror(), unregister_netdev(), xen_device::xen, xen_set_drvdata(), xengrant_alloc(), and xengrant_free().

                                                        {
        struct xen_hypervisor *xen = xendev->xen;
        struct net_device *netdev;
        struct netfront_nic *netfront;
        int rc;

        /* Allocate and initialise structure */
        netdev = alloc_etherdev ( sizeof ( *netfront ) );
        if ( ! netdev ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        netdev_init ( netdev, &netfront_operations );
        netdev->dev = &xendev->dev;
        netfront = netdev->priv;
        netfront->xendev = xendev;
        DBGC ( netfront, "NETFRONT %s backend=\"%s\" in domain %ld\n",
               xendev->key, xendev->backend, xendev->backend_id );

        /* Allocate grant references and initialise descriptor rings */
        if ( ( rc = xengrant_alloc ( xen, netfront->refs,
                                     NETFRONT_REF_COUNT ) ) != 0 ) {
                DBGC ( netfront, "NETFRONT %s could not allocate grant "
                       "references: %s\n", xendev->key, strerror ( rc ) );
                goto err_grant_alloc;
        }
        netfront_init_ring ( &netfront->tx, "tx-ring-ref",
                             netfront->refs[NETFRONT_REF_TX_RING],
                             NETFRONT_NUM_TX_DESC, netfront->tx_iobufs,
                             &netfront->refs[NETFRONT_REF_TX_BASE],
                             netfront->tx_ids );
        netfront_init_ring ( &netfront->rx, "rx-ring-ref",
                             netfront->refs[NETFRONT_REF_RX_RING],
                             NETFRONT_NUM_RX_DESC, netfront->rx_iobufs,
                             &netfront->refs[NETFRONT_REF_RX_BASE],
                             netfront->rx_ids );

        /* Fetch MAC address */
        if ( ( rc = netfront_read_mac ( netfront, netdev->hw_addr ) ) != 0 )
                goto err_read_mac;

        /* Reset device.  Ignore failures; allow the device to be
         * registered so that reset errors can be observed by the user
         * when attempting to open the device.
         */
        netfront_reset ( netfront );

        /* Register network device */
        if ( ( rc = register_netdev ( netdev ) ) != 0 )
                goto err_register_netdev;

        /* Set initial link state */
        netdev_link_down ( netdev );

        xen_set_drvdata ( xendev, netdev );
        return 0;

        unregister_netdev ( netdev );
 err_register_netdev:
 err_read_mac:
        xengrant_free ( xen, netfront->refs, NETFRONT_REF_COUNT );
 err_grant_alloc:
        netdev_nullify ( netdev );
        netdev_put ( netdev );
 err_alloc:
        return rc;
}
static void netfront_remove ( struct xen_device xendev) [static]

Remove Xen device.

Parameters:
xendevXen device

Definition at line 931 of file netfront.c.

References netdev, netdev_nullify(), netdev_put(), NETFRONT_REF_COUNT, net_device::priv, unregister_netdev(), xen_device::xen, xen_get_drvdata(), and xengrant_free().

                                                          {
        struct net_device *netdev = xen_get_drvdata ( xendev );
        struct netfront_nic *netfront = netdev->priv;
        struct xen_hypervisor *xen = xendev->xen;

        /* Unregister network device */
        unregister_netdev ( netdev );

        /* Free resources */
        xengrant_free ( xen, netfront->refs, NETFRONT_REF_COUNT );

        /* Free network device */
        netdev_nullify ( netdev );
        netdev_put ( netdev );
}

Variable Documentation

Initial value:
 {
        .open           = netfront_open,
        .close          = netfront_close,
        .transmit       = netfront_transmit,
        .poll           = netfront_poll,
}

Network device operations.

Definition at line 838 of file netfront.c.

struct xen_driver netfront_driver __xen_driver
Initial value:
 {
        .name = "netfront",
        .type = "vif",
        .probe = netfront_probe,
        .remove = netfront_remove,
}

Xen netfront driver.

Definition at line 948 of file netfront.c.