diff options
author | Michael Brown <mcb30@ipxe.org> | 2015-06-29 14:50:16 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2015-06-29 14:50:16 +0100 |
commit | 8829634bd7188bdfa5528421a8bbecf39c498f40 (patch) | |
tree | 1b5f2aa8169c91c97b286632f3119228ea1eb32e /src/drivers | |
parent | e213a008ca448c41f617d4565e0473ca705e69b3 (diff) | |
download | ipxe-8829634bd7188bdfa5528421a8bbecf39c498f40.zip ipxe-8829634bd7188bdfa5528421a8bbecf39c498f40.tar.gz ipxe-8829634bd7188bdfa5528421a8bbecf39c498f40.tar.bz2 |
[ipoib] Attempt to generate ARPs as needed to repopulate REMAC cache
The only way to map an eIPoIB MAC address (REMAC) to an IPoIB MAC
address is to intercept an incoming ARP request or reply.
If we do not have an REMAC cache entry for a particular destination
MAC address, then we cannot transmit the packet. This can arise in at
least two situations:
- An external program (e.g. a PXE NBP using the UNDI API) may attempt
to transmit to a destination MAC address that has been obtained by
some method other than ARP.
- Memory pressure may have caused REMAC cache entries to be
discarded. This is fairly likely on a busy network, since REMAC
cache entries are created for all received (broadcast) ARP
requests. (We can't sensibly avoid creating these cache entries,
since they are required in order to send an ARP reply, and when we
are being used via the UNDI API we may have no knowledge of which
IP addresses are "ours".)
Attempt to ameliorate the situation by generating a semi-spurious ARP
request whenever we find a missing REMAC cache entry. This will
hopefully trigger an ARP reply, which would then provide us with the
information required to populate the REMAC cache.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers')
-rw-r--r-- | src/drivers/net/ipoib.c | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/src/drivers/net/ipoib.c b/src/drivers/net/ipoib.c index b72e8fc..bec4bba 100644 --- a/src/drivers/net/ipoib.c +++ b/src/drivers/net/ipoib.c @@ -33,8 +33,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/errortab.h> #include <ipxe/malloc.h> #include <ipxe/if_arp.h> +#include <ipxe/arp.h> #include <ipxe/if_ether.h> #include <ipxe/ethernet.h> +#include <ipxe/ip.h> #include <ipxe/iobuf.h> #include <ipxe/netdevice.h> #include <ipxe/infiniband.h> @@ -48,6 +50,20 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * IP over Infiniband */ +/* Disambiguate the various error causes */ +#define ENXIO_ARP_REPLY __einfo_error ( EINFO_ENXIO_ARP_REPLY ) +#define EINFO_ENXIO_ARP_REPLY \ + __einfo_uniqify ( EINFO_ENXIO, 0x01, \ + "Missing REMAC for ARP reply target address" ) +#define ENXIO_NON_IPV4 __einfo_error ( EINFO_ENXIO_NON_IPV4 ) +#define EINFO_ENXIO_NON_IPV4 \ + __einfo_uniqify ( EINFO_ENXIO, 0x02, \ + "Missing REMAC for non-IPv4 packet" ) +#define ENXIO_ARP_SENT __einfo_error ( EINFO_ENXIO_ARP_SENT ) +#define EINFO_ENXIO_ARP_SENT \ + __einfo_uniqify ( EINFO_ENXIO, 0x03, \ + "Missing REMAC for IPv4 packet (ARP sent)" ) + /** Number of IPoIB send work queue entries */ #define IPOIB_NUM_SEND_WQES 2 @@ -336,8 +352,11 @@ static int ipoib_translate_tx_arp ( struct net_device *netdev, /* Look up REMAC, if applicable */ if ( arphdr->ar_op == ARPOP_REPLY ) { target_ha = ipoib_find_remac ( ipoib, arp_target_pa ( arphdr )); - if ( ! target_ha ) - return -ENXIO; + if ( ! target_ha ) { + DBGC ( ipoib, "IPoIB %p no REMAC for %s ARP reply\n", + ipoib, eth_ntoa ( arp_target_pa ( arphdr ) ) ); + return -ENXIO_ARP_REPLY; + } } /* Construct new packet */ @@ -473,6 +492,7 @@ static int ipoib_transmit ( struct net_device *netdev, struct ipoib_device *ipoib = netdev->priv; struct ib_device *ibdev = ipoib->ibdev; struct ethhdr *ethhdr; + struct iphdr *iphdr; struct ipoib_hdr *ipoib_hdr; struct ipoib_mac *mac; struct ib_address_vector dest; @@ -497,9 +517,34 @@ static int ipoib_transmit ( struct net_device *netdev, iob_pull ( iobuf, sizeof ( *ethhdr ) ); /* Identify destination address */ - mac = ipoib_find_remac ( ipoib, ( ( void *) ethhdr->h_dest ) ); - if ( ! mac ) - return -ENXIO; + mac = ipoib_find_remac ( ipoib, ( ( void * ) ethhdr->h_dest ) ); + if ( ! mac ) { + /* Generate a new ARP request (if possible) to trigger + * population of the REMAC cache entry. + */ + if ( ( net_proto != htons ( ETH_P_IP ) ) || + ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) ) { + DBGC ( ipoib, "IPoIB %p no REMAC for %s non-IPv4 " + "packet type %04x\n", ipoib, + eth_ntoa ( ethhdr->h_dest ), + ntohs ( net_proto ) ); + return -ENXIO_NON_IPV4; + } + iphdr = iobuf->data; + if ( ( rc = arp_tx_request ( netdev, &ipv4_protocol, + &iphdr->dest, &iphdr->src ) ) !=0){ + DBGC ( ipoib, "IPoIB %p could not ARP for %s/%s/", + ipoib, eth_ntoa ( ethhdr->h_dest ), + inet_ntoa ( iphdr->dest ) ); + DBGC ( ipoib, "%s: %s\n", inet_ntoa ( iphdr->src ), + strerror ( rc ) ); + return rc; + } + DBGC ( ipoib, "IPoIB %p no REMAC for %s/%s/", ipoib, + eth_ntoa ( ethhdr->h_dest ), inet_ntoa ( iphdr->dest ) ); + DBGC ( ipoib, "%s\n", inet_ntoa ( iphdr->src ) ); + return -ENXIO_ARP_SENT; + } /* Translate packet if applicable */ if ( ( rc = ipoib_translate_tx ( netdev, iobuf, net_proto ) ) != 0 ) |