Index | Thread | Search

From:
Alexander Bluhm <bluhm@openbsd.org>
Subject:
Re: ip6_mroute mp-safe per cpu counter
To:
Jan Klemkow <jan@openbsd.org>
Cc:
tech@openbsd.org
Date:
Mon, 19 May 2025 13:12:54 +0900

Download raw body.

Thread
On Mon, May 19, 2025 at 04:13:40AM +0200, Jan Klemkow wrote:
> Hi,
> 
> This diff uses per CPU counter infrastructure for IPv6 multicast
> counter.
> 
> This netstat diff is needed to view the counter:
> https://marc.info/?l=openbsd-tech&m=174761223518749&w=2
> 
> ok?

Don't forget to remove declaration
#ifdef MROUTING
        extern struct mrt6stat mrt6stat;
#endif
from ip6_sysctl().  This prevented compiling with gcc when you did
the same diff for IPv4.

OK bluhm@

> Index: netinet6/ip6_input.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet6/ip6_input.c,v
> diff -u -p -r1.268 ip6_input.c
> --- netinet6/ip6_input.c	2 Mar 2025 21:28:32 -0000	1.268
> +++ netinet6/ip6_input.c	19 May 2025 02:02:17 -0000
> @@ -161,8 +161,7 @@ ip6_init(void)
>  
>  	ip6counters = counters_alloc(ip6s_ncounters);
>  #ifdef MROUTING
> -	rt_timer_queue_init(&ip6_mrouterq, MCAST_EXPIRE_TIMEOUT,
> -	    &mf6c_expire_route);
> +	mrt6_init();
>  #endif
>  }
>  
> @@ -1536,13 +1535,7 @@ ip6_sysctl(int *name, u_int namelen, voi
>  		return (ip6_sysctl_ip6stat(oldp, oldlenp, newp));
>  #ifdef MROUTING
>  	case IPV6CTL_MRTSTATS:
> -		if (newp != NULL)
> -			return (EPERM);
> -		NET_LOCK();
> -		error = sysctl_struct(oldp, oldlenp, newp, newlen,
> -		    &mrt6stat, sizeof(mrt6stat));
> -		NET_UNLOCK();
> -		return (error);
> +		return mrt6_sysctl_mrt6stat(oldp, oldlenp, newp);
>  	case IPV6CTL_MRTMIF:
>  		if (newp)
>  			return (EPERM);
> Index: netinet6/ip6_mroute.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet6/ip6_mroute.c,v
> diff -u -p -r1.145 ip6_mroute.c
> --- netinet6/ip6_mroute.c	18 May 2025 23:27:29 -0000	1.145
> +++ netinet6/ip6_mroute.c	19 May 2025 02:02:17 -0000
> @@ -133,7 +133,7 @@ struct socket  *ip6_mrouter[RT_TABLEID_M
>  struct rttimer_queue ip6_mrouterq;
>  int		ip6_mrouter_ver = 0;
>  int		ip6_mrtproto;    /* for netstat only */
> -struct mrt6stat	mrt6stat;
> +struct cpumem *mrt6counters;
>  
>  int get_sg6_cnt(struct sioc_sg_req6 *, unsigned int);
>  int get_mif6_cnt(struct sioc_mif_req6 *, unsigned int);
> @@ -142,6 +142,7 @@ int add_m6if(struct socket *, struct mif
>  int del_m6if(struct socket *, mifi_t *);
>  int add_m6fc(struct socket *, struct mf6cctl *);
>  int del_m6fc(struct socket *, struct mf6cctl *);
> +void mf6c_expire_route(struct rtentry *, u_int);
>  struct ifnet *mrt6_iflookupbymif(mifi_t, unsigned int);
>  struct rtentry *mf6c_find(struct ifnet *, struct in6_addr *, unsigned int);
>  struct rtentry *mrt6_mcast_add(struct ifnet *, struct sockaddr *);
> @@ -203,6 +204,15 @@ ip6_mrouter_get(int cmd, struct socket *
>  	}
>  }
>  
> +void
> +mrt6_init(void)
> +{
> +	mrt6counters = counters_alloc(mrt6s_ncounters);
> +
> +	rt_timer_queue_init(&ip6_mrouterq, MCAST_EXPIRE_TIMEOUT,
> +	    &mf6c_expire_route);
> +}
> +
>  /*
>   * Handle ioctl commands to obtain information from the cache
>   */
> @@ -410,6 +420,38 @@ mrt6_rtwalk_mf6csysctl(struct rtentry *r
>  }
>  
>  int
> +mrt6_sysctl_mrt6stat(void *oldp, size_t *oldlenp, void *newp)
> +{
> +	uint64_t counters[mrt6s_ncounters];
> +	struct mrt6stat mrt6stat;
> +	int i = 0;
> +
> +#define ASSIGN(field)  do { mrt6stat.field = counters[i++]; } while (0)
> +
> +	memset(&mrt6stat, 0, sizeof mrt6stat);
> +	counters_read(mrt6counters, counters, nitems(counters), NULL);
> +
> +	ASSIGN(mrt6s_mfc_lookups);
> +	ASSIGN(mrt6s_mfc_misses);
> +	ASSIGN(mrt6s_upcalls);
> +	ASSIGN(mrt6s_no_route);
> +	ASSIGN(mrt6s_bad_tunnel);
> +	ASSIGN(mrt6s_cant_tunnel);
> +	ASSIGN(mrt6s_wrong_if);
> +	ASSIGN(mrt6s_upq_ovflw);
> +	ASSIGN(mrt6s_cache_cleanups);
> +	ASSIGN(mrt6s_drop_sel);
> +	ASSIGN(mrt6s_q_overflow);
> +	ASSIGN(mrt6s_pkt2large);
> +	ASSIGN(mrt6s_upq_sockfull);
> +
> +#undef ASSIGN
> +
> +	return (sysctl_rdstruct(oldp, oldlenp, newp,
> +	    &mrt6stat, sizeof(mrt6stat)));
> +}
> +
> +int
>  mrt6_sysctl_mfc(void *oldp, size_t *oldlenp)
>  {
>  	unsigned int		 rtableid;
> @@ -906,7 +948,7 @@ ip6_mforward(struct ip6_hdr *ip6, struct
>  		 * send message to routing daemon
>  		 */
>  
> -		mrt6stat.mrt6s_no_route++;
> +		mrt6stat_inc(mrt6s_no_route);
>  
>  		{
>  			struct mrt6msg *im;
> @@ -947,11 +989,11 @@ ip6_mforward(struct ip6_hdr *ip6, struct
>  			    &sin6) < 0) {
>  				log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
>  				    "socket queue full\n");
> -				mrt6stat.mrt6s_upq_sockfull++;
> +				mrt6stat_inc(mrt6s_upq_sockfull);
>  				return ENOBUFS;
>  			}
>  
> -			mrt6stat.mrt6s_upcalls++;
> +			mrt6stat_inc(mrt6s_upcalls);
>  
>  			mf6c_add(NULL, &ip6->ip6_src, &ip6->ip6_dst,
>  			    mifp->m6_mifi, rtableid, M_NOWAIT);
> @@ -1012,7 +1054,7 @@ ip6_mdq(struct mbuf *m, struct ifnet *if
>  	 */
>  	if (mifp->m6_mifi != mf6c->mf6c_parent) {
>  		/* came in the wrong interface */
> -		mrt6stat.mrt6s_wrong_if++;
> +		mrt6stat_inc(mrt6s_wrong_if);
>  		mf6c->mf6c_wrong_if++;
>  		rtfree(rt);
>  		return 0;
> Index: netinet6/ip6_mroute.h
> ===================================================================
> RCS file: /cvs/src/sys/netinet6/ip6_mroute.h,v
> diff -u -p -r1.24 ip6_mroute.h
> --- netinet6/ip6_mroute.h	1 Jan 2025 13:44:22 -0000	1.24
> +++ netinet6/ip6_mroute.h	19 May 2025 02:02:17 -0000
> @@ -191,12 +191,35 @@ struct sioc_mif_req6 {
>  };
>  
>  #if defined(_KERNEL)
> +
> +enum mrt6stat_counters {
> +	mrt6s_mfc_lookups,
> +	mrt6s_mfc_misses,
> +	mrt6s_upcalls,
> +	mrt6s_no_route,
> +	mrt6s_bad_tunnel,
> +	mrt6s_cant_tunnel,
> +	mrt6s_wrong_if,
> +	mrt6s_upq_ovflw,
> +	mrt6s_cache_cleanups,
> +	mrt6s_drop_sel,
> +	mrt6s_q_overflow,
> +	mrt6s_pkt2large,
> +	mrt6s_upq_sockfull,
> +	mrt6s_ncounters
> +};
> +
> +extern struct cpumem *mrt6counters;
> +
> +static inline void
> +mrt6stat_inc(enum mrt6stat_counters c)
> +{
> +	counters_inc(mrt6counters, c);
> +}
> +
>  /* How frequent should we look for expired entries (in seconds). */
>  #define	MCAST_EXPIRE_TIMEOUT	30
>  
> -extern struct rttimer_queue ip6_mrouterq;
> -void	mf6c_expire_route(struct rtentry *, u_int);
> -
>  /*
>   * The kernel's multicast-interface structure.
>   */
> @@ -232,8 +255,10 @@ int	ip6_mrouter_set(int, struct socket *
>  int	ip6_mrouter_get(int, struct socket *, struct mbuf *);
>  int	ip6_mrouter_done(struct socket *);
>  void	ip6_mrouter_detach(struct ifnet *);
> +void	mrt6_init(void);
>  int	mrt6_ioctl(struct socket *, u_long, caddr_t);
>  int	mrt6_sysctl_mif(void *, size_t *);
> +int	mrt6_sysctl_mrt6stat(void *, size_t *, void *);
>  int	mrt6_sysctl_mfc(void *, size_t *);
>  #endif /* _KERNEL */
>