Index | Thread | Search

From:
Jan Klemkow <jan@openbsd.org>
Subject:
ip6_mroute mp-safe per cpu counter
To:
tech@openbsd.org
Date:
Mon, 19 May 2025 04:13:40 +0200

Download raw body.

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