Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[netdevice] Add the concept of an "Ethernet-compatible" MAC address
The iBFT is Ethernet-centric in providing only six bytes for a MAC
address.  This is most probably an indirect consequence of a similar
design flaw in the Windows NDIS stack.  (The WinOF IPoIB stack
performs all sorts of contortions in order to pretend to the NDIS
layer that it is dealing with six-byte MAC addresses.)

There is no sensible way in which to extend the iBFT without breaking
compatibility with programs that expect to parse it.  Add the notion
of an "Ethernet-compatible" MAC address to our link layer abstraction,
so that link layers can provide their own workarounds for this
limitation.
  • Loading branch information
Michael Brown committed Oct 23, 2009
1 parent d000c6b commit 1b1e63d
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 6 deletions.
57 changes: 57 additions & 0 deletions src/drivers/net/ipoib.c
Expand Up @@ -296,6 +296,62 @@ static int ipoib_mc_hash ( unsigned int af __unused,
return -ENOTSUP;
}

/**
* Generate Mellanox Ethernet-compatible compressed link-layer address
*
* @v ll_addr Link-layer address
* @v eth_addr Ethernet-compatible address to fill in
*/
static int ipoib_mlx_eth_addr ( const struct ib_gid_half *guid,
uint8_t *eth_addr ) {
eth_addr[0] = ( ( guid->u.bytes[3] == 2 ) ? 0x00 : 0x02 );
eth_addr[1] = guid->u.bytes[1];
eth_addr[2] = guid->u.bytes[2];
eth_addr[3] = guid->u.bytes[5];
eth_addr[4] = guid->u.bytes[6];
eth_addr[5] = guid->u.bytes[7];
return 0;
}

/** An IPoIB Ethernet-compatible compressed link-layer address generator */
struct ipoib_eth_addr_handler {
/** GUID byte 1 */
uint8_t byte1;
/** GUID byte 2 */
uint8_t byte2;
/** Handler */
int ( * eth_addr ) ( const struct ib_gid_half *guid,
uint8_t *eth_addr );
};

/** IPoIB Ethernet-compatible compressed link-layer address generators */
static struct ipoib_eth_addr_handler ipoib_eth_addr_handlers[] = {
{ 0x02, 0xc9, ipoib_mlx_eth_addr },
};

/**
* Generate Ethernet-compatible compressed link-layer address
*
* @v ll_addr Link-layer address
* @v eth_addr Ethernet-compatible address to fill in
*/
static int ipoib_eth_addr ( const void *ll_addr, void *eth_addr ) {
const struct ipoib_mac *ipoib_addr = ll_addr;
const struct ib_gid_half *guid = &ipoib_addr->gid.u.half[1];
struct ipoib_eth_addr_handler *handler;
unsigned int i;

for ( i = 0 ; i < ( sizeof ( ipoib_eth_addr_handlers ) /
sizeof ( ipoib_eth_addr_handlers[0] ) ) ; i++ ) {
handler = &ipoib_eth_addr_handlers[i];
if ( ( handler->byte1 == guid->u.bytes[1] ) &&
( handler->byte2 == guid->u.bytes[2] ) ) {
return handler->eth_addr ( guid, eth_addr );
}
}
return -ENOTSUP;
}

/** IPoIB protocol */
struct ll_protocol ipoib_protocol __ll_protocol = {
.name = "IPoIB",
Expand All @@ -308,6 +364,7 @@ struct ll_protocol ipoib_protocol __ll_protocol = {
.init_addr = ipoib_init_addr,
.ntoa = ipoib_ntoa,
.mc_hash = ipoib_mc_hash,
.eth_addr = ipoib_eth_addr,
};

/**
Expand Down
1 change: 1 addition & 0 deletions src/include/gpxe/ethernet.h
Expand Up @@ -15,6 +15,7 @@ extern void eth_init_addr ( const void *hw_addr, void *ll_addr );
extern const char * eth_ntoa ( const void *ll_addr );
extern int eth_mc_hash ( unsigned int af, const void *net_addr,
void *ll_addr );
extern int eth_eth_addr ( const void *ll_addr, void *eth_addr );
extern struct net_device * alloc_etherdev ( size_t priv_size );

#endif /* _GPXE_ETHERNET_H */
19 changes: 13 additions & 6 deletions src/include/gpxe/netdevice.h
Expand Up @@ -128,8 +128,8 @@ struct ll_protocol {
/**
* Transcribe link-layer address
*
* @v ll_addr Link-layer address
* @ret string Human-readable transcription of address
* @v ll_addr Link-layer address
* @ret string Human-readable transcription of address
*
* This method should convert the link-layer address into a
* human-readable format.
Expand All @@ -141,13 +141,20 @@ struct ll_protocol {
/**
* Hash multicast address
*
* @v af Address family
* @v net_addr Network-layer address
* @v ll_addr Link-layer address to fill in
* @ret rc Return status code
* @v af Address family
* @v net_addr Network-layer address
* @v ll_addr Link-layer address to fill in
* @ret rc Return status code
*/
int ( * mc_hash ) ( unsigned int af, const void *net_addr,
void *ll_addr );
/**
* Generate Ethernet-compatible compressed link-layer address
*
* @v ll_addr Link-layer address
* @v eth_addr Ethernet-compatible address to fill in
*/
int ( * eth_addr ) ( const void *ll_addr, void *eth_addr );
/** Link-layer protocol
*
* This is an ARPHRD_XXX constant, in network byte order.
Expand Down
1 change: 1 addition & 0 deletions src/net/80211/net80211.c
Expand Up @@ -586,6 +586,7 @@ static struct ll_protocol net80211_ll_protocol __ll_protocol = {
.init_addr = eth_init_addr,
.ntoa = eth_ntoa,
.mc_hash = eth_mc_hash,
.eth_addr = eth_eth_addr,
.ll_proto = htons ( ARPHRD_ETHER ), /* "encapsulated Ethernet" */
.hw_addr_len = ETH_ALEN,
.ll_addr_len = ETH_ALEN,
Expand Down
12 changes: 12 additions & 0 deletions src/net/ethernet.c
Expand Up @@ -148,6 +148,17 @@ int eth_mc_hash ( unsigned int af, const void *net_addr, void *ll_addr ) {
}
}

/**
* Generate Ethernet-compatible compressed link-layer address
*
* @v ll_addr Link-layer address
* @v eth_addr Ethernet-compatible address to fill in
*/
int eth_eth_addr ( const void *ll_addr, void *eth_addr ) {
memcpy ( eth_addr, ll_addr, ETH_ALEN );
return 0;
}

/** Ethernet protocol */
struct ll_protocol ethernet_protocol __ll_protocol = {
.name = "Ethernet",
Expand All @@ -160,6 +171,7 @@ struct ll_protocol ethernet_protocol __ll_protocol = {
.init_addr = eth_init_addr,
.ntoa = eth_ntoa,
.mc_hash = eth_mc_hash,
.eth_addr = eth_eth_addr,
};

/**
Expand Down

0 comments on commit 1b1e63d

Please sign in to comment.