From: Jan Klemkow Subject: ip6_mroute mp-safe per cpu counter To: tech@openbsd.org Date: Mon, 19 May 2025 04:13:40 +0200 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? bye, Jan 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 */