瀏覽代碼

[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 年之前
父節點
當前提交
8829634bd7
共有 3 個文件被更改,包括 57 次插入8 次删除
  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 查看文件

@@ -33,8 +33,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
33 33
 #include <ipxe/errortab.h>
34 34
 #include <ipxe/malloc.h>
35 35
 #include <ipxe/if_arp.h>
36
+#include <ipxe/arp.h>
36 37
 #include <ipxe/if_ether.h>
37 38
 #include <ipxe/ethernet.h>
39
+#include <ipxe/ip.h>
38 40
 #include <ipxe/iobuf.h>
39 41
 #include <ipxe/netdevice.h>
40 42
 #include <ipxe/infiniband.h>
@@ -48,6 +50,20 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
48 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 67
 /** Number of IPoIB send work queue entries */
52 68
 #define IPOIB_NUM_SEND_WQES 2
53 69
 
@@ -336,8 +352,11 @@ static int ipoib_translate_tx_arp ( struct net_device *netdev,
336 352
 	/* Look up REMAC, if applicable */
337 353
 	if ( arphdr->ar_op == ARPOP_REPLY ) {
338 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 362
 	/* Construct new packet */
@@ -473,6 +492,7 @@ static int ipoib_transmit ( struct net_device *netdev,
473 492
 	struct ipoib_device *ipoib = netdev->priv;
474 493
 	struct ib_device *ibdev = ipoib->ibdev;
475 494
 	struct ethhdr *ethhdr;
495
+	struct iphdr *iphdr;
476 496
 	struct ipoib_hdr *ipoib_hdr;
477 497
 	struct ipoib_mac *mac;
478 498
 	struct ib_address_vector dest;
@@ -497,9 +517,34 @@ static int ipoib_transmit ( struct net_device *netdev,
497 517
 	iob_pull ( iobuf, sizeof ( *ethhdr ) );
498 518
 
499 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 549
 	/* Translate packet if applicable */
505 550
 	if ( ( rc = ipoib_translate_tx ( netdev, iobuf, net_proto ) ) != 0 )

+ 4
- 0
src/include/ipxe/arp.h 查看文件

@@ -57,4 +57,8 @@ static inline int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev,
57 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 64
 #endif /* _IPXE_ARP_H */

+ 3
- 3
src/net/arp.c 查看文件

@@ -56,9 +56,9 @@ struct net_protocol arp_protocol __net_protocol;
56 56
  * @v net_source	Source network-layer address
57 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 62
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
63 63
 	struct io_buffer *iobuf;
64 64
 	struct arphdr *arphdr;

Loading…
取消
儲存