kern/173444: IPV6_USE_MIN_MTU and TCP is broken
Mark Andrews
marka at isc.org
Wed Nov 7 14:30:02 UTC 2012
>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 at 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:
More information about the freebsd-bugs
mailing list