Date: Tue, 8 Jul 2014 23:11:16 +0000 (UTC) From: "Alexander V. Chernikov" <melifaro@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r268440 - in projects/ipfw: sbin/ipfw sys/netinet sys/netpfil/ipfw Message-ID: <201407082311.s68NBGwb078468@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201407082311.s68NBGwb078468>