diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1667,6 +1667,7 @@ #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) diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h --- a/sys/netpfil/pf/pf.h +++ b/sys/netpfil/pf/pf.h @@ -179,6 +179,15 @@ #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 diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -208,6 +208,7 @@ 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 @@ case DIOCGETSTATENV: case DIOCSETSTATUSIF: case DIOCGETSTATUS: + case DIOCGETSTATUSNV: case DIOCCLRSTATUS: case DIOCNATLOOK: case DIOCSETDEBUG: @@ -2236,6 +2238,7 @@ case DIOCGETSTATE: case DIOCGETSTATENV: case DIOCGETSTATUS: + case DIOCGETSTATUSNV: case DIOCGETSTATES: case DIOCGETSTATESV2: case DIOCGETTIMEOUT: @@ -3096,6 +3099,11 @@ 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 @@ 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!!! */