diff options
-rw-r--r-- | sbin/ipfw/ipfw2.h | 1 | ||||
-rw-r--r-- | sbin/ipfw/tables.c | 72 | ||||
-rw-r--r-- | sys/netinet/ip_fw.h | 5 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw2.c | 87 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_private.h | 4 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_table.c | 96 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_table.h | 6 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_table_algo.c | 496 | ||||
-rw-r--r-- | sys/netpfil/ipfw/nat64/nat64stl.c | 7 |
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); |