Index | Thread | Search

From:
Alexander Bluhm <bluhm@openbsd.org>
Subject:
Re: Unlock ICMPV6CTL_ND6_MAXNUDHINT case of icmp6_sysctl()
To:
Vitaliy Makkoveev <mvs@openbsd.org>
Cc:
tech@openbsd.org
Date:
Wed, 13 Aug 2025 18:44:48 +0200

Download raw body.

Thread
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 *,