Skip to content

Commit

Permalink
[netdevice] Limit MTU by hardware maximum frame length
Browse files Browse the repository at this point in the history
Separate out the concept of "hardware maximum supported frame length"
and "configured link MTU", and limit the latter according to the
former.

In networks where the DHCP-supplied link MTU is inconsistent with the
hardware or driver capabilities (e.g. a network using jumbo frames),
this will result in iPXE advertising a TCP MSS consistent with a size
that can actually be received.

Note that the term "MTU" is typically used to refer to the maximum
length excluding the link-layer headers; we adopt this usage.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Jan 25, 2017
1 parent f450c75 commit 70fc25a
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 10 deletions.
9 changes: 8 additions & 1 deletion src/include/ipxe/netdevice.h
Expand Up @@ -397,9 +397,16 @@ struct net_device {
struct retry_timer link_block;
/** Maximum packet length
*
* This length includes any link-layer headers.
* This is the maximum packet length (including any link-layer
* headers) supported by the hardware.
*/
size_t max_pkt_len;
/** Maximum transmission unit length
*
* This is the maximum transmission unit length (excluding any
* link-layer headers) configured for the link.
*/
size_t mtu;
/** TX packet queue */
struct list_head tx_queue;
/** Deferred TX packet queue */
Expand Down
1 change: 1 addition & 0 deletions src/net/infiniband/xsigo.c
Expand Up @@ -323,6 +323,7 @@ static int xve_update_mtu ( struct xsigo_nic *xve, struct eoib_device *eoib,
* not the EoIB header.
*/
netdev->max_pkt_len = ( mtu + sizeof ( struct ethhdr ) );
netdev->mtu = mtu;
DBGC ( xve, "XVE %s has MTU %zd\n", xve->name, mtu );

return 0;
Expand Down
22 changes: 15 additions & 7 deletions src/net/netdev_settings.c
Expand Up @@ -393,7 +393,8 @@ static int apply_netdev_settings ( void ) {
struct net_device *netdev;
struct settings *settings;
struct ll_protocol *ll_protocol;
size_t old_max_pkt_len;
size_t max_mtu;
size_t old_mtu;
size_t mtu;
int rc;

Expand All @@ -410,18 +411,25 @@ static int apply_netdev_settings ( void ) {
if ( ! mtu )
continue;

/* Update maximum packet length */
/* Limit MTU to maximum supported by hardware */
ll_protocol = netdev->ll_protocol;
old_max_pkt_len = netdev->max_pkt_len;
netdev->max_pkt_len = ( mtu + ll_protocol->ll_header_len );
if ( netdev->max_pkt_len != old_max_pkt_len ) {
max_mtu = ( netdev->max_pkt_len - ll_protocol->ll_header_len );
if ( mtu > max_mtu ) {
DBGC ( netdev, "NETDEV %s cannot support MTU %zd (max "
"%zd)\n", netdev->name, mtu, max_mtu );
mtu = max_mtu;
}

/* Update maximum packet length */
old_mtu = netdev->mtu;
netdev->mtu = mtu;
if ( mtu != old_mtu ) {
DBGC ( netdev, "NETDEV %s MTU is %zd\n",
netdev->name, mtu );
}

/* Close and reopen network device if MTU has increased */
if ( netdev_is_open ( netdev ) &&
( netdev->max_pkt_len > old_max_pkt_len ) ) {
if ( netdev_is_open ( netdev ) && ( mtu > old_mtu ) ) {
netdev_close ( netdev );
if ( ( rc = netdev_open ( netdev ) ) != 0 ) {
DBGC ( netdev, "NETDEV %s could not reopen: "
Expand Down
6 changes: 6 additions & 0 deletions src/net/netdevice.c
Expand Up @@ -663,6 +663,12 @@ int register_netdev ( struct net_device *netdev ) {
ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
}

/* Set MTU, if not already set */
if ( ! netdev->mtu ) {
netdev->mtu = ( netdev->max_pkt_len -
ll_protocol->ll_header_len );
}

/* Reject network devices that are already available via a
* different hardware device.
*/
Expand Down
3 changes: 1 addition & 2 deletions src/net/tcpip.c
Expand Up @@ -144,8 +144,7 @@ size_t tcpip_mtu ( struct sockaddr_tcpip *st_dest ) {
return 0;

/* Calculate MTU */
mtu = ( netdev->max_pkt_len - netdev->ll_protocol->ll_header_len -
tcpip_net->header_len );
mtu = ( netdev->mtu - tcpip_net->header_len );

return mtu;
}
Expand Down

0 comments on commit 70fc25a

Please sign in to comment.