summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sbin/ipfw/ipfw2.h1
-rw-r--r--sbin/ipfw/tables.c72
-rw-r--r--sys/netinet/ip_fw.h5
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c87
-rw-r--r--sys/netpfil/ipfw/ip_fw_private.h4
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.c96
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.h6
-rw-r--r--sys/netpfil/ipfw/ip_fw_table_algo.c496
-rw-r--r--sys/netpfil/ipfw/nat64/nat64stl.c7
9 files changed, 714 insertions, 60 deletions
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
index 0218a4a..6cd452c 100644
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -254,6 +254,7 @@ enum tokens {
TOK_UNLOCK,
TOK_VLIST,
TOK_OLIST,
+ TOK_ZEROCNT,
/* NAT64 tokens */
TOK_NAT64STL,
diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c
index 85350a0..21287da 100644
--- a/sbin/ipfw/tables.c
+++ b/sbin/ipfw/tables.c
@@ -54,6 +54,7 @@ static void table_lock(ipfw_obj_header *oh, int lock);
static int table_swap(ipfw_obj_header *oh, char *second);
static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i);
static int table_show_info(ipfw_xtable_info *i, void *arg);
+static void table_zerocnt(ipfw_obj_header *oh, int ac, char *av[]);
static int table_flush_one(ipfw_xtable_info *i, void *arg);
static int table_show_one(ipfw_xtable_info *i, void *arg);
@@ -114,6 +115,7 @@ static struct _s_x tablecmds[] = {
{ "atomic", TOK_ATOMIC },
{ "lock", TOK_LOCK },
{ "unlock", TOK_UNLOCK },
+ { "zerocnt", TOK_ZEROCNT },
{ NULL, 0 }
};
@@ -289,6 +291,10 @@ ipfw_table_handler(int ac, char *av[])
ac--; av++;
table_lookup(&oh, ac, av);
break;
+ case TOK_ZEROCNT:
+ ac--; av++;
+ table_zerocnt(&oh, ac, av);
+ break;
}
}
@@ -1108,6 +1114,60 @@ table_lookup(ipfw_obj_header *oh, int ac, char *av[])
table_show_entry(&xi, &xtent);
}
+static int
+table_do_zerocnt(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi)
+{
+ char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
+ ipfw_obj_tentry *tent;
+ uint8_t type;
+ uint32_t vmask;
+
+ memcpy(xbuf, oh, sizeof(*oh));
+ oh = (ipfw_obj_header *)xbuf;
+ tent = (ipfw_obj_tentry *)(oh + 1);
+
+ memset(tent, 0, sizeof(*tent));
+ tent->head.length = sizeof(*tent);
+ tent->idx = 1;
+
+ tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi);
+ oh->ntlv.type = type;
+
+ if (do_set3(IP_FW_TABLE_XZEROCNT, &oh->opheader, sizeof(xbuf)) != 0)
+ return (errno);
+
+ return (0);
+}
+
+static void
+table_zerocnt(ipfw_obj_header *oh, int ac, char *av[])
+{
+ ipfw_xtable_info xi;
+ char key[64];
+ int error;
+
+ if (ac == 0)
+ errx(EX_USAGE, "address required");
+
+ strlcpy(key, *av, sizeof(key));
+
+ memset(&xi, 0, sizeof(xi));
+ error = table_do_zerocnt(oh, key, &xi);
+ switch (error) {
+ case 0:
+ break;
+ case ESRCH:
+ errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
+ case ENOENT:
+ errx(EX_UNAVAILABLE, "Entry %s not found", *av);
+ case ENOTSUP:
+ errx(EX_UNAVAILABLE, "Table %s algo does not support "
+ "\"zero_cnt\" method", oh->ntlv.name);
+ default:
+ err(EX_OSERR, "getsockopt(IP_FW_TABLE_XZEROCNT)");
+ }
+}
+
static void
tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
uint8_t tflags)
@@ -1845,21 +1905,21 @@ table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
case IPFW_TABLE_ADDR:
/* IPv4 or IPv6 prefixes */
inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
- printf("%s/%u %s\n", tbuf, tent->masklen, pval);
+ printf("%s/%u %s", tbuf, tent->masklen, pval);
break;
case IPFW_TABLE_MAC2:
/* Ethernet MAC address */
print_mac(tent->k.mac.addr, tent->k.mac.mask);
print_mac(tent->k.mac.addr + 6, tent->k.mac.mask + 6);
- printf(" %s\n", pval);
+ printf(" %s", pval);
break;
case IPFW_TABLE_INTERFACE:
/* Interface names */
- printf("%s %s\n", tent->k.iface, pval);
+ printf("%s %s", tent->k.iface, pval);
break;
case IPFW_TABLE_NUMBER:
/* numbers */
- printf("%u %s\n", tent->k.key, pval);
+ printf("%u %s", tent->k.key, pval);
break;
case IPFW_TABLE_FLOW:
/* flows */
@@ -1902,8 +1962,10 @@ table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
comma = ",";
}
- printf(" %s\n", pval);
+ printf(" %s", pval);
}
+ printf(" %ju %ju %ju\n", (uintmax_t)tent->pcnt,
+ (uintmax_t)tent->bcnt, (uintmax_t)tent->timestamp);
}
static int
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index adbc41b..26f6e48 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -110,6 +110,8 @@ typedef struct _ip_fw3_opheader {
#define IP_FW_DUMP_SOPTCODES 116 /* Dump available sopts/versions */
#define IP_FW_DUMP_SRVOBJECTS 117 /* Dump existing named objects */
+#define IP_FW_TABLE_XZEROCNT 118 /* zero table entry counters */
+
#define IP_FW_NAT64STL_CREATE 130 /* Create stateless NAT64 instance */
#define IP_FW_NAT64STL_DESTROY 131 /* Destroy stateless NAT64 instance */
#define IP_FW_NAT64STL_CONFIG 132 /* Modify stateless NAT64 instance */
@@ -884,6 +886,9 @@ typedef struct _ipfw_obj_tentry {
uint8_t spare0;
uint16_t idx; /* Table name index */
uint16_t spare1;
+ uint64_t bcnt; /* Byte counter */
+ uint64_t pcnt; /* Packet counter */
+ time_t timestamp; /* Timestamp of last match */
union {
/* Longest field needs to be aligned by 8-byte boundary */
struct in_addr addr; /* IPv4 address */
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index 5eb9390..ce2ecbf 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -373,7 +373,7 @@ tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd)
static int
iface_match(struct ifnet *ifp, ipfw_insn_if *cmd, struct ip_fw_chain *chain,
- uint32_t *tablearg)
+ uint32_t *tablearg, void **te)
{
if (ifp == NULL) /* no iface with this packet, match fails */
@@ -383,7 +383,7 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd, struct ip_fw_chain *chain,
if (cmd->name[0] != '\0') { /* match by name */
if (cmd->name[0] == '\1') /* use tablearg to match */
return ipfw_lookup_table(chain, cmd->p.kidx, 0,
- &ifp->if_index, tablearg);
+ &ifp->if_index, tablearg, te);
/* Check name */
if (cmd->p.glob) {
if (fnmatch(cmd->name, ifp->if_xname, 0) == 0)
@@ -976,6 +976,12 @@ ipfw_chk(struct ip_fw_args *args)
struct ip_fw_chain *chain = &V_layer3_chain;
/*
+ * Table match pointers.
+ */
+ void *te = NULL; /* table entry */
+ uint16_t tidx, tkeylen;
+
+ /*
* We store in ulp a pointer to the upper layer protocol header.
* In the ipv4 case this is easy to determine from the header,
* but for ipv6 we might have some additional headers in the middle.
@@ -1306,6 +1312,10 @@ do { \
if (V_set_disable & (1 << f->set) )
continue;
+ te = NULL;
+ tidx = 0;
+ tkeylen = 0;
+
skip_or = 0;
for (l = f->cmd_len, cmd = f->cmd ; l > 0 ;
l -= cmdlen, cmd += cmdlen) {
@@ -1374,29 +1384,42 @@ do { \
case O_RECV:
match = iface_match(m->m_pkthdr.rcvif,
- (ipfw_insn_if *)cmd, chain, &tablearg);
+ (ipfw_insn_if *)cmd, chain, &tablearg, &te);
+ if (match && te != NULL) {
+ tkeylen = 0;
+ tidx = ((ipfw_insn_if *)cmd)->p.kidx;
+ }
break;
case O_XMIT:
match = iface_match(oif, (ipfw_insn_if *)cmd,
- chain, &tablearg);
+ chain, &tablearg, &te);
+ if (match && te != NULL) {
+ tkeylen = 0;
+ tidx = ((ipfw_insn_if *)cmd)->p.kidx;
break;
case O_VIA:
match = iface_match(oif ? oif :
m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd,
- chain, &tablearg);
+ chain, &tablearg, &te);
+ if (match && te != NULL) {
+ tkeylen = 0;
+ tidx = ((ipfw_insn_if *)cmd)->p.kidx;
break;
case O_MACADDR2_LOOKUP:
if (args->eh != NULL) { /* have MAC header */
uint32_t v = 0;
- match = ipfw_lookup_table_extended(chain,
- cmd->arg1, 0, args->eh, &v);
+ match = ipfw_lookup_table(chain,
+ cmd->arg1, 0, args->eh, &v, &te);
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
match = ((ipfw_insn_u32 *)cmd)->d[0] == v;
- if (match)
+ if (match) {
tablearg = v;
+ tkeylen = 0;
+ tidx = cmd->arg1;
+ }
}
break;
@@ -1543,10 +1566,13 @@ do { \
else
break;
match = ipfw_lookup_table(chain,
- cmd->arg1, keylen, pkey, &vidx);
+ cmd->arg1, keylen, pkey, &vidx,
+ &te);
if (!match)
break;
tablearg = vidx;
+ tidx = cmd->arg1;
+ tkeylen = keylen;
break;
}
/* cmdlen =< F_INSN_SIZE(ipfw_insn_u32) */
@@ -1573,7 +1599,7 @@ do { \
} else
break;
match = ipfw_lookup_table(chain, cmd->arg1,
- keylen, pkey, &vidx);
+ keylen, pkey, &vidx, &te);
if (!match)
break;
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) {
@@ -1583,6 +1609,8 @@ do { \
break;
}
tablearg = vidx;
+ tidx = cmd->arg1;
+ tkeylen = keylen;
break;
}
@@ -1590,12 +1618,15 @@ do { \
{
uint32_t v = 0;
match = ipfw_lookup_table(chain,
- cmd->arg1, 0, &args->f_id, &v);
+ cmd->arg1, 0, &args->f_id, &v, &te);
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
match = ((ipfw_insn_u32 *)cmd)->d[0] ==
TARG_VAL(chain, v, tag);
- if (match)
+ if (match) {
tablearg = v;
+ tidx = cmd->arg1;
+ tkeylen = 0;
+ }
}
break;
case O_IP_SRC_MASK:
@@ -2266,11 +2297,19 @@ do { \
case O_COUNT:
IPFW_INC_RULE_COUNTER(f, pktlen);
+ if (te != NULL) {
+ ipfw_cnt_update_tentry(chain, tidx,
+ tkeylen, te, pktlen);
+ }
l = 0; /* exit inner loop */
break;
case O_SKIPTO:
IPFW_INC_RULE_COUNTER(f, pktlen);
+ if (te != NULL) {
+ ipfw_cnt_update_tentry(chain, tidx,
+ tkeylen, te, pktlen);
+ }
f_pos = JUMP(chain, f, cmd->arg1, tablearg, 0);
/*
* Skip disabled rules, and re-enter
@@ -2347,6 +2386,10 @@ do { \
}
IPFW_INC_RULE_COUNTER(f, pktlen);
+ if (te != NULL) {
+ ipfw_cnt_update_tentry(chain, tidx,
+ tkeylen, te, pktlen);
+ }
stack = (uint16_t *)(mtag + 1);
/*
@@ -2512,6 +2555,10 @@ do { \
uint32_t fib;
IPFW_INC_RULE_COUNTER(f, pktlen);
+ if (te != NULL) {
+ ipfw_cnt_update_tentry(chain, tidx,
+ tkeylen, te, pktlen);
+ }
fib = TARG(cmd->arg1, fib) & 0x7FFF;
if (fib >= rt_numfibs)
fib = 0;
@@ -2545,6 +2592,10 @@ do { \
break;
IPFW_INC_RULE_COUNTER(f, pktlen);
+ if (te != NULL) {
+ ipfw_cnt_update_tentry(chain, tidx,
+ tkeylen, te, pktlen);
+ }
break;
}
@@ -2584,6 +2635,10 @@ do { \
int ip_off;
IPFW_INC_RULE_COUNTER(f, pktlen);
+ if (te != NULL) {
+ ipfw_cnt_update_tentry(chain, tidx,
+ tkeylen, te, pktlen);
+ }
l = 0; /* in any case exit inner loop */
ip_off = ntohs(ip->ip_off);
@@ -2625,6 +2680,10 @@ do { \
*/
if (retval == 0 && done == 0) {
IPFW_INC_RULE_COUNTER(f, pktlen);
+ if (te != NULL) {
+ ipfw_cnt_update_tentry(chain,
+ tidx, tkeylen, te, pktlen);
+ }
/*
* Reset the result of the last
* dynamic state lookup.
@@ -2668,6 +2727,10 @@ do { \
struct ip_fw *rule = chain->map[f_pos];
/* Update statistics */
IPFW_INC_RULE_COUNTER(rule, pktlen);
+ if (te != NULL) {
+ ipfw_cnt_update_tentry(chain, tidx, tkeylen, te,
+ pktlen);
+ }
} else {
retval = IP_FW_DENY;
printf("ipfw: ouch!, skip past end of rules, denying packet\n");
diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h
index b6471a0..394b45a 100644
--- a/sys/netpfil/ipfw/ip_fw_private.h
+++ b/sys/netpfil/ipfw/ip_fw_private.h
@@ -735,10 +735,12 @@ int ipfw_run_eaction(struct ip_fw_chain *ch, struct ip_fw_args *args,
struct table_info;
typedef int (table_lookup_t)(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val);
+ uint32_t *val, void **te);
int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
void *paddr, uint32_t *val);
+void ipfw_cnt_update_tentry(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
+ void *e, int pktlen);
struct named_object *ipfw_objhash_lookup_table_kidx(struct ip_fw_chain *ch,
uint16_t kidx);
int ipfw_ref_table(struct ip_fw_chain *ch, ipfw_obj_ntlv *ntlv, uint16_t *kidx);
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
index ed500b1..ac269cd 100644
--- a/sys/netpfil/ipfw/ip_fw_table.c
+++ b/sys/netpfil/ipfw/ip_fw_table.c
@@ -185,6 +185,66 @@ get_table_value(struct ip_fw_chain *ch, struct table_config *tc, uint32_t kidx)
return (&pval[kidx]);
}
+static int
+zero_cnt_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
+ struct sockopt_data *sd)
+{
+ ipfw_obj_tentry *tent;
+ ipfw_obj_header *oh;
+ struct tid_info ti;
+ struct table_config *tc;
+ struct table_algo *ta;
+ struct table_info *kti;
+ struct namedobj_instance *ni;
+ int error;
+ size_t sz;
+
+ /* Check minimum header size */
+ sz = sizeof(*oh) + sizeof(*tent);
+ if (sd->valsize != sz)
+ return (EINVAL);
+
+ oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
+ tent = (ipfw_obj_tentry *)(oh + 1);
+
+ /* Basic length checks for TLVs */
+ if (oh->ntlv.head.length != sizeof(oh->ntlv))
+ return (EINVAL);
+
+ objheader_to_ti(oh, &ti);
+ ti.type = oh->ntlv.type;
+ ti.uidx = tent->idx;
+
+ IPFW_UH_RLOCK(ch);
+ ni = CHAIN_TO_NI(ch);
+
+ /*
+ * Find existing table and check its type .
+ */
+ ta = NULL;
+ if ((tc = find_table(ni, &ti)) == NULL) {
+ IPFW_UH_RUNLOCK(ch);
+ return (ESRCH);
+ }
+
+ /* check table type */
+ if (tc->no.subtype != ti.type) {
+ IPFW_UH_RUNLOCK(ch);
+ return (EINVAL);
+ }
+
+ kti = KIDX_TO_TI(ch, tc->no.kidx);
+ ta = tc->ta;
+
+ if (ta->zero_cnt_tentry == NULL)
+ return (ENOTSUP);
+
+ error = ta->zero_cnt_tentry(tc->astate, kti, tent);
+ IPFW_UH_RUNLOCK(ch);
+
+ return (error);
+}
+
/*
* Checks if we're able to insert/update entry @tei into table
@@ -1665,13 +1725,37 @@ ipfw_unref_table(struct ip_fw_chain *ch, uint16_t kidx)
*/
int
ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
- void *paddr, uint32_t *val)
+ void *paddr, uint32_t *val, void **te)
{
struct table_info *ti;
ti = KIDX_TO_TI(ch, tbl);
- return (ti->lookup(ti, paddr, plen, val));
+ return (ti->lookup(ti, paddr, plen, val, te));
+}
+
+/*
+ * Update the table entry counter.
+ */
+void
+ipfw_cnt_tentry_update(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen,
+ void *e, int pktlen)
+{
+ struct namedobj_instance *ni;
+ struct table_algo *ta;
+ struct table_config *tc;
+ struct table_info *ti;
+
+ ni = CHAIN_TO_NI(ch);
+ tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, tbl);
+ if (tc == NULL)
+ return;
+ ta = tc->ta;
+ if (ta->cnt_tentry == NULL)
+ return;
+
+ ti = KIDX_TO_TI(ch, tbl);
+ ta->cnt_tentry(tc->astate, ti, plen, e, pktlen);
}
/*
@@ -2013,6 +2097,7 @@ struct dump_args {
ta_foreach_f *f;
void *farg;
ipfw_obj_tentry tent;
+ time_t boottime;
};
static int
@@ -2171,6 +2256,7 @@ dump_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
struct tid_info ti;
struct table_config *tc;
struct table_algo *ta;
+ struct timeval boottime;
struct dump_args da;
uint32_t sz;
@@ -2209,6 +2295,8 @@ dump_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
da.ti = KIDX_TO_TI(ch, tc->no.kidx);
da.tc = tc;
da.sd = sd;
+ getboottime(&boottime);
+ da.boottime = boottime.tv_sec;
ta = tc->ta;
@@ -2449,6 +2537,9 @@ dump_table_tentry(void *e, void *arg)
pval = get_table_value(da->ch, da->tc, tent->v.kidx);
ipfw_export_table_value_v1(pval, &tent->v.value);
+ if (tent->timestamp != 0)
+ tent->timestamp += da->boottime;
+
return (0);
}
@@ -3312,6 +3403,7 @@ static struct ipfw_sopt_handler scodes[] = {
{ IP_FW_TABLE_XSWAP, 0, HDIR_SET, swap_table },
{ IP_FW_TABLES_ALIST, 0, HDIR_GET, list_table_algo },
{ IP_FW_TABLE_XGETSIZE, 0, HDIR_GET, get_table_size },
+ { IP_FW_TABLE_XZEROCNT, 0, HDIR_SET, zero_cnt_entry },
};
static int
diff --git a/sys/netpfil/ipfw/ip_fw_table.h b/sys/netpfil/ipfw/ip_fw_table.h
index d657848..5adb488 100644
--- a/sys/netpfil/ipfw/ip_fw_table.h
+++ b/sys/netpfil/ipfw/ip_fw_table.h
@@ -111,6 +111,10 @@ typedef int ta_find_tentry(void *ta_state, struct table_info *ti,
typedef void ta_dump_tinfo(void *ta_state, struct table_info *ti,
ipfw_ta_tinfo *tinfo);
typedef uint32_t ta_get_count(void *ta_state, struct table_info *ti);
+typedef void ta_cnt_tentry(void *ta_state, struct table_info *ti,
+ uint32_t keylen, void *e, int pktlen);
+typedef int ta_zero_cnt_tentry(void *ta_state, struct table_info *ti,
+ ipfw_obj_tentry *tent);
struct table_algo {
char name[16];
@@ -139,6 +143,8 @@ struct table_algo {
ta_print_config *print_config;
ta_dump_tinfo *dump_tinfo;
ta_get_count *get_count;
+ ta_cnt_tentry *cnt_tentry;
+ ta_zero_cnt_tentry *zero_cnt_tentry;
};
#define TA_FLAG_DEFAULT 0x01 /* Algo is default for given type */
#define TA_FLAG_READONLY 0x02 /* Algo does not support modifications*/
diff --git a/sys/netpfil/ipfw/ip_fw_table_algo.c b/sys/netpfil/ipfw/ip_fw_table_algo.c
index 0444e2a..dab6640 100644
--- a/sys/netpfil/ipfw/ip_fw_table_algo.c
+++ b/sys/netpfil/ipfw/ip_fw_table_algo.c
@@ -330,6 +330,9 @@ struct radix_addr_entry {
struct radix_node rn[2];
struct sockaddr_in addr;
uint32_t value;
+ uint64_t bcnt;
+ uint64_t pcnt;
+ time_t timestamp;
uint8_t masklen;
};
@@ -344,6 +347,9 @@ struct radix_addr_xentry {
struct radix_node rn[2];
struct sa_in6 addr6;
uint32_t value;
+ uint64_t bcnt;
+ uint64_t pcnt;
+ time_t timestamp;
uint8_t masklen;
};
@@ -372,7 +378,7 @@ struct ta_buf_radix
};
static int ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val);
+ uint32_t *val, void **te);
static int ta_init_radix(struct ip_fw_chain *ch, void **ta_state,
struct table_info *ti, char *data, uint8_t tflags);
static int flush_radix_entry(struct radix_node *rn, void *arg);
@@ -399,10 +405,14 @@ static void ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei
void *ta_buf);
static int ta_need_modify_radix(void *ta_state, struct table_info *ti,
uint32_t count, uint64_t *pflags);
+static void ta_cnt_radix_tentry(void *ta_state, struct table_info *ti,
+ uint32_t keylen, void *e, int pktlen);
+static int ta_zero_cnt_radix_tentry(void *ta_state, struct table_info *ti,
+ ipfw_obj_tentry *tent);
static int
ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val)
+ uint32_t *val, void **te)
{
struct radix_node_head *rnh;
@@ -415,6 +425,8 @@ ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
ent = (struct radix_addr_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh));
if (ent != NULL) {
*val = ent->value;
+ if (te != NULL)
+ *te = (void *)ent;
return (1);
}
} else {
@@ -426,6 +438,8 @@ ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
xent = (struct radix_addr_xentry *)(rnh->rnh_matchaddr(&sa6, &rnh->rh));
if (xent != NULL) {
*val = xent->value;
+ if (te != NULL)
+ *te = (void *)xent;
return (1);
}
}
@@ -525,6 +539,9 @@ ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e,
tent->masklen = n->masklen;
tent->subtype = AF_INET;
tent->v.kidx = n->value;
+ tent->bcnt = n->bcnt;
+ tent->pcnt = n->pcnt;
+ tent->timestamp = n->timestamp;
#ifdef INET6
} else {
xn = (struct radix_addr_xentry *)e;
@@ -532,6 +549,9 @@ ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e,
tent->masklen = xn->masklen;
tent->subtype = AF_INET6;
tent->v.kidx = xn->value;
+ tent->bcnt = n->bcnt;
+ tent->pcnt = n->pcnt;
+ tent->timestamp = n->timestamp;
#endif
}
@@ -869,6 +889,63 @@ ta_need_modify_radix(void *ta_state, struct table_info *ti, uint32_t count,
return (0);
}
+static void
+ta_cnt_radix_tentry(void *ta_state, struct table_info *ti, uint32_t keylen,
+ void *e, int pktlen)
+{
+
+ if (keylen == sizeof(in_addr_t)) {
+ struct radix_addr_entry *ent;
+ ent = (struct radix_addr_entry *)e;
+ ent->pcnt++;
+ ent->bcnt += pktlen;
+ ent->timestamp = time_uptime;
+ } else {
+ struct radix_addr_xentry *xent;
+ xent = (struct radix_addr_xentry *)e;
+ xent->pcnt++;
+ xent->bcnt += pktlen;
+ xent->timestamp = time_uptime;
+ }
+}
+
+static int
+ta_zero_cnt_radix_tentry(void *ta_state, struct table_info *ti,
+ ipfw_obj_tentry *tent)
+{
+ struct radix_node_head *rnh;
+
+ if (tent->subtype == AF_INET) {
+ struct radix_addr_entry *ent;
+ struct sockaddr_in sa;
+ KEY_LEN(sa) = KEY_LEN_INET;
+ sa.sin_addr.s_addr = tent->k.addr.s_addr;
+ rnh = (struct radix_node_head *)ti->state;
+ ent = (struct radix_addr_entry *)rnh->rnh_matchaddr(&sa,
+ &rnh->rh);
+ if (ent == NULL)
+ return (ENOENT);
+ ent->pcnt = 0;
+ ent->bcnt = 0;
+ ent->timestamp = 0;
+ } else {
+ struct radix_addr_xentry *xent;
+ struct sa_in6 sa6;
+ KEY_LEN(sa6) = KEY_LEN_INET6;
+ memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr));
+ rnh = (struct radix_node_head *)ti->xstate;
+ xent = (struct radix_addr_xentry *)rnh->rnh_matchaddr(&sa6,
+ &rnh->rh);
+ if (xent == NULL)
+ return (ENOENT);
+ xent->pcnt = 0;
+ xent->bcnt = 0;
+ xent->timestamp = 0;
+ }
+
+ return (0);
+}
+
struct table_algo addr_radix = {
.name = "addr:radix",
.type = IPFW_TABLE_ADDR,
@@ -886,6 +963,8 @@ struct table_algo addr_radix = {
.find_tentry = ta_find_radix_tentry,
.dump_tinfo = ta_dump_radix_tinfo,
.need_modify = ta_need_modify_radix,
+ .cnt_tentry = ta_cnt_radix_tentry,
+ .zero_cnt_tentry = ta_zero_cnt_radix_tentry,
};
@@ -928,6 +1007,9 @@ struct chashentry {
SLIST_ENTRY(chashentry) next;
uint32_t value;
uint32_t type;
+ uint64_t bcnt;
+ uint64_t pcnt;
+ time_t timestamp;
union {
uint32_t a4; /* Host format */
struct in6_addr a6; /* Network format */
@@ -952,11 +1034,11 @@ static __inline uint32_t hash_ip6_al(struct in6_addr *addr6, void *key, int mask
int hsize);
#endif
static int ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val);
+ uint32_t *val, void **te);
static int ta_lookup_chash_aligned(struct table_info *ti, void *key,
- uint32_t keylen, uint32_t *val);
+ uint32_t keylen, uint32_t *val, void **te);
static int ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val);
+ uint32_t *val, void **te);
static int chash_parse_opts(struct chash_cfg *cfg, char *data);
static void ta_print_chash_config(void *ta_state, struct table_info *ti,
char *buf, size_t bufsize);
@@ -993,7 +1075,10 @@ static int ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf
static void ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf,
uint64_t pflags);
static void ta_flush_mod_chash(void *ta_buf);
-
+static void ta_cnt_chash_tentry(void *ta_state, struct table_info *ti,
+ uint32_t keylen, void *e, int pktlen);
+static int ta_zero_cnt_chash_tentry(void *ta_state, struct table_info *ti,
+ ipfw_obj_tentry *tent);
#ifdef INET
static __inline uint32_t
@@ -1054,7 +1139,7 @@ hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize)
static int
ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val)
+ uint32_t *val, void **te)
{
struct chashbhead *head;
struct chashentry *ent;
@@ -1073,6 +1158,8 @@ ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
SLIST_FOREACH(ent, &head[hash], next) {
if (ent->a.a4 == a) {
*val = ent->value;
+ if (te != NULL)
+ *te = (void *)ent;
return (1);
}
}
@@ -1088,6 +1175,8 @@ ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
SLIST_FOREACH(ent, &head[hash], next) {
if (memcmp(&ent->a.a6, &addr6, 16) == 0) {
*val = ent->value;
+ if (te != NULL)
+ *te = (void *)ent;
return (1);
}
}
@@ -1099,7 +1188,7 @@ ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
static int
ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val)
+ uint32_t *val, void **te)
{
struct chashbhead *head;
struct chashentry *ent;
@@ -1118,6 +1207,8 @@ ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
SLIST_FOREACH(ent, &head[hash], next) {
if (ent->a.a4 == a) {
*val = ent->value;
+ if (te != NULL)
+ *te = (void *)ent;
return (1);
}
}
@@ -1137,6 +1228,8 @@ ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
ptmp = (uint64_t *)&ent->a.a6;
if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) {
*val = ent->value;
+ if (te != NULL)
+ *te = (void *)ent;
return (1);
}
}
@@ -1148,7 +1241,7 @@ ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
static int
ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val)
+ uint32_t *val, void **te)
{
struct chashbhead *head;
struct chashentry *ent;
@@ -1167,6 +1260,8 @@ ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
SLIST_FOREACH(ent, &head[hash], next) {
if (ent->a.a4 == a) {
*val = ent->value;
+ if (te != NULL)
+ *te = (void *)ent;
return (1);
}
}
@@ -1184,6 +1279,8 @@ ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
paddr = (uint64_t *)&ent->a.a6;
if (a6 == *paddr) {
*val = ent->value;
+ if (te != NULL)
+ *te = (void *)ent;
return (1);
}
}
@@ -1381,12 +1478,18 @@ ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e,
tent->masklen = cfg->mask4;
tent->subtype = AF_INET;
tent->v.kidx = ent->value;
+ tent->bcnt = ent->bcnt;
+ tent->pcnt = ent->pcnt;
+ tent->timestamp = ent->timestamp;
#ifdef INET6
} else {
memcpy(&tent->k, &ent->a.a6, sizeof(struct in6_addr));
tent->masklen = cfg->mask6;
tent->subtype = AF_INET6;
tent->v.kidx = ent->value;
+ tent->bcnt = ent->bcnt;
+ tent->pcnt = ent->pcnt;
+ tent->timestamp = ent->timestamp;
#endif
}
@@ -1862,6 +1965,82 @@ ta_flush_mod_chash(void *ta_buf)
free(mi->main_ptr6, M_IPFW);
}
+static void
+ta_cnt_chash_tentry(void *ta_state, struct table_info *ti, uint32_t keylen,
+ void *e, int pktlen)
+{
+ struct chashentry *ent;
+
+ ent = (struct chashentry *)e;
+ ent->pcnt++;
+ ent->bcnt += pktlen;
+ ent->timestamp = time_uptime;
+}
+
+static int
+ta_zero_cnt_chash_tentry(void *ta_state, struct table_info *ti,
+ ipfw_obj_tentry *tent)
+{
+ struct chash_cfg *cfg;
+ struct chashbhead *head;
+ struct chashentry ent, *tmp;
+ struct tentry_info tei;
+ int error;
+ uint32_t hash;
+ bool done;
+
+ cfg = (struct chash_cfg *)ta_state;
+
+ done = false;
+ memset(&ent, 0, sizeof(ent));
+ memset(&tei, 0, sizeof(tei));
+
+ if (tent->subtype == AF_INET) {
+ tei.paddr = &tent->k.addr;
+ tei.masklen = cfg->mask4;
+ tei.subtype = AF_INET;
+
+ if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
+ return (error);
+
+ head = cfg->head4;
+ hash = hash_ent(&ent, AF_INET, cfg->mask4, cfg->size4);
+ /* Check for existence */
+ SLIST_FOREACH(tmp, &head[hash], next) {
+ if (tmp->a.a4 != ent.a.a4)
+ continue;
+ done = true;
+ break;
+ }
+ } else {
+ tei.paddr = &tent->k.addr6;
+ tei.masklen = cfg->mask6;
+ tei.subtype = AF_INET6;
+
+ if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
+ return (error);
+
+ head = cfg->head6;
+ hash = hash_ent(&ent, AF_INET6, cfg->mask6, cfg->size6);
+ /* Check for existence */
+ SLIST_FOREACH(tmp, &head[hash], next) {
+ if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0)
+ continue;
+ done = true;
+ break;
+ }
+ }
+
+ if (!done)
+ return (ENOENT);
+
+ tmp->pcnt = 0;
+ tmp->bcnt = 0;
+ tmp->timestamp = 0;
+
+ return (0);
+}
+
struct table_algo addr_hash = {
.name = "addr:hash",
.type = IPFW_TABLE_ADDR,
@@ -1883,6 +2062,8 @@ struct table_algo addr_hash = {
.fill_mod = ta_fill_mod_chash,
.modify = ta_modify_chash,
.flush_mod = ta_flush_mod_chash,
+ .cnt_tentry = ta_cnt_chash_tentry,
+ .zero_cnt_tentry = ta_zero_cnt_chash_tentry,
};
@@ -1908,6 +2089,9 @@ struct ifidx {
uint16_t kidx;
uint16_t spare;
uint32_t value;
+ uint64_t bcnt;
+ uint64_t pcnt;
+ time_t timestamp;
};
#define DEFAULT_IFIDX_SIZE 64
@@ -1940,7 +2124,7 @@ struct ta_buf_ifidx
int compare_ifidx(const void *k, const void *v);
static struct ifidx * ifidx_find(struct table_info *ti, void *key);
static int ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val);
+ uint32_t *val, void **te);
static int ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state,
struct table_info *ti, char *data, uint8_t tflags);
static void ta_change_ti_ifidx(void *ta_state, struct table_info *ti);
@@ -1976,6 +2160,10 @@ static int foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
void *arg);
static void ta_foreach_ifidx(void *ta_state, struct table_info *ti,
ta_foreach_f *f, void *arg);
+static void ta_cnt_ifidx_tentry(void *ta_state, struct table_info *ti,
+ uint32_t keylen, void *e, int pktlen);
+static int ta_zero_cnt_ifidx_tentry(void *ta_state, struct table_info *ti,
+ ipfw_obj_tentry *tent);
int
compare_ifidx(const void *k, const void *v)
@@ -2082,7 +2270,7 @@ ifidx_find(struct table_info *ti, void *key)
static int
ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val)
+ uint32_t *val, void **te)
{
struct ifidx *ifi;
@@ -2090,6 +2278,8 @@ ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
if (ifi != NULL) {
*val = ifi->value;
+ if (te != NULL)
+ *te = ifi;
return (1);
}
@@ -2397,6 +2587,9 @@ if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex)
ifi.kidx = ifindex;
ifi.spare = 0;
ifi.value = ife->value;
+ ifi.bcnt = 0;
+ ifi.pcnt = 0;
+ ifi.timestamp = 0;
res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used,
sizeof(struct ifidx), compare_ifidx);
KASSERT(res == 1, ("index %d already exists", ifindex));
@@ -2525,6 +2718,7 @@ ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
ipfw_obj_tentry *tent)
{
struct ifentry *ife;
+ struct ifidx *ifi;
ife = (struct ifentry *)e;
@@ -2532,6 +2726,13 @@ ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
memcpy(&tent->k, ife->no.name, IF_NAMESIZE);
tent->v.kidx = ife->value;
+ ifi = ifidx_find(ti, &ife->ic.iface->ifindex);
+ if (ifi != NULL) {
+ tent->bcnt = ifi->bcnt;
+ tent->pcnt = ifi->pcnt;
+ tent->timestamp = ifi->timestamp;
+ }
+
return (0);
}
@@ -2593,6 +2794,47 @@ ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f,
ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa);
}
+static void
+ta_cnt_ifidx_tentry(void *ta_state, struct table_info *ti, uint32_t keylen,
+ void *e, int pktlen)
+{
+ struct ifidx *ifi;
+
+ ifi = (struct ifidx *)e;
+ ifi->pcnt++;
+ ifi->bcnt += pktlen;
+ ifi->timestamp = time_uptime;
+}
+
+static int
+ta_zero_cnt_ifidx_tentry(void *ta_state, struct table_info *ti,
+ ipfw_obj_tentry *tent)
+{
+ struct iftable_cfg *icfg;
+ struct ifentry *ife;
+ struct ifidx *ifi;
+ char *ifname;
+
+ icfg = (struct iftable_cfg *)ta_state;
+ ifname = tent->k.iface;
+
+ if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
+ return (EINVAL);
+
+ ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
+ if (ife == NULL)
+ return (ENOENT);
+
+ ifi = ifidx_find(ti, &ife->ic.iface->ifindex);
+ if (ifi == NULL)
+ return (ENOENT);
+ ifi->pcnt = 0;
+ ifi->bcnt = 0;
+ ifi->timestamp = 0;
+
+ return (0);
+}
+
struct table_algo iface_idx = {
.name = "iface:array",
.type = IPFW_TABLE_INTERFACE,
@@ -2615,6 +2857,8 @@ struct table_algo iface_idx = {
.modify = ta_modify_ifidx,
.flush_mod = ta_flush_mod_ifidx,
.change_ti = ta_change_ti_ifidx,
+ .cnt_tentry = ta_cnt_ifidx_tentry,
+ .zero_cnt_tentry = ta_zero_cnt_ifidx_tentry,
};
/*
@@ -2632,6 +2876,9 @@ struct table_algo iface_idx = {
struct numarray {
uint32_t number;
uint32_t value;
+ uint64_t bcnt;
+ uint64_t pcnt;
+ time_t timestamp;
};
struct numarray_cfg {
@@ -2648,7 +2895,7 @@ struct ta_buf_numarray
int compare_numarray(const void *k, const void *v);
static struct numarray *numarray_find(struct table_info *ti, void *key);
static int ta_lookup_numarray(struct table_info *ti, void *key,
- uint32_t keylen, uint32_t *val);
+ uint32_t keylen, uint32_t *val, void **te);
static int ta_init_numarray(struct ip_fw_chain *ch, void **ta_state,
struct table_info *ti, char *data, uint8_t tflags);
static void ta_destroy_numarray(void *ta_state, struct table_info *ti);
@@ -2676,6 +2923,10 @@ static int ta_find_numarray_tentry(void *ta_state, struct table_info *ti,
ipfw_obj_tentry *tent);
static void ta_foreach_numarray(void *ta_state, struct table_info *ti,
ta_foreach_f *f, void *arg);
+static void ta_cnt_numarray_tentry(void *ta_state, struct table_info *ti,
+ uint32_t keylen, void *e, int pktlen);
+static int ta_zero_cnt_numarray_tentry(void *ta_state, struct table_info *ti,
+ ipfw_obj_tentry *tent);
int
compare_numarray(const void *k, const void *v)
@@ -2707,7 +2958,7 @@ numarray_find(struct table_info *ti, void *key)
static int
ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val)
+ uint32_t *val, void **te)
{
struct numarray *ri;
@@ -2715,6 +2966,8 @@ ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen,
if (ri != NULL) {
*val = ri->value;
+ if (te != NULL)
+ *te = ri;
return (1);
}
@@ -2988,6 +3241,9 @@ ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e,
tent->k.key = na->number;
tent->v.kidx = na->value;
+ tent->bcnt = na->bcnt;
+ tent->pcnt = na->pcnt;
+ tent->timestamp = na->timestamp;
return (0);
}
@@ -3026,6 +3282,37 @@ ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f,
f(&array[i], arg);
}
+static void
+ta_cnt_numarray_tentry(void *ta_state, struct table_info *ti, uint32_t keylen,
+ void *e, int pktlen)
+{
+ struct numarray *na;
+
+ na = (struct numarray *)e;
+ na->pcnt++;
+ na->bcnt += pktlen;
+ na->timestamp = time_uptime;
+}
+
+static int
+ta_zero_cnt_numarray_tentry(void *ta_state, struct table_info *ti,
+ ipfw_obj_tentry *tent)
+{
+ struct numarray_cfg *cfg;
+ struct numarray *na;
+
+ cfg = (struct numarray_cfg *)ta_state;
+
+ na = numarray_find(ti, &tent->k.key);
+ if (na == NULL)
+ return (ENOENT);
+ na->pcnt = 0;
+ na->bcnt = 0;
+ na->timestamp = 0;
+
+ return (0);
+}
+
struct table_algo number_array = {
.name = "number:array",
.type = IPFW_TABLE_NUMBER,
@@ -3046,6 +3333,8 @@ struct table_algo number_array = {
.fill_mod = ta_fill_mod_numarray,
.modify = ta_modify_numarray,
.flush_mod = ta_flush_mod_numarray,
+ .cnt_tentry = ta_cnt_numarray_tentry,
+ .zero_cnt_tentry = ta_zero_cnt_numarray_tentry,
};
/*
@@ -3080,6 +3369,9 @@ struct fhashentry {
uint16_t dport;
uint16_t sport;
uint32_t value;
+ uint64_t bcnt;
+ uint64_t pcnt;
+ time_t timestamp;
uint32_t spare1;
};
@@ -3114,7 +3406,7 @@ static __inline uint32_t hash_flow4(struct fhashentry4 *f, int hsize);
static __inline uint32_t hash_flow6(struct fhashentry6 *f, int hsize);
static uint32_t hash_flow_ent(struct fhashentry *ent, uint32_t size);
static int ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val);
+ uint32_t *val, void **te);
static int ta_init_fhash(struct ip_fw_chain *ch, void **ta_state,
struct table_info *ti, char *data, uint8_t tflags);
static void ta_destroy_fhash(void *ta_state, struct table_info *ti);
@@ -3145,6 +3437,10 @@ static int ta_fill_mod_fhash(void *ta_state, struct table_info *ti,
static void ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
uint64_t pflags);
static void ta_flush_mod_fhash(void *ta_buf);
+static void ta_cnt_fhash_tentry(void *ta_state, struct table_info *ti,
+ uint32_t keylen, void *e, int pktlen);
+static int ta_zero_cnt_fhash_tentry(void *ta_state, struct table_info *ti,
+ ipfw_obj_tentry *tent);
static __inline int
cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz)
@@ -3200,7 +3496,7 @@ hash_flow_ent(struct fhashentry *ent, uint32_t size)
static int
ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val)
+ uint32_t *val, void **te)
{
struct fhashbhead *head;
struct fhashentry *ent;
@@ -3228,6 +3524,8 @@ ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
SLIST_FOREACH(ent, &head[hash], next) {
if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) {
*val = ent->value;
+ if (te != NULL)
+ *te = ent;
return (1);
}
}
@@ -3253,6 +3551,8 @@ ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
SLIST_FOREACH(ent, &head[hash], next) {
if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) {
*val = ent->value;
+ if (te != NULL)
+ *te = ent;
return (1);
}
}
@@ -3375,6 +3675,9 @@ ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e,
tfe->sport = htons(ent->sport);
tent->v.kidx = ent->value;
tent->subtype = ent->af;
+ tent->bcnt = ent->bcnt;
+ tent->pcnt = ent->pcnt;
+ tent->timestamp = ent->timestamp;
if (ent->af == AF_INET) {
fe4 = (struct fhashentry4 *)ent;
@@ -3752,6 +4055,65 @@ ta_flush_mod_fhash(void *ta_buf)
free(mi->main_ptr, M_IPFW);
}
+static void
+ta_cnt_fhash_tentry(void *ta_state, struct table_info *ti, uint32_t keylen,
+ void *e, int pktlen)
+{
+ struct fhashentry *ent;
+
+ ent = (struct fhashentry *)e;
+ ent->pcnt++;
+ ent->bcnt += pktlen;
+ ent->timestamp = time_uptime;
+}
+
+static int
+ta_zero_cnt_fhash_tentry(void *ta_state, struct table_info *ti,
+ ipfw_obj_tentry *tent)
+{
+ struct fhash_cfg *cfg;
+ struct fhashbhead *head;
+ struct fhashentry *ent, *tmp;
+ struct fhashentry6 fe6;
+ struct tentry_info tei;
+ int error;
+ uint32_t hash;
+ size_t sz;
+
+ cfg = (struct fhash_cfg *)ta_state;
+
+ ent = &fe6.e;
+
+ memset(&fe6, 0, sizeof(fe6));
+ memset(&tei, 0, sizeof(tei));
+
+ tei.paddr = &tent->k.flow;
+ tei.subtype = tent->subtype;
+
+ if ((error = tei_to_fhash_ent(&tei, ent)) != 0)
+ return (error);
+
+ head = cfg->head;
+ hash = hash_flow_ent(ent, cfg->size);
+
+ if (tei.subtype == AF_INET)
+ sz = 2 * sizeof(struct in_addr);
+ else
+ sz = 2 * sizeof(struct in6_addr);
+
+ /* Check for existence */
+ SLIST_FOREACH(tmp, &head[hash], next) {
+ if (cmp_flow_ent(tmp, ent, sz) != 0) {
+ ent->pcnt = 0;
+ ent->bcnt = 0;
+ ent->timestamp = 0;
+ return (0);
+ }
+ }
+
+ return (ENOENT);
+}
+
struct table_algo flow_hash = {
.name = "flow:hash",
.type = IPFW_TABLE_FLOW,
@@ -3773,6 +4135,8 @@ struct table_algo flow_hash = {
.fill_mod = ta_fill_mod_fhash,
.modify = ta_modify_fhash,
.flush_mod = ta_flush_mod_fhash,
+ .cnt_tentry = ta_cnt_fhash_tentry,
+ .zero_cnt_tentry = ta_zero_cnt_fhash_tentry,
};
/*
@@ -3787,7 +4151,7 @@ struct table_algo flow_hash = {
*/
static int ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val);
+ uint32_t *val, void **te);
static int kfib_parse_opts(int *pfib, char *data);
static void ta_print_kfib_config(void *ta_state, struct table_info *ti,
char *buf, size_t bufsize);
@@ -3809,7 +4173,7 @@ static void ta_foreach_kfib(void *ta_state, struct table_info *ti,
static int
ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val)
+ uint32_t *val, void **te)
{
#ifdef INET
struct nhop4_basic nh4;
@@ -3838,6 +4202,8 @@ ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
return (0);
*val = 0;
+ if (te != NULL)
+ *te = NULL;
return (1);
}
@@ -4100,9 +4466,12 @@ struct mhash_cfg {
};
struct macdata {
- u_char addr[12]; /* dst[6] + src[6] */
- u_char mask[12]; /* dst[6] + src[6] */
+ u_char addr[12]; /* dst[6] + src[6] */
+ u_char mask[12]; /* dst[6] + src[6] */
uint32_t value;
+ uint64_t bcnt;
+ uint64_t pcnt;
+ time_t timestamp;
};
struct mhashentry {
@@ -4136,15 +4505,20 @@ ta_print_mhash_config(void *ta_state, struct table_info *ti, char *buf,
}
static __inline int
-ta_lookup_find_mhash(struct mhashbhead *head, uint32_t hash2, struct macdata *mac,
- uint32_t *val)
+ta_lookup_find_mhash(struct mhashbhead *head, uint32_t hash2,
+ struct macdata *mac, uint32_t *val, void **te)
{
+ struct macdata any;
struct mhashentry *ent;
+ memset(any.addr, 0, sizeof(any.addr));
SLIST_FOREACH(ent, &head[hash2], next) {
- if (memcmp(&ent->mac->addr, mac->addr, sizeof(mac->addr)) != 0)
+ if (memcmp(&ent->mac->addr, any.addr, sizeof(any.addr)) != 0 &&
+ memcmp(&ent->mac->addr, mac->addr, sizeof(mac->addr)) != 0)
continue;
*val = ent->mac->value;
+ if (te != NULL)
+ *te = (void *)ent;
return (1);
}
@@ -4153,7 +4527,7 @@ ta_lookup_find_mhash(struct mhashbhead *head, uint32_t hash2, struct macdata *ma
static int
ta_lookup_mhash(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val)
+ uint32_t *val, void **te)
{
struct macdata mac;
struct mhashbhead *head;
@@ -4166,21 +4540,22 @@ ta_lookup_mhash(struct table_info *ti, void *key, uint32_t keylen,
head = (struct mhashbhead *)ti->state;
hsize = 1 << (ti->data & 0xFF);
hash2 = hash_mac2(key, hsize);
- if (ta_lookup_find_mhash(head, hash2, (struct macdata *)key, val) == 1)
+ if (ta_lookup_find_mhash(head, hash2,
+ (struct macdata *)key, val, te) == 1)
return (1);
/* src any */
memcpy(mac.addr, key, 6);
memset(mac.addr + 6, 0, 6);
hash2 = hash_mac2(mac.addr, hsize);
- if (ta_lookup_find_mhash(head, hash2, &mac, val) == 1)
+ if (ta_lookup_find_mhash(head, hash2, &mac, val, te) == 1)
return (1);
/* dst any */
memset(mac.addr, 0, 6);
memcpy(mac.addr + 6, (uintptr_t *)key + 6, 6);
hash2 = hash_mac2(mac.addr, hsize);
- if (ta_lookup_find_mhash(head, hash2, &mac, val) == 1)
+ if (ta_lookup_find_mhash(head, hash2, &mac, val, te) == 1)
return (1);
return (0);
@@ -4253,10 +4628,13 @@ ta_dump_mhash_tentry(void *ta_state, struct table_info *ti, void *e,
cfg = (struct mhash_cfg *)ta_state;
mac = ((struct mhashentry *)e)->mac;
- memcpy(&tent->k.mac, mac->addr, sizeof(*mac) - sizeof(uint32_t));
+ memcpy(&tent->k.mac, mac->addr, sizeof(mac->addr) + sizeof(mac->mask));
tent->masklen = ETHER_ADDR_LEN * 8;
tent->subtype = AF_LINK;
tent->v.kidx = mac->value;
+ tent->bcnt = mac->bcnt;
+ tent->pcnt = mac->pcnt;
+ tent->timestamp = mac->timestamp;
return (0);
}
@@ -4267,28 +4645,26 @@ ta_find_mhash_tentry(void *ta_state, struct table_info *ti,
{
struct macdata mac;
struct mhash_cfg *cfg;
- struct mhashentry ent, *tmp;
+ struct mhashentry *ent;
struct tentry_info tei;
uint32_t hash2;
cfg = (struct mhash_cfg *)ta_state;
- memset(&ent, 0, sizeof(ent));
memset(&mac, 0, sizeof(mac));
memset(&tei, 0, sizeof(tei));
tei.paddr = &tent->k.mac;
tei.subtype = AF_LINK;
- ent.mac = &mac;
- memcpy(mac.addr, tei.paddr, sizeof(mac) - sizeof(uint32_t));
+ memcpy(mac.addr, tei.paddr, sizeof(mac.addr) + sizeof(mac.mask));
/* Check for existence */
hash2 = hash_mac2(mac.addr, cfg->size);
- SLIST_FOREACH(tmp, &cfg->head[hash2], next) {
- if (memcmp(&tmp->mac->addr, &mac.addr, sizeof(mac.addr)) != 0)
+ SLIST_FOREACH(ent, &cfg->head[hash2], next) {
+ if (memcmp(&ent->mac->addr, &mac.addr, sizeof(mac.addr)) != 0)
continue;
- ta_dump_mhash_tentry(ta_state, ti, tmp, tent);
+ ta_dump_mhash_tentry(ta_state, ti, ent, tent);
return (0);
}
@@ -4321,11 +4697,9 @@ ta_prepare_add_mhash(struct ip_fw_chain *ch, struct tentry_info *tei,
return (EINVAL);
tb = (struct ta_buf_mhash *)ta_buf;
-
ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
mac = malloc(sizeof(*mac), M_IPFW_TBL, M_WAITOK | M_ZERO);
-
- memcpy(mac->addr, tei->paddr, sizeof(*mac) - sizeof(uint32_t));
+ memcpy(mac->addr, tei->paddr, sizeof(mac->addr) + sizeof(mac->mask));
ent->mac = mac;
tb->ent_ptr = ent;
@@ -4453,6 +4827,52 @@ ta_flush_mhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
}
}
+static void
+ta_cnt_mhash_tentry(void *ta_state, struct table_info *ti, uint32_t keylen,
+ void *e, int pktlen)
+{
+ struct mhashentry *ent;
+
+ ent = (struct mhashentry *)e;
+ ent->mac->pcnt++;
+ ent->mac->bcnt += pktlen;
+ ent->mac->timestamp = time_uptime;
+}
+
+static int
+ta_zero_cnt_mhash_tentry(void *ta_state, struct table_info *ti,
+ ipfw_obj_tentry *tent)
+{
+ struct macdata mac;
+ struct mhash_cfg *cfg;
+ struct mhashentry *ent;
+ struct tentry_info tei;
+ uint32_t hash2;
+
+ cfg = (struct mhash_cfg *)ta_state;
+
+ memset(&mac, 0, sizeof(mac));
+ memset(&tei, 0, sizeof(tei));
+
+ tei.paddr = &tent->k.mac;
+ tei.subtype = AF_LINK;
+
+ memcpy(mac.addr, tei.paddr, sizeof(mac.addr) + sizeof(mac.mask));
+
+ /* Check for existence */
+ hash2 = hash_mac2(mac.addr, cfg->size);
+ SLIST_FOREACH(ent, &cfg->head[hash2], next) {
+ if (memcmp(&ent->mac->addr, &mac.addr, sizeof(mac.addr)) != 0)
+ continue;
+ ent->mac->pcnt = 0;
+ ent->mac->bcnt = 0;
+ ent->mac->timestamp = 0;
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
struct table_algo mac_hash = {
.name = "mac:hash",
.type = IPFW_TABLE_MAC2,
@@ -4470,6 +4890,8 @@ struct table_algo mac_hash = {
.dump_tentry = ta_dump_mhash_tentry,
.find_tentry = ta_find_mhash_tentry,
.dump_tinfo = ta_dump_mhash_tinfo,
+ .cnt_tentry = ta_cnt_mhash_tentry,
+ .zero_cnt_tentry = ta_zero_cnt_mhash_tentry,
};
void
diff --git a/sys/netpfil/ipfw/nat64/nat64stl.c b/sys/netpfil/ipfw/nat64/nat64stl.c
index 3a13aba..a1c34ef 100644
--- a/sys/netpfil/ipfw/nat64/nat64stl.c
+++ b/sys/netpfil/ipfw/nat64/nat64stl.c
@@ -185,7 +185,7 @@ nat64stl_handle_icmp6(struct ip_fw_chain *chain, struct nat64stl_cfg *cfg,
*/
ip6i = mtodo(m, hlen);
if (ipfw_lookup_table(chain, cfg->map64,
- sizeof(struct in6_addr), &ip6i->ip6_dst, &tablearg) == 0) {
+ sizeof(struct in6_addr), &ip6i->ip6_dst, &tablearg, NULL) == 0) {
m_freem(m);
return (NAT64RETURN);
}
@@ -222,11 +222,12 @@ ipfw_nat64stl(struct ip_fw_chain *chain, struct ip_fw_args *args,
case 4:
dst4 = htonl(args->f_id.dst_ip);
ret = ipfw_lookup_table(chain, cfg->map46, sizeof(in_addr_t),
- &dst4, &tablearg);
+ &dst4, &tablearg, NULL);
break;
case 6:
ret = ipfw_lookup_table(chain, cfg->map64,
- sizeof(struct in6_addr), &args->f_id.src_ip6, &tablearg);
+ sizeof(struct in6_addr), &args->f_id.src_ip6,
+ &tablearg, NULL);
break;
default:
return (0);
OpenPOWER on IntegriCloud