diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index a1d207ff..d498ab69 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -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 */ diff --git a/src/net/infiniband/xsigo.c b/src/net/infiniband/xsigo.c index 91b7b71f..0ee753c3 100644 --- a/src/net/infiniband/xsigo.c +++ b/src/net/infiniband/xsigo.c @@ -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; diff --git a/src/net/netdev_settings.c b/src/net/netdev_settings.c index 67a45bed..c54288d4 100644 --- a/src/net/netdev_settings.c +++ b/src/net/netdev_settings.c @@ -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; @@ -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: " diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 9df21196..41ece77f 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -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. */ diff --git a/src/net/tcpip.c b/src/net/tcpip.c index c9e4ee78..cc7d0200 100644 --- a/src/net/tcpip.c +++ b/src/net/tcpip.c @@ -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; }