igmp: convert igmpstat to use PCPU counters

Currently there is no locking done to protect this structure. It is
likely okay due to the low-volume nature of IGMP, but allows for
the possibility of underflow. This appears to be one of the only
holdouts of the conversion to counter(9) which was done for most
protocol stat structures around 2013.

This also updates the visibility of this stats structure so that it can
be consumed from elsewhere in the kernel, consistent with the vast
majority of VNET_PCPUSTAT structures.

Reviewed by:	kp
Sponsored by:	NetApp, Inc.
Sponsored by:	Klara, Inc.
Differential Revision:	https://reviews.freebsd.org/D27023
This commit is contained in:
Mitchell Horne 2020-11-08 18:49:23 +00:00
parent 4d0770f172
commit b02c4e5c78
2 changed files with 31 additions and 21 deletions

View File

@ -230,16 +230,15 @@ VNET_DEFINE_STATIC(int, current_state_timers_running); /* IGMPv1/v2 host
#define V_state_change_timers_running VNET(state_change_timers_running)
#define V_current_state_timers_running VNET(current_state_timers_running)
VNET_PCPUSTAT_DEFINE(struct igmpstat, igmpstat);
VNET_PCPUSTAT_SYSINIT(igmpstat);
VNET_PCPUSTAT_SYSUNINIT(igmpstat);
VNET_DEFINE_STATIC(LIST_HEAD(, igmp_ifsoftc), igi_head) =
LIST_HEAD_INITIALIZER(igi_head);
VNET_DEFINE_STATIC(struct igmpstat, igmpstat) = {
.igps_version = IGPS_VERSION_3,
.igps_len = sizeof(struct igmpstat),
};
VNET_DEFINE_STATIC(struct timeval, igmp_gsrdelay) = {10, 0};
#define V_igi_head VNET(igi_head)
#define V_igmpstat VNET(igmpstat)
#define V_igmp_gsrdelay VNET(igmp_gsrdelay)
VNET_DEFINE_STATIC(int, igmp_recvifkludge) = 1;
@ -263,7 +262,8 @@ VNET_DEFINE_STATIC(int, igmp_default_version) = IGMP_VERSION_3;
*/
SYSCTL_PROC(_net_inet_igmp, IGMPCTL_STATS, stats,
CTLFLAG_VNET | CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_MPSAFE,
&VNET_NAME(igmpstat), 0, sysctl_igmp_stat, "S,igmpstat", "");
&VNET_NAME(igmpstat), 0, sysctl_igmp_stat, "S,igmpstat",
"IGMP statistics (struct igmpstat, netinet/igmp_var.h)");
SYSCTL_INT(_net_inet_igmp, OID_AUTO, recvifkludge, CTLFLAG_VNET | CTLFLAG_RW,
&VNET_NAME(igmp_recvifkludge), 0,
"Rewrite IGMPv1/v2 reports from 0.0.0.0 to contain subnet address");
@ -347,22 +347,31 @@ sysctl_igmp_stat(SYSCTL_HANDLER_ARGS)
int error;
char *p;
error = sysctl_wire_old_buffer(req, sizeof(V_igmpstat));
error = sysctl_wire_old_buffer(req, sizeof(struct igmpstat));
if (error)
return (error);
if (req->oldptr != NULL) {
if (req->oldlen < sizeof(V_igmpstat))
if (req->oldlen < sizeof(struct igmpstat))
error = ENOMEM;
else
error = SYSCTL_OUT(req, &V_igmpstat,
sizeof(V_igmpstat));
else {
/*
* Copy the counters, and explicitly set the struct's
* version and length fields.
*/
COUNTER_ARRAY_COPY(VNET(igmpstat), &igps0,
sizeof(struct igmpstat) / sizeof(uint64_t));
igps0.igps_version = IGPS_VERSION_3;
igps0.igps_len = IGPS_VERSION3_LEN;
error = SYSCTL_OUT(req, &igps0,
sizeof(struct igmpstat));
}
} else
req->validlen = sizeof(V_igmpstat);
req->validlen = sizeof(struct igmpstat);
if (error)
goto out;
if (req->newptr != NULL) {
if (req->newlen < sizeof(V_igmpstat))
if (req->newlen < sizeof(struct igmpstat))
error = ENOMEM;
else
error = SYSCTL_IN(req, &igps0,
@ -379,12 +388,8 @@ sysctl_igmp_stat(SYSCTL_HANDLER_ARGS)
error = EINVAL;
goto out;
}
/*
* Avoid overwrite of the version and length field.
*/
igps0.igps_version = V_igmpstat.igps_version;
igps0.igps_len = V_igmpstat.igps_len;
bcopy(&igps0, &V_igmpstat, sizeof(V_igmpstat));
COUNTER_ARRAY_ZERO(VNET(igmpstat),
sizeof(struct igmpstat) / sizeof(uint64_t));
}
out:
return (error);

View File

@ -54,6 +54,7 @@
struct igmpstat {
/*
* Structure header (to insulate ABI changes).
* XXX: unset inside the kernel, exported via sysctl_igmp_stat().
*/
uint32_t igps_version; /* version of this structure */
uint32_t igps_len; /* length of this structure */
@ -184,8 +185,12 @@ struct igmp_ifinfo {
};
#ifdef _KERNEL
#define IGMPSTAT_ADD(name, val) V_igmpstat.name += (val)
#define IGMPSTAT_INC(name) IGMPSTAT_ADD(name, 1)
#include <sys/counter.h>
VNET_PCPUSTAT_DECLARE(struct igmpstat, igmpstat);
#define IGMPSTAT_ADD(name, val) \
VNET_PCPUSTAT_ADD(struct igmpstat, igmpstat, name, (val))
#define IGMPSTAT_INC(name) IGMPSTAT_ADD(name, 1)
/*
* Subsystem lock macros.