iPXE
Defines | Functions | Variables
neighbour.c File Reference

Neighbour discovery. More...

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ipxe/iobuf.h>
#include <ipxe/retry.h>
#include <ipxe/timer.h>
#include <ipxe/malloc.h>
#include <ipxe/neighbour.h>

Go to the source code of this file.

Defines

#define NEIGHBOUR_MIN_TIMEOUT   ( TICKS_PER_SEC / 8 )
 Neighbour discovery minimum timeout.
#define NEIGHBOUR_MAX_TIMEOUT   ( TICKS_PER_SEC * 3 )
 Neighbour discovery maximum timeout.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static void neighbour_expired (struct retry_timer *timer, int fail)
 Handle neighbour timer expiry.
static void neighbour_free (struct refcnt *refcnt)
 Free neighbour cache entry.
static struct neighbourneighbour_create (struct net_device *netdev, struct net_protocol *net_protocol, const void *net_dest)
 Create neighbour cache entry.
static struct neighbourneighbour_find (struct net_device *netdev, struct net_protocol *net_protocol, const void *net_dest)
 Find neighbour cache entry.
static void neighbour_discover (struct neighbour *neighbour, struct neighbour_discovery *discovery, const void *net_source)
 Start neighbour discovery.
static void neighbour_discovered (struct neighbour *neighbour, const void *ll_dest)
 Complete neighbour discovery.
static void neighbour_destroy (struct neighbour *neighbour, int rc)
 Destroy neighbour cache entry.
int neighbour_tx (struct io_buffer *iobuf, struct net_device *netdev, struct net_protocol *net_protocol, const void *net_dest, struct neighbour_discovery *discovery, const void *net_source, const void *ll_source)
 Transmit packet, determining link-layer address via neighbour discovery.
int neighbour_update (struct net_device *netdev, struct net_protocol *net_protocol, const void *net_dest, const void *ll_dest)
 Update existing neighbour cache entry.
int neighbour_define (struct net_device *netdev, struct net_protocol *net_protocol, const void *net_dest, const void *ll_dest)
 Define neighbour cache entry.
static void neighbour_flush (struct net_device *netdev)
 Update neighbour cache on network device state change or removal.
static unsigned int neighbour_discard (void)
 Discard some cached neighbour entries.
struct cache_discarder
neighbour_discarder 
__cache_discarder (CACHE_EXPENSIVE)
 Neighbour cache discarder.

Variables

struct list_head neighbours = LIST_HEAD_INIT ( neighbours )
 The neighbour cache.
struct net_driver
neighbour_net_driver 
__net_driver
 Neighbour driver (for net device notifications)

Detailed Description

Neighbour discovery.

This file implements the abstract functions of neighbour discovery, independent of the underlying network protocol (e.g. ARP or NDP).

Definition in file neighbour.c.


Define Documentation

#define NEIGHBOUR_MIN_TIMEOUT   ( TICKS_PER_SEC / 8 )

Neighbour discovery minimum timeout.

Definition at line 46 of file neighbour.c.

Referenced by neighbour_create().

#define NEIGHBOUR_MAX_TIMEOUT   ( TICKS_PER_SEC * 3 )

Neighbour discovery maximum timeout.

Definition at line 49 of file neighbour.c.

Referenced by neighbour_create().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static void neighbour_expired ( struct retry_timer timer,
int  fail 
) [static]

Handle neighbour timer expiry.

Parameters:
timerRetry timer
failFailure indicator

Definition at line 255 of file neighbour.c.

References container_of, DBGC, neighbour::discovery, ETIMEDOUT, neighbour_discovery::name, net_protocol::name, net_device::name, neighbour_destroy(), neighbour::net_dest, neighbour::net_protocol, neighbour::net_source, neighbour::netdev, netdev, net_protocol::ntoa, rc, start_timer(), strerror(), neighbour::timer, and neighbour_discovery::tx_request.

Referenced by neighbour_create().

                                                                      {
        struct neighbour *neighbour =
                container_of ( timer, struct neighbour, timer );
        struct net_device *netdev = neighbour->netdev;
        struct net_protocol *net_protocol = neighbour->net_protocol;
        struct neighbour_discovery *discovery =
                neighbour->discovery;
        const void *net_dest = neighbour->net_dest;
        const void *net_source = neighbour->net_source;
        int rc;

        /* If we have failed, destroy the cache entry */
        if ( fail ) {
                neighbour_destroy ( neighbour, -ETIMEDOUT );
                return;
        }

        /* Restart the timer */
        start_timer ( &neighbour->timer );

        /* Transmit neighbour request */
        if ( ( rc = discovery->tx_request ( netdev, net_protocol, net_dest,
                                            net_source ) ) != 0 ) {
                DBGC ( neighbour, "NEIGHBOUR %s %s %s could not transmit %s "
                       "request: %s\n", netdev->name, net_protocol->name,
                       net_protocol->ntoa ( neighbour->net_dest ),
                       neighbour->discovery->name, strerror ( rc ) );
                /* Retransmit when timer expires */
                return;
        }
}
static void neighbour_free ( struct refcnt refcnt) [static]

Free neighbour cache entry.

Parameters:
refcntReference count

Definition at line 61 of file neighbour.c.

References assert, container_of, free, list_empty, neighbour::netdev, netdev_put(), and neighbour::tx_queue.

Referenced by neighbour_create().

                                                     {
        struct neighbour *neighbour =
                container_of ( refcnt, struct neighbour, refcnt );

        /* Sanity check */
        assert ( list_empty ( &neighbour->tx_queue ) );

        /* Drop reference to network device */
        netdev_put ( neighbour->netdev );

        /* Free neighbour */
        free ( neighbour );
}
static struct neighbour* neighbour_create ( struct net_device netdev,
struct net_protocol net_protocol,
const void *  net_dest 
) [static, read]

Create neighbour cache entry.

Parameters:
netdevNetwork device
net_protocolNetwork-layer protocol
net_destDestination network-layer address
Return values:
neighbourNeighbour cache entry, or NULL if allocation failed

Definition at line 83 of file neighbour.c.

References DBGC, INIT_LIST_HEAD, neighbour::list, list_add, memcpy(), net_protocol::name, net_device::name, neighbour_expired(), neighbour_free(), NEIGHBOUR_MAX_TIMEOUT, NEIGHBOUR_MIN_TIMEOUT, net_protocol::net_addr_len, neighbour::net_dest, neighbour::net_protocol, neighbour::netdev, netdev_get(), net_protocol::ntoa, NULL, ref_init, neighbour::refcnt, neighbour::timer, neighbour::tx_queue, and zalloc().

Referenced by neighbour_define(), and neighbour_tx().

                                                                    {
        struct neighbour *neighbour;

        /* Allocate and initialise entry */
        neighbour = zalloc ( sizeof ( *neighbour ) );
        if ( ! neighbour )
                return NULL;
        ref_init ( &neighbour->refcnt, neighbour_free );
        neighbour->netdev = netdev_get ( netdev );
        neighbour->net_protocol = net_protocol;
        memcpy ( neighbour->net_dest, net_dest,
                 net_protocol->net_addr_len );
        timer_init ( &neighbour->timer, neighbour_expired, &neighbour->refcnt );
        set_timer_limits ( &neighbour->timer, NEIGHBOUR_MIN_TIMEOUT,
                           NEIGHBOUR_MAX_TIMEOUT );
        INIT_LIST_HEAD ( &neighbour->tx_queue );

        /* Transfer ownership to cache */
        list_add ( &neighbour->list, &neighbours );

        DBGC ( neighbour, "NEIGHBOUR %s %s %s created\n", netdev->name,
               net_protocol->name, net_protocol->ntoa ( net_dest ) );
        return neighbour;
}
static struct neighbour* neighbour_find ( struct net_device netdev,
struct net_protocol net_protocol,
const void *  net_dest 
) [static, read]

Find neighbour cache entry.

Parameters:
netdevNetwork device
net_protocolNetwork-layer protocol
net_destDestination network-layer address
Return values:
neighbourNeighbour cache entry, or NULL if not found

Definition at line 118 of file neighbour.c.

References neighbour::list, list_add, list_del, list_for_each_entry, memcmp(), net_protocol::net_addr_len, neighbour::net_dest, neighbour::net_protocol, neighbour::netdev, and NULL.

Referenced by neighbour_define(), neighbour_tx(), and neighbour_update().

                                                                  {
        struct neighbour *neighbour;

        list_for_each_entry ( neighbour, &neighbours, list ) {
                if ( ( neighbour->netdev == netdev ) &&
                     ( neighbour->net_protocol == net_protocol ) &&
                     ( memcmp ( neighbour->net_dest, net_dest,
                                net_protocol->net_addr_len ) == 0 ) ) {

                        /* Move to start of cache */
                        list_del ( &neighbour->list );
                        list_add ( &neighbour->list, &neighbours );

                        return neighbour;
                }
        }
        return NULL;
}
static void neighbour_discover ( struct neighbour neighbour,
struct neighbour_discovery discovery,
const void *  net_source 
) [static]

Start neighbour discovery.

Parameters:
neighbourNeighbour cache entry
discoveryNeighbour discovery protocol
net_sourceSource network-layer address

Definition at line 146 of file neighbour.c.

References DBGC, neighbour::discovery, memcpy(), neighbour_discovery::name, net_protocol::name, net_device::name, net_protocol::net_addr_len, neighbour::net_dest, neighbour::net_protocol, neighbour::net_source, neighbour::netdev, netdev, net_protocol::ntoa, start_timer_nodelay(), and neighbour::timer.

Referenced by neighbour_tx().

                                                          {
        struct net_device *netdev = neighbour->netdev;
        struct net_protocol *net_protocol = neighbour->net_protocol;

        /* Record discovery protocol and source network-layer address */
        neighbour->discovery = discovery;
        memcpy ( neighbour->net_source, net_source,
                 net_protocol->net_addr_len );

        /* Start timer to trigger neighbour discovery */
        start_timer_nodelay ( &neighbour->timer );

        DBGC ( neighbour, "NEIGHBOUR %s %s %s discovering via %s\n",
               netdev->name, net_protocol->name,
               net_protocol->ntoa ( neighbour->net_dest ),
               neighbour->discovery->name );
}
static void neighbour_discovered ( struct neighbour neighbour,
const void *  ll_dest 
) [static]

Complete neighbour discovery.

Parameters:
neighbourNeighbour cache entry
ll_destDestination link-layer address

Definition at line 172 of file neighbour.c.

References DBGC, DBGC2, io_buffer::list, list_del, list_first_entry, net_device::ll_addr, ll_protocol::ll_addr_len, neighbour::ll_dest, net_device::ll_protocol, memcpy(), net_protocol::name, ll_protocol::name, net_device::name, neighbour::net_dest, neighbour::net_protocol, net_tx(), neighbour::netdev, netdev, net_protocol::ntoa, ll_protocol::ntoa, NULL, rc, ref_get, ref_put, neighbour::refcnt, stop_timer(), strerror(), neighbour::timer, and neighbour::tx_queue.

Referenced by neighbour_define(), and neighbour_update().

                                                         {
        struct net_device *netdev = neighbour->netdev;
        struct ll_protocol *ll_protocol = netdev->ll_protocol;
        struct net_protocol *net_protocol = neighbour->net_protocol;
        struct io_buffer *iobuf;
        int rc;

        /* Fill in link-layer address */
        memcpy ( neighbour->ll_dest, ll_dest, ll_protocol->ll_addr_len );
        DBGC ( neighbour, "NEIGHBOUR %s %s %s is %s %s\n", netdev->name,
               net_protocol->name, net_protocol->ntoa ( neighbour->net_dest ),
               ll_protocol->name, ll_protocol->ntoa ( neighbour->ll_dest ) );

        /* Stop retransmission timer */
        stop_timer ( &neighbour->timer );

        /* Transmit any packets in queue.  Take out a temporary
         * reference on the entry to prevent it from going out of
         * scope during the call to net_tx().
         */
        ref_get ( &neighbour->refcnt );
        while ( ( iobuf = list_first_entry ( &neighbour->tx_queue,
                                             struct io_buffer, list )) != NULL){
                DBGC2 ( neighbour, "NEIGHBOUR %s %s %s transmitting deferred "
                        "packet\n", netdev->name, net_protocol->name,
                        net_protocol->ntoa ( neighbour->net_dest ) );
                list_del ( &iobuf->list );
                if ( ( rc = net_tx ( iobuf, netdev, net_protocol, ll_dest,
                                     netdev->ll_addr ) ) != 0 ) {
                        DBGC ( neighbour, "NEIGHBOUR %s %s %s could not "
                               "transmit deferred packet: %s\n",
                               netdev->name, net_protocol->name,
                               net_protocol->ntoa ( neighbour->net_dest ),
                               strerror ( rc ) );
                        /* Ignore error and continue */
                }
        }
        ref_put ( &neighbour->refcnt );
}
static void neighbour_destroy ( struct neighbour neighbour,
int  rc 
) [static]

Destroy neighbour cache entry.

Parameters:
neighbourNeighbour cache entry
rcReason for destruction

Definition at line 219 of file neighbour.c.

References DBGC, DBGC2, io_buffer::list, neighbour::list, list_del, list_first_entry, net_protocol::name, net_device::name, neighbour::net_dest, neighbour::net_protocol, neighbour::netdev, netdev, netdev_tx_err(), net_protocol::ntoa, NULL, ref_put, neighbour::refcnt, stop_timer(), strerror(), neighbour::timer, and neighbour::tx_queue.

Referenced by neighbour_discard(), neighbour_expired(), and neighbour_flush().

                                                                      {
        struct net_device *netdev = neighbour->netdev;
        struct net_protocol *net_protocol = neighbour->net_protocol;
        struct io_buffer *iobuf;

        /* Take ownership from cache */
        list_del ( &neighbour->list );

        /* Stop timer */
        stop_timer ( &neighbour->timer );

        /* Discard any outstanding I/O buffers */
        while ( ( iobuf = list_first_entry ( &neighbour->tx_queue,
                                             struct io_buffer, list )) != NULL){
                DBGC2 ( neighbour, "NEIGHBOUR %s %s %s discarding deferred "
                        "packet: %s\n", netdev->name, net_protocol->name,
                        net_protocol->ntoa ( neighbour->net_dest ),
                        strerror ( rc ) );
                list_del ( &iobuf->list );
                netdev_tx_err ( neighbour->netdev, iobuf, rc );
        }

        DBGC ( neighbour, "NEIGHBOUR %s %s %s destroyed: %s\n", netdev->name,
               net_protocol->name, net_protocol->ntoa ( neighbour->net_dest ),
               strerror ( rc ) );

        /* Drop remaining reference */
        ref_put ( &neighbour->refcnt );
}
int neighbour_tx ( struct io_buffer iobuf,
struct net_device netdev,
struct net_protocol net_protocol,
const void *  net_dest,
struct neighbour_discovery discovery,
const void *  net_source,
const void *  ll_source 
)

Transmit packet, determining link-layer address via neighbour discovery.

Parameters:
iobufI/O buffer
netdevNetwork device
discoveryNeighbour discovery protocol
net_protocolNetwork-layer protocol
net_destDestination network-layer address
net_sourceSource network-layer address
ll_sourceSource link-layer address
Return values:
rcReturn status code

Definition at line 299 of file neighbour.c.

References DBGC2, ENOMEM, io_buffer::list, list_add_tail, neighbour::ll_dest, net_protocol::name, net_device::name, neighbour_create(), neighbour_discover(), neighbour_find(), neighbour_has_ll_dest(), net_tx(), net_protocol::ntoa, and neighbour::tx_queue.

Referenced by arp_tx(), and ndp_tx().

                                                                   {
        struct neighbour *neighbour;

        /* Find or create neighbour cache entry */
        neighbour = neighbour_find ( netdev, net_protocol, net_dest );
        if ( ! neighbour ) {
                neighbour = neighbour_create ( netdev, net_protocol, net_dest );
                if ( ! neighbour )
                        return -ENOMEM;
                neighbour_discover ( neighbour, discovery, net_source );
        }

        /* If a link-layer address is available then transmit
         * immediately, otherwise queue for later transmission.
         */
        if ( neighbour_has_ll_dest ( neighbour ) ) {
                return net_tx ( iobuf, netdev, net_protocol, neighbour->ll_dest,
                                ll_source );
        } else {
                DBGC2 ( neighbour, "NEIGHBOUR %s %s %s deferring packet\n",
                        netdev->name, net_protocol->name,
                        net_protocol->ntoa ( net_dest ) );
                list_add_tail ( &iobuf->list, &neighbour->tx_queue );
                return 0;
        }
}
int neighbour_update ( struct net_device netdev,
struct net_protocol net_protocol,
const void *  net_dest,
const void *  ll_dest 
)

Update existing neighbour cache entry.

Parameters:
netdevNetwork device
net_protocolNetwork-layer protocol
net_destDestination network-layer address
ll_destDestination link-layer address
Return values:
rcReturn status code

Definition at line 338 of file neighbour.c.

References ENOENT, neighbour_discovered(), and neighbour_find().

Referenced by arp_rx(), and ndp_rx_neighbour_advertisement_ll_target().

                                                                   {
        struct neighbour *neighbour;

        /* Find neighbour cache entry */
        neighbour = neighbour_find ( netdev, net_protocol, net_dest );
        if ( ! neighbour )
                return -ENOENT;

        /* Set destination address */
        neighbour_discovered ( neighbour, ll_dest );

        return 0;
}
int neighbour_define ( struct net_device netdev,
struct net_protocol net_protocol,
const void *  net_dest,
const void *  ll_dest 
)

Define neighbour cache entry.

Parameters:
netdevNetwork device
net_protocolNetwork-layer protocol
net_destDestination network-layer address
ll_destDestination link-layer address, if known
Return values:
rcReturn status code

Definition at line 363 of file neighbour.c.

References ENOMEM, neighbour_create(), neighbour_discovered(), and neighbour_find().

Referenced by ndp_rx_neighbour_solicitation_ll_source(), and ndp_rx_router_advertisement_ll_source().

                                                                   {
        struct neighbour *neighbour;

        /* Find or create neighbour cache entry */
        neighbour = neighbour_find ( netdev, net_protocol, net_dest );
        if ( ! neighbour ) {
                neighbour = neighbour_create ( netdev, net_protocol, net_dest );
                if ( ! neighbour )
                        return -ENOMEM;
        }

        /* Set destination address */
        neighbour_discovered ( neighbour, ll_dest );

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

Update neighbour cache on network device state change or removal.

Parameters:
netdevNetwork device

Definition at line 387 of file neighbour.c.

References ENODEV, neighbour::list, list_for_each_entry_safe, neighbour_destroy(), and netdev_is_open().

                                                          {
        struct neighbour *neighbour;
        struct neighbour *tmp;

        /* Remove all neighbour cache entries when a network device is closed */
        if ( ! netdev_is_open ( netdev ) ) {
                list_for_each_entry_safe ( neighbour, tmp, &neighbours, list )
                        neighbour_destroy ( neighbour, -ENODEV );
        }
}
static unsigned int neighbour_discard ( void  ) [static]

Discard some cached neighbour entries.

Return values:
discardedNumber of cached items discarded

Definition at line 410 of file neighbour.c.

References ENOBUFS, neighbour::list, list_last_entry, and neighbour_destroy().

                                               {
        struct neighbour *neighbour;

        /* Drop oldest cache entry, if any */
        neighbour = list_last_entry ( &neighbours, struct neighbour, list );
        if ( neighbour ) {
                neighbour_destroy ( neighbour, -ENOBUFS );
                return 1;
        } else {
                return 0;
        }
}
struct cache_discarder neighbour_discarder __cache_discarder ( CACHE_EXPENSIVE  ) [read]

Neighbour cache discarder.

Neighbour cache entries are deemed to have a high replacement cost, since flushing an active neighbour cache entry midway through a TCP transfer will cause substantial disruption.


Variable Documentation

The neighbour cache.

Definition at line 52 of file neighbour.c.

Referenced by nstat().

struct net_driver neighbour_net_driver __net_driver
Initial value:
 {
        .name = "Neighbour",
        .notify = neighbour_flush,
        .remove = neighbour_flush,
}

Neighbour driver (for net device notifications)

Definition at line 399 of file neighbour.c.