]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[netdevice] Limit MTU by hardware maximum frame length
authorMichael Brown <mcb30@ipxe.org>
Wed, 25 Jan 2017 14:48:24 +0000 (14:48 +0000)
committerMichael Brown <mcb30@ipxe.org>
Wed, 25 Jan 2017 14:55:09 +0000 (14:55 +0000)
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>
src/include/ipxe/netdevice.h
src/net/infiniband/xsigo.c
src/net/netdev_settings.c
src/net/netdevice.c
src/net/tcpip.c

index a1d207ffc47dcae88aacd0e34487c455e79eb4a6..d498ab697dccbc248d8ff137da916abbf70d9d93 100644 (file)
@@ -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 */
index 91b7b71f1eb9966fb86f9ef7fd49001ea6da60a5..0ee753c38a1c113bd6969edc6ca3ad346b04a7a2 100644 (file)
@@ -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;
index 67a45bedee1ce10e25e1a6aff0e15dfba4ba326d..c54288d4f86ef2c0469fe47db80fc942aa371cfa 100644 (file)
@@ -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: "
index 9df21196c1db5097697e800f2165141e708e7dc7..41ece77f0c5e9c48bc72a1d8a04476678bce8b2e 100644 (file)
@@ -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.
         */
index c9e4ee789c979fde93ace4b80d5c8a0406a4252b..cc7d02005024bc4b8e4a7fa62ef982e649e51768 100644 (file)
@@ -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;
 }