summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/drivers/net/ipoib.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/ipxe/src/drivers/net/ipoib.c')
-rw-r--r--qemu/roms/ipxe/src/drivers/net/ipoib.c90
1 files changed, 76 insertions, 14 deletions
diff --git a/qemu/roms/ipxe/src/drivers/net/ipoib.c b/qemu/roms/ipxe/src/drivers/net/ipoib.c
index 1b5391776..6552d764e 100644
--- a/qemu/roms/ipxe/src/drivers/net/ipoib.c
+++ b/qemu/roms/ipxe/src/drivers/net/ipoib.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
@@ -29,8 +33,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
#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>
@@ -44,6 +50,20 @@ FILE_LICENCE ( GPL2_OR_LATER );
* 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
@@ -96,6 +116,8 @@ struct errortab ipoib_errors[] __errortab = {
__einfo_errortab ( EINFO_EINPROGRESS_JOINING ),
};
+static struct net_device_operations ipoib_operations;
+
/****************************************************************************
*
* IPoIB REMAC cache
@@ -124,8 +146,10 @@ static struct ipoib_mac * ipoib_find_remac ( struct ipoib_device *ipoib,
const struct ipoib_remac *remac ) {
struct ipoib_peer *peer;
- /* Check for broadcast REMAC */
- if ( is_broadcast_ether_addr ( remac ) )
+ /* Check for broadcast or multicast REMAC. We transmit
+ * multicasts as broadcasts for simplicity.
+ */
+ if ( is_multicast_ether_addr ( remac ) )
return &ipoib->broadcast;
/* Try to find via REMAC cache */
@@ -202,14 +226,20 @@ static void ipoib_flush_remac ( struct ipoib_device *ipoib ) {
* @ret discarded Number of cached items discarded
*/
static unsigned int ipoib_discard_remac ( void ) {
- struct ib_device *ibdev;
+ struct net_device *netdev;
struct ipoib_device *ipoib;
struct ipoib_peer *peer;
unsigned int discarded = 0;
/* Try to discard one cache entry for each IPoIB device */
- for_each_ibdev ( ibdev ) {
- ipoib = ib_get_ownerdata ( ibdev );
+ for_each_netdev ( netdev ) {
+
+ /* Skip non-IPoIB devices */
+ if ( netdev->op != &ipoib_operations )
+ continue;
+ ipoib = netdev->priv;
+
+ /* Discard least recently used cache entry (if any) */
list_for_each_entry_reverse ( peer, &ipoib->peers, list ) {
list_del ( &peer->list );
free ( peer );
@@ -222,7 +252,7 @@ static unsigned int ipoib_discard_remac ( void ) {
}
/** IPoIB cache discarder */
-struct cache_discarder ipoib_discarder __cache_discarder ( CACHE_NORMAL ) = {
+struct cache_discarder ipoib_discarder __cache_discarder ( CACHE_EXPENSIVE ) = {
.discard = ipoib_discard_remac,
};
@@ -324,8 +354,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 */
@@ -461,6 +494,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;
@@ -485,9 +519,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 )
@@ -732,7 +791,8 @@ static void ipoib_link_state_changed ( struct ib_device *ibdev ) {
int rc;
/* Leave existing broadcast group */
- ipoib_leave_broadcast_group ( ipoib );
+ if ( ipoib->qp )
+ ipoib_leave_broadcast_group ( ipoib );
/* Update MAC address based on potentially-new GID prefix */
memcpy ( &ipoib->mac.gid.s.prefix, &ibdev->gid.s.prefix,
@@ -747,7 +807,7 @@ static void ipoib_link_state_changed ( struct ib_device *ibdev ) {
netdev_link_err ( netdev, ( rc ? rc : -EINPROGRESS_JOINING ) );
/* Join new broadcast group */
- if ( ib_is_open ( ibdev ) && ib_link_ok ( ibdev ) &&
+ if ( ib_is_open ( ibdev ) && ib_link_ok ( ibdev ) && ipoib->qp &&
( ( rc = ipoib_join_broadcast_group ( ipoib ) ) != 0 ) ) {
DBGC ( ipoib, "IPoIB %p could not rejoin broadcast group: "
"%s\n", ipoib, strerror ( rc ) );
@@ -835,7 +895,9 @@ static void ipoib_close ( struct net_device *netdev ) {
/* Tear down the queues */
ib_destroy_qp ( ibdev, ipoib->qp );
+ ipoib->qp = NULL;
ib_destroy_cq ( ibdev, ipoib->cq );
+ ipoib->cq = NULL;
/* Close IB device */
ib_close ( ibdev );