From: Alexander Bluhm Subject: multicast route counter To: tech@openbsd.org Date: Fri, 26 Jun 2026 22:42:44 +0200 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,