Make CARP status per-cpu.

This commit is contained in:
thorpej 2008-04-15 06:03:28 +00:00
parent 0e499be12d
commit 1121526b25
3 changed files with 108 additions and 67 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_carp.c,v 1.23 2008/03/15 16:44:03 ws Exp $ */
/* $NetBSD: ip_carp.c,v 1.24 2008/04/15 06:03:28 thorpej Exp $ */
/* $OpenBSD: ip_carp.c,v 1.113 2005/11/04 08:11:54 mcbride Exp $ */
/*
@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.23 2008/03/15 16:44:03 ws Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.24 2008/04/15 06:03:28 thorpej Exp $");
/*
* TODO:
@ -53,6 +53,7 @@ __KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.23 2008/03/15 16:44:03 ws Exp $");
#include <sys/ucred.h>
#include <sys/syslog.h>
#include <sys/acct.h>
#include <sys/percpu.h>
#include <sys/cpu.h>
@ -155,7 +156,15 @@ struct carp_softc {
int carp_suppress_preempt = 0;
int carp_opts[CARPCTL_MAXID] = { 0, 1, 0, 0, 0 }; /* XXX for now */
struct carpstats carpstats;
static percpu_t *carpstat_percpu;
#define CARP_STATINC(x) \
do { \
uint64_t *_carps_ = percpu_getref(carpstat_percpu); \
_carps_[x]++; \
percpu_putref(carpstat_percpu); \
} while (/*CONSTCOND*/0)
struct carp_if {
TAILQ_HEAD(, carp_softc) vhif_vrs;
@ -460,7 +469,7 @@ carp_proto_input(struct mbuf *m, ...)
hlen = va_arg(ap, int);
va_end(ap);
carpstats.carps_ipackets++;
CARP_STATINC(CARP_STAT_IPACKETS);
if (!carp_opts[CARPCTL_ALLOW]) {
m_freem(m);
@ -469,7 +478,7 @@ carp_proto_input(struct mbuf *m, ...)
/* check if received on a valid carp interface */
if (m->m_pkthdr.rcvif->if_type != IFT_CARP) {
carpstats.carps_badif++;
CARP_STATINC(CARP_STAT_BADIF);
CARP_LOG(sc, ("packet received on non-carp interface: %s",
m->m_pkthdr.rcvif->if_xname));
m_freem(m);
@ -478,7 +487,7 @@ carp_proto_input(struct mbuf *m, ...)
/* verify that the IP TTL is 255. */
if (ip->ip_ttl != CARP_DFLTTL) {
carpstats.carps_badttl++;
CARP_STATINC(CARP_STAT_BADTTL);
CARP_LOG(sc, ("received ttl %d != %d on %s", ip->ip_ttl,
CARP_DFLTTL, m->m_pkthdr.rcvif->if_xname));
m_freem(m);
@ -492,7 +501,7 @@ carp_proto_input(struct mbuf *m, ...)
iplen = ip->ip_hl << 2;
len = iplen + sizeof(*ch);
if (len > m->m_pkthdr.len) {
carpstats.carps_badlen++;
CARP_STATINC(CARP_STAT_BADLEN);
CARP_LOG(sc, ("packet too short %d on %s", m->m_pkthdr.len,
m->m_pkthdr.rcvif->if_xname));
m_freem(m);
@ -500,7 +509,7 @@ carp_proto_input(struct mbuf *m, ...)
}
if ((m = m_pullup(m, len)) == NULL) {
carpstats.carps_hdrops++;
CARP_STATINC(CARP_STAT_HDROPS);
return;
}
ip = mtod(m, struct ip *);
@ -508,7 +517,7 @@ carp_proto_input(struct mbuf *m, ...)
/* verify the CARP checksum */
m->m_data += iplen;
if (carp_cksum(m, len - iplen)) {
carpstats.carps_badsum++;
CARP_STATINC(CARP_STAT_BADSUM);
CARP_LOG(sc, ("checksum failed on %s",
m->m_pkthdr.rcvif->if_xname));
m_freem(m);
@ -529,7 +538,7 @@ carp6_proto_input(struct mbuf **mp, int *offp, int proto)
struct carp_header *ch;
u_int len;
carpstats.carps_ipackets6++;
CARP_STATINC(CARP_STAT_IPACKETS6);
if (!carp_opts[CARPCTL_ALLOW]) {
m_freem(m);
@ -538,7 +547,7 @@ carp6_proto_input(struct mbuf **mp, int *offp, int proto)
/* check if received on a valid carp interface */
if (m->m_pkthdr.rcvif->if_type != IFT_CARP) {
carpstats.carps_badif++;
CARP_STATINC(CARP_STAT_BADIF);
CARP_LOG(sc, ("packet received on non-carp interface: %s",
m->m_pkthdr.rcvif->if_xname));
m_freem(m);
@ -547,7 +556,7 @@ carp6_proto_input(struct mbuf **mp, int *offp, int proto)
/* verify that the IP TTL is 255 */
if (ip6->ip6_hlim != CARP_DFLTTL) {
carpstats.carps_badttl++;
CARP_STATINC(CARP_STAT_BADTTL);
CARP_LOG(sc, ("received ttl %d != %d on %s", ip6->ip6_hlim,
CARP_DFLTTL, m->m_pkthdr.rcvif->if_xname));
m_freem(m);
@ -558,7 +567,7 @@ carp6_proto_input(struct mbuf **mp, int *offp, int proto)
len = m->m_len;
IP6_EXTHDR_GET(ch, struct carp_header *, m, *offp, sizeof(*ch));
if (ch == NULL) {
carpstats.carps_badlen++;
CARP_STATINC(CARP_STAT_BADLEN);
CARP_LOG(sc, ("packet size %u too small", len));
return (IPPROTO_DONE);
}
@ -567,7 +576,7 @@ carp6_proto_input(struct mbuf **mp, int *offp, int proto)
/* verify the CARP checksum */
m->m_data += *offp;
if (carp_cksum(m, sizeof(*ch))) {
carpstats.carps_badsum++;
CARP_STATINC(CARP_STAT_BADSUM);
CARP_LOG(sc, ("checksum failed, on %s",
m->m_pkthdr.rcvif->if_xname));
m_freem(m);
@ -594,7 +603,7 @@ carp_proto_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
if (!sc || (sc->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
(IFF_UP|IFF_RUNNING)) {
carpstats.carps_badvhid++;
CARP_STATINC(CARP_STAT_BADVHID);
m_freem(m);
return;
}
@ -647,7 +656,7 @@ carp_proto_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
/* verify the CARP version. */
if (ch->carp_version != CARP_VERSION) {
carpstats.carps_badver++;
CARP_STATINC(CARP_STAT_BADVER);
sc->sc_if.if_ierrors++;
CARP_LOG(sc, ("invalid version %d != %d",
ch->carp_version, CARP_VERSION));
@ -657,7 +666,7 @@ carp_proto_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
/* verify the hash */
if (carp_hmac_verify(sc, ch->carp_counter, ch->carp_md)) {
carpstats.carps_badauth++;
CARP_STATINC(CARP_STAT_BADAUTH);
sc->sc_if.if_ierrors++;
CARP_LOG(sc, ("incorrect hash"));
m_freem(m);
@ -740,6 +749,8 @@ void
carpattach(int n)
{
if_clone_attach(&carp_cloner);
carpstat_percpu = percpu_alloc(sizeof(uint64_t) * CARP_NSTATS);
}
int
@ -959,7 +970,7 @@ carp_send_ad(void *v)
MGETHDR(m, M_DONTWAIT, MT_HEADER);
if (m == NULL) {
sc->sc_if.if_oerrors++;
carpstats.carps_onomem++;
CARP_STATINC(CARP_STAT_ONOMEM);
/* XXX maybe less ? */
goto retry_later;
}
@ -1002,13 +1013,13 @@ carp_send_ad(void *v)
microtime(&sc->sc_if.if_lastchange);
sc->sc_if.if_opackets++;
sc->sc_if.if_obytes += len;
carpstats.carps_opackets++;
CARP_STATINC(CARP_STAT_OPACKETS);
error = ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo,
NULL);
if (error) {
if (error == ENOBUFS)
carpstats.carps_onomem++;
CARP_STATINC(CARP_STAT_ONOMEM);
else
CARP_LOG(sc, ("ip_output failed: %d", error));
sc->sc_if.if_oerrors++;
@ -1039,7 +1050,7 @@ carp_send_ad(void *v)
MGETHDR(m, M_DONTWAIT, MT_HEADER);
if (m == NULL) {
sc->sc_if.if_oerrors++;
carpstats.carps_onomem++;
CARP_STATINC(CARP_STAT_ONOMEM);
/* XXX maybe less ? */
goto retry_later;
}
@ -1087,12 +1098,12 @@ carp_send_ad(void *v)
microtime(&sc->sc_if.if_lastchange);
sc->sc_if.if_opackets++;
sc->sc_if.if_obytes += len;
carpstats.carps_opackets6++;
CARP_STATINC(CARP_STAT_OPACKETS6);
error = ip6_output(m, NULL, NULL, 0, &sc->sc_im6o, NULL, NULL);
if (error) {
if (error == ENOBUFS)
carpstats.carps_onomem++;
CARP_STATINC(CARP_STAT_ONOMEM);
else
CARP_LOG(sc, ("ip6_output failed: %d", error));
sc->sc_if.if_oerrors++;
@ -2233,6 +2244,38 @@ carp_ether_purgemulti(struct carp_softc *sc)
}
}
static void
carpstat_convert_to_user_cb(void *v1, void *v2, struct cpu_info *ci)
{
uint64_t *carpsc = v1;
uint64_t *carps = v2;
u_int i;
for (i = 0; i < CARP_NSTATS; i++)
carps[i] += carpsc[i];
}
static void
carpstat_convert_to_user(uint64_t *carps)
{
memset(carps, 0, sizeof(uint64_t) * CARP_NSTATS);
percpu_foreach(carpstat_percpu, carpstat_convert_to_user_cb, carps);
}
static int
sysctl_net_inet_carp_stats(SYSCTLFN_ARGS)
{
struct sysctlnode node;
uint64_t carps[CARP_NSTATS];
carpstat_convert_to_user(carps);
node = *rnode;
node.sysctl_data = carps;
node.sysctl_size = sizeof(carps);
return (sysctl_lookup(SYSCTLFN_CALL(&node)));
}
SYSCTL_SETUP(sysctl_net_inet_carp_setup, "sysctl net.inet.carp subtree setup")
{
@ -2285,7 +2328,7 @@ SYSCTL_SETUP(sysctl_net_inet_carp_setup, "sysctl net.inet.carp subtree setup")
CTLFLAG_PERMANENT,
CTLTYPE_STRUCT, "stats",
SYSCTL_DESCR("CARP statistics"),
NULL, 0, &carpstats, sizeof(carpstats),
sysctl_net_inet_carp_stats, 0, NULL, 0,
CTL_NET, PF_INET, IPPROTO_CARP, CARPCTL_STATS,
CTL_EOL);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_carp.h,v 1.3 2007/02/17 22:34:11 dyoung Exp $ */
/* $NetBSD: ip_carp.h,v 1.4 2008/04/15 06:03:28 thorpej Exp $ */
/* $OpenBSD: ip_carp.h,v 1.18 2005/04/20 23:00:41 mpf Exp $ */
/*
@ -92,26 +92,24 @@ struct carp_header {
/*
* Statistics.
*/
struct carpstats {
u_int64_t carps_ipackets; /* total input packets, IPv4 */
u_int64_t carps_ipackets6; /* total input packets, IPv6 */
u_int64_t carps_badif; /* wrong interface */
u_int64_t carps_badttl; /* TTL is not CARP_DFLTTL */
u_int64_t carps_hdrops; /* packets shorter than hdr */
u_int64_t carps_badsum; /* bad checksum */
u_int64_t carps_badver; /* bad (incl unsupp) version */
u_int64_t carps_badlen; /* data length does not match */
u_int64_t carps_badauth; /* bad authentication */
u_int64_t carps_badvhid; /* bad VHID */
u_int64_t carps_badaddrs; /* bad address list */
#define CARP_STAT_IPACKETS 0 /* total input packets, IPv4 */
#define CARP_STAT_IPACKETS6 1 /* total input packets, IPv6 */
#define CARP_STAT_BADIF 2 /* wrong interface */
#define CARP_STAT_BADTTL 3 /* TTL is not CARP_DFLTTL */
#define CARP_STAT_HDROPS 4 /* packets shorter than hdr */
#define CARP_STAT_BADSUM 5 /* bad checksum */
#define CARP_STAT_BADVER 6 /* bad (incl unsupported) version */
#define CARP_STAT_BADLEN 7 /* data length does not match */
#define CARP_STAT_BADAUTH 8 /* bad authentication */
#define CARP_STAT_BADVHID 9 /* bad VHID */
#define CARP_STAT_BADADDRS 10 /* bad address list */
#define CARP_STAT_OPACKETS 11 /* total output packets, IPv4 */
#define CARP_STAT_OPACKETS6 12 /* total output packets, IPv6 */
#define CARP_STAT_ONOMEM 13 /* no memory for an mbuf */
#define CARP_STAT_OSTATES 14 /* total state updates sent */
#define CARP_STAT_PREEMPT 15 /* in enabled, preemptions */
u_int64_t carps_opackets; /* total output packets, IPv4 */
u_int64_t carps_opackets6; /* total output packets, IPv6 */
u_int64_t carps_onomem; /* no memory for an mbuf */
u_int64_t carps_ostates; /* total state updates sent */
u_int64_t carps_preempt; /* if enabled, preemptions */
};
#define CARP_NSTATS 16
#define CARPDEVNAMSIZ 16
#ifdef IFNAMSIZ

View File

@ -1,4 +1,4 @@
/* $NetBSD: inet.c,v 1.84 2008/04/15 04:50:05 thorpej Exp $ */
/* $NetBSD: inet.c,v 1.85 2008/04/15 06:03:28 thorpej Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@ -34,7 +34,7 @@
#if 0
static char sccsid[] = "from: @(#)inet.c 8.4 (Berkeley) 4/20/94";
#else
__RCSID("$NetBSD: inet.c,v 1.84 2008/04/15 04:50:05 thorpej Exp $");
__RCSID("$NetBSD: inet.c,v 1.85 2008/04/15 06:03:28 thorpej Exp $");
#endif
#endif /* not lint */
@ -631,12 +631,12 @@ igmp_stats(u_long off, char *name)
void
carp_stats(u_long off, char *name)
{
struct carpstats carpstat;
uint64_t carpstat[CARP_NSTATS];
if (use_sysctl) {
size_t size = sizeof(carpstat);
if (sysctlbyname("net.inet.carp.stats", &carpstat, &size,
if (sysctlbyname("net.inet.carp.stats", carpstat, &size,
NULL, 0) == -1) {
/* most likely CARP is not compiled in the kernel */
return;
@ -644,37 +644,37 @@ carp_stats(u_long off, char *name)
} else {
if (off == 0)
return;
kread(off, (char *)&carpstat, sizeof(carpstat));
kread(off, (char *)carpstat, sizeof(carpstat));
}
printf("%s:\n", name);
#define p(f, m) if (carpstat.f || sflag <= 1) \
printf(m, carpstat.f, plural(carpstat.f))
#define p2(f, m) if (carpstat.f || sflag <= 1) \
printf(m, carpstat.f)
#define p(f, m) if (carpstat[f] || sflag <= 1) \
printf(m, carpstat[f], plural(carpstat[f]))
#define p2(f, m) if (carpstat[f] || sflag <= 1) \
printf(m, carpstat[f])
p(carps_ipackets, "\t%" PRIu64 " packet%s received (IPv4)\n");
p(carps_ipackets6, "\t%" PRIu64 " packet%s received (IPv6)\n");
p(carps_badif,
p(CARP_STAT_IPACKETS, "\t%" PRIu64 " packet%s received (IPv4)\n");
p(CARP_STAT_IPACKETS6, "\t%" PRIu64 " packet%s received (IPv6)\n");
p(CARP_STAT_BADIF,
"\t\t%" PRIu64 " packet%s discarded for bad interface\n");
p(carps_badttl,
p(CARP_STAT_BADTTL,
"\t\t%" PRIu64 " packet%s discarded for wrong TTL\n");
p(carps_hdrops, "\t\t%" PRIu64 " packet%s shorter than header\n");
p(carps_badsum, "\t\t%" PRIu64
p(CARP_STAT_HDROPS, "\t\t%" PRIu64 " packet%s shorter than header\n");
p(CARP_STAT_BADSUM, "\t\t%" PRIu64
" packet%s discarded for bad checksum\n");
p(carps_badver,
p(CARP_STAT_BADVER,
"\t\t%" PRIu64 " packet%s discarded with a bad version\n");
p2(carps_badlen,
p2(CARP_STAT_BADLEN,
"\t\t%" PRIu64 " discarded because packet was too short\n");
p(carps_badauth,
p(CARP_STAT_BADAUTH,
"\t\t%" PRIu64 " packet%s discarded for bad authentication\n");
p(carps_badvhid, "\t\t%" PRIu64 " packet%s discarded for bad vhid\n");
p(carps_badaddrs, "\t\t%" PRIu64
p(CARP_STAT_BADVHID, "\t\t%" PRIu64 " packet%s discarded for bad vhid\n");
p(CARP_STAT_BADADDRS, "\t\t%" PRIu64
" packet%s discarded because of a bad address list\n");
p(carps_opackets, "\t%" PRIu64 " packet%s sent (IPv4)\n");
p(carps_opackets6, "\t%" PRIu64 " packet%s sent (IPv6)\n");
p2(carps_onomem,
p(CARP_STAT_OPACKETS, "\t%" PRIu64 " packet%s sent (IPv4)\n");
p(CARP_STAT_OPACKETS6, "\t%" PRIu64 " packet%s sent (IPv6)\n");
p2(CARP_STAT_ONOMEM,
"\t\t%" PRIu64 " send failed due to mbuf memory error\n");
#undef p
#undef p2