Bläddra i källkod

[eoib] Support non-FullMember gateway devices

Some EoIB implementations utilise an EoIB-to-Ethernet gateway device
that does not perform a FullMember join to the multicast group for the
EoIB broadcast domain.  This has various exciting side-effects, such
as requiring every EoIB node to send every broadcast packet twice.

As an added bonus, the gateway may also break the EoIB MAC address to
GID mapping protocol by sending Ethernet-sourced packets from the
wrong QPN.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 år sedan
förälder
incheckning
3144e4fb64
2 ändrade filer med 120 tillägg och 2 borttagningar
  1. 98
    2
      src/drivers/net/eoib.c
  2. 22
    0
      src/include/ipxe/eoib.h

+ 98
- 2
src/drivers/net/eoib.c Visa fil

269
 		return;
269
 		return;
270
 	}
270
 	}
271
 
271
 
272
+	/* Some dubious EoIB implementations utilise an Ethernet-to-
273
+	 * EoIB gateway that will send packets from the wrong QPN.
274
+	 */
275
+	if ( eoib_has_gateway ( eoib ) &&
276
+	     ( memcmp ( gid, &eoib->gateway.gid, sizeof ( *gid ) ) == 0 ) ) {
277
+		qpn = eoib->gateway.qpn;
278
+	}
279
+
272
 	/* Do nothing if peer cache entry is complete and correct */
280
 	/* Do nothing if peer cache entry is complete and correct */
273
 	if ( ( peer->av.lid == av->lid ) && ( peer->av.qpn == qpn ) ) {
281
 	if ( ( peer->av.lid == av->lid ) && ( peer->av.qpn == qpn ) ) {
274
 		DBGCP ( eoib, "EoIB %s %s RX unchanged\n",
282
 		DBGCP ( eoib, "EoIB %s %s RX unchanged\n",
326
 	if ( iob_len ( iobuf ) < zlen )
334
 	if ( iob_len ( iobuf ) < zlen )
327
 		iob_pad ( iobuf, zlen );
335
 		iob_pad ( iobuf, zlen );
328
 
336
 
329
-	/* If we have no unicast address then send as a broadcast */
330
-	if ( ! av )
337
+	/* If we have no unicast address then send as a broadcast,
338
+	 * with a duplicate sent to the gateway if applicable.
339
+	 */
340
+	if ( ! av ) {
331
 		av = &eoib->broadcast;
341
 		av = &eoib->broadcast;
342
+		if ( eoib_has_gateway ( eoib ) )
343
+			eoib->duplicate ( eoib, iobuf );
344
+	}
332
 
345
 
333
 	/* Post send work queue entry */
346
 	/* Post send work queue entry */
334
 	return ib_post_send ( eoib->ibdev, eoib->qp, av, iobuf );
347
 	return ib_post_send ( eoib->ibdev, eoib->qp, av, iobuf );
797
 	.rx = eoib_heartbeat_rx,
810
 	.rx = eoib_heartbeat_rx,
798
 	.ntoa = eoib_heartbeat_ntoa,
811
 	.ntoa = eoib_heartbeat_ntoa,
799
 };
812
 };
813
+
814
+/****************************************************************************
815
+ *
816
+ * EoIB gateway
817
+ *
818
+ ****************************************************************************
819
+ *
820
+ * Some dubious EoIB implementations require all broadcast traffic to
821
+ * be sent twice: once to the actual broadcast group, and once as a
822
+ * unicast to the EoIB-to-Ethernet gateway.  This somewhat curious
823
+ * design arises since the EoIB-to-Ethernet gateway hardware lacks the
824
+ * ability to attach a queue pair to a multicast GID (or LID), and so
825
+ * cannot receive traffic sent to the broadcast group.
826
+ *
827
+ */
828
+
829
+/**
830
+ * Transmit duplicate packet to the EoIB gateway
831
+ *
832
+ * @v eoib		EoIB device
833
+ * @v original		Original I/O buffer
834
+ */
835
+static void eoib_duplicate ( struct eoib_device *eoib,
836
+			     struct io_buffer *original ) {
837
+	struct net_device *netdev = eoib->netdev;
838
+	struct ib_device *ibdev = eoib->ibdev;
839
+	struct ib_address_vector *av = &eoib->gateway;
840
+	size_t len = iob_len ( original );
841
+	struct io_buffer *copy;
842
+	int rc;
843
+
844
+	/* Create copy of I/O buffer */
845
+	copy = alloc_iob ( len );
846
+	if ( ! copy ) {
847
+		rc = -ENOMEM;
848
+		goto err_alloc;
849
+	}
850
+	memcpy ( iob_put ( copy, len ), original->data, len );
851
+
852
+	/* Append to network device's transmit queue */
853
+	list_add_tail ( &copy->list, &original->list );
854
+
855
+	/* Resolve path to gateway */
856
+	if ( ( rc = ib_resolve_path ( ibdev, av ) ) != 0 ) {
857
+		DBGC ( eoib, "EoIB %s no path to gateway: %s\n",
858
+		       eoib->name, strerror ( rc ) );
859
+		goto err_path;
860
+	}
861
+
862
+	/* Force use of GRH even for local destinations */
863
+	av->gid_present = 1;
864
+
865
+	/* Post send work queue entry */
866
+	if ( ( rc = ib_post_send ( eoib->ibdev, eoib->qp, av, copy ) ) != 0 )
867
+		goto err_post_send;
868
+
869
+	return;
870
+
871
+ err_post_send:
872
+ err_path:
873
+ err_alloc:
874
+	netdev_tx_complete_err ( netdev, copy, rc );
875
+}
876
+
877
+/**
878
+ * Set EoIB gateway
879
+ *
880
+ * @v eoib		EoIB device
881
+ * @v av		Address vector, or NULL to clear gateway
882
+ */
883
+void eoib_set_gateway ( struct eoib_device *eoib,
884
+			struct ib_address_vector *av ) {
885
+
886
+	if ( av ) {
887
+		DBGC ( eoib, "EoIB %s using gateway " IB_GID_FMT "\n",
888
+		       eoib->name, IB_GID_ARGS ( &av->gid ) );
889
+		memcpy ( &eoib->gateway, av, sizeof ( eoib->gateway ) );
890
+		eoib->duplicate = eoib_duplicate;
891
+	} else {
892
+		DBGC ( eoib, "EoIB %s not using gateway\n", eoib->name );
893
+		eoib->duplicate = NULL;
894
+	}
895
+}

+ 22
- 0
src/include/ipxe/eoib.h Visa fil

49
 	/** Peer cache */
49
 	/** Peer cache */
50
 	struct list_head peers;
50
 	struct list_head peers;
51
 
51
 
52
+	/** Send duplicate packet to gateway (or NULL)
53
+	 *
54
+	 * @v eoib		EoIB device
55
+	 * @v original		Original I/O buffer
56
+	 */
57
+	void ( * duplicate ) ( struct eoib_device *eoib,
58
+			       struct io_buffer *original );
59
+	/** Gateway (if any) */
60
+	struct ib_address_vector gateway;
52
 	/** Multicast group additional component mask */
61
 	/** Multicast group additional component mask */
53
 	unsigned int mask;
62
 	unsigned int mask;
54
 };
63
 };
55
 
64
 
65
+/**
66
+ * Check if EoIB device uses a gateway
67
+ *
68
+ * @v eoib		EoIB device
69
+ * @v has_gw		EoIB device uses a gateway
70
+ */
71
+static inline int eoib_has_gateway ( struct eoib_device *eoib ) {
72
+
73
+	return ( eoib->duplicate != NULL );
74
+}
75
+
56
 /**
76
 /**
57
  * Force creation of multicast group
77
  * Force creation of multicast group
58
  *
78
  *
77
 extern struct eoib_device * eoib_find ( struct ib_device *ibdev,
97
 extern struct eoib_device * eoib_find ( struct ib_device *ibdev,
78
 					const uint8_t *hw_addr );
98
 					const uint8_t *hw_addr );
79
 extern void eoib_destroy ( struct eoib_device *eoib );
99
 extern void eoib_destroy ( struct eoib_device *eoib );
100
+extern void eoib_set_gateway ( struct eoib_device *eoib,
101
+			       struct ib_address_vector *av );
80
 
102
 
81
 #endif /* _IPXE_EOIB_H */
103
 #endif /* _IPXE_EOIB_H */

Laddar…
Avbryt
Spara