Browse Source

[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>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
8829634bd7
3 changed files with 57 additions and 8 deletions
  1. 50
    5
      src/drivers/net/ipoib.c
  2. 4
    0
      src/include/ipxe/arp.h
  3. 3
    3
      src/net/arp.c

+ 50
- 5
src/drivers/net/ipoib.c View File

33
 #include <ipxe/errortab.h>
33
 #include <ipxe/errortab.h>
34
 #include <ipxe/malloc.h>
34
 #include <ipxe/malloc.h>
35
 #include <ipxe/if_arp.h>
35
 #include <ipxe/if_arp.h>
36
+#include <ipxe/arp.h>
36
 #include <ipxe/if_ether.h>
37
 #include <ipxe/if_ether.h>
37
 #include <ipxe/ethernet.h>
38
 #include <ipxe/ethernet.h>
39
+#include <ipxe/ip.h>
38
 #include <ipxe/iobuf.h>
40
 #include <ipxe/iobuf.h>
39
 #include <ipxe/netdevice.h>
41
 #include <ipxe/netdevice.h>
40
 #include <ipxe/infiniband.h>
42
 #include <ipxe/infiniband.h>
48
  * IP over Infiniband
50
  * IP over Infiniband
49
  */
51
  */
50
 
52
 
53
+/* Disambiguate the various error causes */
54
+#define ENXIO_ARP_REPLY __einfo_error ( EINFO_ENXIO_ARP_REPLY )
55
+#define EINFO_ENXIO_ARP_REPLY						\
56
+	__einfo_uniqify ( EINFO_ENXIO, 0x01,				\
57
+			  "Missing REMAC for ARP reply target address" )
58
+#define ENXIO_NON_IPV4 __einfo_error ( EINFO_ENXIO_NON_IPV4 )
59
+#define EINFO_ENXIO_NON_IPV4						\
60
+	__einfo_uniqify ( EINFO_ENXIO, 0x02,				\
61
+			  "Missing REMAC for non-IPv4 packet" )
62
+#define ENXIO_ARP_SENT __einfo_error ( EINFO_ENXIO_ARP_SENT )
63
+#define EINFO_ENXIO_ARP_SENT						\
64
+	__einfo_uniqify ( EINFO_ENXIO, 0x03,				\
65
+			  "Missing REMAC for IPv4 packet (ARP sent)" )
66
+
51
 /** Number of IPoIB send work queue entries */
67
 /** Number of IPoIB send work queue entries */
52
 #define IPOIB_NUM_SEND_WQES 2
68
 #define IPOIB_NUM_SEND_WQES 2
53
 
69
 
336
 	/* Look up REMAC, if applicable */
352
 	/* Look up REMAC, if applicable */
337
 	if ( arphdr->ar_op == ARPOP_REPLY ) {
353
 	if ( arphdr->ar_op == ARPOP_REPLY ) {
338
 		target_ha = ipoib_find_remac ( ipoib, arp_target_pa ( arphdr ));
354
 		target_ha = ipoib_find_remac ( ipoib, arp_target_pa ( arphdr ));
339
-		if ( ! target_ha )
340
-			return -ENXIO;
355
+		if ( ! target_ha ) {
356
+			DBGC ( ipoib, "IPoIB %p no REMAC for %s ARP reply\n",
357
+			       ipoib, eth_ntoa ( arp_target_pa ( arphdr ) ) );
358
+			return -ENXIO_ARP_REPLY;
359
+		}
341
 	}
360
 	}
342
 
361
 
343
 	/* Construct new packet */
362
 	/* Construct new packet */
473
 	struct ipoib_device *ipoib = netdev->priv;
492
 	struct ipoib_device *ipoib = netdev->priv;
474
 	struct ib_device *ibdev = ipoib->ibdev;
493
 	struct ib_device *ibdev = ipoib->ibdev;
475
 	struct ethhdr *ethhdr;
494
 	struct ethhdr *ethhdr;
495
+	struct iphdr *iphdr;
476
 	struct ipoib_hdr *ipoib_hdr;
496
 	struct ipoib_hdr *ipoib_hdr;
477
 	struct ipoib_mac *mac;
497
 	struct ipoib_mac *mac;
478
 	struct ib_address_vector dest;
498
 	struct ib_address_vector dest;
497
 	iob_pull ( iobuf, sizeof ( *ethhdr ) );
517
 	iob_pull ( iobuf, sizeof ( *ethhdr ) );
498
 
518
 
499
 	/* Identify destination address */
519
 	/* Identify destination address */
500
-	mac = ipoib_find_remac ( ipoib, ( ( void *) ethhdr->h_dest ) );
501
-	if ( ! mac )
502
-		return -ENXIO;
520
+	mac = ipoib_find_remac ( ipoib, ( ( void * ) ethhdr->h_dest ) );
521
+	if ( ! mac ) {
522
+		/* Generate a new ARP request (if possible) to trigger
523
+		 * population of the REMAC cache entry.
524
+		 */
525
+		if ( ( net_proto != htons ( ETH_P_IP ) ) ||
526
+		     ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) ) {
527
+			DBGC ( ipoib, "IPoIB %p no REMAC for %s non-IPv4 "
528
+			       "packet type %04x\n", ipoib,
529
+			       eth_ntoa ( ethhdr->h_dest ),
530
+			       ntohs ( net_proto ) );
531
+			return -ENXIO_NON_IPV4;
532
+		}
533
+		iphdr = iobuf->data;
534
+		if ( ( rc = arp_tx_request ( netdev, &ipv4_protocol,
535
+					     &iphdr->dest, &iphdr->src ) ) !=0){
536
+			DBGC ( ipoib, "IPoIB %p could not ARP for %s/%s/",
537
+			       ipoib, eth_ntoa ( ethhdr->h_dest ),
538
+			       inet_ntoa ( iphdr->dest ) );
539
+			DBGC ( ipoib, "%s: %s\n", inet_ntoa ( iphdr->src ),
540
+			       strerror ( rc ) );
541
+			return rc;
542
+		}
543
+		DBGC ( ipoib, "IPoIB %p no REMAC for %s/%s/", ipoib,
544
+		       eth_ntoa ( ethhdr->h_dest ), inet_ntoa ( iphdr->dest ) );
545
+		DBGC  ( ipoib, "%s\n", inet_ntoa ( iphdr->src ) );
546
+		return -ENXIO_ARP_SENT;
547
+	}
503
 
548
 
504
 	/* Translate packet if applicable */
549
 	/* Translate packet if applicable */
505
 	if ( ( rc = ipoib_translate_tx ( netdev, iobuf, net_proto ) ) != 0 )
550
 	if ( ( rc = ipoib_translate_tx ( netdev, iobuf, net_proto ) ) != 0 )

+ 4
- 0
src/include/ipxe/arp.h View File

57
 			      &arp_discovery, net_source, ll_source );
57
 			      &arp_discovery, net_source, ll_source );
58
 }
58
 }
59
 
59
 
60
+extern int arp_tx_request ( struct net_device *netdev,
61
+			    struct net_protocol *net_protocol,
62
+			    const void *net_dest, const void *net_source );
63
+
60
 #endif /* _IPXE_ARP_H */
64
 #endif /* _IPXE_ARP_H */

+ 3
- 3
src/net/arp.c View File

56
  * @v net_source	Source network-layer address
56
  * @v net_source	Source network-layer address
57
  * @ret rc		Return status code
57
  * @ret rc		Return status code
58
  */
58
  */
59
-static int arp_tx_request ( struct net_device *netdev,
60
-			    struct net_protocol *net_protocol,
61
-			    const void *net_dest, const void *net_source ) {
59
+int arp_tx_request ( struct net_device *netdev,
60
+		     struct net_protocol *net_protocol,
61
+		     const void *net_dest, const void *net_source ) {
62
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
62
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
63
 	struct io_buffer *iobuf;
63
 	struct io_buffer *iobuf;
64
 	struct arphdr *arphdr;
64
 	struct arphdr *arphdr;

Loading…
Cancel
Save