From: Alexander Bluhm Subject: Re: mp-safe multicast counter To: Jan Klemkow Cc: tech@openbsd.org Date: Fri, 9 May 2025 16:09:17 +0200 On Fri, May 09, 2025 at 11:55:30AM +0200, Jan Klemkow wrote: > Hi, > > This diff uses the per CPU counters infrastructure for mrtstats. While > here, I also moved the ip_mrouterq() call in a new mrt_init() function. > > ok? OK bluhm@ > Index: netinet/ip_input.c > =================================================================== > RCS file: /cvs/src/sys/netinet/ip_input.c,v > diff -u -p -r1.405 ip_input.c > --- netinet/ip_input.c 12 Mar 2025 23:27:17 -0000 1.405 > +++ netinet/ip_input.c 8 May 2025 20:53:57 -0000 > @@ -235,8 +235,7 @@ ip_init(void) > ipsec_init(); > #endif > #ifdef MROUTING > - rt_timer_queue_init(&ip_mrouterq, MCAST_EXPIRE_FREQUENCY, > - &mfc_expire_route); > + mrt_init(); > #endif > } > > @@ -1790,8 +1789,7 @@ ip_sysctl(int *name, u_int namelen, void > return (ip_sysctl_ipstat(oldp, oldlenp, newp)); > #ifdef MROUTING > case IPCTL_MRTSTATS: > - return (sysctl_rdstruct(oldp, oldlenp, newp, > - &mrtstat, sizeof(mrtstat))); > + return (mrt_sysctl_mrtstat(oldp, oldlenp, newp)); > case IPCTL_MRTMFC: > if (newp) > return (EPERM); > Index: netinet/ip_mroute.c > =================================================================== > RCS file: /cvs/src/sys/netinet/ip_mroute.c,v > diff -u -p -r1.144 ip_mroute.c > --- netinet/ip_mroute.c 11 Mar 2025 15:31:03 -0000 1.144 > +++ netinet/ip_mroute.c 8 May 2025 21:04:05 -0000 > @@ -64,6 +64,7 @@ > #include > #include > #include > +#include > > #include > #include > @@ -100,7 +101,7 @@ struct rttimer_queue ip_mrouterq; > uint64_t mrt_count[RT_TABLEID_MAX + 1]; > int ip_mrtproto = IGMP_DVMRP; /* for netstat only */ > > -struct mrtstat mrtstat; > +struct cpumem *mrtcounters; > > struct rtentry *mfc_find(struct ifnet *, struct in_addr *, > struct in_addr *, unsigned int); > @@ -113,6 +114,7 @@ int get_version(struct mbuf *); > int add_vif(struct socket *, struct mbuf *); > int del_vif(struct socket *, struct mbuf *); > void update_mfc_params(struct mfcctl2 *, int, unsigned int); > +void mfc_expire_route(struct rtentry *, u_int); > int mfc_add(struct mfcctl2 *, struct in_addr *, struct in_addr *, > int, unsigned int, int); > int add_mfc(struct socket *, struct mbuf *); > @@ -140,8 +142,8 @@ static u_int32_t mrt_api_config = 0; > /* > * Find a route for a given origin IP address and Multicast group address > * Type of service parameter to be added in the future!!! > - * Statistics are updated by the caller if needed > - * (mrtstat.mrts_mfc_lookups and mrtstat.mrts_mfc_misses) > + * Statistics are updated by the caller if needed (mrts_mfc_lookups and > + * mrts_mfc_misses) > */ > struct rtentry * > mfc_find(struct ifnet *ifp, struct in_addr *origin, struct in_addr *group, > @@ -249,6 +251,15 @@ ip_mrouter_get(struct socket *so, int op > return (error); > } > > +void > +mrt_init(void) > +{ > + mrtcounters = counters_alloc(mrts_ncounters); > + > + rt_timer_queue_init(&ip_mrouterq, MCAST_EXPIRE_FREQUENCY, > + &mfc_expire_route); > +} > + > /* > * Handle ioctl commands to obtain information from the cache > */ > @@ -463,6 +474,38 @@ mrt_rtwalk_mfcsysctl(struct rtentry *rt, > } > > int > +mrt_sysctl_mrtstat(void *oldp, size_t *oldlenp, void *newp) > +{ > + uint64_t counters[mrts_ncounters]; > + struct mrtstat mrtstat; > + int i = 0; > + > +#define ASSIGN(field) do { mrtstat.field = counters[i++]; } while (0) > + > + memset(&mrtstat, 0, sizeof mrtstat); > + counters_read(mrtcounters, counters, nitems(counters), NULL); > + > + ASSIGN(mrts_mfc_lookups); > + ASSIGN(mrts_mfc_misses); > + ASSIGN(mrts_upcalls); > + ASSIGN(mrts_no_route); > + ASSIGN(mrts_bad_tunnel); > + ASSIGN(mrts_cant_tunnel); > + ASSIGN(mrts_wrong_if); > + ASSIGN(mrts_upq_ovflw); > + ASSIGN(mrts_cache_cleanups); > + ASSIGN(mrts_drop_sel); > + ASSIGN(mrts_q_overflow); > + ASSIGN(mrts_pkt2large); > + ASSIGN(mrts_upq_sockfull); > + > +#undef ASSIGN > + > + return (sysctl_rdstruct(oldp, oldlenp, newp, > + &mrtstat, sizeof(mrtstat))); > +} > + > +int > mrt_sysctl_mfc(void *oldp, size_t *oldlenp) > { > unsigned int rtableid; > @@ -1116,7 +1159,7 @@ ip_mforward(struct mbuf *m, struct ifnet > /* > * Determine forwarding vifs from the forwarding cache table > */ > - ++mrtstat.mrts_mfc_lookups; > + mrtstat_inc(mrts_mfc_lookups); > rt = mfc_find(NULL, &ip->ip_src, &ip->ip_dst, rtableid); > > /* Entry exists, so forward if necessary */ > @@ -1129,8 +1172,8 @@ ip_mforward(struct mbuf *m, struct ifnet > */ > int hlen = ip->ip_hl << 2; > > - ++mrtstat.mrts_mfc_misses; > - mrtstat.mrts_no_route++; > + mrtstat_inc(mrts_mfc_misses); > + mrtstat_inc(mrts_no_route); > > { > struct igmpmsg *im; > @@ -1161,13 +1204,13 @@ ip_mforward(struct mbuf *m, struct ifnet > im->im_mbz = 0; > im->im_vif = v->v_id; > > - mrtstat.mrts_upcalls++; > + mrtstat_inc(mrts_upcalls); > > sin.sin_addr = ip->ip_src; > if (socket_send(ip_mrouter[rtableid], mm, &sin) < 0) { > log(LOG_WARNING, "ip_mforward: ip_mrouter " > "socket queue full\n"); > - ++mrtstat.mrts_upq_sockfull; > + mrtstat_inc(mrts_upq_sockfull); > return (ENOBUFS); > } > > @@ -1203,7 +1246,7 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp > */ > if (mfc->mfc_parent != v->v_id) { > /* came in the wrong interface */ > - ++mrtstat.mrts_wrong_if; > + mrtstat_inc(mrts_wrong_if); > mfc->mfc_wrong_if++; > rtfree(rt); > return (0); > Index: netinet/ip_mroute.h > =================================================================== > RCS file: /cvs/src/sys/netinet/ip_mroute.h,v > diff -u -p -r1.33 ip_mroute.h > --- netinet/ip_mroute.h 1 Jan 2025 13:44:22 -0000 1.33 > +++ netinet/ip_mroute.h 9 May 2025 07:34:39 -0000 > @@ -167,15 +167,36 @@ struct mrtstat { > u_long mrts_upq_sockfull; /* upcalls dropped - socket full */ > }; > > - > #ifdef _KERNEL > > +enum mrtstat_counters { > + mrts_mfc_lookups, > + mrts_mfc_misses, > + mrts_upcalls, > + mrts_no_route, > + mrts_bad_tunnel, > + mrts_cant_tunnel, > + mrts_wrong_if, > + mrts_upq_ovflw, > + mrts_cache_cleanups, > + mrts_drop_sel, > + mrts_q_overflow, > + mrts_pkt2large, > + mrts_upq_sockfull, > + mrts_ncounters > +}; > + > +extern struct cpumem *mrtcounters; > + > +static inline void > +mrtstat_inc(enum mrtstat_counters c) > +{ > + counters_inc(mrtcounters, c); > +} > + > /* How frequent should we look for expired entries (in seconds). */ > #define MCAST_EXPIRE_FREQUENCY 30 > > -extern struct rttimer_queue ip_mrouterq; > -void mfc_expire_route(struct rtentry *, u_int); > - > extern int ip_mrtproto; > > /* > @@ -228,8 +249,10 @@ struct igmpmsg { > > int ip_mrouter_set(struct socket *, int, struct mbuf *); > int ip_mrouter_get(struct socket *, int, struct mbuf *); > +void mrt_init(void); > int mrt_ioctl(struct socket *, u_long, caddr_t); > int mrt_sysctl_vif(void *, size_t *); > +int mrt_sysctl_mrtstat(void *, size_t *, void *); > int mrt_sysctl_mfc(void *, size_t *); > int ip_mrouter_done(struct socket *); > void vif_delete(struct ifnet *);