multicast route counter

Alexander Bluhm <[email protected]>
Newsgroups gmane.os.openbsd.tech
Message-ID <[email protected]>
Hi,

I want to use per CPU counter for the multicast routes.  Note that
I have to call counters_alloc() with M_NOWAIT, so I extended the
API.

ok?

bluhm

Index: kern/subr_percpu.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/subr_percpu.c,v
diff -u -p -r1.11 subr_percpu.c
--- kern/subr_percpu.c	16 Sep 2023 09:33:27 -0000	1.11
+++ kern/subr_percpu.c	26 Jun 2026 11:54:40 -0000
@@ -59,17 +59,17 @@ cpumem_put(struct pool *pp, struct cpume
 }
 
 struct cpumem *
-cpumem_malloc(size_t sz, int type)
+cpumem_malloc_wait(size_t sz, int type, int wait)
 {
 	struct cpumem *cm;
 	unsigned int cpu;
 
 	sz = roundup(sz, CACHELINESIZE);
 
-	cm = pool_get(&cpumem_pl, PR_WAITOK);
+	cm = pool_get(&cpumem_pl, wait == M_WAITOK ? PR_WAITOK : PR_NOWAIT);
 
 	for (cpu = 0; cpu < ncpusfound; cpu++)
-		cm[cpu].mem = malloc(sz, type, M_WAITOK | M_ZERO);
+		cm[cpu].mem = malloc(sz, type, wait | M_ZERO);
 
 	return (cm);
 }
@@ -124,7 +124,7 @@ cpumem_next(struct cpumem_iter *i, struc
 }
 
 struct cpumem *
-counters_alloc(unsigned int n)
+counters_alloc_wait(unsigned int n, int wait)
 {
 	struct cpumem *cm;
 	struct cpumem_iter cmi;
@@ -134,7 +134,7 @@ counters_alloc(unsigned int n)
 	KASSERT(n > 0);
 
 	n++; /* add space for a generation number */
-	cm = cpumem_malloc(n * sizeof(uint64_t), M_COUNTERS);
+	cm = cpumem_malloc_wait(n * sizeof(uint64_t), M_COUNTERS, wait);
 
 	CPUMEM_FOREACH(counters, &cmi, cm) {
 		for (i = 0; i < n; i++)
@@ -257,9 +257,9 @@ cpumem_put(struct pool *pp, struct cpume
 }
 
 struct cpumem *
-cpumem_malloc(size_t sz, int type)
+cpumem_malloc_wait(size_t sz, int type, int wait)
 {
-	return (malloc(sz, type, M_WAITOK | M_ZERO));
+	return (malloc(sz, type, wait | M_ZERO));
 }
 
 struct cpumem *
@@ -287,11 +287,11 @@ cpumem_next(struct cpumem_iter *i, struc
 }
 
 struct cpumem *
-counters_alloc(unsigned int n)
+counters_alloc_wait(unsigned int n, int wait)
 {
 	KASSERT(n > 0);
 
-	return (cpumem_malloc(n * sizeof(uint64_t), M_COUNTERS));
+	return (cpumem_malloc_wait(n * sizeof(uint64_t), M_COUNTERS, wait));
 }
 
 struct cpumem *
@@ -339,3 +339,15 @@ counters_zero(struct cpumem *cm, unsigne
 }
 
 #endif /* MULTIPROCESSOR */
+
+struct cpumem *
+cpumem_malloc(size_t sz, int type)
+{
+	return (cpumem_malloc_wait(sz, type, M_WAITOK));
+}
+
+struct cpumem *
+counters_alloc(unsigned int n)
+{
+	return (counters_alloc_wait(n, M_WAITOK));
+}
Index: netinet/ip_mroute.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_mroute.c,v
diff -u -p -r1.153 ip_mroute.c
--- netinet/ip_mroute.c	24 Jun 2026 12:33:49 -0000	1.153
+++ netinet/ip_mroute.c	26 Jun 2026 11:54:40 -0000
@@ -318,6 +318,8 @@ get_sg_cnt(unsigned int rtableid, struct
 
 	req->pktcnt = req->bytecnt = req->wrong_if = 0;
 	do {
+		uint64_t count[mfc_ncounters], scratch[mfc_ncounters];
+
 		/* Don't consider non multicast routes. */
 		if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
 		    (RTF_HOST | RTF_MULTICAST))
@@ -327,9 +329,10 @@ get_sg_cnt(unsigned int rtableid, struct
 		if (mfc == NULL)
 			continue;
 
-		req->pktcnt += mfc->mfc_pkt_cnt;
-		req->bytecnt += mfc->mfc_byte_cnt;
-		req->wrong_if += mfc->mfc_wrong_if;
+		counters_read(mfc->mfc_counter, count, mfc_ncounters, scratch);
+		req->pktcnt += count[mfc_packets];
+		req->bytecnt += count[mfc_bytes];
+		req->wrong_if += count[mfc_wrong_if];
 	} while ((rt = rtable_iterate(rt)) != NULL);
 
 	return (0);
@@ -474,6 +477,8 @@ mrt_rtwalk_mfcsysctl(struct rtentry *rt,
 	    (uint8_t *)(minfo + 1) <=
 	    (uint8_t *)msa->msa_minfos + msa->msa_len;
 	    minfo++) {
+		uint64_t count[mfc_ncounters], scratch[mfc_ncounters];
+
 		/* Find a new entry or update old entry. */
 		if (minfo->mfc_origin.s_addr !=
 		    satosin(rt->rt_gateway)->sin_addr.s_addr ||
@@ -489,8 +494,9 @@ mrt_rtwalk_mfcsysctl(struct rtentry *rt,
 		minfo->mfc_origin = satosin(rt->rt_gateway)->sin_addr;
 		minfo->mfc_mcastgrp = satosin(rt_key(rt))->sin_addr;
 		minfo->mfc_parent = mfc->mfc_parent;
-		minfo->mfc_pkt_cnt += mfc->mfc_pkt_cnt;
-		minfo->mfc_byte_cnt += mfc->mfc_byte_cnt;
+		counters_read(mfc->mfc_counter, count, mfc_ncounters, scratch);
+		minfo->mfc_pkt_cnt += count[mfc_packets];
+		minfo->mfc_byte_cnt += count[mfc_bytes];
 		minfo->mfc_ttls[v->v_id] = mfc->mfc_ttl;
 		break;
 	}
@@ -895,11 +901,13 @@ mfc_add_route(struct ifnet *ifp, struct 
 
 	mfc = malloc(sizeof(*mfc), M_MRTABLE, wait | M_ZERO);
 	if (mfc == NULL) {
-		DPRINTF("origin %#08X group %#08X parent %d (%s) "
-		    "malloc failed",
-		    satosin(origin)->sin_addr.s_addr,
-		    satosin(group)->sin_addr.s_addr,
-		    mfccp->mfcc_parent, ifp->if_xname);
+		mrt_mcast_del(rt, rtableid);
+		rtfree(rt);
+		return (ENOMEM);
+	}
+	mfc->mfc_counter = counters_alloc_wait(mfc_ncounters, wait);
+	if (mfc->mfc_counter == NULL) {
+		free(mfc, M_MRTABLE, sizeof(struct mfc));
 		mrt_mcast_del(rt, rtableid);
 		rtfree(rt);
 		return (ENOMEM);
@@ -910,9 +918,6 @@ mfc_add_route(struct ifnet *ifp, struct 
 	rt_timer_add(rt, &ip_mrouterq, rtableid);
 
 	mfc->mfc_parent = mfccp->mfcc_parent;
-	mfc->mfc_pkt_cnt = 0;
-	mfc->mfc_byte_cnt = 0;
-	mfc->mfc_wrong_if = 0;
 	mfc->mfc_ttl = mfccp->mfcc_ttls[v->v_id];
 	mfc->mfc_flags = mfccp->mfcc_flags[v->v_id] & mrt_api_config &
 	    MRT_MFC_FLAGS_ALL;
@@ -1278,7 +1283,7 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp
 	if (mfc->mfc_parent != v->v_id) {
 		/* came in the wrong interface */
 		mrtstat_inc(mrts_wrong_if);
-		mfc->mfc_wrong_if++;
+		counters_inc(mfc->mfc_counter, mfc_wrong_if);
 		rtfree(rt);
 		return (0);
 	}
@@ -1308,8 +1313,8 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp
 		if (mfc == NULL)
 			continue;
 
-		mfc->mfc_pkt_cnt++;
-		mfc->mfc_byte_cnt += m->m_pkthdr.len;
+		counters_pkt(mfc->mfc_counter, mfc_packets, mfc_bytes,
+		    m->m_pkthdr.len);
 
 		/* Don't let this route expire. */
 		mfc->mfc_expire = 0;
@@ -1414,13 +1419,16 @@ void
 mrt_mcast_del(struct rtentry *rt, unsigned int rtableid)
 {
 	struct ifnet		*ifp;
+	struct mfc		*mfc;
 	int			 error;
 
 	/* Remove all timers related to this route. */
 	rt_timer_remove_all(rt);
 
-	free(rt->rt_llinfo, M_MRTABLE, sizeof(struct mfc));
+	mfc = (struct mfc *)rt->rt_llinfo;
 	rt->rt_llinfo = NULL;
+	counters_free(mfc->mfc_counter, mfc_ncounters);
+	free(mfc, M_MRTABLE, sizeof(struct mfc));
 
 	ifp = if_get(rt->rt_ifidx);
 	if (ifp == NULL)
Index: netinet/ip_mroute.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_mroute.h,v
diff -u -p -r1.35 ip_mroute.h
--- netinet/ip_mroute.h	24 Jun 2026 12:33:49 -0000	1.35
+++ netinet/ip_mroute.h	26 Jun 2026 11:54:40 -0000
@@ -224,14 +224,19 @@ struct vif {
  * at a future point.)
  */
 struct mfc {
+	struct	 cpumem *mfc_counter;		/* counters for src-grp */
+	u_long	 mfc_expire;			/* expire timer */
+	struct	 in_addr mfc_rp;		/* the RP address */
 	vifi_t	 mfc_parent;			/* incoming vif */
-	u_long	 mfc_pkt_cnt;			/* pkt count for src-grp */
-	u_long	 mfc_byte_cnt;			/* byte count for src-grp */
-	u_long	 mfc_wrong_if;			/* wrong if for src-grp	*/
 	uint8_t	 mfc_ttl;			/* route interface ttl */
 	uint8_t  mfc_flags;			/* MRT_MFC_FLAGS_* flags */
-	struct in_addr	mfc_rp;			/* the RP address	     */
-	u_long	 mfc_expire;			/* expire timer */
+};
+
+enum mfc_counters {
+	mfc_packets,			/* packet count for src-grp */
+	mfc_bytes,			/* byte count for src-grp */
+	mfc_wrong_if,			/* wrong if for src-grp	*/
+	mfc_ncounters
 };
 
 /*
Index: sys/percpu.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/sys/percpu.h,v
diff -u -p -r1.9 percpu.h
--- sys/percpu.h	16 Sep 2023 09:33:27 -0000	1.9
+++ sys/percpu.h	26 Jun 2026 11:54:40 -0000
@@ -54,6 +54,7 @@ struct cpumem	*cpumem_get(struct pool *)
 void		 cpumem_put(struct pool *, struct cpumem *);
 
 struct cpumem	*cpumem_malloc(size_t, int);
+struct cpumem	*cpumem_malloc_wait(size_t, int, int);
 struct cpumem	*cpumem_malloc_ncpus(struct cpumem *, size_t, int);
 void		 cpumem_free(struct cpumem *, int, size_t);
 
@@ -111,6 +112,7 @@ static struct {								\
  */
 
 struct cpumem	*counters_alloc(unsigned int);
+struct cpumem	*counters_alloc_wait(unsigned int, int);
 struct cpumem	*counters_alloc_ncpus(struct cpumem *, unsigned int);
 void		 counters_free(struct cpumem *, unsigned int);
 void		 counters_read(struct cpumem *, uint64_t *, unsigned int,
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.