Download raw body.
ip6_mroute mp-safe per cpu counter
On Mon, May 19, 2025 at 04:13:40AM +0200, Jan Klemkow wrote:
> 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?
Don't forget to remove declaration
#ifdef MROUTING
extern struct mrt6stat mrt6stat;
#endif
from ip6_sysctl(). This prevented compiling with gcc when you did
the same diff for IPv4.
OK bluhm@
> 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 */
>
ip6_mroute mp-safe per cpu counter