Index | Thread | Search

From:
Alexander Bluhm <bluhm@openbsd.org>
Subject:
multicast route counter
To:
tech@openbsd.org
Date:
Fri, 26 Jun 2026 22:42:44 +0200

Download raw body.

Thread
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,