Index: lib/libpfctl/libpfctl.h =================================================================== --- lib/libpfctl/libpfctl.h +++ lib/libpfctl/libpfctl.h @@ -99,6 +99,7 @@ uint64_t evaluations; uint64_t packets[2]; uint64_t bytes[2]; + uint32_t last_active_timestamp; /* Action */ char qname[PF_QNAME_SIZE]; @@ -171,6 +172,7 @@ uint64_t evaluations; uint64_t packets[2]; uint64_t bytes[2]; + uint32_t last_active_timestamp; struct pfi_kif *kif; struct pfctl_anchor *anchor; Index: lib/libpfctl/libpfctl.c =================================================================== --- lib/libpfctl/libpfctl.c +++ lib/libpfctl/libpfctl.c @@ -47,6 +47,7 @@ #include #include #include +#include /* _long_to_time */ #include "libpfctl.h" @@ -512,6 +513,10 @@ pf_nvuint_64_array(nvl, "packets", 2, rule->packets, NULL); pf_nvuint_64_array(nvl, "bytes", 2, rule->bytes, NULL); + if (nvlist_exists_number(nvl, "timestamp")) { + rule->last_active_timestamp = nvlist_get_number(nvl, "timestamp"); + } + rule->os_fingerprint = nvlist_get_number(nvl, "os_fingerprint"); rule->rtableid = nvlist_get_number(nvl, "rtableid"); @@ -642,6 +647,10 @@ rule->bytes[0] = nvlist_get_number(nvl, "bytes-in"); rule->bytes[1] = nvlist_get_number(nvl, "bytes-out"); + if (nvlist_exists_number(nvl, "timestamp")) { + rule->last_active_timestamp = nvlist_get_number(nvl, "timestamp"); + } + strlcpy(rule->qname, nvlist_get_string(nvl, "qname"), PF_QNAME_SIZE); strlcpy(rule->tagname, nvlist_get_string(nvl, "tagname"), PF_TAG_NAME_SIZE); @@ -737,7 +746,7 @@ nvlist_add_number(nvl, "nr", nr); nvlist_add_bool(nvl, "clear", clear); - if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULE, 2048, &nvl)) != 0) + if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULE, 4096, &nvl)) != 0) return (ret); pfctl_nveth_rule_to_eth_rule(nvl, rule); Index: sbin/pfctl/pfctl.c =================================================================== --- sbin/pfctl/pfctl.c +++ sbin/pfctl/pfctl.c @@ -1016,6 +1016,14 @@ (unsigned long long)(rule->bytes[0] + rule->bytes[1])); } + if (opts & PF_OPT_VERBOSE2) { + char timestr[30]; + time_t last_active = rule->last_active_timestamp; + bcopy(ctime(&last_active), timestr, sizeof(timestr)); + *strchr(timestr, '\n') = '\0'; + printf(" [ Last Active Timestamp: %d Last Active " + "Time: %s ]\n", rule->last_active_timestamp, timestr); + } } void @@ -1055,6 +1063,14 @@ (unsigned)rule->cuid, (unsigned)rule->cpid, (uintmax_t)rule->states_tot); } + if (opts & PF_OPT_VERBOSE2) { + char timestr[30]; + time_t last_active = rule->last_active_timestamp; + bcopy(ctime(&last_active), timestr, sizeof(timestr)); + *strchr(timestr, '\n') = '\0'; + printf(" [ Last Active Timestamp: %d Last Active " + "Time: %s ]\n", rule->last_active_timestamp, timestr); + } } void Index: sys/net/pfvar.h =================================================================== --- sys/net/pfvar.h +++ sys/net/pfvar.h @@ -35,6 +35,7 @@ #ifndef _NET_PFVAR_H_ #define _NET_PFVAR_H_ +#include "sys/_stdint.h" #include #include #include @@ -286,6 +287,19 @@ } #endif +#define pf_get_timestamp(prule)({ \ + uint32_t* _ts; \ + uint32_t* __ts; \ + int cpu; \ + CPU_FOREACH(cpu) { \ + __ts = zpcpu_get_cpu(prule->timestamp, cpu); \ + if (cpu == 0 || *__ts > *_ts) \ + _ts = __ts; \ + } \ + *_ts; \ +}) + + SYSCTL_DECL(_net_pf); MALLOC_DECLARE(M_PFHASH); @@ -657,6 +671,7 @@ counter_u64_t evaluations; counter_u64_t packets[2]; counter_u64_t bytes[2]; + uint32_t *timestamp; /* Action */ char qname[PF_QNAME_SIZE]; @@ -696,6 +711,7 @@ struct pf_counter_u64 evaluations; struct pf_counter_u64 packets[2]; struct pf_counter_u64 bytes[2]; + uint32_t *timestamp; struct pfi_kkif *kif; struct pf_kanchor *anchor; Index: sys/netpfil/pf/pf.c =================================================================== --- sys/netpfil/pf/pf.c +++ sys/netpfil/pf/pf.c @@ -3971,6 +3971,8 @@ /* Execute action. */ counter_u64_add(r->packets[dir == PF_OUT], 1); counter_u64_add(r->bytes[dir == PF_OUT], m_length(m, NULL)); + if (*zpcpu_get(r->timestamp) < time_second) + *zpcpu_get(r->timestamp) = time_second; /* Shortcut. Don't tag if we're just going to drop anyway. */ if (r->action == PF_DROP) { @@ -7198,6 +7200,9 @@ dirndx = (dir == PF_OUT); pf_counter_u64_add_protected(&r->packets[dirndx], 1); pf_counter_u64_add_protected(&r->bytes[dirndx], pd.tot_len); + if (*zpcpu_get(r->timestamp) < time_second) + *zpcpu_get(r->timestamp) = time_second; + if (a != NULL) { pf_counter_u64_add_protected(&a->packets[dirndx], 1); pf_counter_u64_add_protected(&a->bytes[dirndx], pd.tot_len); Index: sys/netpfil/pf/pf_ioctl.c =================================================================== --- sys/netpfil/pf/pf_ioctl.c +++ sys/netpfil/pf/pf_ioctl.c @@ -37,6 +37,7 @@ * $OpenBSD: pf_ioctl.c,v 1.213 2009/02/15 21:46:12 mbalmer Exp $ */ +#include "vm/uma.h" #include __FBSDID("$FreeBSD$"); @@ -530,6 +531,7 @@ counter_u64_free(rule->packets[i]); counter_u64_free(rule->bytes[i]); } + uma_zfree_pcpu(pcpu_zone_4, rule->timestamp); pf_keth_anchor_remove(rule); free(rule, M_PFRULE); @@ -1801,6 +1803,7 @@ counter_u64_free(rule->states_cur); counter_u64_free(rule->states_tot); counter_u64_free(rule->src_nodes); + uma_zfree_pcpu(pcpu_zone_4, rule->timestamp); mtx_destroy(&rule->rpool.mtx); free(rule, M_PFRULE); @@ -2130,6 +2133,7 @@ rule->states_cur = counter_u64_alloc(M_WAITOK); rule->states_tot = counter_u64_alloc(M_WAITOK); rule->src_nodes = counter_u64_alloc(M_WAITOK); + rule->timestamp = uma_zalloc_pcpu(pcpu_zone_4, M_WAITOK | M_ZERO); rule->cuid = td->td_ucred->cr_ruid; rule->cpid = td->td_proc ? td->td_proc->p_pid : 0; TAILQ_INIT(&rule->rpool.list); @@ -2829,7 +2833,7 @@ ERROUT(EBUSY); } - rule = malloc(sizeof(*rule), M_PFRULE, M_WAITOK); + rule = malloc(sizeof(*rule), M_PFRULE, M_WAITOK | M_ZERO); if (rule == NULL) ERROUT(ENOMEM); @@ -2844,6 +2848,8 @@ rule->packets[i] = counter_u64_alloc(M_WAITOK); rule->bytes[i] = counter_u64_alloc(M_WAITOK); } + rule->timestamp = uma_zalloc_pcpu(pcpu_zone_4, + M_WAITOK | M_ZERO); PF_RULES_WLOCK(); Index: sys/netpfil/pf/pf_nv.c =================================================================== --- sys/netpfil/pf/pf_nv.c +++ sys/netpfil/pf/pf_nv.c @@ -686,6 +686,7 @@ pf_krule_to_nvrule(struct pf_krule *rule) { nvlist_t *nvl, *tmp; + struct timeval boottime; nvl = nvlist_create(0); if (nvl == NULL) @@ -737,6 +738,7 @@ nvlist_append_number_array(nvl, "bytes", pf_counter_u64_fetch(&rule->bytes[i])); } + nvlist_add_number(nvl, "timestamp", pf_get_timestamp(rule)); nvlist_add_number(nvl, "os_fingerprint", rule->os_fingerprint); @@ -1045,6 +1047,7 @@ pf_keth_rule_to_nveth_rule(const struct pf_keth_rule *krule) { nvlist_t *nvl, *addr; + struct timeval boottime; nvl = nvlist_create(0); if (nvl == NULL) @@ -1098,6 +1101,8 @@ nvlist_add_number(nvl, "bytes-out", counter_u64_fetch(krule->bytes[1])); + getboottime(&boottime); + nvlist_add_number(nvl, "timestamp", pf_get_timestamp(krule)); nvlist_add_string(nvl, "qname", krule->qname); nvlist_add_string(nvl, "tagname", krule->tagname);