/*
 * DF0632 instrumentation probe: read ipfw3_basic state counters from kernel
 * memory and log them to dmesg. Used to demonstrate that count_* is monotonic
 * (incremented on state creation, never decremented on state expiry).
 *
 * Build (in-guest):
 *   mkdir -p /usr/src/sys/modules/df0632_probe
 *   cp ipfw3_counter_probe.c /usr/src/sys/modules/df0632_probe/
 *   cd /usr/src/sys/modules/df0632_probe
 *   cat > Makefile <<EOF
 *   KMOD=   df0632_probe
 *   SRCS=   ipfw3_counter_probe.c
 *   .include <bsd.kmod.mk>
 *   EOF
 *   make
 *
 * Use:
 *   kldload /usr/src/sys/modules/df0632_probe/df0632_probe.ko
 *   dmesg | tail -10 | grep DF0632
 *   kldunload df0632_probe
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/tree.h>
#include <net/ipfw3/ip_fw.h>
#include <net/ipfw3_basic/ip_fw3_state.h>

extern struct ipfw3_state_context *fw3_state_ctx[MAXCPU];

static int
probe_load(struct module *m, int what, void *arg)
{
	int cpu;
	switch (what) {
	case MOD_LOAD:
		for (cpu = 0; cpu < ncpus; cpu++) {
			struct ipfw3_state_context *c = fw3_state_ctx[cpu];
			if (c == NULL) {
				kprintf("DF0632: cpu%d=NULL\n", cpu);
				continue;
			}
			kprintf("DF0632 cpu%d: tcp_in=%d tcp_out=%d "
				"udp_in=%d udp_out=%d icmp_in=%d icmp_out=%d\n",
				cpu, c->count_tcp_in, c->count_tcp_out,
				c->count_udp_in, c->count_udp_out,
				c->count_icmp_in, c->count_icmp_out);
		}
		return 0;
	case MOD_UNLOAD:
		return 0;
	default:
		return EOPNOTSUPP;
	}
}

static moduledata_t mod_data = { "df0632_probe", probe_load, NULL };
DECLARE_MODULE(df0632_probe, mod_data, SI_SUB_EXEC, SI_ORDER_ANY);
MODULE_DEPEND(df0632_probe, ipfw3_basic, 1, 1, 1);
