summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuiz Souza <luiz@netgate.com>2017-07-15 09:05:39 -0500
committerLuiz Souza <luiz@netgate.com>2017-07-15 11:24:41 -0500
commite1d7d4f6c8167b601dfec75902ed603d0b5ef347 (patch)
tree06a9d27860f45cf1973a77ae9ce2b80ab8f6cfcf
parent2a5777d0acaec430d6893f33afc2a1f3b43e6455 (diff)
downloadFreeBSD-src-e1d7d4f6c8167b601dfec75902ed603d0b5ef347.zip
FreeBSD-src-e1d7d4f6c8167b601dfec75902ed603d0b5ef347.tar.gz
Add the timestamp of the last match, packet and byte counters to table
entries with a new ipfw table command to zero the counters. Each table type implementation needs to be modified to add the support to this feature and the FIB backend is the only one that was not modified (because the backend does not have any local storage). (cherry picked from commit 3b06c382c8a2e04b7a64291bfb6b0ca0e5dd8dca) (cherry picked from commit b969fab78206744b1d323f47828125389299e450)
-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