diff options
-rw-r--r-- | src/drivers/net/ipoib.c | 55 | ||||
-rw-r--r-- | src/include/ipxe/arp.h | 4 | ||||
-rw-r--r-- | src/net/arp.c | 6 |
3 files changed, 57 insertions, 8 deletions
diff --git a/src/drivers/net/ipoib.c b/src/drivers/net/ipoib.c index b72e8fc5..bec4bbae 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 ) diff --git a/src/include/ipxe/arp.h b/src/include/ipxe/arp.h index 93195010..5822fa09 100644 --- a/src/include/ipxe/arp.h +++ b/src/include/ipxe/arp.h @@ -57,4 +57,8 @@ static inline int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev, &arp_discovery, net_source, ll_source ); } +extern int arp_tx_request ( struct net_device *netdev, + struct net_protocol *net_protocol, + const void *net_dest, const void *net_source ); + #endif /* _IPXE_ARP_H */ diff --git a/src/net/arp.c b/src/net/arp.c index 663dc002..1e27c44e 100644 --- a/src/net/arp.c +++ b/src/net/arp.c @@ -56,9 +56,9 @@ struct net_protocol arp_protocol __net_protocol; * @v net_source Source network-layer address * @ret rc Return status code */ -static int arp_tx_request ( struct net_device *netdev, - struct net_protocol *net_protocol, - const void *net_dest, const void *net_source ) { +int arp_tx_request ( struct net_device *netdev, + struct net_protocol *net_protocol, + const void *net_dest, const void *net_source ) { struct ll_protocol *ll_protocol = netdev->ll_protocol; struct io_buffer *iobuf; struct arphdr *arphdr; |