From: Alexander Bluhm Subject: Re: ip6_mroute mp-safe per cpu counter To: Jan Klemkow Cc: tech@openbsd.org Date: Mon, 19 May 2025 13:12:54 +0900 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 */ >