summaryrefslogtreecommitdiffstats
path: root/sys/netpfil/ipfw
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netpfil/ipfw')
-rw-r--r--sys/netpfil/ipfw/ip_dn_glue.c4
-rw-r--r--sys/netpfil/ipfw/ip_dn_io.c4
-rw-r--r--sys/netpfil/ipfw/ip_dummynet.c3
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c127
-rw-r--r--sys/netpfil/ipfw/ip_fw_pfil.c145
-rw-r--r--sys/netpfil/ipfw/ip_fw_private.h6
-rw-r--r--sys/netpfil/ipfw/ip_fw_sockopt.c12
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.c121
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.h7
-rw-r--r--sys/netpfil/ipfw/ip_fw_table_algo.c927
-rw-r--r--sys/netpfil/ipfw/nat64/nat64stl.c9
11 files changed, 1252 insertions, 113 deletions
diff --git a/sys/netpfil/ipfw/ip_dn_glue.c b/sys/netpfil/ipfw/ip_dn_glue.c
index 4c4659a..7686155 100644
--- a/sys/netpfil/ipfw/ip_dn_glue.c
+++ b/sys/netpfil/ipfw/ip_dn_glue.c
@@ -164,7 +164,7 @@ struct dn_pipe7 { /* a pipe */
SLIST_ENTRY(dn_pipe7) next; /* linked list in a hash slot */
int pipe_nr ; /* number */
- int bandwidth; /* really, bytes/tick. */
+ uint32_t bandwidth; /* really, bytes/tick. */
int delay ; /* really, ticks */
struct mbuf *head, *tail ; /* packets in delay line */
@@ -230,7 +230,7 @@ struct dn_pipe8 { /* a pipe */
SLIST_ENTRY(dn_pipe8) next; /* linked list in a hash slot */
int pipe_nr ; /* number */
- int bandwidth; /* really, bytes/tick. */
+ uint32_t bandwidth; /* really, bytes/tick. */
int delay ; /* really, ticks */
struct mbuf *head, *tail ; /* packets in delay line */
diff --git a/sys/netpfil/ipfw/ip_dn_io.c b/sys/netpfil/ipfw/ip_dn_io.c
index 7295f7b..5d6ecf7 100644
--- a/sys/netpfil/ipfw/ip_dn_io.c
+++ b/sys/netpfil/ipfw/ip_dn_io.c
@@ -601,7 +601,8 @@ serve_sched(struct mq *q, struct dn_sch_inst *si, uint64_t now)
struct dn_schk *s = si->sched;
struct mbuf *m = NULL;
int delay_line_idle = (si->dline.mq.head == NULL);
- int done, bw;
+ int done;
+ uint32_t bw;
if (q == NULL) {
q = &def_q;
@@ -759,6 +760,7 @@ dummynet_send(struct mbuf *m)
dst = DIR_DROP;
} else {
dst = pkt->dn_dir;
+ pkt->rule.info |= IPFW_IS_DUMMYNET;
ifp = pkt->ifp;
tag->m_tag_cookie = MTAG_IPFW_RULE;
tag->m_tag_id = 0;
diff --git a/sys/netpfil/ipfw/ip_dummynet.c b/sys/netpfil/ipfw/ip_dummynet.c
index 7240a99..9fdcc13 100644
--- a/sys/netpfil/ipfw/ip_dummynet.c
+++ b/sys/netpfil/ipfw/ip_dummynet.c
@@ -153,7 +153,7 @@ ipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg)
op = "Clamp";
} else
return *v;
- if (op && msg)
+ if (op && msg && bootverbose)
printf("%s %s to %d (was %d)\n", op, msg, *v, oldv);
return *v;
}
@@ -2682,7 +2682,6 @@ static moduledata_t dummynet_mod = {
#define DN_SI_SUB SI_SUB_PROTO_FIREWALL
#define DN_MODEV_ORD (SI_ORDER_ANY - 128) /* after ipfw */
DECLARE_MODULE(dummynet, dummynet_mod, DN_SI_SUB, DN_MODEV_ORD);
-MODULE_DEPEND(dummynet, ipfw, 3, 3, 3);
MODULE_VERSION(dummynet, 3);
/*
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index 64cb3d3..12762ef 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -376,7 +376,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 */
@@ -386,7 +386,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, NULL, te);
/* Check name */
if (cmd->p.glob) {
if (fnmatch(cmd->name, ifp->if_xname, 0) == 0)
@@ -1390,6 +1390,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.
@@ -1746,11 +1752,17 @@ do { \
uint32_t tablearg = 0;
int l, cmdlen, skip_or; /* skip rest of OR block */
struct ip_fw *f;
+ uint8_t *ea;
f = chain->map[f_pos];
if (V_set_disable & (1 << f->set) )
continue;
+ ea = NULL;
+ te = NULL;
+ tidx = 0;
+ tkeylen = 0;
+
skip_or = 0;
for (l = f->cmd_len, cmd = f->cmd ; l > 0 ;
l -= cmdlen, cmd += cmdlen) {
@@ -1819,19 +1831,63 @@ do { \
break;
case O_RECV:
+ {
+ void *ifte = NULL;
+
match = iface_match(m->m_pkthdr.rcvif,
- (ipfw_insn_if *)cmd, chain, &tablearg);
+ (ipfw_insn_if *)cmd, chain, &tablearg,
+ &ifte);
+ if (match && ifte != NULL) {
+ te = ifte;
+ tkeylen = 0;
+ tidx = ((ipfw_insn_if *)cmd)->p.kidx;
+ }
break;
+ }
case O_XMIT:
+ {
+ void *ifte = NULL;
+
match = iface_match(oif, (ipfw_insn_if *)cmd,
- chain, &tablearg);
+ chain, &tablearg, &ifte);
+ if (match && ifte != NULL) {
+ te = ifte;
+ tkeylen = 0;
+ tidx = ((ipfw_insn_if *)cmd)->p.kidx;
+ }
break;
+ }
case O_VIA:
+ {
+ void *ifte = NULL;
+
match = iface_match(oif ? oif :
m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd,
- chain, &tablearg);
+ chain, &tablearg, &ifte);
+ if (match && ifte != NULL) {
+ te = ifte;
+ 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(chain,
+ cmd->arg1, 0, args->eh, &v, NULL,
+ &te);
+ if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
+ match = ((ipfw_insn_u32 *)cmd)->d[0] == v;
+ if (match) {
+ tablearg = v;
+ tkeylen = 0;
+ tidx = cmd->arg1;
+ }
+ }
break;
case O_MACADDR2:
@@ -1977,11 +2033,16 @@ do { \
#endif /* !USERSPACE */
else
break;
+ if (args->eh != NULL) /* have MAC header */
+ ea = (uint8_t *)args->eh->ether_dhost;
match = ipfw_lookup_table(chain,
- cmd->arg1, keylen, pkey, &vidx);
+ cmd->arg1, keylen, pkey, &vidx,
+ ea, &te);
if (!match)
break;
tablearg = vidx;
+ tidx = cmd->arg1;
+ tkeylen = keylen;
break;
}
/* cmdlen =< F_INSN_SIZE(ipfw_insn_u32) */
@@ -2007,8 +2068,14 @@ do { \
pkey = &args->f_id.src_ip6;
} else
break;
+ if (args->eh != NULL) { /* have MAC header */
+ if (cmd->opcode == O_IP_DST_LOOKUP)
+ ea = (uint8_t *)args->eh->ether_dhost;
+ else
+ ea = (uint8_t *)args->eh->ether_shost;
+ }
match = ipfw_lookup_table(chain, cmd->arg1,
- keylen, pkey, &vidx);
+ keylen, pkey, &vidx, ea, &te);
if (!match)
break;
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) {
@@ -2018,6 +2085,8 @@ do { \
break;
}
tablearg = vidx;
+ tidx = cmd->arg1;
+ tkeylen = keylen;
break;
}
@@ -2025,12 +2094,16 @@ do { \
{
uint32_t v = 0;
match = ipfw_lookup_table(chain,
- cmd->arg1, 0, &args->f_id, &v);
+ cmd->arg1, 0, &args->f_id, &v,
+ NULL, &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:
@@ -2685,11 +2758,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
@@ -2766,6 +2847,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);
/*
@@ -2849,8 +2934,6 @@ do { \
break;
case O_FORWARD_IP:
- if (args->eh) /* not valid on layer2 pkts */
- break;
if (q != f ||
dyn_info.direction == MATCH_FORWARD) {
struct sockaddr_in *sa;
@@ -2910,8 +2993,6 @@ do { \
#ifdef INET6
case O_FORWARD_IP6:
- if (args->eh) /* not valid on layer2 pkts */
- break;
if (q != f ||
dyn_info.direction == MATCH_FORWARD) {
struct sockaddr_in6 *sin6;
@@ -2941,6 +3022,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;
@@ -2974,6 +3059,10 @@ do { \
break;
IPFW_INC_RULE_COUNTER(f, pktlen);
+ if (te != NULL) {
+ ipfw_cnt_update_tentry(chain, tidx,
+ tkeylen, te, pktlen);
+ }
break;
}
@@ -3020,6 +3109,10 @@ do { \
if (is_ipv6) /* IPv6 is not supported yet */
break;
IPFW_INC_RULE_COUNTER(f, pktlen);
+ if (te != NULL) {
+ ipfw_cnt_update_tentry(chain, tidx,
+ tkeylen, te, pktlen);
+ }
ip_off = ntohs(ip->ip_off);
/* if not fragmented, go to next rule */
@@ -3060,6 +3153,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.
@@ -3103,6 +3200,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_pfil.c b/sys/netpfil/ipfw/ip_fw_pfil.c
index 4316526..f014dfb 100644
--- a/sys/netpfil/ipfw/ip_fw_pfil.c
+++ b/sys/netpfil/ipfw/ip_fw_pfil.c
@@ -113,6 +113,74 @@ SYSEND
#endif /* SYSCTL_NODE */
+static int
+ipfw_check_next_hop(struct ip_fw_args *args, int dir, struct mbuf *m)
+{
+ struct m_tag *fwd_tag;
+ size_t len;
+
+#if (!defined(INET6) && !defined(INET))
+ return (EACCES);
+#else
+
+ KASSERT(args->next_hop == NULL || args->next_hop6 == NULL,
+ ("%s: both next_hop=%p and next_hop6=%p not NULL", __func__,
+ args->next_hop, args->next_hop6));
+#ifdef INET6
+ if (args->next_hop6 != NULL)
+ len = sizeof(struct sockaddr_in6);
+#endif
+#ifdef INET
+ if (args->next_hop != NULL)
+ len = sizeof(struct sockaddr_in);
+#endif
+
+ /* Incoming packets should not be tagged so we do not
+ * m_tag_find. Outgoing packets may be tagged, so we
+ * reuse the tag if present.
+ */
+ fwd_tag = (dir == DIR_IN) ? NULL :
+ m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
+ if (fwd_tag != NULL) {
+ m_tag_unlink(m, fwd_tag);
+ } else {
+ fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, len,
+ M_NOWAIT);
+ if (fwd_tag == NULL)
+ return (EACCES);
+ }
+#ifdef INET6
+ if (args->next_hop6 != NULL) {
+ struct sockaddr_in6 *sa6;
+
+ sa6 = (struct sockaddr_in6 *)(fwd_tag + 1);
+ bcopy(args->next_hop6, sa6, len);
+ /*
+ * If nh6 address is link-local we should convert
+ * it to kernel internal form before doing any
+ * comparisons.
+ */
+ if (sa6_embedscope(sa6, V_ip6_use_defzone) != 0)
+ return (EACCES);
+ if (in6_localip(&sa6->sin6_addr))
+ m->m_flags |= M_FASTFWD_OURS;
+ m->m_flags |= M_IP6_NEXTHOP;
+ }
+#endif
+#ifdef INET
+ if (args->next_hop != NULL) {
+ bcopy(args->next_hop, (fwd_tag+1), len);
+ if (in_localip(args->next_hop->sin_addr))
+ m->m_flags |= M_FASTFWD_OURS;
+ m->m_flags |= M_IP_NEXTHOP;
+ }
+#endif
+ m_tag_prepend(m, fwd_tag);
+#endif /* INET || INET6 */
+
+ return (IP_FW_PASS);
+}
+
/*
* The pfilter hook to pass packets to ipfw_chk and then to
* dummynet, divert, netgraph or other modules.
@@ -161,72 +229,7 @@ again:
/* next_hop may be set by ipfw_chk */
if (args.next_hop == NULL && args.next_hop6 == NULL)
break; /* pass */
-#if (!defined(INET6) && !defined(INET))
- ret = EACCES;
-#else
- {
- struct m_tag *fwd_tag;
- size_t len;
-
- KASSERT(args.next_hop == NULL || args.next_hop6 == NULL,
- ("%s: both next_hop=%p and next_hop6=%p not NULL", __func__,
- args.next_hop, args.next_hop6));
-#ifdef INET6
- if (args.next_hop6 != NULL)
- len = sizeof(struct sockaddr_in6);
-#endif
-#ifdef INET
- if (args.next_hop != NULL)
- len = sizeof(struct sockaddr_in);
-#endif
-
- /* Incoming packets should not be tagged so we do not
- * m_tag_find. Outgoing packets may be tagged, so we
- * reuse the tag if present.
- */
- fwd_tag = (dir == DIR_IN) ? NULL :
- m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
- if (fwd_tag != NULL) {
- m_tag_unlink(*m0, fwd_tag);
- } else {
- fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, len,
- M_NOWAIT);
- if (fwd_tag == NULL) {
- ret = EACCES;
- break; /* i.e. drop */
- }
- }
-#ifdef INET6
- if (args.next_hop6 != NULL) {
- struct sockaddr_in6 *sa6;
-
- sa6 = (struct sockaddr_in6 *)(fwd_tag + 1);
- bcopy(args.next_hop6, sa6, len);
- /*
- * If nh6 address is link-local we should convert
- * it to kernel internal form before doing any
- * comparisons.
- */
- if (sa6_embedscope(sa6, V_ip6_use_defzone) != 0) {
- ret = EACCES;
- break;
- }
- if (in6_localip(&sa6->sin6_addr))
- (*m0)->m_flags |= M_FASTFWD_OURS;
- (*m0)->m_flags |= M_IP6_NEXTHOP;
- }
-#endif
-#ifdef INET
- if (args.next_hop != NULL) {
- bcopy(args.next_hop, (fwd_tag+1), len);
- if (in_localip(args.next_hop->sin_addr))
- (*m0)->m_flags |= M_FASTFWD_OURS;
- (*m0)->m_flags |= M_IP_NEXTHOP;
- }
-#endif
- m_tag_prepend(*m0, fwd_tag);
- }
-#endif /* INET || INET6 */
+ ret = ipfw_check_next_hop(&args, dir, *m0);
break;
case IP_FW_DENY:
@@ -368,6 +371,10 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
/* Check result of ipfw_chk() */
switch (i) {
case IP_FW_PASS:
+ /* next_hop may be set by ipfw_chk */
+ if (args.next_hop == NULL && args.next_hop6 == NULL)
+ break; /* pass */
+ ret = ipfw_check_next_hop(&args, dir, *m0);
break;
case IP_FW_DENY:
@@ -505,7 +512,11 @@ ipfw_hook(int onoff, int pf)
hook_func = (pf == AF_LINK) ? ipfw_check_frame : ipfw_check_packet;
- (void) (onoff ? pfil_add_hook : pfil_remove_hook)
+ if (onoff)
+ (void) pfil_add_named_hook
+ (hook_func, NULL, "ipfw", PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh);
+ else
+ (void) pfil_remove_hook
(hook_func, NULL, PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh);
return 0;
diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h
index 6c29505..3762d20 100644
--- a/sys/netpfil/ipfw/ip_fw_private.h
+++ b/sys/netpfil/ipfw/ip_fw_private.h
@@ -761,10 +761,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, uint8_t *ea, void **te);
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, uint8_t *ea, void **te);
+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_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
index 93df4af..724cb07 100644
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
@@ -1880,10 +1880,22 @@ check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci)
goto bad_size;
ci->object_opcodes++;
break;
+
case O_MACADDR2:
if (cmdlen != F_INSN_SIZE(ipfw_insn_mac))
goto bad_size;
break;
+ case O_MACADDR2_LOOKUP:
+ if (cmd->arg1 >= V_fw_tables_max) {
+ printf("ipfw: invalid table number %d\n",
+ cmd->arg1);
+ return (EINVAL);
+ }
+ if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
+ cmdlen != F_INSN_SIZE(ipfw_insn_u32))
+ goto bad_size;
+ ci->object_opcodes++;
+ break;
case O_NOP:
case O_IPID:
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
index 64651c5..de88a10 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
@@ -1029,6 +1089,7 @@ manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
ptei = tei_buf;
ptent = tent;
for (i = 0; i < ctlv->count; i++, ptent++, ptei++) {
+ ptei->mac = ptent->mac;
ptei->paddr = &ptent->k;
ptei->subtype = ptent->subtype;
ptei->masklen = ptent->masklen;
@@ -1089,6 +1150,7 @@ find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
struct table_algo *ta;
struct table_info *kti;
struct table_value *pval;
+ struct timeval boottime;
struct namedobj_instance *ni;
int error;
size_t sz;
@@ -1137,6 +1199,10 @@ find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
if (error == 0) {
pval = get_table_value(ch, tc, tent->v.kidx);
ipfw_export_table_value_v1(pval, &tent->v.value);
+ if (tent->timestamp != 0) {
+ getboottime(&boottime);
+ tent->timestamp += boottime.tv_sec;
+ }
}
IPFW_UH_RUNLOCK(ch);
@@ -1665,13 +1731,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, uint8_t *ea, 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, ea, te));
+}
+
+/*
+ * Update the table entry counter.
+ */
+void
+ipfw_cnt_update_tentry(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);
}
/*
@@ -2011,6 +2101,7 @@ struct dump_args {
ta_foreach_f *f;
void *farg;
ipfw_obj_tentry tent;
+ time_t boottime;
};
static int
@@ -2169,6 +2260,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;
@@ -2207,6 +2299,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;
@@ -2447,6 +2541,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);
}
@@ -2806,6 +2903,15 @@ classify_flow(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
return (0);
}
+static int
+classify_mac(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
+{
+ *puidx = cmd->arg1;
+ *ptype = IPFW_TABLE_MAC2;
+
+ return (0);
+}
+
static void
update_arg1(ipfw_insn *cmd, uint16_t idx)
{
@@ -2957,6 +3063,16 @@ static struct opcode_obj_rewrite opcodes[] = {
.manage_sets = table_manage_sets,
},
{
+ .opcode = O_MACADDR2_LOOKUP,
+ .etlv = IPFW_TLV_TBL_NAME,
+ .classifier = classify_mac,
+ .update = update_arg1,
+ .find_byname = table_findbyname,
+ .find_bykidx = table_findbykidx,
+ .create_object = create_table_compat,
+ .manage_sets = table_manage_sets,
+ },
+ {
.opcode = O_XMIT,
.etlv = IPFW_TLV_TBL_NAME,
.classifier = classify_via,
@@ -3290,6 +3406,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..cf0309c 100644
--- a/sys/netpfil/ipfw/ip_fw_table.h
+++ b/sys/netpfil/ipfw/ip_fw_table.h
@@ -62,6 +62,7 @@ struct tentry_info {
uint8_t subtype;
uint16_t flags; /* record flags */
uint32_t value; /* value index */
+ uint64_t mac;
};
#define TEI_FLAGS_UPDATE 0x0001 /* Add or update rec if exists */
#define TEI_FLAGS_UPDATED 0x0002 /* Entry has been updated */
@@ -111,6 +112,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 +144,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 1fb8075..67dafac 100644
--- a/sys/netpfil/ipfw/ip_fw_table_algo.c
+++ b/sys/netpfil/ipfw/ip_fw_table_algo.c
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <sys/rmlock.h>
#include <sys/socket.h>
#include <sys/queue.h>
+#include <net/ethernet.h>
#include <net/if.h> /* ip_fw.h requires IFNAMSIZ */
#include <net/radix.h>
#include <net/route.h>
@@ -71,7 +72,8 @@ __FBSDID("$FreeBSD$");
* Algo init:
* * struct table_algo has to be filled with:
* name: "type:algoname" format, e.g. "addr:radix". Currently
- * there are the following types: "addr", "iface", "number" and "flow".
+ * there are the following types: "addr", "iface", "mac", "number" and
+ * "flow".
* type: one of IPFW_TABLE_* types
* flags: one or more TA_FLAGS_*
* ta_buf_size: size of structure used to store add/del item state.
@@ -328,6 +330,10 @@ struct radix_addr_entry {
struct radix_node rn[2];
struct sockaddr_in addr;
uint32_t value;
+ uint64_t bcnt;
+ uint64_t mac;
+ uint64_t pcnt;
+ time_t timestamp;
uint8_t masklen;
};
@@ -342,6 +348,10 @@ struct radix_addr_xentry {
struct radix_node rn[2];
struct sa_in6 addr6;
uint32_t value;
+ uint64_t bcnt;
+ uint64_t mac;
+ uint64_t pcnt;
+ time_t timestamp;
uint8_t masklen;
};
@@ -370,7 +380,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, uint8_t *ea, 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);
@@ -397,10 +407,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, uint8_t *ea, void **te)
{
struct radix_node_head *rnh;
@@ -412,7 +426,14 @@ ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
rnh = (struct radix_node_head *)ti->state;
ent = (struct radix_addr_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh));
if (ent != NULL) {
+ if (ent->mac != 0 && ea == NULL)
+ return (0);
+ if (ent->mac != 0 &&
+ memcmp(ea, &ent->mac, ETHER_ADDR_LEN) != 0)
+ return (0);
*val = ent->value;
+ if (te != NULL)
+ *te = (void *)ent;
return (1);
}
} else {
@@ -423,7 +444,14 @@ ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
rnh = (struct radix_node_head *)ti->xstate;
xent = (struct radix_addr_xentry *)(rnh->rnh_matchaddr(&sa6, &rnh->rh));
if (xent != NULL) {
+ if (xent->mac != 0 && ea == NULL)
+ return (0);
+ if (xent->mac != 0 &&
+ memcmp(ea, &xent->mac, ETHER_ADDR_LEN) != 0)
+ return (0);
*val = xent->value;
+ if (te != NULL)
+ *te = (void *)xent;
return (1);
}
}
@@ -523,6 +551,10 @@ 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->mac = n->mac;
+ tent->bcnt = n->bcnt;
+ tent->pcnt = n->pcnt;
+ tent->timestamp = n->timestamp;
#ifdef INET6
} else {
xn = (struct radix_addr_xentry *)e;
@@ -531,6 +563,10 @@ 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->mac = n->mac;
+ tent->bcnt = n->bcnt;
+ tent->pcnt = n->pcnt;
+ tent->timestamp = n->timestamp;
#endif
}
@@ -718,9 +754,11 @@ ta_add_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
/* Save current entry value from @tei */
if (tei->subtype == AF_INET) {
rnh = ti->state;
+ ((struct radix_addr_entry *)tb->ent_ptr)->mac = tei->mac;
((struct radix_addr_entry *)tb->ent_ptr)->value = tei->value;
} else {
rnh = ti->xstate;
+ ((struct radix_addr_xentry *)tb->ent_ptr)->mac = tei->mac;
((struct radix_addr_xentry *)tb->ent_ptr)->value = tei->value;
}
@@ -868,6 +906,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,
@@ -885,6 +980,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,
};
@@ -927,6 +1024,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 */
@@ -951,11 +1051,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, uint8_t *ea, 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, uint8_t *ea, void **te);
static int ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
- uint32_t *val);
+ uint32_t *val, uint8_t *ea, 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);
@@ -992,7 +1092,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
@@ -1053,7 +1156,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, uint8_t *ea, void **te)
{
struct chashbhead *head;
struct chashentry *ent;
@@ -1072,6 +1175,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);
}
}
@@ -1087,6 +1192,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);
}
}
@@ -1098,7 +1205,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, uint8_t *ea, void **te)
{
struct chashbhead *head;
struct chashentry *ent;
@@ -1117,6 +1224,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);
}
}
@@ -1136,6 +1245,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);
}
}
@@ -1147,7 +1258,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, uint8_t *ea, void **te)
{
struct chashbhead *head;
struct chashentry *ent;
@@ -1166,6 +1277,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);
}
}
@@ -1183,6 +1296,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);
}
}
@@ -1380,12 +1495,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.addr6, &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
}
@@ -1861,6 +1982,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,
@@ -1882,6 +2079,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,
};
@@ -1907,6 +2106,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
@@ -1939,7 +2141,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, uint8_t *ea, 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);
@@ -1975,6 +2177,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)
@@ -2081,7 +2287,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, uint8_t *ea, void **te)
{
struct ifidx *ifi;
@@ -2089,6 +2295,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);
}
@@ -2396,6 +2604,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));
@@ -2524,6 +2735,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;
@@ -2531,6 +2743,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);
}
@@ -2592,6 +2811,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,
@@ -2614,6 +2874,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,
};
/*
@@ -2631,6 +2893,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 {
@@ -2647,7 +2912,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, uint8_t *ea, 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);
@@ -2675,6 +2940,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)
@@ -2706,7 +2975,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, uint8_t *ea, void **te)
{
struct numarray *ri;
@@ -2714,6 +2983,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);
}
@@ -2987,6 +3258,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);
}
@@ -3025,6 +3299,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,
@@ -3045,6 +3350,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,
};
/*
@@ -3079,6 +3386,9 @@ struct fhashentry {
uint16_t dport;
uint16_t sport;
uint32_t value;
+ uint64_t bcnt;
+ uint64_t pcnt;
+ time_t timestamp;
uint32_t spare1;
};
@@ -3113,7 +3423,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, uint8_t *ea, 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);
@@ -3144,6 +3454,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)
@@ -3199,7 +3513,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, uint8_t *ea, void **te)
{
struct fhashbhead *head;
struct fhashentry *ent;
@@ -3227,6 +3541,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);
}
}
@@ -3252,6 +3568,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);
}
}
@@ -3374,6 +3692,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;
@@ -3751,6 +4072,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,
@@ -3772,6 +4152,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,
};
/*
@@ -3786,7 +4168,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, uint8_t *ea, 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);
@@ -3808,7 +4190,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, uint8_t *ea, void **te)
{
#ifdef INET
struct nhop4_basic nh4;
@@ -3837,6 +4219,8 @@ ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
return (0);
*val = 0;
+ if (te != NULL)
+ *te = NULL;
return (1);
}
@@ -4080,6 +4464,509 @@ struct table_algo addr_kfib = {
.print_config = ta_print_kfib_config,
};
+/*
+ * mac:hash cmds
+ *
+ * ti->data:
+ * [unused][log2hsize]
+ * [ 24][ 8]
+ *
+ */
+
+struct mhashentry;
+
+SLIST_HEAD(mhashbhead, mhashentry);
+
+struct mhash_cfg {
+ struct mhashbhead *head;
+ size_t size;
+ size_t items;
+};
+
+struct macdata {
+ 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 {
+ SLIST_ENTRY(mhashentry) next;
+ struct macdata *mac;
+};
+
+struct ta_buf_mhash {
+ void *ent_ptr;
+ struct macdata mac;
+};
+
+static __inline uint32_t
+hash_mac2(u_char *mac, int hsize)
+{
+ uint32_t i;
+
+ i = ((mac[2] << 16) | (mac[1] << 8) | (mac[0] << 0)) ^
+ ((mac[5] << 16) | (mac[4] << 8) | (mac[3] << 0)) ^
+ ((mac[8] << 16) | (mac[7] << 8) | (mac[6] << 0)) ^
+ ((mac[11] << 16) | (mac[10] << 8) | (mac[9] << 0));
+
+ return (i % (hsize - 1));
+}
+
+static void
+ta_print_mhash_config(void *ta_state, struct table_info *ti, char *buf,
+ size_t bufsize)
+{
+ snprintf(buf, bufsize, "%s", "mac:hash");
+}
+
+static __inline int
+ta_lookup_find_mhash(struct mhashbhead *head, uint32_t hash2,
+ struct macdata *mac, uint32_t *val, uint8_t *ea, void **te)
+{
+ struct mhashentry *ent;
+
+ SLIST_FOREACH(ent, &head[hash2], next) {
+ if (memcmp(&ent->mac->addr, mac->addr, sizeof(mac->addr)) != 0)
+ continue;
+ *val = ent->mac->value;
+ if (te != NULL)
+ *te = (void *)ent;
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+ta_lookup_mhash(struct table_info *ti, void *key, uint32_t keylen,
+ uint32_t *val, uint8_t *ea, void **te)
+{
+ struct macdata mac;
+ struct mhashbhead *head;
+ uint32_t hash2, hsize;
+
+ /* any any always match. */
+ if (ti->xstate != NULL) {
+ *te = ti->xstate;
+ return (1);
+ }
+
+ /*
+ * Look three times for a MAC is still faster than looking at whole
+ * table (128 entries by default).
+ */
+ 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, ea, 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, ea, te) == 1)
+ return (1);
+
+ /* dst any */
+ memset(mac.addr, 0, 6);
+ memcpy(mac.addr + 6, (uint8_t *)key + 6, 6);
+ hash2 = hash_mac2(mac.addr, hsize);
+ if (ta_lookup_find_mhash(head, hash2, &mac, val, ea, te) == 1)
+ return (1);
+
+ return (0);
+}
+
+static int
+ta_init_mhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
+ char *data, uint8_t tflags)
+{
+ int i;
+ struct mhash_cfg *cfg;
+
+ cfg = malloc(sizeof(struct mhash_cfg), M_IPFW, M_WAITOK | M_ZERO);
+
+ cfg->size = 128;
+ cfg->head = malloc(sizeof(struct mhashbhead) * cfg->size, M_IPFW,
+ M_WAITOK | M_ZERO);
+ for (i = 0; i < cfg->size; i++)
+ SLIST_INIT(&cfg->head[i]);
+ *ta_state = cfg;
+ ti->xstate = NULL;
+ ti->state = cfg->head;
+ ti->data = ta_log2(cfg->size);
+ ti->lookup = ta_lookup_mhash;
+
+ return (0);
+}
+
+static void
+ta_destroy_mhash(void *ta_state, struct table_info *ti)
+{
+ int i;
+ struct mhash_cfg *cfg;
+ struct mhashentry *ent, *ent_next;
+
+ cfg = (struct mhash_cfg *)ta_state;
+
+ for (i = 0; i < cfg->size; i++)
+ SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) {
+ free(ent->mac, M_IPFW_TBL);
+ free(ent, M_IPFW_TBL);
+ }
+
+ free(cfg->head, M_IPFW);
+
+ free(cfg, M_IPFW);
+}
+
+static void
+ta_foreach_mhash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
+ void *arg)
+{
+ struct mhash_cfg *cfg;
+ struct mhashentry *ent, *ent_next;
+ int i;
+
+ cfg = (struct mhash_cfg *)ta_state;
+
+ if (ti->xstate != NULL)
+ f(ti->xstate, arg);
+ for (i = 0; i < cfg->size; i++)
+ SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
+ f(ent, arg);
+}
+
+static int
+ta_dump_mhash_tentry(void *ta_state, struct table_info *ti, void *e,
+ ipfw_obj_tentry *tent)
+{
+ struct macdata *mac;
+ struct mhash_cfg *cfg;
+
+ cfg = (struct mhash_cfg *)ta_state;
+ mac = ((struct mhashentry *)e)->mac;
+
+ 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);
+}
+
+static int
+ta_find_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;
+ u_char any[12];
+
+ 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));
+
+ /* any any */
+ memset(any, 0, sizeof(any));
+ if (memcmp(mac.addr, any, sizeof(mac.addr)) == 0 &&
+ ti->xstate != NULL) {
+ ta_dump_mhash_tentry(ta_state, ti, ti->xstate, tent);
+ return (0);
+ }
+
+ /* 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;
+ ta_dump_mhash_tentry(ta_state, ti, ent, tent);
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+static void
+ta_dump_mhash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
+{
+ struct mhash_cfg *cfg;
+
+ cfg = (struct mhash_cfg *)ta_state;
+
+ tinfo->taclass4 = IPFW_TACLASS_HASH;
+ tinfo->size4 = cfg->size;
+ tinfo->count4 = cfg->items;
+ tinfo->itemsize4 = sizeof(struct mhashentry) + sizeof(struct macdata) -
+ sizeof(void *);
+}
+
+static int
+ta_prepare_add_mhash(struct ip_fw_chain *ch, struct tentry_info *tei,
+ void *ta_buf)
+{
+ struct ta_buf_mhash *tb;
+ struct mhashentry *ent;
+ struct macdata *mac;
+
+ if (tei->subtype != AF_LINK)
+ 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->addr) + sizeof(mac->mask));
+
+ ent->mac = mac;
+ tb->ent_ptr = ent;
+
+ return (0);
+}
+
+static int
+ta_add_mhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
+ void *ta_buf, uint32_t *pnum)
+{
+ int exists;
+ struct macdata *mac;
+ struct mhash_cfg *cfg;
+ struct mhashentry *ent, *tmp;
+ struct ta_buf_mhash *tb;
+ uint32_t hash2, value;
+ u_char any[12];
+
+ cfg = (struct mhash_cfg *)ta_state;
+ tb = (struct ta_buf_mhash *)ta_buf;
+ ent = (struct mhashentry *)tb->ent_ptr;
+ mac = ent->mac;
+ exists = 0;
+
+ /* Read current value from @tei */
+ mac->value = tei->value;
+
+ if (tei->subtype != AF_LINK)
+ return (EINVAL);
+
+ /* any any */
+ memset(any, 0, sizeof(any));
+ if (memcmp(mac->addr, any, sizeof(mac->addr)) == 0) {
+ if (ti->xstate != NULL) {
+ if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
+ return (EEXIST);
+ /* Record already exists. Update value if we're asked to */
+ value = ((struct mhashentry *)ti->xstate)->mac->value;
+ ((struct mhashentry *)ti->xstate)->mac->value = tei->value;
+ tei->value = value;
+ /* Indicate that update has happened instead of addition */
+ tei->flags |= TEI_FLAGS_UPDATED;
+ *pnum = 0;
+ } else {
+ if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
+ return (EFBIG);
+ ti->xstate = ent;
+ tb->ent_ptr = NULL;
+ *pnum = 1;
+
+ /* Update counters */
+ cfg->items++;
+ }
+ return (0);
+ }
+
+ /* 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) {
+ exists = 1;
+ break;
+ }
+ }
+
+ if (exists == 1) {
+ if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
+ return (EEXIST);
+ /* Record already exists. Update value if we're asked to */
+ value = tmp->mac->value;
+ tmp->mac->value = tei->value;
+ tei->value = value;
+ /* Indicate that update has happened instead of addition */
+ tei->flags |= TEI_FLAGS_UPDATED;
+ *pnum = 0;
+ } else {
+ if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
+ return (EFBIG);
+ SLIST_INSERT_HEAD(&cfg->head[hash2], ent, next);
+ tb->ent_ptr = NULL;
+ *pnum = 1;
+
+ /* Update counters */
+ cfg->items++;
+ }
+
+ return (0);
+}
+
+static int
+ta_prepare_del_mhash(struct ip_fw_chain *ch, struct tentry_info *tei,
+ void *ta_buf)
+{
+ struct ta_buf_mhash *tb;
+
+ tb = (struct ta_buf_mhash *)ta_buf;
+
+ memcpy(tb->mac.addr, tei->paddr, sizeof(tb->mac.addr));
+
+ return (0);
+}
+
+static int
+ta_del_mhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
+ void *ta_buf, uint32_t *pnum)
+{
+ struct macdata *mac;
+ struct mhash_cfg *cfg;
+ struct mhashentry *tmp, *tmp_next;
+ struct ta_buf_mhash *tb;
+ uint32_t hash2;
+ u_char any[12];
+
+ cfg = (struct mhash_cfg *)ta_state;
+ tb = (struct ta_buf_mhash *)ta_buf;
+ mac = &tb->mac;
+
+ if (tei->masklen != ETHER_ADDR_LEN * 8)
+ return (EINVAL);
+
+ /* any any */
+ memset(any, 0, sizeof(any));
+ if (memcmp(mac->addr, any, sizeof(mac->addr)) == 0 &&
+ ti->xstate != NULL) {
+ cfg->items--;
+ tb->ent_ptr = ti->xstate;
+ tei->value = ((struct mhashentry *)ti->xstate)->mac->value;
+ ti->xstate = NULL;
+ *pnum = 1;
+ return (0);
+ }
+
+ hash2 = hash_mac2(mac->addr, cfg->size);
+ SLIST_FOREACH_SAFE(tmp, &cfg->head[hash2], next, tmp_next) {
+ if (memcmp(&tmp->mac->addr, &mac->addr, sizeof(mac->addr)) != 0)
+ continue;
+
+ SLIST_REMOVE(&cfg->head[hash2], tmp, mhashentry, next);
+ cfg->items--;
+ tb->ent_ptr = tmp;
+ tei->value = tmp->mac->value;
+ *pnum = 1;
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+static void
+ta_flush_mhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
+ void *ta_buf)
+{
+ struct mhashentry *ent;
+ struct ta_buf_mhash *tb;
+
+ tb = (struct ta_buf_mhash *)ta_buf;
+
+ if (tb->ent_ptr != NULL) {
+ ent = (struct mhashentry *)tb->ent_ptr;
+ free(ent->mac, M_IPFW_TBL);
+ free(tb->ent_ptr, M_IPFW_TBL);
+ tb->ent_ptr = NULL;
+ }
+}
+
+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,
+ .flags = TA_FLAG_DEFAULT,
+ .ta_buf_size = sizeof(struct ta_buf_mhash),
+ .print_config = ta_print_mhash_config,
+ .init = ta_init_mhash,
+ .destroy = ta_destroy_mhash,
+ .prepare_add = ta_prepare_add_mhash,
+ .prepare_del = ta_prepare_del_mhash,
+ .add = ta_add_mhash,
+ .del = ta_del_mhash,
+ .flush_entry = ta_flush_mhash_entry,
+ .foreach = ta_foreach_mhash,
+ .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
ipfw_table_algo_init(struct ip_fw_chain *ch)
{
@@ -4092,6 +4979,7 @@ ipfw_table_algo_init(struct ip_fw_chain *ch)
ipfw_add_table_algo(ch, &addr_radix, sz, &addr_radix.idx);
ipfw_add_table_algo(ch, &addr_hash, sz, &addr_hash.idx);
ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx);
+ ipfw_add_table_algo(ch, &mac_hash, sz, &mac_hash.idx);
ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx);
ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx);
ipfw_add_table_algo(ch, &addr_kfib, sz, &addr_kfib.idx);
@@ -4104,9 +4992,8 @@ ipfw_table_algo_destroy(struct ip_fw_chain *ch)
ipfw_del_table_algo(ch, addr_radix.idx);
ipfw_del_table_algo(ch, addr_hash.idx);
ipfw_del_table_algo(ch, iface_idx.idx);
+ ipfw_del_table_algo(ch, mac_hash.idx);
ipfw_del_table_algo(ch, number_array.idx);
ipfw_del_table_algo(ch, flow_hash.idx);
ipfw_del_table_algo(ch, addr_kfib.idx);
}
-
-
diff --git a/sys/netpfil/ipfw/nat64/nat64stl.c b/sys/netpfil/ipfw/nat64/nat64stl.c
index 87e64ec..bd4b9aa 100644
--- a/sys/netpfil/ipfw/nat64/nat64stl.c
+++ b/sys/netpfil/ipfw/nat64/nat64stl.c
@@ -185,8 +185,8 @@ nat64stl_handle_icmp6(struct ip_fw_chain *chain, struct nat64stl_cfg *cfg,
* IPv4 mapped address.
*/
ip6i = mtodo(m, hlen);
- if (ipfw_lookup_table(chain, cfg->map64,
- sizeof(struct in6_addr), &ip6i->ip6_dst, &tablearg) == 0) {
+ if (ipfw_lookup_table(chain, cfg->map64, sizeof(struct in6_addr),
+ &ip6i->ip6_dst, &tablearg, NULL, NULL) == 0) {
m_freem(m);
return (NAT64RETURN);
}
@@ -223,11 +223,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, 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, NULL);
break;
default:
return (0);
OpenPOWER on IntegriCloud