diff --git a/sys/netinet/ip6.h b/sys/netinet/ip6.h --- a/sys/netinet/ip6.h +++ b/sys/netinet/ip6.h @@ -254,7 +254,7 @@ */ #define IPV6_MAXHLIM 255 /* maximum hoplimit */ #define IPV6_DEFHLIM 64 /* default hlim */ -#define IPV6_FRAGTTL 120 /* ttl for fragment packets, in slowtimo tick */ +#define IPV6_DEFFRAGTTL 60000 /* Default fragment packets lifetime, in milliseconds */ #define IPV6_HLIMDEC 1 /* subtracted when forwarding */ #define IPV6_MMTU 1280 /* minimal MTU and reassembly. 1024 + 256 */ diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c --- a/sys/netinet6/frag6.c +++ b/sys/netinet6/frag6.c @@ -125,6 +125,10 @@ #define V_ip6_maxfragpackets VNET(ip6_maxfragpackets) #define V_frag6_nfragpackets VNET(frag6_nfragpackets) +/* Maximum per-VNET reassembly timeout (milliseconds) */ +VNET_DEFINE_STATIC(u_int, ip6_fraglifetime) = IPV6_DEFFRAGTTL; +#define V_ip6_fraglifetime VNET(ip6_fraglifetime) + /* Maximum per-VNET reassembly queues per bucket and fragments per packet. */ VNET_DEFINE_STATIC(int, ip6_maxfragbucketsize); VNET_DEFINE_STATIC(int, ip6_maxfragsperpacket); @@ -159,6 +163,9 @@ #define IP6_MAXFRAGS (nmbclusters / 32) #define IP6_MAXFRAGPACKETS (imin(IP6_MAXFRAGS, IP6REASS_NHASH * 50)) +/* Interval between periodic reassembly queue inspections */ +#define IP6_CALLOUT_INTERVAL_MS 500 + /* * Sysctls and helper function. */ @@ -213,6 +220,53 @@ CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_maxfragbucketsize), 0, "Maximum number of reassembly queues per hash bucket"); +static int +frag6_milli_to_callout_ticks(int ms) +{ + return (ms / IP6_CALLOUT_INTERVAL_MS); +} + +static int +frag6_callout_ticks_to_milli(int ms) +{ + return (ms * IP6_CALLOUT_INTERVAL_MS); +} + +_Static_assert(sizeof(((struct ip6q *)NULL)->ip6q_ttl) >= 2, + "ip6q_ttl field is not large enough"); + +static int +sysctl_ip6_fraglifetime(SYSCTL_HANDLER_ARGS) +{ + int error, val; + + val = V_ip6_fraglifetime; + error = sysctl_handle_int(oidp, &val, 0, req); + if (error != 0 || !req->newptr) + return (error); + if (val <= 0) + val = IPV6_DEFFRAGTTL; + + if (frag6_milli_to_callout_ticks(val) >= 65536) + val = frag6_callout_ticks_to_milli(65535); +#ifdef VIMAGE + if (!IS_DEFAULT_VNET(curvnet)) { + CURVNET_SET(vnet0); + int host_val = V_ip6_fraglifetime; + CURVNET_RESTORE(); + + if (val > host_val) + val = host_val; + } +#endif + V_ip6_fraglifetime = val; + return (0); +} +SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, fraglifetime_ms, + CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, + NULL, 0, sysctl_ip6_fraglifetime, "I", + "Fragment lifetime, in milliseconds"); + /* * Remove the IPv6 fragmentation header from the mbuf. */ @@ -552,7 +606,7 @@ /* ip6q_nxt will be filled afterwards, from 1st fragment. */ TAILQ_INIT(&q6->ip6q_frags); q6->ip6q_ident = ip6f->ip6f_ident; - q6->ip6q_ttl = IPV6_FRAGTTL; + q6->ip6q_ttl = frag6_milli_to_callout_ticks(V_ip6_fraglifetime); q6->ip6q_src = ip6->ip6_src; q6->ip6q_dst = ip6->ip6_dst; q6->ip6q_ecn = IPV6_ECN(ip6); @@ -952,8 +1006,8 @@ } VNET_LIST_RUNLOCK_NOSLEEP(); done: - callout_reset_sbt(&frag6_callout, SBT_1MS * 500, SBT_1MS * 10, - frag6_slowtimo, NULL, 0); + callout_reset_sbt(&frag6_callout, SBT_1MS * IP6_CALLOUT_INTERVAL_MS, + SBT_1MS * 10, frag6_slowtimo, NULL, 0); } static void @@ -961,8 +1015,8 @@ { callout_init(&frag6_callout, 1); - callout_reset_sbt(&frag6_callout, SBT_1MS * 500, SBT_1MS * 10, - frag6_slowtimo, NULL, 0); + callout_reset_sbt(&frag6_callout, SBT_1MS * IP6_CALLOUT_INTERVAL_MS, + SBT_1MS * 10, frag6_slowtimo, NULL, 0); } SYSINIT(frag6, SI_SUB_VNET_DONE, SI_ORDER_ANY, frag6_slowtimo_init, NULL); diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -81,7 +81,7 @@ u_int32_t ip6q_ident; u_int8_t ip6q_nxt; u_int8_t ip6q_ecn; - u_int8_t ip6q_ttl; + u_int16_t ip6q_ttl; struct in6_addr ip6q_src, ip6q_dst; TAILQ_ENTRY(ip6q) ip6q_tq; int ip6q_unfrglen; /* len of unfragmentable part */ diff --git a/tests/sys/netinet6/frag6/frag6.subr b/tests/sys/netinet6/frag6/frag6.subr --- a/tests/sys/netinet6/frag6/frag6.subr +++ b/tests/sys/netinet6/frag6/frag6.subr @@ -59,13 +59,17 @@ jname="v6t-${id}-${yl}-${xl}" vnet_mkjail ${jname} ${epair}b + jexec ${jname} sysctl net.inet6.ip6.dad_count=0 jexec ${jname} ifconfig ${epair}b up jexec ${jname} ifconfig ${epair}b inet6 ${ip6b}/64 + # Set max fragment reassembly time to 2 seconds + jexec ${jname} sysctl net.inet6.ip6.fraglifetime_ms=2000 + # Let IPv6 ND do its thing. - #ping6 -q -c 1 ff02::1%${epair}a - #ping6 -q -c 1 ${ip6b} - sleep 3 + while [ `ifconfig ${epair}a inet6 | grep -c tentative` != "0" ]; do + sleep 0.1 + done # We need to try to make sure all expiry happened, otherwise there might # be global fragments queued. (This still does not rule out that there diff --git a/tests/sys/netinet6/frag6/frag6_01.py b/tests/sys/netinet6/frag6/frag6_01.py --- a/tests/sys/netinet6/frag6/frag6_01.py +++ b/tests/sys/netinet6/frag6/frag6_01.py @@ -105,7 +105,7 @@ # We should only need to sleep 0.10 but it seems scapy # takes time for this one. - sleep(75) + sleep(3) sniffer.setEnd() sniffer.join() if not sniffer.foundCorrectPacket: diff --git a/tests/sys/netinet6/frag6/frag6_05.py b/tests/sys/netinet6/frag6/frag6_05.py --- a/tests/sys/netinet6/frag6/frag6_05.py +++ b/tests/sys/netinet6/frag6/frag6_05.py @@ -79,7 +79,7 @@ sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) # Wait for possible expiry to happen. - sleep(75) + sleep(3) sys.exit(0) if __name__ == '__main__': diff --git a/tests/sys/netinet6/frag6/frag6_07.py b/tests/sys/netinet6/frag6/frag6_07.py --- a/tests/sys/netinet6/frag6/frag6_07.py +++ b/tests/sys/netinet6/frag6/frag6_07.py @@ -168,7 +168,7 @@ sys.exit(1) # Wait for expiry from first test run. - sleep(75) + sleep(3) sniffer2.setEnd() sniffer2.join() if not sniffer2.foundCorrectPacket: diff --git a/tests/sys/netinet6/frag6/frag6_08.py b/tests/sys/netinet6/frag6/frag6_08.py --- a/tests/sys/netinet6/frag6/frag6_08.py +++ b/tests/sys/netinet6/frag6/frag6_08.py @@ -142,7 +142,7 @@ sniffer.join() if not sniffer.foundCorrectPacket: sys.exit(1) - sleep(75) + sleep(3) sniffer2.setEnd() sniffer2.join() if not sniffer2.foundCorrectPacket: diff --git a/tests/sys/netinet6/frag6/frag6_09.py b/tests/sys/netinet6/frag6/frag6_09.py --- a/tests/sys/netinet6/frag6/frag6_09.py +++ b/tests/sys/netinet6/frag6/frag6_09.py @@ -99,7 +99,7 @@ sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) # Wait for ICMPv6 error generation on timeout. - sleep(75) + sleep(3) sniffer.setEnd() sniffer.join() if not sniffer.foundCorrectPacket: diff --git a/tests/sys/netinet6/frag6/frag6_10.py b/tests/sys/netinet6/frag6/frag6_10.py --- a/tests/sys/netinet6/frag6/frag6_10.py +++ b/tests/sys/netinet6/frag6/frag6_10.py @@ -75,7 +75,7 @@ # We do not generate ICMPv6 for non-off=0-segments. # Wait for expiry. - sleep(75) + sleep(3) sys.exit(0) diff --git a/tests/sys/netinet6/frag6/frag6_11.py b/tests/sys/netinet6/frag6/frag6_11.py --- a/tests/sys/netinet6/frag6/frag6_11.py +++ b/tests/sys/netinet6/frag6/frag6_11.py @@ -75,7 +75,7 @@ # Wait for expiration to happen. We will not see an ICMPv6 as there # is no frag with offset=0. - sleep(75) + sleep(3) sys.exit(0) diff --git a/tests/sys/netinet6/frag6/frag6_12.py b/tests/sys/netinet6/frag6/frag6_12.py --- a/tests/sys/netinet6/frag6/frag6_12.py +++ b/tests/sys/netinet6/frag6/frag6_12.py @@ -101,7 +101,7 @@ sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) # Wait for ICMPv6 error generation on timeout. - sleep(75) + sleep(3) sniffer.setEnd() sniffer.join() if not sniffer.foundCorrectPacket: diff --git a/tests/sys/netinet6/frag6/frag6_13.py b/tests/sys/netinet6/frag6/frag6_13.py --- a/tests/sys/netinet6/frag6/frag6_13.py +++ b/tests/sys/netinet6/frag6/frag6_13.py @@ -117,7 +117,7 @@ sp.sendp(ip6f02, iface=args.sendif[0], verbose=False) # Wait for expiry. - sleep(75) + sleep(3) sys.exit(0) if __name__ == '__main__': diff --git a/tests/sys/netinet6/frag6/frag6_14.py b/tests/sys/netinet6/frag6/frag6_14.py --- a/tests/sys/netinet6/frag6/frag6_14.py +++ b/tests/sys/netinet6/frag6/frag6_14.py @@ -132,7 +132,7 @@ sp.sendp(ip6f02, iface=args.sendif[0], verbose=False) # Wait for expiry. - sleep(75) + sleep(3) sys.exit(0) if __name__ == '__main__': diff --git a/tests/sys/netinet6/frag6/frag6_20.py b/tests/sys/netinet6/frag6/frag6_20.py --- a/tests/sys/netinet6/frag6/frag6_20.py +++ b/tests/sys/netinet6/frag6/frag6_20.py @@ -127,7 +127,7 @@ sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) sp.sendp(ip6f02, iface=args.sendif[0], verbose=False) - sleep(75) + sleep(3) sniffer.setEnd() sniffer.join() if not sniffer.foundCorrectPacket: