pf: Introduce nvlist variant of DIOCGETSTATUS

Make it possible to extend the GETSTATUS call (e.g. when we want to add
new counters, such as for syncookie support) by introducing an
nvlist-based alternative.

MFC after:	1 week
Sponsored by:   Modirum MDPay
Differential Revision:	https://reviews.freebsd.org/D31694
This commit is contained in:
Kristof Provost 2021-08-16 21:55:27 +02:00
parent 5d785ad65e
commit 2b10cf85f8
3 changed files with 143 additions and 0 deletions

View File

@ -1667,6 +1667,7 @@ struct pfioc_iface {
#define DIOCGETSTATENV _IOWR('D', 19, struct pfioc_nv)
#define DIOCSETSTATUSIF _IOWR('D', 20, struct pfioc_if)
#define DIOCGETSTATUS _IOWR('D', 21, struct pf_status)
#define DIOCGETSTATUSNV _IOWR('D', 21, struct pfioc_nv)
#define DIOCCLRSTATUS _IO ('D', 22)
#define DIOCNATLOOK _IOWR('D', 23, struct pfioc_natlook)
#define DIOCSETDEBUG _IOWR('D', 24, u_int32_t)

View File

@ -179,6 +179,15 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
#define FCNT_STATE_REMOVALS 2
#define FCNT_MAX 3
#ifdef _KERNEL
#define FCNT_NAMES { \
"searches", \
"inserts", \
"removals", \
NULL \
}
#endif
/* src_node operation counters */
#define SCNT_SRC_NODE_SEARCH 0
#define SCNT_SRC_NODE_INSERT 1

View File

@ -208,6 +208,7 @@ static int pf_killstates_row(struct pf_kstate_kill *,
static int pf_killstates_nv(struct pfioc_nv *);
static int pf_clearstates_nv(struct pfioc_nv *);
static int pf_getstate(struct pfioc_nv *);
static int pf_getstatus(struct pfioc_nv *);
static int pf_clear_tables(void);
static void pf_clear_srcnodes(struct pf_ksrc_node *);
static void pf_kill_srcnodes(struct pfioc_src_node_kill *);
@ -2179,6 +2180,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
case DIOCGETSTATENV:
case DIOCSETSTATUSIF:
case DIOCGETSTATUS:
case DIOCGETSTATUSNV:
case DIOCCLRSTATUS:
case DIOCNATLOOK:
case DIOCSETDEBUG:
@ -2236,6 +2238,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
case DIOCGETSTATE:
case DIOCGETSTATENV:
case DIOCGETSTATUS:
case DIOCGETSTATUSNV:
case DIOCGETSTATES:
case DIOCGETSTATESV2:
case DIOCGETTIMEOUT:
@ -3096,6 +3099,11 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
break;
}
case DIOCGETSTATUSNV: {
error = pf_getstatus((struct pfioc_nv *)addr);
break;
}
case DIOCSETSTATUSIF: {
struct pfioc_if *pi = (struct pfioc_if *)addr;
@ -4887,6 +4895,131 @@ pf_tbladdr_copyout(struct pf_addr_wrap *aw)
kt->pfrkt_cnt : -1;
}
static int
pf_add_status_counters(nvlist_t *nvl, const char *name, counter_u64_t *counters,
size_t number, char **names)
{
nvlist_t *nvc;
nvc = nvlist_create(0);
if (nvc == NULL)
return (ENOMEM);
for (int i = 0; i < number; i++) {
nvlist_append_number_array(nvc, "counters",
counter_u64_fetch(counters[i]));
nvlist_append_string_array(nvc, "names",
names[i]);
nvlist_append_number_array(nvc, "ids",
i);
}
nvlist_add_nvlist(nvl, name, nvc);
nvlist_destroy(nvc);
return (0);
}
static int
pf_getstatus(struct pfioc_nv *nv)
{
nvlist_t *nvl = NULL, *nvc = NULL;
void *nvlpacked = NULL;
int error;
struct pf_status s;
char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
char *pf_lcounter[LCNT_MAX+1] = LCNT_NAMES;
char *pf_fcounter[FCNT_MAX+1] = FCNT_NAMES;
PF_RULES_RLOCK_TRACKER;
#define ERROUT(x) ERROUT_FUNCTION(errout, x)
PF_RULES_RLOCK();
nvl = nvlist_create(0);
if (nvl == NULL)
ERROUT(ENOMEM);
nvlist_add_bool(nvl, "running", V_pf_status.running);
nvlist_add_number(nvl, "since", V_pf_status.since);
nvlist_add_number(nvl, "debug", V_pf_status.debug);
nvlist_add_number(nvl, "hostid", V_pf_status.hostid);
nvlist_add_number(nvl, "states", V_pf_status.states);
nvlist_add_number(nvl, "src_nodes", V_pf_status.src_nodes);
/* counters */
error = pf_add_status_counters(nvl, "counters", V_pf_status.counters,
PFRES_MAX, pf_reasons);
if (error != 0)
ERROUT(error);
/* lcounters */
error = pf_add_status_counters(nvl, "lcounters", V_pf_status.lcounters,
LCNT_MAX, pf_lcounter);
if (error != 0)
ERROUT(error);
/* fcounters */
nvc = nvlist_create(0);
if (nvc == NULL)
ERROUT(ENOMEM);
for (int i = 0; i < FCNT_MAX; i++) {
nvlist_append_number_array(nvc, "counters",
pf_counter_u64_fetch(&V_pf_status.fcounters[i]));
nvlist_append_string_array(nvc, "names",
pf_fcounter[i]);
nvlist_append_number_array(nvc, "ids",
i);
}
nvlist_add_nvlist(nvl, "fcounters", nvc);
nvlist_destroy(nvc);
nvc = NULL;
/* scounters */
error = pf_add_status_counters(nvl, "scounters", V_pf_status.scounters,
SCNT_MAX, pf_fcounter);
if (error != 0)
ERROUT(error);
nvlist_add_string(nvl, "ifname", V_pf_status.ifname);
nvlist_add_binary(nvl, "chksum", V_pf_status.pf_chksum,
PF_MD5_DIGEST_LENGTH);
pfi_update_status(V_pf_status.ifname, &s);
/* pcounters / bcounters */
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 2; k++) {
nvlist_append_number_array(nvl, "pcounters",
s.pcounters[i][j][k]);
}
nvlist_append_number_array(nvl, "bcounters",
s.bcounters[i][j]);
}
}
nvlpacked = nvlist_pack(nvl, &nv->len);
if (nvlpacked == NULL)
ERROUT(ENOMEM);
if (nv->size == 0)
ERROUT(0);
else if (nv->size < nv->len)
ERROUT(ENOSPC);
error = copyout(nvlpacked, nv->data, nv->len);
#undef ERROUT
errout:
PF_RULES_RUNLOCK();
free(nvlpacked, M_NVLIST);
nvlist_destroy(nvc);
nvlist_destroy(nvl);
return (error);
}
/*
* XXX - Check for version missmatch!!!
*/