svn commit: r268440 - in projects/ipfw: sbin/ipfw sys/netinet sys/netpfil/ipfw
Alexander V. Chernikov
melifaro at FreeBSD.org
Tue Jul 8 23:11:17 UTC 2014
Author: melifaro
Date: Tue Jul 8 23:11:15 2014
New Revision: 268440
URL: http://svnweb.freebsd.org/changeset/base/268440
Log:
* Use different rule structures in kernel/userland.
* Switch kernel to use per-cpu counters for rules.
* Keep ABI/API.
Kernel changes:
* Each rules is now exported as TLV with optional extenable
counter block (ip_fW_bcounter for base one) and
ip_fw_rule for rule&cmd data.
* Counters needs to be explicitly requested by IPFW_CFG_GET_COUNTERS flag.
* Separate counters from rules in kernel and clean up ip_fw a bit.
* Pack each rule in IPFW_TLV_RULE_ENT tlv to ease parsing.
* Introduce versioning in container TLV (may be needed in future).
* Fix ipfw_cfg_lheader broken u64 alignment.
Userland changes:
* Use set_mask from cfg header when requesting config
* Fix incorrect read accouting in ipfw_show_config()
* Use IPFW_RULE_NOOPT flag instead of playing with _pad
* Fix "ipfw -d list": do not print counters for dynamic states
* Some small fixes
Modified:
projects/ipfw/sbin/ipfw/ipfw2.c
projects/ipfw/sys/netinet/ip_fw.h
projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h
projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c
projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h
Modified: projects/ipfw/sbin/ipfw/ipfw2.c
==============================================================================
--- projects/ipfw/sbin/ipfw/ipfw2.c Tue Jul 8 23:07:09 2014 (r268439)
+++ projects/ipfw/sbin/ipfw/ipfw2.c Tue Jul 8 23:11:15 2014 (r268440)
@@ -61,6 +61,7 @@ struct format_opts {
int bcwidth;
int pcwidth;
int show_counters;
+ uint32_t set_mask; /* enabled sets mask */
uint32_t flags; /* request flags */
uint32_t first; /* first rule to request */
uint32_t last; /* last rule to request */
@@ -1298,7 +1299,7 @@ show_prerequisites(int *flags, int want,
static void
show_static_rule(struct cmdline_opts *co, struct format_opts *fo,
- struct buf_pr *bp, struct ip_fw *rule)
+ struct buf_pr *bp, struct ip_fw_rule *rule, struct ip_fw_bcounter *cntr)
{
static int twidth = 0;
int l;
@@ -1309,11 +1310,9 @@ show_static_rule(struct cmdline_opts *co
ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */
ipfw_insn_altq *altqptr = NULL; /* set if we find an O_ALTQ */
int or_block = 0; /* we are in an or block */
- uint32_t set_disable;
- bcopy(&rule->next_rule, &set_disable, sizeof(set_disable));
-
- if (set_disable & (1 << rule->set)) { /* disabled */
+ if ((fo->set_mask & (1 << rule->set)) == 0) {
+ /* disabled mask */
if (!co->show_sets)
return;
else
@@ -1321,13 +1320,14 @@ show_static_rule(struct cmdline_opts *co
}
bprintf(bp, "%05u ", rule->rulenum);
+ /* Print counters if enabled */
if (fo->pcwidth > 0 || fo->bcwidth > 0) {
- pr_u64(bp, &rule->pcnt, fo->pcwidth);
- pr_u64(bp, &rule->bcnt, fo->bcwidth);
+ pr_u64(bp, &cntr->pcnt, fo->pcwidth);
+ pr_u64(bp, &cntr->bcnt, fo->bcwidth);
}
if (co->do_time == 2)
- bprintf(bp, "%10u ", rule->timestamp);
+ bprintf(bp, "%10u ", cntr->timestamp);
else if (co->do_time == 1) {
char timestr[30];
time_t t = (time_t)0;
@@ -1337,8 +1337,8 @@ show_static_rule(struct cmdline_opts *co
*strchr(timestr, '\n') = '\0';
twidth = strlen(timestr);
}
- if (rule->timestamp) {
- t = _long_to_time(rule->timestamp);
+ if (cntr->timestamp > 0) {
+ t = _long_to_time(cntr->timestamp);
strcpy(timestr, ctime(&t));
*strchr(timestr, '\n') = '\0';
@@ -1537,7 +1537,7 @@ show_static_rule(struct cmdline_opts *co
/*
* then print the body.
*/
- for (l = rule->act_ofs, cmd = rule->cmd ;
+ for (l = rule->act_ofs, cmd = rule->cmd;
l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
if ((cmd->len & F_OR) || (cmd->len & F_NOT))
continue;
@@ -1549,7 +1549,7 @@ show_static_rule(struct cmdline_opts *co
break;
}
}
- if (rule->_pad & 1) { /* empty rules before options */
+ if (rule->flags & IPFW_RULE_NOOPT) { /* empty rules before options */
if (!co->do_compact) {
show_prerequisites(&flags, HAVE_PROTO, 0);
printf(" from any to any");
@@ -1561,7 +1561,7 @@ show_static_rule(struct cmdline_opts *co
if (co->comment_only)
comment = "...";
- for (l = rule->act_ofs, cmd = rule->cmd ;
+ for (l = rule->act_ofs, cmd = rule->cmd;
l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
/* useful alias */
ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
@@ -2177,6 +2177,9 @@ prepare_format_dyn(struct cmdline_opts *
/* Count _ALL_ states */
fo->dcnt++;
+ if (fo->show_counters == 0)
+ return;
+
if (co->use_set) {
/* skip states from another set */
bcopy((char *)&d->rule + sizeof(uint16_t), &set,
@@ -2237,27 +2240,31 @@ foreach_state(struct cmdline_opts *co, s
static void
prepare_format_opts(struct cmdline_opts *co, struct format_opts *fo,
- struct ip_fw *r, int rcnt, caddr_t base, size_t sz)
+ ipfw_obj_tlv *rtlv, int rcnt, caddr_t dynbase, size_t dynsz)
{
int bcwidth, pcwidth, width;
int n;
-#define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r)))
+ struct ip_fw_bcounter *cntr;
+ struct ip_fw_rule *r;
bcwidth = 0;
pcwidth = 0;
if (fo->show_counters != 0) {
- for (n = 0; n < rcnt; n++, r = NEXT(r)) {
+ for (n = 0; n < rcnt; n++,
+ rtlv = (ipfw_obj_tlv *)((caddr_t)rtlv + rtlv->length)) {
+ cntr = (struct ip_fw_bcounter *)(rtlv + 1);
+ r = (struct ip_fw_rule *)((caddr_t)cntr + cntr->size);
/* skip rules from another set */
if (co->use_set && r->set != co->use_set - 1)
continue;
/* packet counter */
- width = pr_u64(NULL, &r->pcnt, 0);
+ width = pr_u64(NULL, &cntr->pcnt, 0);
if (width > pcwidth)
pcwidth = width;
/* byte counter */
- width = pr_u64(NULL, &r->bcnt, 0);
+ width = pr_u64(NULL, &cntr->bcnt, 0);
if (width > bcwidth)
bcwidth = width;
}
@@ -2266,23 +2273,36 @@ prepare_format_opts(struct cmdline_opts
fo->pcwidth = pcwidth;
fo->dcnt = 0;
- if (co->do_dynamic && sz > 0)
- sz = foreach_state(co, fo, base, sz, prepare_format_dyn, NULL);
+ if (co->do_dynamic && dynsz > 0)
+ foreach_state(co, fo, dynbase, dynsz, prepare_format_dyn, NULL);
}
static int
list_static_range(struct cmdline_opts *co, struct format_opts *fo,
- struct buf_pr *bp, struct ip_fw *r, int rcnt)
+ struct buf_pr *bp, ipfw_obj_tlv *rtlv, int rcnt)
{
int n, seen;
-
- for (n = seen = 0; n < rcnt; n++, r = NEXT(r) ) {
+ struct ip_fw_rule *r;
+ struct ip_fw_bcounter *cntr;
+ int c = 0;
+
+ for (n = seen = 0; n < rcnt; n++,
+ rtlv = (ipfw_obj_tlv *)((caddr_t)rtlv + rtlv->length)) {
+
+ if (fo->show_counters != 0) {
+ cntr = (struct ip_fw_bcounter *)(rtlv + 1);
+ r = (struct ip_fw_rule *)((caddr_t)cntr + cntr->size);
+ } else {
+ cntr = NULL;
+ r = (struct ip_fw_rule *)(rtlv + 1);
+ }
if (r->rulenum > fo->last)
break;
if (co->use_set && r->set != co->use_set - 1)
continue;
if (r->rulenum >= fo->first && r->rulenum <= fo->last) {
- show_static_rule(co, fo, bp, r);
+ show_static_rule(co, fo, bp, r, cntr);
+ c += rtlv->length;
bp_flush(bp);
seen++;
}
@@ -2369,27 +2389,27 @@ ipfw_list(int ac, char *av[], int show_c
/* get configuraion from kernel */
cfg = NULL;
+ sfo.show_counters = show_counters;
sfo.flags = IPFW_CFG_GET_STATIC;
if (co.do_dynamic != 0)
sfo.flags |= IPFW_CFG_GET_STATES;
+ if (sfo.show_counters != 0)
+ sfo.flags |= IPFW_CFG_GET_COUNTERS;
if ((error = ipfw_get_config(&co, &sfo, &cfg, &sz)) != 0)
err(EX_OSERR, "retrieving config failed");
- sfo.show_counters = show_counters;
error = ipfw_show_config(&co, &sfo, cfg, sz, ac, av);
free(cfg);
if (error != EX_OK)
exit(error);
-#undef NEXT
}
static int
ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo,
ipfw_cfg_lheader *cfg, size_t sz, int ac, char *av[])
{
- struct ip_fw *rbase;
caddr_t dynbase;
size_t dynsz;
int rcnt;
@@ -2400,6 +2420,7 @@ ipfw_show_config(struct cmdline_opts *co
size_t read;
struct buf_pr bp;
ipfw_obj_ctlv *ctlv, *tstate;
+ ipfw_obj_tlv *rbase;
/*
* Handle tablenames TLV first, if any
@@ -2408,7 +2429,9 @@ ipfw_show_config(struct cmdline_opts *co
rbase = NULL;
dynbase = NULL;
dynsz = 0;
- read = 0;
+ read = sizeof(*cfg);
+
+ fo->set_mask = cfg->set_mask;
ctlv = (ipfw_obj_ctlv *)(cfg + 1);
@@ -2422,7 +2445,7 @@ ipfw_show_config(struct cmdline_opts *co
}
if (ctlv->head.type == IPFW_TLV_RULE_LIST) {
- rbase = (struct ip_fw *)(ctlv + 1);
+ rbase = (ipfw_obj_tlv *)(ctlv + 1);
rcnt = ctlv->count;
read += ctlv->head.length;
ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv +
@@ -2432,8 +2455,12 @@ ipfw_show_config(struct cmdline_opts *co
if ((cfg->flags & IPFW_CFG_GET_STATES) && (read != sz)) {
/* We may have some dynamic states */
- dynbase = (caddr_t)ctlv;
dynsz = sz - read;
+ /* Skip empty header */
+ if (dynsz != sizeof(ipfw_obj_ctlv))
+ dynbase = (caddr_t)ctlv;
+ else
+ dynsz = 0;
}
prepare_format_opts(co, fo, rbase, rcnt, dynbase, dynsz);
@@ -2446,7 +2473,7 @@ ipfw_show_config(struct cmdline_opts *co
list_static_range(co, fo, &bp, rbase, rcnt);
if (co->do_dynamic && dynsz > 0) {
- printf("## Dynamic rules (%d):\n", fo->dcnt);
+ printf("## Dynamic rules (%d %lu):\n", fo->dcnt, dynsz);
list_dyn_range(co, fo, &bp, dynbase, dynsz);
}
@@ -3304,7 +3331,7 @@ compile_rule(char *av[], uint32_t *rbuf,
ipfw_insn *src, *dst, *cmd, *action, *prev=NULL;
ipfw_insn *first_cmd; /* first match pattern */
- struct ip_fw *rule;
+ struct ip_fw_rule *rule;
/*
* various flags used to record that we entered some fields.
@@ -3326,12 +3353,12 @@ compile_rule(char *av[], uint32_t *rbuf,
bzero(cmdbuf, sizeof(cmdbuf));
bzero(rbuf, *rbufsize);
- rule = (struct ip_fw *)rbuf;
+ rule = (struct ip_fw_rule *)rbuf;
cmd = (ipfw_insn *)cmdbuf;
action = (ipfw_insn *)actbuf;
rblen = *rbufsize / sizeof(uint32_t);
- rblen -= offsetof(struct ip_fw, cmd) / sizeof(uint32_t);
+ rblen -= sizeof(struct ip_fw_rule) / sizeof(uint32_t);
ablen = sizeof(actbuf) / sizeof(actbuf[0]);
cblen = sizeof(cmdbuf) / sizeof(cmdbuf[0]);
cblen -= F_INSN_SIZE(ipfw_insn_u32) + 1;
@@ -3884,7 +3911,7 @@ read_options:
* nothing specified so far, store in the rule to ease
* printout later.
*/
- rule->_pad = 1;
+ rule->flags |= IPFW_RULE_NOOPT;
}
prev = NULL;
while ( av[0] != NULL ) {
@@ -4467,13 +4494,13 @@ done:
* [
* ip_fw3_opheader
* [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional *1)
- * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ] (*2) (*3)
+ * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) [ ip_fw_rule ip_fw_insn ] x N ] (*2) (*3)
* ]
* Reply:
* [
* ip_fw3_opheader
* [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional)
- * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ]
+ * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) [ ip_fw_rule ip_fw_insn ] x N ]
* ]
*
* Rules in reply are modified to store their actual ruleset number.
@@ -4490,7 +4517,7 @@ ipfw_add(char *av[])
int rbufsize, default_off, tlen, rlen;
size_t sz;
struct tidx ts;
- struct ip_fw *rule;
+ struct ip_fw_rule *rule;
caddr_t tbuf;
ip_fw3_opheader *op3;
ipfw_obj_ctlv *ctlv, *tstate;
@@ -4502,7 +4529,7 @@ ipfw_add(char *av[])
default_off = sizeof(ipfw_obj_ctlv) + sizeof(ip_fw3_opheader);
op3 = (ip_fw3_opheader *)rulebuf;
ctlv = (ipfw_obj_ctlv *)(op3 + 1);
- rule = (struct ip_fw *)(ctlv + 1);
+ rule = (struct ip_fw_rule *)(ctlv + 1);
rbufsize -= default_off;
compile_rule(av, (uint32_t *)rule, &rbufsize, &ts);
@@ -4552,8 +4579,9 @@ ipfw_add(char *av[])
struct buf_pr bp;
memset(&sfo, 0, sizeof(sfo));
sfo.tstate = tstate;
+ sfo.set_mask = (uint32_t)(-1);
bp_alloc(&bp, 4096);
- show_static_rule(&co, &sfo, &bp, rule);
+ show_static_rule(&co, &sfo, &bp, rule, NULL);
bp_free(&bp);
}
Modified: projects/ipfw/sys/netinet/ip_fw.h
==============================================================================
--- projects/ipfw/sys/netinet/ip_fw.h Tue Jul 8 23:07:09 2014 (r268439)
+++ projects/ipfw/sys/netinet/ip_fw.h Tue Jul 8 23:11:15 2014 (r268440)
@@ -36,10 +36,8 @@
*/
#define IPFW_DEFAULT_RULE 65535
-/*
- * Number of sets supported by ipfw
- */
-#define IPFW_MAX_SETS 32
+#define RESVD_SET 31 /*set for default and persistent rules*/
+#define IPFW_MAX_SETS 32 /* Number of sets supported by ipfw*/
/*
* Default number of ipfw tables.
@@ -513,15 +511,17 @@ typedef struct _ipfw_insn_icmp6 {
/*
* Here we have the structure representing an ipfw rule.
*
- * It starts with a general area (with link fields and counters)
- * followed by an array of one or more instructions, which the code
- * accesses as an array of 32-bit values.
- *
- * Given a rule pointer r:
+ * Layout:
+ * struct ip_fw_rule
+ * [ counter block, size = rule->cntr_len ]
+ * [ one or more instructions, size = rule->cmd_len * 4 ]
*
- * r->cmd is the start of the first instruction.
- * ACTION_PTR(r) is the start of the first action (things to do
- * once a rule matched).
+ * It starts with a general area (with link fields).
+ * Counter block may be next (if rule->cntr_len > 0),
+ * followed by an array of one or more instructions, which the code
+ * accesses as an array of 32-bit values. rule->cmd_len represents
+ * the total instructions legth in u32 worrd, while act_ofs represents
+ * rule action offset in u32 words.
*
* When assembling instruction, remember the following:
*
@@ -532,11 +532,41 @@ typedef struct _ipfw_insn_icmp6 {
* + if a rule has an "altq" option, it comes after "log"
* + if a rule has an O_TAG option, it comes after "log" and "altq"
*
- * NOTE: we use a simple linked list of rules because we never need
- * to delete a rule without scanning the list. We do not use
- * queue(3) macros for portability and readability.
+ *
+ * All structures (excluding instructions) are u64-aligned.
+ * Please keep this.
*/
+struct ip_fw_rule {
+ uint16_t act_ofs; /* offset of action in 32-bit units */
+ uint16_t cmd_len; /* # of 32-bit words in cmd */
+ uint16_t spare;
+ uint8_t set; /* rule set (0..31) */
+ uint8_t flags; /* rule flags */
+ uint32_t rulenum; /* rule number */
+ uint32_t id; /* rule id */
+
+ ipfw_insn cmd[1]; /* storage for commands */
+};
+#define IPFW_RULE_NOOPT 0x01 /* Has no options in body */
+
+/* Unaligned version */
+
+/* Base ipfw rule counter block. */
+struct ip_fw_bcounter {
+ uint16_t size; /* Size of counter block, bytes */
+ uint8_t flags; /* flags for given block */
+ uint8_t spare;
+ uint32_t timestamp; /* tv_sec of last match */
+ uint64_t pcnt; /* Packet counter */
+ uint64_t bcnt; /* Byte counter */
+};
+
+
+#ifndef _KERNEL
+/*
+ * Legacy rule format
+ */
struct ip_fw {
struct ip_fw *x_next; /* linked list of rules */
struct ip_fw *next_rule; /* ptr to next [skipto] rule */
@@ -546,7 +576,6 @@ struct ip_fw {
uint16_t cmd_len; /* # of 32-bit words in cmd */
uint16_t rulenum; /* rule number */
uint8_t set; /* rule set (0..31) */
-#define RESVD_SET 31 /* set for default and persistent rules */
uint8_t _pad; /* padding */
uint32_t id; /* rule id */
@@ -557,12 +586,13 @@ struct ip_fw {
ipfw_insn cmd[1]; /* storage for commands */
};
+#endif
#define ACTION_PTR(rule) \
(ipfw_insn *)( (u_int32_t *)((rule)->cmd) + ((rule)->act_ofs) )
-#define RULESIZE(rule) (sizeof(struct ip_fw) + \
- ((struct ip_fw *)(rule))->cmd_len * 4 - 4)
+#define RULESIZE(rule) (sizeof(*(rule)) + (rule)->cmd_len * 4 - 4)
+
#if 1 // should be moved to in.h
/*
@@ -698,6 +728,7 @@ typedef struct _ipfw_obj_tlv {
#define IPFW_TLV_DYNSTATE_LIST 4
#define IPFW_TLV_TBL_ENT 5
#define IPFW_TLV_DYN_ENT 6
+#define IPFW_TLV_RULE_ENT 7
/* Object name TLV */
typedef struct _ipfw_obj_ntlv {
@@ -737,7 +768,9 @@ typedef struct _ipfw_obj_dyntlv {
typedef struct _ipfw_obj_ctlv {
ipfw_obj_tlv head; /* TLV header */
uint32_t count; /* Number of sub-TLVs */
- uint32_t objsize; /* Single object size */
+ uint16_t objsize; /* Single object size */
+ uint8_t version; /* TLV version */
+ uint8_t spare;
} ipfw_obj_ctlv;
typedef struct _ipfw_xtable_info {
@@ -772,11 +805,13 @@ typedef struct _ipfw_obj_lheader {
uint32_t objsize; /* Size of one object */
} ipfw_obj_lheader;
-#define IPFW_CFG_GET_STATIC 1
-#define IPFW_CFG_GET_STATES 2
+#define IPFW_CFG_GET_STATIC 0x01
+#define IPFW_CFG_GET_STATES 0x02
+#define IPFW_CFG_GET_COUNTERS 0x04
typedef struct _ipfw_cfg_lheader {
ip_fw3_opheader opheader; /* IP_FW3 opcode */
uint32_t set_mask; /* enabled set mask */
+ uint32_t spare;
uint32_t flags; /* Request flags */
uint32_t size; /* neded buffer size */
uint32_t start_rule;
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Tue Jul 8 23:07:09 2014 (r268439)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Tue Jul 8 23:11:15 2014 (r268440)
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/condvar.h>
+#include <sys/counter.h>
#include <sys/eventhandler.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
@@ -2647,12 +2648,11 @@ vnet_ipfw_init(const void *unused)
LIST_INIT(&chain->nat);
#endif
+ ipfw_init_counters();
/* insert the default rule and create the initial map */
chain->n_rules = 1;
- chain->static_len = sizeof(struct ip_fw);
chain->map = malloc(sizeof(struct ip_fw *), M_IPFW, M_WAITOK | M_ZERO);
- if (chain->map)
- rule = malloc(chain->static_len, M_IPFW, M_WAITOK | M_ZERO);
+ rule = ipfw_alloc_rule(chain, sizeof(struct ip_fw));
/* Set initial number of tables */
V_fw_tables_max = default_fw_tables;
@@ -2673,6 +2673,8 @@ vnet_ipfw_init(const void *unused)
rule->cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY;
chain->default_rule = chain->map[0] = rule;
chain->id = rule->id = 1;
+ /* Pre-calculate rules length for legacy dump format */
+ chain->static_len = sizeof(struct ip_fw_rule0);
IPFW_LOCK_INIT(chain);
ipfw_dyn_init(chain);
@@ -2740,7 +2742,8 @@ vnet_ipfw_uninit(const void *unused)
ipfw_reap_rules(reap);
IPFW_LOCK_DESTROY(chain);
ipfw_dyn_uninit(1); /* free the remaining parts */
- return 0;
+ ipfw_destroy_counters();
+ return (0);
}
/*
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h Tue Jul 8 23:07:09 2014 (r268439)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h Tue Jul 8 23:11:15 2014 (r268440)
@@ -220,6 +220,44 @@ VNET_DECLARE(unsigned int, fw_tables_set
struct tables_config;
+#ifdef _KERNEL
+typedef struct ip_fw_cntr {
+ uint64_t pcnt; /* Packet counter */
+ uint64_t bcnt; /* Byte counter */
+ uint64_t timestamp; /* tv_sec of last match */
+} ip_fw_cntr;
+
+/*
+ * Here we have the structure representing an ipfw rule.
+ *
+ * It starts with a general area
+ * followed by an array of one or more instructions, which the code
+ * accesses as an array of 32-bit values.
+ *
+ * Given a rule pointer r:
+ *
+ * r->cmd is the start of the first instruction.
+ * ACTION_PTR(r) is the start of the first action (things to do
+ * once a rule matched).
+ */
+
+struct ip_fw {
+ uint16_t act_ofs; /* offset of action in 32-bit units */
+ uint16_t cmd_len; /* # of 32-bit words in cmd */
+ uint16_t rulenum; /* rule number */
+ uint8_t set; /* rule set (0..31) */
+ uint8_t flags; /* currently unused */
+ counter_u64_t cntr; /* Pointer to rule counters */
+ uint32_t timestamp; /* tv_sec of last match */
+ uint32_t id; /* rule id */
+ struct ip_fw *x_next; /* linked list of rules */
+ struct ip_fw *next_rule; /* ptr to next [skipto] rule */
+
+ ipfw_insn cmd[1]; /* storage for commands */
+};
+
+#endif
+
struct ip_fw_chain {
struct ip_fw **map; /* array of rule ptrs to ease lookup */
uint32_t id; /* ruleset id */
@@ -231,7 +269,7 @@ struct ip_fw_chain {
#else
struct rwlock rwmtx;
#endif
- int static_len; /* total len of static rules */
+ int static_len; /* total len of static rules (v0) */
uint32_t gencnt; /* NAT generation count */
struct ip_fw *reap; /* list of rules to reap */
struct ip_fw *default_rule;
@@ -255,6 +293,7 @@ struct sockopt_data {
};
/* Macro for working with various counters */
+#ifdef USERSPACE
#define IPFW_INC_RULE_COUNTER(_cntr, _bytes) do { \
(_cntr)->pcnt++; \
(_cntr)->bcnt += _bytes; \
@@ -276,6 +315,31 @@ struct sockopt_data {
(_cntr)->pcnt = 0; \
(_cntr)->bcnt = 0; \
} while (0)
+#else
+#define IPFW_INC_RULE_COUNTER(_cntr, _bytes) do { \
+ counter_u64_add((_cntr)->cntr, 1); \
+ counter_u64_add((_cntr)->cntr + 1, _bytes); \
+ if ((_cntr)->timestamp != time_uptime) \
+ (_cntr)->timestamp = time_uptime; \
+ } while (0)
+
+#define IPFW_INC_DYN_COUNTER(_cntr, _bytes) do { \
+ (_cntr)->pcnt++; \
+ (_cntr)->bcnt += _bytes; \
+ } while (0)
+
+#define IPFW_ZERO_RULE_COUNTER(_cntr) do { \
+ counter_u64_zero((_cntr)->cntr); \
+ counter_u64_zero((_cntr)->cntr + 1); \
+ (_cntr)->timestamp = 0; \
+ } while (0)
+
+#define IPFW_ZERO_DYN_COUNTER(_cntr) do { \
+ (_cntr)->pcnt = 0; \
+ (_cntr)->bcnt = 0; \
+ } while (0)
+#endif
+
#define IP_FW_ARG_TABLEARG(a) (((a) == IP_FW_TABLEARG) ? tablearg : (a))
/*
@@ -322,17 +386,70 @@ struct obj_idx {
struct rule_check_info {
uint16_t table_opcodes; /* count of opcodes referencing table */
uint16_t new_tables; /* count of opcodes referencing table */
+ uint16_t urule_numoff; /* offset of rulenum in bytes */
+ uint8_t version; /* rule version */
ipfw_obj_ctlv *ctlv; /* name TLV containter */
struct ip_fw *krule; /* resulting rule pointer */
- struct ip_fw *urule; /* original rule pointer */
+ caddr_t urule; /* original rule pointer */
struct obj_idx obuf[8]; /* table references storage */
};
+/* Legacy interface support */
+/*
+ * FreeBSD 8 export rule format
+ */
+struct ip_fw_rule0 {
+ struct ip_fw *x_next; /* linked list of rules */
+ struct ip_fw *next_rule; /* ptr to next [skipto] rule */
+ /* 'next_rule' is used to pass up 'set_disable' status */
+
+ uint16_t act_ofs; /* offset of action in 32-bit units */
+ uint16_t cmd_len; /* # of 32-bit words in cmd */
+ uint16_t rulenum; /* rule number */
+ uint8_t set; /* rule set (0..31) */
+ uint8_t _pad; /* padding */
+ uint32_t id; /* rule id */
+
+ /* These fields are present in all rules. */
+ uint64_t pcnt; /* Packet counter */
+ uint64_t bcnt; /* Byte counter */
+ uint32_t timestamp; /* tv_sec of last match */
+
+ ipfw_insn cmd[1]; /* storage for commands */
+};
+
+struct ip_fw_bcounter0 {
+ uint64_t pcnt; /* Packet counter */
+ uint64_t bcnt; /* Byte counter */
+ uint32_t timestamp; /* tv_sec of last match */
+};
+
+/* Kernel rule length */
+/*
+ * RULE _K_ SIZE _V_ ->
+ * get kernel size from userland rool version _V_.
+ * RULE _U_ SIZE _V_ ->
+ * get user size version _V_ from kernel rule
+ * RULESIZE _V_ ->
+ * get user size rule length
+ */
+/* FreeBSD8 <> current kernel format */
+#define RULEUSIZE0(r) (sizeof(struct ip_fw_rule0) + (r)->cmd_len * 4 - 4)
+#define RULEKSIZE0(r) roundup2((sizeof(struct ip_fw) + (r)->cmd_len*4 - 4), 8)
+/* FreeBSD11 <> current kernel format */
+#define RULEUSIZE1(r) (roundup2(sizeof(struct ip_fw_rule) + \
+ (r)->cmd_len * 4 - 4, 8))
+#define RULEKSIZE1(r) roundup2((sizeof(struct ip_fw) + (r)->cmd_len*4 - 4), 8)
+
+
/* In ip_fw_sockopt.c */
int ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id);
int ipfw_ctl(struct sockopt *sopt);
int ipfw_chk(struct ip_fw_args *args);
void ipfw_reap_rules(struct ip_fw *head);
+void ipfw_init_counters(void);
+void ipfw_destroy_counters(void);
+struct ip_fw *ipfw_alloc_rule(struct ip_fw_chain *chain, size_t rulesize);
caddr_t ipfw_get_sopt_space(struct sockopt_data *sd, size_t needed);
caddr_t ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed);
Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c
==============================================================================
--- projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Tue Jul 8 23:07:09 2014 (r268439)
+++ projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Tue Jul 8 23:11:15 2014 (r268440)
@@ -69,6 +69,13 @@ __FBSDID("$FreeBSD$");
#include <security/mac/mac_framework.h>
#endif
+static int check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len,
+ struct rule_check_info *ci);
+static int check_ipfw_rule1(struct ip_fw_rule *rule, int size,
+ struct rule_check_info *ci);
+static int check_ipfw_rule0(struct ip_fw_rule0 *rule, int size,
+ struct rule_check_info *ci);
+
#define NAMEDOBJ_HASH_SIZE 32
struct namedobj_instance {
@@ -92,9 +99,79 @@ static int ipfw_flush_sopt_data(struct s
MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
/*
- * static variables followed by global ones (none in this file)
+ * static variables followed by global ones
*/
+#ifndef USERSPACE
+
+static VNET_DEFINE(uma_zone_t, ipfw_cntr_zone);
+#define V_ipfw_cntr_zone VNET(ipfw_cntr_zone)
+
+void
+ipfw_init_counters()
+{
+
+ V_ipfw_cntr_zone = uma_zcreate("IPFW counters",
+ sizeof(ip_fw_cntr), NULL, NULL, NULL, NULL,
+ UMA_ALIGN_PTR, UMA_ZONE_PCPU);
+}
+
+void
+ipfw_destroy_counters()
+{
+
+ uma_zdestroy(V_ipfw_cntr_zone);
+}
+
+struct ip_fw *
+ipfw_alloc_rule(struct ip_fw_chain *chain, size_t rulesize)
+{
+ struct ip_fw *rule;
+
+ rule = malloc(rulesize, M_IPFW, M_WAITOK | M_ZERO);
+ rule->cntr = uma_zalloc(V_ipfw_cntr_zone, M_WAITOK | M_ZERO);
+
+ return (rule);
+}
+
+static void
+free_rule(struct ip_fw *rule)
+{
+
+ uma_zfree(V_ipfw_cntr_zone, rule->cntr);
+ free(rule, M_IPFW);
+}
+#else
+void
+ipfw_init_counters()
+{
+}
+
+void
+ipfw_destroy_counters()
+{
+}
+
+struct ip_fw *
+ipfw_alloc_rule(struct ip_fw_chain *chain, size_t rulesize)
+{
+ struct ip_fw *rule;
+
+ rule = malloc(rulesize, M_IPFW, M_WAITOK | M_ZERO);
+
+ return (rule);
+}
+
+static void
+free_rule(struct ip_fw *rule)
+{
+
+ free(rule, M_IPFW);
+}
+
+#endif
+
+
/*
* Find the smallest rule >= key, id.
* We could use bsearch but it is so simple that we code it directly
@@ -167,20 +244,151 @@ swap_map(struct ip_fw_chain *chain, stru
return old_map;
}
+
+static void
+export_cntr1_base(struct ip_fw *krule, struct ip_fw_bcounter *cntr)
+{
+
+ cntr->size = sizeof(*cntr);
+
+ if (krule->cntr != NULL) {
+ cntr->pcnt = counter_u64_fetch(krule->cntr);
+ cntr->bcnt = counter_u64_fetch(krule->cntr + 1);
+ cntr->timestamp = krule->timestamp;
+ }
+ if (cntr->timestamp > 0)
+ cntr->timestamp += boottime.tv_sec;
+}
+
+static void
+export_cntr0_base(struct ip_fw *krule, struct ip_fw_bcounter0 *cntr)
+{
+
+ if (krule->cntr != NULL) {
+ cntr->pcnt = counter_u64_fetch(krule->cntr);
+ cntr->bcnt = counter_u64_fetch(krule->cntr + 1);
+ cntr->timestamp = krule->timestamp;
+ }
+ if (cntr->timestamp > 0)
+ cntr->timestamp += boottime.tv_sec;
+}
+
/*
- * Copies rule @urule from userland format to kernel @krule.
+ * Copies rule @urule from v1 userland format
+ * to kernel @krule.
+ * Assume @krule is zeroed.
*/
static void
-copy_rule(struct ip_fw *urule, struct ip_fw *krule)
+import_rule1(struct rule_check_info *ci)
{
- int l;
+ struct ip_fw_rule *urule;
+ struct ip_fw *krule;
+
+ urule = (struct ip_fw_rule *)ci->urule;
+ krule = (struct ip_fw *)ci->krule;
+
+ /* copy header */
+ krule->act_ofs = urule->act_ofs;
+ krule->cmd_len = urule->cmd_len;
+ krule->rulenum = urule->rulenum;
+ krule->set = urule->set;
+ krule->flags = urule->flags;
+
+ /* Save rulenum offset */
+ ci->urule_numoff = offsetof(struct ip_fw_rule, rulenum);
+
+ /* Copy opcodes */
+ memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t));
+}
+
+/*
+ * Export rule into v1 format (Current).
+ * Layout:
+ * [ ipfw_obj_tlv(IPFW_TLV_RULE_ENT)
+ * [ ip_fw_rule ] OR
+ * [ ip_fw_bcounter ip_fw_rule] (depends on rcntrs).
+ * ]
+ * Assume @data is zeroed.
+ */
+static void
+export_rule1(struct ip_fw *krule, caddr_t data, int len, int rcntrs)
+{
+ struct ip_fw_bcounter *cntr;
+ struct ip_fw_rule *urule;
+ ipfw_obj_tlv *tlv;
+
+ /* Fill in TLV header */
+ tlv = (ipfw_obj_tlv *)data;
+ tlv->type = IPFW_TLV_RULE_ENT;
+ tlv->length = len;
+
+ if (rcntrs != 0) {
+ /* Copy counters */
+ cntr = (struct ip_fw_bcounter *)(tlv + 1);
+ urule = (struct ip_fw_rule *)(cntr + 1);
+ export_cntr1_base(krule, cntr);
+ } else
+ urule = (struct ip_fw_rule *)(tlv + 1);
+
+ /* copy header */
+ urule->act_ofs = krule->act_ofs;
+ urule->cmd_len = krule->cmd_len;
+ urule->rulenum = krule->rulenum;
+ urule->set = krule->set;
+ urule->flags = krule->flags;
+ urule->id = krule->id;
+
+ /* Copy opcodes */
+ memcpy(urule->cmd, krule->cmd, krule->cmd_len * sizeof(uint32_t));
+}
+
+
+/*
+ * Copies rule @urule from FreeBSD8 userland format (v0)
+ * to kernel @krule.
+ * Assume @krule is zeroed.
+ */
+static void
+import_rule0(struct rule_check_info *ci)
+{
+ struct ip_fw_rule0 *urule;
+ struct ip_fw *krule;
+
+ urule = (struct ip_fw_rule0 *)ci->urule;
+ krule = (struct ip_fw *)ci->krule;
+
+ /* copy header */
+ krule->act_ofs = urule->act_ofs;
+ krule->cmd_len = urule->cmd_len;
+ krule->rulenum = urule->rulenum;
+ krule->set = urule->set;
+ if ((urule->_pad & 1) != 0)
+ krule->flags |= IPFW_RULE_NOOPT;
- l = RULESIZE(urule);
- bcopy(urule, krule, l);
- /* clear fields not settable from userland */
- krule->x_next = NULL;
- krule->next_rule = NULL;
- IPFW_ZERO_RULE_COUNTER(krule);
+ /* Save rulenum offset */
+ ci->urule_numoff = offsetof(struct ip_fw_rule0, rulenum);
+
+ /* Copy opcodes */
+ memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t));
+}
+
+static void
+export_rule0(struct ip_fw *krule, struct ip_fw_rule0 *urule, int len)
+{
+ /* copy header */
+ memset(urule, 0, len);
+ urule->act_ofs = krule->act_ofs;
+ urule->cmd_len = krule->cmd_len;
+ urule->rulenum = krule->rulenum;
+ urule->set = krule->set;
+ if ((krule->flags & IPFW_RULE_NOOPT) != 0)
+ urule->_pad |= 1;
+
+ /* Copy opcodes */
+ memcpy(urule->cmd, krule->cmd, krule->cmd_len * sizeof(uint32_t));
+
+ /* Export counters */
+ export_cntr0_base(krule, (struct ip_fw_bcounter0 *)&urule->pcnt);
}
/*
@@ -191,9 +399,10 @@ copy_rule(struct ip_fw *urule, struct ip
static int
commit_rules(struct ip_fw_chain *chain, struct rule_check_info *rci, int count)
{
- int error, i, l, insert_before, tcount;
+ int error, i, insert_before, tcount;
+ uint16_t rulenum, *pnum;
struct rule_check_info *ci;
- struct ip_fw *rule, *urule;
+ struct ip_fw *krule;
struct ip_fw **map; /* the new array of pointers */
/* Check if we need to do table remap */
@@ -264,31 +473,33 @@ commit_rules(struct ip_fw_chain *chain,
/* FIXME: Handle count > 1 */
ci = rci;
- rule = ci->krule;
- urule = ci->urule;
- l = RULESIZE(rule);
+ krule = ci->krule;
+ rulenum = krule->rulenum;
/* find the insertion point, we will insert before */
- insert_before = rule->rulenum ? rule->rulenum + 1 : IPFW_DEFAULT_RULE;
+ insert_before = rulenum ? rulenum + 1 : IPFW_DEFAULT_RULE;
i = ipfw_find_rule(chain, insert_before, 0);
/* duplicate first part */
if (i > 0)
bcopy(chain->map, map, i * sizeof(struct ip_fw *));
- map[i] = rule;
+ map[i] = krule;
/* duplicate remaining part, we always have the default rule */
bcopy(chain->map + i, map + i + 1,
sizeof(struct ip_fw *) *(chain->n_rules - i));
- if (rule->rulenum == 0) {
- /* write back the number */
- rule->rulenum = i > 0 ? map[i-1]->rulenum : 0;
- if (rule->rulenum < IPFW_DEFAULT_RULE - V_autoinc_step)
- rule->rulenum += V_autoinc_step;
- urule->rulenum = rule->rulenum;
+ if (rulenum == 0) {
+ /* Compute rule number and write it back */
+ rulenum = i > 0 ? map[i-1]->rulenum : 0;
+ if (rulenum < IPFW_DEFAULT_RULE - V_autoinc_step)
+ rulenum += V_autoinc_step;
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-projects
mailing list