Print this page
7819 IPv6 Packet and MTU bug

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/inet/ip/ip6.c
          +++ new/usr/src/uts/common/inet/ip/ip6.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   * Copyright (c) 1990 Mentat Inc.
       24 + * Copyright 2017 OmniTI Computer Consulting, Inc. All rights reserved.
  24   25   */
  25   26  
  26   27  #include <sys/types.h>
  27   28  #include <sys/stream.h>
  28   29  #include <sys/dlpi.h>
  29   30  #include <sys/stropts.h>
  30   31  #include <sys/sysmacros.h>
  31   32  #include <sys/strsun.h>
  32   33  #include <sys/strlog.h>
  33   34  #include <sys/strsubr.h>
↓ open down ↓ 641 lines elided ↑ open up ↑
 675  676          ill_t           *ill = ira->ira_ill;    /* Upper ill if IPMP */
 676  677          ip_stack_t      *ipst = ill->ill_ipst;
 677  678          int             old_max_frag;
 678  679          in6_addr_t      final_dst;
 679  680          ip6_t           *ip6h;  /* Inner IP header */
 680  681  
 681  682          /* Caller has already pulled up everything. */
 682  683          ip6h = (ip6_t *)&icmp6[1];
 683  684          final_dst = ip_get_dst_v6(ip6h, NULL, NULL);
 684  685  
      686 +        mtu = ntohl(icmp6->icmp6_mtu);
      687 +        if (mtu < IPV6_MIN_MTU) {
      688 +                /*
      689 +                 * RFC 8021 suggests to ignore messages where mtu is
      690 +                 * less than the IPv6 minimum.
      691 +                 */
      692 +                ip1dbg(("Received mtu less than IPv6 "
      693 +                    "min mtu %d: %d\n", IPV6_MIN_MTU, mtu));
      694 +                DTRACE_PROBE1(icmp6__too__small__mtu, uint32_t, mtu);
      695 +                return;
      696 +        }
      697 +
 685  698          /*
 686  699           * For link local destinations matching simply on address is not
 687  700           * sufficient. Same link local addresses for different ILL's is
 688  701           * possible.
 689  702           */
 690  703          if (IN6_IS_ADDR_LINKSCOPE(&final_dst)) {
 691  704                  dce = dce_lookup_and_add_v6(&final_dst,
 692  705                      ill->ill_phyint->phyint_ifindex, ipst);
 693  706          } else {
 694  707                  dce = dce_lookup_and_add_v6(&final_dst, 0, ipst);
↓ open down ↓ 2 lines elided ↑ open up ↑
 697  710                  /* Couldn't add a unique one - ENOMEM */
 698  711                  if (ip_debug > 2) {
 699  712                          /* ip1dbg */
 700  713                          pr_addr_dbg("icmp_inbound_too_big_v6:"
 701  714                              "no dce for dst %s\n", AF_INET6,
 702  715                              &final_dst);
 703  716                  }
 704  717                  return;
 705  718          }
 706  719  
 707      -        mtu = ntohl(icmp6->icmp6_mtu);
 708      -
 709  720          mutex_enter(&dce->dce_lock);
 710  721          if (dce->dce_flags & DCEF_PMTU)
 711  722                  old_max_frag = dce->dce_pmtu;
 712  723          else if (IN6_IS_ADDR_MULTICAST(&final_dst))
 713  724                  old_max_frag = ill->ill_mc_mtu;
 714  725          else
 715  726                  old_max_frag = ill->ill_mtu;
 716  727  
 717      -        if (mtu < IPV6_MIN_MTU) {
 718      -                ip1dbg(("Received mtu less than IPv6 "
 719      -                    "min mtu %d: %d\n", IPV6_MIN_MTU, mtu));
 720      -                mtu = IPV6_MIN_MTU;
 721      -                /*
 722      -                 * If an mtu less than IPv6 min mtu is received,
 723      -                 * we must include a fragment header in
 724      -                 * subsequent packets.
 725      -                 */
 726      -                dce->dce_flags |= DCEF_TOO_SMALL_PMTU;
 727      -        } else {
 728      -                dce->dce_flags &= ~DCEF_TOO_SMALL_PMTU;
 729      -        }
 730  728          ip1dbg(("Received mtu from router: %d\n", mtu));
      729 +        DTRACE_PROBE1(icmp6__received__mtu, uint32_t, mtu);
 731  730          dce->dce_pmtu = MIN(old_max_frag, mtu);
      731 +        icmp6->icmp6_mtu = htonl(dce->dce_pmtu);
 732  732  
 733      -        /* Prepare to send the new max frag size for the ULP. */
 734      -        if (dce->dce_flags & DCEF_TOO_SMALL_PMTU) {
 735      -                /*
 736      -                 * If we need a fragment header in every packet
 737      -                 * (above case or multirouting), make sure the
 738      -                 * ULP takes it into account when computing the
 739      -                 * payload size.
 740      -                 */
 741      -                icmp6->icmp6_mtu = htonl(dce->dce_pmtu - sizeof (ip6_frag_t));
 742      -        } else {
 743      -                icmp6->icmp6_mtu = htonl(dce->dce_pmtu);
 744      -        }
 745  733          /* We now have a PMTU for sure */
 746  734          dce->dce_flags |= DCEF_PMTU;
 747  735          dce->dce_last_change_time = TICK_TO_SEC(ddi_get_lbolt64());
      736 +
 748  737          mutex_exit(&dce->dce_lock);
 749  738          /*
 750  739           * After dropping the lock the new value is visible to everyone.
 751  740           * Then we bump the generation number so any cached values reinspect
 752  741           * the dce_t.
 753  742           */
 754  743          dce_increment_generation(dce);
 755  744          dce_refrele(dce);
 756  745  }
 757  746  
↓ open down ↓ 4293 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX