git: e32221a15f08 - main - netinet6: make IPv6 fragment TTL per-VNET configurable.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 01 Jun 2023 12:08:16 UTC
The branch main has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=e32221a15f089282e5dfe18891c5312b26cbe3ba commit e32221a15f089282e5dfe18891c5312b26cbe3ba Author: Alexander V. Chernikov <melifaro@FreeBSD.org> AuthorDate: 2023-06-01 12:04:49 +0000 Commit: Alexander V. Chernikov <melifaro@FreeBSD.org> CommitDate: 2023-06-01 12:04:49 +0000 netinet6: make IPv6 fragment TTL per-VNET configurable. Having it configurable adds more flexibility, especially for the systems with low amount of memory. Additionally, it allows to speedup frag6/ tests execution. Reviewed by: kp, markj, bz Differential Revision: https://reviews.freebsd.org/D35755 MFC after: 2 weeks --- sys/netinet/ip6.h | 2 +- sys/netinet6/frag6.c | 64 +++++++++++++++++++++++++++++++++--- sys/netinet6/ip6_var.h | 2 +- tests/sys/netinet6/frag6/frag6.subr | 10 ++++-- tests/sys/netinet6/frag6/frag6_01.py | 2 +- tests/sys/netinet6/frag6/frag6_05.py | 2 +- tests/sys/netinet6/frag6/frag6_07.py | 2 +- tests/sys/netinet6/frag6/frag6_08.py | 2 +- tests/sys/netinet6/frag6/frag6_09.py | 2 +- tests/sys/netinet6/frag6/frag6_10.py | 2 +- tests/sys/netinet6/frag6/frag6_11.py | 2 +- tests/sys/netinet6/frag6/frag6_12.py | 2 +- tests/sys/netinet6/frag6/frag6_13.py | 2 +- tests/sys/netinet6/frag6/frag6_14.py | 2 +- tests/sys/netinet6/frag6/frag6_20.py | 2 +- 15 files changed, 79 insertions(+), 21 deletions(-) diff --git a/sys/netinet/ip6.h b/sys/netinet/ip6.h index 6617e1ca7d00..30482c6985cf 100644 --- a/sys/netinet/ip6.h +++ b/sys/netinet/ip6.h @@ -254,7 +254,7 @@ struct ip6_frag { */ #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 index d634f869acd5..5acdc1b20981 100644 --- a/sys/netinet6/frag6.c +++ b/sys/netinet6/frag6.c @@ -125,6 +125,10 @@ VNET_DEFINE_STATIC(volatile u_int, frag6_nfragpackets); #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 @@ VNET_DEFINE_STATIC(uint32_t, ip6qb_hashseed); #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 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MAXFRAGBUCKETSIZE, maxfragbucketsize, 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 @@ frag6_input(struct mbuf **mp, int *offp, int proto) /* 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 @@ frag6_slowtimo(void *arg __unused) } 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 @@ frag6_slowtimo_init(void *arg __unused) { 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 index c267503d7151..bc409780feec 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -81,7 +81,7 @@ struct ip6q { 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 index 1ea947c72de5..6f7d0799642c 100644 --- a/tests/sys/netinet6/frag6/frag6.subr +++ b/tests/sys/netinet6/frag6/frag6.subr @@ -59,13 +59,17 @@ frag6_body() 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 index efa99ce65759..db6cabc1a84a 100644 --- a/tests/sys/netinet6/frag6/frag6_01.py +++ b/tests/sys/netinet6/frag6/frag6_01.py @@ -105,7 +105,7 @@ def main(): # 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 index f9bc947d5465..9c98ea1aaf2e 100644 --- a/tests/sys/netinet6/frag6/frag6_05.py +++ b/tests/sys/netinet6/frag6/frag6_05.py @@ -79,7 +79,7 @@ def main(): 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 index 231f49eac2e0..540c5012e524 100644 --- a/tests/sys/netinet6/frag6/frag6_07.py +++ b/tests/sys/netinet6/frag6/frag6_07.py @@ -168,7 +168,7 @@ def main(): 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 index 25f57f702e71..74d7495f43cb 100644 --- a/tests/sys/netinet6/frag6/frag6_08.py +++ b/tests/sys/netinet6/frag6/frag6_08.py @@ -142,7 +142,7 @@ def main(): 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 index 63ec646e1175..b5c519040292 100644 --- a/tests/sys/netinet6/frag6/frag6_09.py +++ b/tests/sys/netinet6/frag6/frag6_09.py @@ -99,7 +99,7 @@ def main(): 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 index fcd331190c02..191e3fc3e075 100644 --- a/tests/sys/netinet6/frag6/frag6_10.py +++ b/tests/sys/netinet6/frag6/frag6_10.py @@ -75,7 +75,7 @@ def main(): # 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 index 6b9643337597..be50a766ab1a 100644 --- a/tests/sys/netinet6/frag6/frag6_11.py +++ b/tests/sys/netinet6/frag6/frag6_11.py @@ -75,7 +75,7 @@ def main(): # 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 index a683782f2b69..d82610a0f75b 100644 --- a/tests/sys/netinet6/frag6/frag6_12.py +++ b/tests/sys/netinet6/frag6/frag6_12.py @@ -101,7 +101,7 @@ def main(): 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 index e377a4272fa1..a8717c2c795c 100644 --- a/tests/sys/netinet6/frag6/frag6_13.py +++ b/tests/sys/netinet6/frag6/frag6_13.py @@ -117,7 +117,7 @@ def main(): 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 index b53a65e67529..49fae50f4bae 100644 --- a/tests/sys/netinet6/frag6/frag6_14.py +++ b/tests/sys/netinet6/frag6/frag6_14.py @@ -132,7 +132,7 @@ def main(): 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 index 6dd4c2379357..4a68b242a23e 100755 --- a/tests/sys/netinet6/frag6/frag6_20.py +++ b/tests/sys/netinet6/frag6/frag6_20.py @@ -127,7 +127,7 @@ def main(): 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: