Print this page
7819 IPv6 Packet and MTU bug
        
*** 19,28 ****
--- 19,29 ----
   * CDDL HEADER END
   */
  /*
   * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
   * Copyright (c) 1990 Mentat Inc.
+  * Copyright 2017 OmniTI Computer Consulting, Inc. All rights reserved.
   */
  
  #include <sys/types.h>
  #include <sys/stream.h>
  #include <sys/dlpi.h>
*** 680,690 ****
--- 681,703 ----
  
          /* Caller has already pulled up everything. */
          ip6h = (ip6_t *)&icmp6[1];
          final_dst = ip_get_dst_v6(ip6h, NULL, NULL);
  
+         mtu = ntohl(icmp6->icmp6_mtu);
+         if (mtu < IPV6_MIN_MTU) {
                  /*
+                  * RFC 8021 suggests to ignore messages where mtu is
+                  * less than the IPv6 minimum.
+                  */
+                 ip1dbg(("Received mtu less than IPv6 "
+                     "min mtu %d: %d\n", IPV6_MIN_MTU, mtu));
+                 DTRACE_PROBE1(icmp6__too__small__mtu, uint32_t, mtu);
+                 return;
+         }
+ 
+         /*
           * For link local destinations matching simply on address is not
           * sufficient. Same link local addresses for different ILL's is
           * possible.
           */
          if (IN6_IS_ADDR_LINKSCOPE(&final_dst)) {
*** 702,752 ****
                              &final_dst);
                  }
                  return;
          }
  
-         mtu = ntohl(icmp6->icmp6_mtu);
- 
          mutex_enter(&dce->dce_lock);
          if (dce->dce_flags & DCEF_PMTU)
                  old_max_frag = dce->dce_pmtu;
          else if (IN6_IS_ADDR_MULTICAST(&final_dst))
                  old_max_frag = ill->ill_mc_mtu;
          else
                  old_max_frag = ill->ill_mtu;
  
-         if (mtu < IPV6_MIN_MTU) {
-                 ip1dbg(("Received mtu less than IPv6 "
-                     "min mtu %d: %d\n", IPV6_MIN_MTU, mtu));
-                 mtu = IPV6_MIN_MTU;
-                 /*
-                  * If an mtu less than IPv6 min mtu is received,
-                  * we must include a fragment header in
-                  * subsequent packets.
-                  */
-                 dce->dce_flags |= DCEF_TOO_SMALL_PMTU;
-         } else {
-                 dce->dce_flags &= ~DCEF_TOO_SMALL_PMTU;
-         }
          ip1dbg(("Received mtu from router: %d\n", mtu));
          dce->dce_pmtu = MIN(old_max_frag, mtu);
- 
-         /* Prepare to send the new max frag size for the ULP. */
-         if (dce->dce_flags & DCEF_TOO_SMALL_PMTU) {
-                 /*
-                  * If we need a fragment header in every packet
-                  * (above case or multirouting), make sure the
-                  * ULP takes it into account when computing the
-                  * payload size.
-                  */
-                 icmp6->icmp6_mtu = htonl(dce->dce_pmtu - sizeof (ip6_frag_t));
-         } else {
                  icmp6->icmp6_mtu = htonl(dce->dce_pmtu);
!         }
          /* We now have a PMTU for sure */
          dce->dce_flags |= DCEF_PMTU;
          dce->dce_last_change_time = TICK_TO_SEC(ddi_get_lbolt64());
          mutex_exit(&dce->dce_lock);
          /*
           * After dropping the lock the new value is visible to everyone.
           * Then we bump the generation number so any cached values reinspect
           * the dce_t.
--- 715,741 ----
                              &final_dst);
                  }
                  return;
          }
  
          mutex_enter(&dce->dce_lock);
          if (dce->dce_flags & DCEF_PMTU)
                  old_max_frag = dce->dce_pmtu;
          else if (IN6_IS_ADDR_MULTICAST(&final_dst))
                  old_max_frag = ill->ill_mc_mtu;
          else
                  old_max_frag = ill->ill_mtu;
  
          ip1dbg(("Received mtu from router: %d\n", mtu));
+         DTRACE_PROBE1(icmp6__received__mtu, uint32_t, mtu);
          dce->dce_pmtu = MIN(old_max_frag, mtu);
          icmp6->icmp6_mtu = htonl(dce->dce_pmtu);
! 
          /* We now have a PMTU for sure */
          dce->dce_flags |= DCEF_PMTU;
          dce->dce_last_change_time = TICK_TO_SEC(ddi_get_lbolt64());
+ 
          mutex_exit(&dce->dce_lock);
          /*
           * After dropping the lock the new value is visible to everyone.
           * Then we bump the generation number so any cached values reinspect
           * the dce_t.