Date: Thu, 8 Nov 2012 01:23:41 +1100 (EST) From: Mark Andrews <marka@isc.org> To: FreeBSD-gnats-submit@FreeBSD.org Subject: kern/173444: IPV6_USE_MIN_MTU and TCP is broken Message-ID: <201211071423.qA7ENfHK076243@sex.dv.isc.org> Resent-Message-ID: <201211071430.qA7EU12Q048205@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 173444 >Category: kern >Synopsis: IPV6_USE_MIN_MTU and TCP is broken >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed Nov 07 14:30:01 UTC 2012 >Closed-Date: >Last-Modified: >Originator: Mark Andrews >Release: FreeBSD 8.3-STABLE i386 >Organization: ISC >Environment: System: FreeBSD sex.dv.isc.org 8.3-STABLE FreeBSD 8.3-STABLE #18: Mon Jun 18 11:57:52 EST 2012 root@sex.dv.isc.org:/usr/obj/usr/src/sys/DEBUG i386 >Description: Setting IPV6_USE_MIN_MTU to one (1) on a IPv6 TCP socket results in fragmented IPv6 packets being sent rather than the TCP segment size being adjusted to reflect the MTU limit on the socket. 00:56:44.177930 IP6 2001:470:1f00:820:218:f3ff:feba:9a37 > 2001:470:1f00:820:6233:4bff:fe01:7585: frag (0|1232) 5555 > 63656: Flags [.], ack 42, win 8211, options [nop,nop,TS val 2829969063 ecr 1028520077], length 1200 00:56:44.177936 IP6 2001:470:1f00:820:218:f3ff:feba:9a37 > 2001:470:1f00:820:6233:4bff:fe01:7585: frag (1232|228) 00:56:44.177953 IP6 2001:470:1f00:820:218:f3ff:feba:9a37 > 2001:470:1f00:820:6233:4bff:fe01:7585: frag (0|1232) 5555 > 63656: Flags [.], ack 42, win 8211, options [nop,nop,TS val 2829969063 ecr 1028520077], length 1200 00:56:44.177957 IP6 2001:470:1f00:820:218:f3ff:feba:9a37 > 2001:470:1f00:820:6233:4bff:fe01:7585: frag (1232|228) 00:56:44.177974 IP6 2001:470:1f00:820:218:f3ff:feba:9a37 > 2001:470:1f00:820:6233:4bff:fe01:7585: frag (0|1232) 5555 > 63656: Flags [.], ack 42, win 8211, options [nop,nop,TS val 2829969063 ecr 1028520077], length 1200 >How-To-Repeat: Apply the following patch to named and transfer a zone. [The intent of the patch is to avoid PMTUD issues. Too many nameservers are behind load balancers / firewalls that don't pass PTB messages.] diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index ffe7e02..6fb8860 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -2262,6 +2264,31 @@ clear_bsdcompat(void) { } #endif +static void +use_min_mtu(isc__socket_t *sock) { +#if !defined(IPV6_USE_MIN_MTU) && !defined(IPV6_MTU) + UNUSED(sock); +#endif +#ifdef IPV6_USE_MIN_MTU + /* use minimum MTU */ + if (sock->pf == AF_INET6) { + int on = 1; + (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU, + (void *)&on, sizeof(on)); + } +#endif +#if defined(IPV6_MTU) + /* + * Use minimum MTU on IPv6 sockets. + */ + if (sock->pf == AF_INET6) { + int mtu = 1280; + (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_MTU, + &mtu, sizeof(mtu)); + } +#endif +} + static isc_result_t opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, isc__socket_t *dup_socket) @@ -2426,6 +2453,11 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, } #endif + /* + * Use minimum mtu if possible. + */ + use_min_mtu(sock); + #if defined(USE_CMSG) || defined(SO_RCVBUF) if (sock->type == isc_sockettype_udp) { @@ -2490,32 +2522,6 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, } #endif /* IPV6_RECVPKTINFO */ #endif /* ISC_PLATFORM_HAVEIN6PKTINFO */ -#ifdef IPV6_USE_MIN_MTU /* RFC 3542, not too common yet*/ - /* use minimum MTU */ - if (sock->pf == AF_INET6 && - setsockopt(sock->fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU, - (void *)&on, sizeof(on)) < 0) { - isc__strerror(errno, strbuf, sizeof(strbuf)); - UNEXPECTED_ERROR(__FILE__, __LINE__, - "setsockopt(%d, IPV6_USE_MIN_MTU) " - "%s: %s", sock->fd, - isc_msgcat_get(isc_msgcat, - ISC_MSGSET_GENERAL, - ISC_MSG_FAILED, - "failed"), - strbuf); - } -#endif -#if defined(IPV6_MTU) - /* - * Use minimum MTU on IPv6 sockets. - */ - if (sock->pf == AF_INET6) { - int mtu = 1280; - (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_MTU, - &mtu, sizeof(mtu)); - } -#endif #if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DONT) /* * Turn off Path MTU discovery on IPv6/UDP sockets. @@ -3313,6 +3319,11 @@ internal_accept(isc_task_t *me, isc_event_t *ev) { NEWCONNSOCK(dev)->connected = 1; /* + * Use minimum mtu if possible. + */ + use_min_mtu(NEWCONNSOCK(dev)); + + /* * Save away the remote address */ dev->address = NEWCONNSOCK(dev)->peer_address; >Fix: The TCP layer should check whether ip6po_minmtu is set on the socket and adjust the maxmtu appropriately. The code fragment below should do that but has not been tested. sys/netinet/tcp_input.c: if (isipv6) { struct ip6_pktopts *opt; maxmtu = tcp_maxmtu6(&inp->inp_inc, mtuflags); opt = inp->inp_depend6.inp6_outputopts; if (opt && opt->ip6po_minmtu) maxmtu = min(maxmtu, IPV6_MMTU); tp->t_maxopd = tp->t_maxseg = V_tcp_v6mssdflt; } else >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201211071423.qA7ENfHK076243>