From: Alexander Bluhm Subject: Re: Unlock ICMPV6CTL_ND6_MAXNUDHINT case of icmp6_sysctl() To: Vitaliy Makkoveev Cc: tech@openbsd.org Date: Wed, 13 Aug 2025 18:44:48 +0200 On Wed, Aug 13, 2025 at 06:46:03PM +0300, Vitaliy Makkoveev wrote: > Load value of `nd6_maxnudhint' to local variable and pass it to > nd6_nud_hint(). It called in loop in tcp_flush_queue(). Also it > called multiple times in tcp_input_solocked(). OK bluhm@ > Index: sys/netinet/tcp_input.c > =================================================================== > RCS file: /cvs/src/sys/netinet/tcp_input.c,v > diff -u -p -r1.459 tcp_input.c > --- sys/netinet/tcp_input.c 11 Aug 2025 15:34:30 -0000 1.459 > +++ sys/netinet/tcp_input.c 13 Aug 2025 15:42:28 -0000 > @@ -129,16 +129,16 @@ struct timeval tcp_ackdrop_ppslim_last; > * Neighbor Discovery, Neighbor Unreachability Detection Upper layer hint. > */ > #ifdef INET6 > -#define ND6_HINT(tp) \ > +#define ND6_HINT(tp, hint) \ > do { \ > if (tp && tp->t_inpcb && \ > ISSET(tp->t_inpcb->inp_flags, INP_IPV6) && \ > rtisvalid(tp->t_inpcb->inp_route.ro_rt)) { \ > - nd6_nud_hint(tp->t_inpcb->inp_route.ro_rt); \ > + nd6_nud_hint(tp->t_inpcb->inp_route.ro_rt, hint); \ > } \ > } while (0) > #else > -#define ND6_HINT(tp) > +#define ND6_HINT(tp, hint) > #endif > > #ifdef TCP_ECN > @@ -311,6 +311,9 @@ tcp_flush_queue(struct tcpcb *tp) > { > struct socket *so = tp->t_inpcb->inp_socket; > struct tcpqent *q, *nq; > +#ifdef INET6 > + int nd6_maxnudhint_local = atomic_load_int(&nd6_maxnudhint); > +#endif > int flags; > > /* > @@ -330,7 +333,7 @@ tcp_flush_queue(struct tcpcb *tp) > > nq = TAILQ_NEXT(q, tcpqe_q); > TAILQ_REMOVE(&tp->t_segq, q, tcpqe_q); > - ND6_HINT(tp); > + ND6_HINT(tp, nd6_maxnudhint_local); > if (so->so_rcv.sb_state & SS_CANTRCVMORE) > m_freem(q->tcpqe_m); > else { > @@ -424,6 +427,9 @@ tcp_input_solocked(struct mbuf **mp, int > struct ip6_hdr *ip6 = NULL; > #endif /* INET6 */ > int do_ecn = 0; > +#ifdef INET6 > + int nd6_maxnudhint_local = atomic_load_int(&nd6_maxnudhint); > +#endif > #ifdef TCP_ECN > u_char iptos; > #endif > @@ -1021,7 +1027,7 @@ findpcb: > tcpstat_pkt(tcps_rcvackpack, tcps_rcvackbyte, > acked); > tp->t_rcvacktime = now; > - ND6_HINT(tp); > + ND6_HINT(tp, nd6_maxnudhint_local); > > mtx_enter(&so->so_snd.sb_mtx); > sbdrop(&so->so_snd, acked); > @@ -1106,7 +1112,7 @@ findpcb: > /* Packet has most recent segment, no urgent exists. */ > tp->rcv_up = tp->rcv_nxt; > tcpstat_pkt(tcps_rcvpack, tcps_rcvbyte, tlen); > - ND6_HINT(tp); > + ND6_HINT(tp, nd6_maxnudhint_local); > > TCP_SETUP_ACK(tp, tiflags, m); > /* > @@ -1811,7 +1817,7 @@ trimthenstep6: > tp->snd_cwnd = ulmin(cw + incr, > TCP_MAXWIN << tp->snd_scale); > } > - ND6_HINT(tp); > + ND6_HINT(tp, nd6_maxnudhint_local); > if (acked > so->so_snd.sb_cc) { > if (tp->snd_wnd > so->so_snd.sb_cc) > tp->snd_wnd -= so->so_snd.sb_cc; > @@ -2041,7 +2047,7 @@ dodata: /* XXX */ > tp->rcv_nxt += tlen; > tiflags = th->th_flags & TH_FIN; > tcpstat_pkt(tcps_rcvpack, tcps_rcvbyte, tlen); > - ND6_HINT(tp); > + ND6_HINT(tp, nd6_maxnudhint_local); > if (so->so_rcv.sb_state & SS_CANTRCVMORE) > m_freem(m); > else { > Index: sys/netinet6/icmp6.c > =================================================================== > RCS file: /cvs/src/sys/netinet6/icmp6.c,v > diff -u -p -r1.277 icmp6.c > --- sys/netinet6/icmp6.c 13 Aug 2025 11:30:31 -0000 1.277 > +++ sys/netinet6/icmp6.c 13 Aug 2025 15:42:28 -0000 > @@ -1781,12 +1781,12 @@ const struct sysctl_bounded_args icmpv6c > { ICMPV6CTL_ND6_UMAXTRIES, &nd6_umaxtries, 0, INT_MAX }, > { ICMPV6CTL_ND6_MMAXTRIES, &nd6_mmaxtries, 0, INT_MAX }, > { ICMPV6CTL_MTUDISC_HIWAT, &icmp6_mtudisc_hiwat, 0, INT_MAX }, > + { ICMPV6CTL_ND6_MAXNUDHINT, &nd6_maxnudhint, 0, INT_MAX }, > { ICMPV6CTL_MTUDISC_LOWAT, &icmp6_mtudisc_lowat, 0, INT_MAX }, > }; > > const struct sysctl_bounded_args icmpv6ctl_vars[] = { > { ICMPV6CTL_ERRPPSLIMIT, &icmp6errppslim, -1, 1000 }, > - { ICMPV6CTL_ND6_MAXNUDHINT, &nd6_maxnudhint, 0, INT_MAX }, > }; > > int > @@ -1851,6 +1851,7 @@ icmp6_sysctl(int *name, u_int namelen, v > case ICMPV6CTL_ND6_DELAY: > case ICMPV6CTL_ND6_UMAXTRIES: > case ICMPV6CTL_ND6_MMAXTRIES: > + case ICMPV6CTL_ND6_MAXNUDHINT: > case ICMPV6CTL_MTUDISC_HIWAT: > case ICMPV6CTL_MTUDISC_LOWAT: > error = sysctl_bounded_arr(icmpv6ctl_vars_unlocked, > Index: sys/netinet6/nd6.c > =================================================================== > RCS file: /cvs/src/sys/netinet6/nd6.c,v > diff -u -p -r1.299 nd6.c > --- sys/netinet6/nd6.c 4 Aug 2025 21:50:59 -0000 1.299 > +++ sys/netinet6/nd6.c 13 Aug 2025 15:42:28 -0000 > @@ -83,7 +83,7 @@ int nd6_gctimer = (60 * 60 * 24); /* 1 d > /* preventing too many loops in ND option parsing */ > int nd6_maxndopt = 10; /* max # of ND options allowed */ > > -int nd6_maxnudhint = 0; /* max # of subsequent upper layer hints */ > +int nd6_maxnudhint = 0; /* [a] max # of subsequent upper layer hints */ > > /* llinfo_nd6 live time, rt_llinfo and RTF_LLINFO are protected by nd6_mtx */ > struct mutex nd6_mtx = MUTEX_INITIALIZER(IPL_SOFTNET); > @@ -674,7 +674,7 @@ nd6_free(struct rtentry *rt, struct ifne > * XXX cost-effective methods? > */ > void > -nd6_nud_hint(struct rtentry *rt) > +nd6_nud_hint(struct rtentry *rt, int maxnudhint) > { > struct llinfo_nd6 *ln; > struct ifnet *ifp; > @@ -706,7 +706,7 @@ nd6_nud_hint(struct rtentry *rt) > * it is possible we have false information. > */ > ln->ln_byhint++; > - if (ln->ln_byhint > nd6_maxnudhint) > + if (ln->ln_byhint > maxnudhint) > goto out; > > ln->ln_state = ND6_LLINFO_REACHABLE; > Index: sys/netinet6/nd6.h > =================================================================== > RCS file: /cvs/src/sys/netinet6/nd6.h,v > diff -u -p -r1.102 nd6.h > --- sys/netinet6/nd6.h 19 May 2025 06:50:00 -0000 1.102 > +++ sys/netinet6/nd6.h 13 Aug 2025 15:42:28 -0000 > @@ -125,7 +125,7 @@ struct rtentry *nd6_lookup(const struct > u_int); > void nd6_llinfo_settimer(const struct llinfo_nd6 *, unsigned int); > void nd6_purge(struct ifnet *); > -void nd6_nud_hint(struct rtentry *); > +void nd6_nud_hint(struct rtentry *, int); > void nd6_rtrequest(struct ifnet *, int, struct rtentry *); > int nd6_ioctl(u_long, caddr_t, struct ifnet *); > void nd6_cache_lladdr(struct ifnet *, const struct in6_addr *, char *,