Date: Sun, 31 Aug 2014 23:51:09 +0000 (UTC) From: "Alexander V. Chernikov" <melifaro@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r270906 - in projects/ipfw: sbin/ipfw sys/conf sys/modules/ipfw sys/netinet sys/netpfil/ipfw Message-ID: <201408312351.s7VNp9Ir047310@svn.freebsd.org>
index | next in thread | raw e-mail
Author: melifaro Date: Sun Aug 31 23:51:09 2014 New Revision: 270906 URL: http://svnweb.freebsd.org/changeset/base/270906 Log: Add support for multi-field values inside ipfw tables. This is the last major change in given branch. Kernel changes: * Use 64-bytes structures to hold multi-value variables. * Use shared array to hold values from all tables (assume each table algo is capable of holding 32-byte variables). * Add some placeholders to support per-table value arrays in future. * Use simple eventhandler-style API to ease the process of adding new table items. Currently table addition may required multiple UH drops/ acquires which is quite tricky due to atomic table modificatio/swap support, shared array resize, etc. Deal with it by calling special notifier capable of rolling back state before actually performing swap/resize operations. Original operation then restarts itself after acquiring UH lock. * Bump all objhash users default values to at least 64 * Fix custom hashing inside objhash. Userland changes: * Add support for dumping shared value array via "vlist" internal cmd. * Some small print/fill_flags dixes to support u32 values. * valtype is now bitmask of <skipto|pipe|fib|nat|dscp|tag|divert|netgraph|limit|ipv4|ipv6>. New values can hold distinct values for each of this types. * Provide special "legacy" type which assumes all values are the same. * More helpers/docs following.. Some examples: 3:41 [1] zfscurr0# ipfw table mimimi create valtype skipto,limit,ipv4,ipv6 3:41 [1] zfscurr0# ipfw table mimimi info +++ table(mimimi), set(0) +++ kindex: 2, type: addr references: 0, valtype: skipto,limit,ipv4,ipv6 algorithm: addr:radix items: 0, size: 296 3:42 [1] zfscurr0# ipfw table mimimi add 10.0.0.5 3000,10,10.0.0.1,2a02:978:2::1 added: 10.0.0.5/32 3000,10,10.0.0.1,2a02:978:2::1 3:42 [1] zfscurr0# ipfw table mimimi list +++ table(mimimi), set(0) +++ 10.0.0.5/32 3000,0,10.0.0.1,2a02:978:2::1 Added: projects/ipfw/sys/netpfil/ipfw/ip_fw_table_value.c Modified: projects/ipfw/sbin/ipfw/ipfw2.c projects/ipfw/sbin/ipfw/ipfw2.h projects/ipfw/sbin/ipfw/tables.c projects/ipfw/sys/conf/files projects/ipfw/sys/modules/ipfw/Makefile projects/ipfw/sys/netinet/ip_fw.h projects/ipfw/sys/netpfil/ipfw/ip_fw2.c projects/ipfw/sys/netpfil/ipfw/ip_fw_dynamic.c projects/ipfw/sys/netpfil/ipfw/ip_fw_log.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 projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Modified: projects/ipfw/sbin/ipfw/ipfw2.c ============================================================================== --- projects/ipfw/sbin/ipfw/ipfw2.c Sun Aug 31 23:09:23 2014 (r270905) +++ projects/ipfw/sbin/ipfw/ipfw2.c Sun Aug 31 23:51:09 2014 (r270906) @@ -712,12 +712,13 @@ concat_tokens(char *buf, size_t bufsize, * helper function to process a set of flags and set bits in the * appropriate masks. */ -void -fill_flags(struct _s_x *flags, char *p, uint8_t *set, uint8_t *clear) +int +fill_flags(struct _s_x *flags, char *p, char **e, uint32_t *set, + uint32_t *clear) { char *q; /* points to the separator */ int val; - uint8_t *which; /* mask we are working on */ + uint32_t *which; /* mask we are working on */ while (p && *p) { if (*p == '!') { @@ -729,15 +730,19 @@ fill_flags(struct _s_x *flags, char *p, if (q) *q++ = '\0'; val = match_token(flags, p); - if (val <= 0) - errx(EX_DATAERR, "invalid flag %s", p); - *which |= (uint8_t)val; + if (val <= 0) { + if (e != NULL) + *e = p; + return (-1); + } + *which |= (uint32_t)val; p = q; } + return (0); } void -print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint8_t set) +print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint32_t set) { char const *comma = ""; int i, l; @@ -2992,9 +2997,11 @@ static void fill_flags_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, struct _s_x *flags, char *p) { - uint8_t set = 0, clear = 0; + char *e; + uint32_t set = 0, clear = 0; - fill_flags(flags, p, &set, &clear); + if (fill_flags(flags, p, &e, &set, &clear) != 0) + errx(EX_DATAERR, "invalid flag %s", e); cmd->opcode = opcode; cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; @@ -4825,6 +4832,7 @@ ipfw_flush(int force) static struct _s_x intcmds[] = { { "talist", TOK_TALIST }, { "iflist", TOK_IFLIST }, + { "vlist", TOK_VLIST }, { NULL, 0 } }; @@ -4846,6 +4854,9 @@ ipfw_internal_handler(int ac, char *av[] case TOK_TALIST: ipfw_list_ta(ac, av); break; + case TOK_VLIST: + ipfw_list_values(ac, av); + break; } } Modified: projects/ipfw/sbin/ipfw/ipfw2.h ============================================================================== --- projects/ipfw/sbin/ipfw/ipfw2.h Sun Aug 31 23:09:23 2014 (r270905) +++ projects/ipfw/sbin/ipfw/ipfw2.h Sun Aug 31 23:51:09 2014 (r270906) @@ -223,10 +223,10 @@ enum tokens { TOK_VALTYPE, TOK_ALGO, TOK_TALIST, - TOK_FTYPE, TOK_ATOMIC, TOK_LOCK, TOK_UNLOCK, + TOK_VLIST, }; /* @@ -265,8 +265,9 @@ int match_token_relaxed(struct _s_x *tab char const *match_value(struct _s_x *p, int value); size_t concat_tokens(char *buf, size_t bufsize, struct _s_x *table, char *delimiter); -void fill_flags(struct _s_x *flags, char *p, uint8_t *set, uint8_t *clear); -void print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint8_t set); +int fill_flags(struct _s_x *flags, char *p, char **e, uint32_t *set, + uint32_t *clear); +void print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint32_t set); struct _ip_fw3_opheader; int do_cmd(int optname, void *optval, uintptr_t optlen); @@ -347,4 +348,5 @@ char *table_search_ctlv(struct _ipfw_obj void table_sort_ctlv(struct _ipfw_obj_ctlv *ctlv); int table_check_name(char *tablename); void ipfw_list_ta(int ac, char *av[]); +void ipfw_list_values(int ac, char *av[]); Modified: projects/ipfw/sbin/ipfw/tables.c ============================================================================== --- projects/ipfw/sbin/ipfw/tables.c Sun Aug 31 23:09:23 2014 (r270905) +++ projects/ipfw/sbin/ipfw/tables.c Sun Aug 31 23:51:09 2014 (r270906) @@ -67,9 +67,11 @@ static void table_show_list(ipfw_obj_hea static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent); static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, - char *key, int add, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi); + char *key, int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi); static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, - char *arg, uint8_t type, uint8_t vtype); + char *arg, uint8_t type, uint32_t vmask); +static void table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, + uint32_t vmask, int print_ip); typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg); static int tables_foreach(table_cb_t *f, void *arg, int sort); @@ -87,13 +89,17 @@ static struct _s_x tabletypes[] = { }; static struct _s_x tablevaltypes[] = { - { "number", IPFW_VTYPE_U32 }, - { NULL, 0 } -}; - -static struct _s_x tablefvaltypes[] = { - { "ip", IPFW_VFTYPE_IP }, - { "number", IPFW_VFTYPE_U32 }, + { "skipto", IPFW_VTYPE_SKIPTO }, + { "pipe", IPFW_VTYPE_PIPE }, + { "fib", IPFW_VTYPE_FIB }, + { "nat", IPFW_VTYPE_NAT }, + { "dscp", IPFW_VTYPE_DSCP }, + { "tag", IPFW_VTYPE_TAG }, + { "divert", IPFW_VTYPE_DIVERT }, + { "netgraph", IPFW_VTYPE_NETGRAPH }, + { "limit", IPFW_VTYPE_LIMIT }, + { "ipv4", IPFW_VTYPE_NH4 }, + { "ipv6", IPFW_VTYPE_NH6 }, { NULL, 0 } }; @@ -311,7 +317,6 @@ table_fill_objheader(ipfw_obj_header *oh static struct _s_x tablenewcmds[] = { { "type", TOK_TYPE }, - { "ftype", TOK_FTYPE }, { "valtype", TOK_VALTYPE }, { "algo", TOK_ALGO }, { "limit", TOK_LIMIT }, @@ -331,14 +336,16 @@ static struct _s_x flowtypecmds[] = { int table_parse_type(uint8_t ttype, char *p, uint8_t *tflags) { - uint8_t fset, fclear; + uint32_t fset, fclear; + char *e; /* Parse type options */ switch(ttype) { case IPFW_TABLE_FLOW: fset = fclear = 0; - fill_flags(flowtypecmds, p, &fset, - &fclear); + if (fill_flags(flowtypecmds, p, &e, &fset, &fclear) != 0) + errx(EX_USAGE, + "unable to parse flow option %s", e); *tflags = fset; break; default: @@ -383,8 +390,9 @@ table_create(ipfw_obj_header *oh, int ac { ipfw_xtable_info xi; int error, tcmd, val; + uint32_t fset, fclear; size_t sz; - char *p; + char *e, *p; char tbuf[128]; sz = sizeof(tbuf); @@ -424,27 +432,16 @@ table_create(ipfw_obj_header *oh, int ac break; case TOK_VALTYPE: NEED1("table value type required"); - val = match_token(tablevaltypes, *av); + fset = fclear = 0; + val = fill_flags(tablevaltypes, *av, &e, &fset, &fclear); if (val != -1) { - xi.vtype = val; + xi.vmask = fset; ac--; av++; break; } concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", "); errx(EX_USAGE, "Unknown value type: %s. Supported: %s", - *av, tbuf); - break; - case TOK_FTYPE: - NEED1("table value format type required"); - val = match_token(tablefvaltypes, *av); - if (val != -1) { - xi.vftype = val; - ac--; av++; - break; - } - concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", "); - errx(EX_USAGE, "Unknown format type: %s. Supported: %s", - *av, tbuf); + e, tbuf); break; case TOK_ALGO: NEED1("table algorithm name required"); @@ -462,8 +459,8 @@ table_create(ipfw_obj_header *oh, int ac /* Set some defaults to preserve compability */ if (xi.algoname[0] == '\0' && xi.type == 0) xi.type = IPFW_TABLE_ADDR; - if (xi.vtype == 0) - xi.vtype = IPFW_VTYPE_U32; + if (xi.vmask == 0) + xi.vmask = IPFW_VTYPE_LEGACY; if ((error = table_do_create(oh, &xi)) != 0) err(EX_OSERR, "Table creation failed"); @@ -494,13 +491,13 @@ table_do_create(ipfw_obj_header *oh, ipf /* * Modifies existing table * - * ipfw table NAME modify [ limit number ] [ ftype { number | ip } ] + * ipfw table NAME modify [ limit number ] */ static void table_modify(ipfw_obj_header *oh, int ac, char *av[]) { ipfw_xtable_info xi; - int error, tcmd, val; + int error, tcmd; size_t sz; char tbuf[128]; @@ -518,19 +515,8 @@ table_modify(ipfw_obj_header *oh, int ac xi.mflags |= IPFW_TMFLAGS_LIMIT; ac--; av++; break; - case TOK_FTYPE: - NEED1("table value format type required"); - val = match_token(tablefvaltypes, *av); - if (val != -1) { - xi.vftype = val; - xi.mflags |= IPFW_TMFLAGS_FTYPE; - ac--; av++; - break; - } - concat_tokens(tbuf, sizeof(tbuf), tablefvaltypes, ", "); - errx(EX_USAGE, "Unknown value type: %s. Supported: %s", - *av, tbuf); - break; + default: + errx(EX_USAGE, "cmd is not supported for modificatiob"); } } @@ -726,34 +712,39 @@ table_show_tainfo(ipfw_xtable_info *i, s } } +static void +table_print_valheader(char *buf, size_t bufsize, uint32_t vmask) +{ + + if (vmask == IPFW_VTYPE_LEGACY) { + snprintf(buf, bufsize, "legacy"); + return; + } + + print_flags_buffer(buf, bufsize, tablevaltypes, vmask); +} + /* * Prints table info struct @i in human-readable form. */ static int table_show_info(ipfw_xtable_info *i, void *arg) { - const char *vtype, *vftype; + const char *vtype; ipfw_ta_tinfo *tainfo; int afdata, afitem; struct ta_cldata d; char ttype[64], tvtype[64]; table_print_type(ttype, sizeof(ttype), i->type, i->tflags); - if ((vtype = match_value(tablevaltypes, i->vtype)) == NULL) - vtype = "unknown"; - if ((vftype = match_value(tablefvaltypes, i->vftype)) == NULL) - vftype = "unknown"; - if (strcmp(vtype, vftype) != 0) - snprintf(tvtype, sizeof(tvtype), "%s(%s)", vtype, vftype); - else - snprintf(tvtype, sizeof(tvtype), "%s", vtype); + table_print_valheader(tvtype, sizeof(tvtype), i->vmask); printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0) printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype); else printf(" kindex: %d, type: %s\n", i->kidx, ttype); - printf(" valtype: %s, references: %u\n", tvtype, i->refcnt); + printf(" references: %u, valtype: %s\n", i->refcnt, tvtype); printf(" algorithm: %s\n", i->algoname); printf(" items: %u, size: %u\n", i->count, i->size); if (i->limit > 0) @@ -895,7 +886,8 @@ table_modify_record(ipfw_obj_header *oh, { ipfw_obj_tentry *ptent, tent, *tent_buf; ipfw_xtable_info xi; - uint8_t type, vtype; + uint8_t type; + uint32_t vmask; int cmd, count, error, i, ignored; char *texterr, *etxt, *px; @@ -933,14 +925,14 @@ table_modify_record(ipfw_obj_header *oh, memset(&xi, 0, sizeof(xi)); count = 0; while (ac > 0) { - tentry_fill_key(oh, ptent, *av, add, &type, &vtype, &xi); + tentry_fill_key(oh, ptent, *av, add, &type, &vmask, &xi); /* * compability layer: auto-create table if not exists */ if (xi.tablename[0] == '\0') { xi.type = type; - xi.vtype = vtype; + xi.vmask = vmask; strlcpy(xi.tablename, oh->ntlv.name, sizeof(xi.tablename)); fprintf(stderr, "DEPRECATED: inserting data info " @@ -953,7 +945,7 @@ table_modify_record(ipfw_obj_header *oh, ac--; av++; if (add != 0 && ac > 0) { - tentry_fill_value(oh, ptent, *av, type, vtype); + tentry_fill_value(oh, ptent, *av, type, vmask); ac--; av++; } @@ -966,6 +958,8 @@ table_modify_record(ipfw_obj_header *oh, error = table_do_modify_record(cmd, oh, tent_buf, count, atomic); + quiet = 0; + /* * Compatibility stuff: do not yell on duplicate keys or * failed deletions. @@ -1062,7 +1056,8 @@ table_do_lookup(ipfw_obj_header *oh, cha { char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; ipfw_obj_tentry *tent; - uint8_t type, vtype; + uint8_t type; + uint32_t vmask; int error; size_t sz; @@ -1074,7 +1069,7 @@ table_do_lookup(ipfw_obj_header *oh, cha tent->head.length = sizeof(*tent); tent->idx = 1; - tentry_fill_key(oh, tent, key, 0, &type, &vtype, xi); + tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi); oh->ntlv.type = type; sz = sizeof(xbuf); @@ -1321,15 +1316,16 @@ tentry_fill_key_type(char *arg, ipfw_obj static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, - int add, uint8_t *ptype, uint8_t *pvtype, ipfw_xtable_info *xi) + int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi) { - uint8_t type, tflags, vtype; + uint8_t type, tflags; + uint32_t vmask; int error; char *del; type = 0; tflags = 0; - vtype = 0; + vmask = 0; if (xi->tablename[0] == '\0') error = table_get_info(oh, xi); @@ -1340,7 +1336,7 @@ tentry_fill_key(ipfw_obj_header *oh, ipf /* Table found. */ type = xi->type; tflags = xi->tflags; - vtype = xi->vtype; + vmask = xi->vmask; } else { if (error != ESRCH) errx(EX_OSERR, "Error requesting table %s info", @@ -1359,11 +1355,7 @@ tentry_fill_key(ipfw_obj_header *oh, ipf inet_pton(AF_INET6, key, &tent->k.addr6) == 1) { /* OK Prepare and send */ type = IPFW_TABLE_ADDR; - /* - * XXX: Value type is forced to be u32. - * This should be changed for MFC. - */ - vtype = IPFW_VTYPE_U32; + vmask = IPFW_VTYPE_LEGACY; } else { /* Inknown key */ errx(EX_USAGE, "Table %s does not exist, cannot guess " @@ -1376,57 +1368,156 @@ tentry_fill_key(ipfw_obj_header *oh, ipf tentry_fill_key_type(key, tent, type, tflags); *ptype = type; - *pvtype = vtype; + *pvmask = vmask; } static void -tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, - uint8_t type, uint8_t vtype) +set_legacy_value(uint32_t val, ipfw_table_value *v) { - uint32_t val; - char *p; + v->tag = val; + v->pipe = val; + v->divert = val; + v->skipto = val; + v->netgraph = val; + v->fib = val; + v->nat = val; + v->nh4 = val; + v->dscp = (uint8_t)val; + v->limit = val; +} - /* Try to interpret as number first */ - tent->v.value = strtoul(arg, &p, 0); - if (*p == '\0') - return; - if (inet_pton(AF_INET, arg, &val) == 1) { - tent->v.value = ntohl(val); - return; +static void +tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, + uint8_t type, uint32_t vmask) +{ + uint32_t a4, flag, val, vm; + ipfw_table_value *v; + uint32_t i; + char *comma, *e, *etype, *n, *p; + + v = &tent->v.value; + vm = vmask; + + /* Compat layer: keep old behavior for legacy value types */ + if (vmask == IPFW_VTYPE_LEGACY) { + /* Try to interpret as number first */ + val = strtoul(arg, &p, 0); + if (*p == '\0') { + set_legacy_value(val, v); + return; + } + if (inet_pton(AF_INET, arg, &val) == 1) { + set_legacy_value(ntohl(val), v); + return; + } + /* Try hostname */ + if (lookup_host(arg, (struct in_addr *)&val) == 0) { + set_legacy_value(val, v); + return; + } + errx(EX_OSERR, "Unable to parse value %s", arg); } - /* Try hostname */ - if (lookup_host(arg, (struct in_addr *)&tent->v.value) == 0) - return; - errx(EX_OSERR, "Unable to parse value %s", arg); -#if 0 - switch (vtype) { - case IPFW_VTYPE_U32: - tent->value = strtoul(arg, &p, 0); - if (*p != '\0') - errx(EX_USAGE, "Invalid number: %s", arg); - break; - case IPFW_VTYPE_IP: - if (inet_pton(AF_INET, arg, &tent->value) == 1) + + /* + * Shorthands: handle single value if vmask consists + * of numbers only. e.g.: + * vmask = "fib,skipto" -> treat input "1" as "1,1" + */ + + n = arg; + etype = NULL; + for (i = 1; i < (1 << 31); i *= 2) { + if ((flag = (vmask & i)) == 0) + continue; + vmask &= ~flag; + + if ((comma = strchr(n, ',')) != NULL) + *comma = '\0'; + + switch (flag) { + case IPFW_VTYPE_TAG: + v->tag = strtol(n, &e, 10); + if (*e != '\0') + etype = "tag"; + break; + case IPFW_VTYPE_PIPE: + v->pipe = strtol(n, &e, 10); + if (*e != '\0') + etype = "pipe"; + break; + case IPFW_VTYPE_DIVERT: + v->divert = strtol(n, &e, 10); + if (*e != '\0') + etype = "divert"; + break; + case IPFW_VTYPE_SKIPTO: + v->skipto = strtol(n, &e, 10); + if (*e != '\0') + etype = "skipto"; + break; + case IPFW_VTYPE_NETGRAPH: + v->netgraph = strtol(n, &e, 10); + if (*e != '\0') + etype = "netgraph"; + break; + case IPFW_VTYPE_FIB: + v->fib = strtol(n, &e, 10); + if (*e != '\0') + etype = "fib"; + break; + case IPFW_VTYPE_NAT: + v->nat = strtol(n, &e, 10); + if (*e != '\0') + etype = "nat"; + break; + case IPFW_VTYPE_LIMIT: + v->limit = strtol(n, &e, 10); + if (*e != '\0') + etype = "limit"; + break; + case IPFW_VTYPE_NH4: + if (strchr(n, '.') != NULL && + inet_pton(AF_INET, n, &a4) == 1) { + v->nh4 = ntohl(a4); + break; + } + if (lookup_host(n, (struct in_addr *)&v->nh4) == 0) + break; + etype = "ipv4"; + break; + case IPFW_VTYPE_DSCP: + if (isalpha(*n)) { + if ((v->dscp = match_token(f_ipdscp, n)) != -1) + break; + else + etype = "DSCP code"; + } else { + v->dscp = strtol(n, &e, 10); + if (v->dscp > 63 || *e != '\0') + etype = "DSCP value"; + } + break; + case IPFW_VTYPE_NH6: + if (strchr(n, ':') != NULL && + inet_pton(AF_INET6, n, &v->nh6) == 1) + break; + etype = "ipv6"; break; - /* Try hostname */ - if (lookup_host(arg, (struct in_addr *)&tent->value) != 0) - errx(EX_USAGE, "Invalid IPv4 address: %s", arg); - break; - case IPFW_VTYPE_DSCP: - if (isalpha(*arg)) { - if ((code = match_token(f_ipdscp, arg)) == -1) - errx(EX_DATAERR, "Unknown DSCP code"); - } else { - code = strtoul(arg, NULL, 10); - if (code < 0 || code > 63) - errx(EX_DATAERR, "Invalid DSCP value"); } - tent->value = code; - break; - default: - errx(EX_OSERR, "Unsupported format type %d", vtype); + + if (etype != NULL) + errx(EX_USAGE, "Unable to parse %s as %s", n, etype); + + if (comma != NULL) + *comma++ = ','; + + if ((n = comma) != NULL) + continue; + + /* End of input. */ + if (vmask != 0) + errx(EX_USAGE, "Not enough fields inside value"); } -#endif } /* @@ -1558,20 +1649,90 @@ table_show_list(ipfw_obj_header *oh, int } static void +table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, + uint32_t vmask, int print_ip) +{ + uint32_t flag, i, l; + size_t sz; + struct in_addr a4; + char abuf[INET6_ADDRSTRLEN]; + + sz = bufsize; + + /* + * Some shorthands for printing values: + * legacy assumes all values are equal, so keep the first one. + */ + if (vmask == IPFW_VTYPE_LEGACY) { + if (print_ip != 0) { + flag = htonl(v->tag); + inet_ntop(AF_INET, &flag, buf, sz); + } else + snprintf(buf, sz, "%u", v->tag); + return; + } + + for (i = 1; i < (1 << 31); i *= 2) { + if ((flag = (vmask & i)) == 0) + continue; + l = 0; + + switch (flag) { + case IPFW_VTYPE_TAG: + l = snprintf(buf, sz, "%u,", v->tag); + break; + case IPFW_VTYPE_PIPE: + l = snprintf(buf, sz, "%u,", v->pipe); + break; + case IPFW_VTYPE_DIVERT: + l = snprintf(buf, sz, "%d,", v->divert); + break; + case IPFW_VTYPE_SKIPTO: + l = snprintf(buf, sz, "%d,", v->skipto); + break; + case IPFW_VTYPE_NETGRAPH: + l = snprintf(buf, sz, "%u,", v->netgraph); + break; + case IPFW_VTYPE_FIB: + l = snprintf(buf, sz, "%u,", v->fib); + break; + case IPFW_VTYPE_NAT: + l = snprintf(buf, sz, "%u,", v->nat); + break; + case IPFW_VTYPE_LIMIT: + l = snprintf(buf, sz, "%u,", v->limit); + break; + case IPFW_VTYPE_NH4: + a4.s_addr = htonl(v->nh4); + inet_ntop(AF_INET, &a4, abuf, sizeof(abuf)); + l = snprintf(buf, sz, "%s,", abuf); + break; + case IPFW_VTYPE_DSCP: + l = snprintf(buf, sz, "%d,", v->dscp); + break; + case IPFW_VTYPE_NH6: + inet_ntop(AF_INET6, &v->nh6, abuf, sizeof(abuf)); + l = snprintf(buf, sz, "%s,", abuf); + break; + } + + buf += l; + sz -= l; + } + + if (sz != bufsize) + *(buf - 1) = '\0'; +} + +static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) { - char *comma, tbuf[128], pval[32]; + char *comma, tbuf[128], pval[128]; void *paddr; - uint32_t tval; struct tflow_entry *tfe; - tval = tent->v.value; - - if (co.do_value_as_ip || i->vftype == IPFW_VFTYPE_IP) { - tval = htonl(tval); - inet_ntop(AF_INET, &tval, pval, sizeof(pval)); - } else - snprintf(pval, sizeof(pval), "%u", tval); + table_show_value(pval, sizeof(pval), &tent->v.value, i->vmask, + co.do_value_as_ip); switch (i->type) { case IPFW_TABLE_ADDR: @@ -1633,7 +1794,7 @@ table_show_entry(ipfw_xtable_info *i, ip } static int -table_do_get_algolist(ipfw_obj_lheader **polh) +table_do_get_stdlist(uint16_t opcode, ipfw_obj_lheader **polh) { ipfw_obj_lheader req, *olh; size_t sz; @@ -1642,7 +1803,7 @@ table_do_get_algolist(ipfw_obj_lheader * memset(&req, 0, sizeof(req)); sz = sizeof(req); - error = do_get3(IP_FW_TABLES_ALIST, &req.opheader, &sz); + error = do_get3(opcode, &req.opheader, &sz); if (error != 0 && error != ENOMEM) return (error); @@ -1651,7 +1812,7 @@ table_do_get_algolist(ipfw_obj_lheader * return (ENOMEM); olh->size = sz; - if ((error = do_get3(IP_FW_TABLES_ALIST, &olh->opheader, &sz)) != 0) { + if ((error = do_get3(opcode, &olh->opheader, &sz)) != 0) { free(olh); return (error); } @@ -1660,6 +1821,20 @@ table_do_get_algolist(ipfw_obj_lheader * return (0); } +static int +table_do_get_algolist(ipfw_obj_lheader **polh) +{ + + return (table_do_get_stdlist(IP_FW_TABLES_ALIST, polh)); +} + +static int +table_do_get_vlist(ipfw_obj_lheader **polh) +{ + + return (table_do_get_stdlist(IP_FW_TABLE_VLIST, polh)); +} + void ipfw_list_ta(int ac, char *av[]) { @@ -1685,6 +1860,71 @@ ipfw_list_ta(int ac, char *av[]) free(olh); } + +/* Copy of current kernel table_value structure */ +struct _table_value { + uint32_t tag; /* O_TAG/O_TAGGED */ + uint32_t pipe; /* O_PIPE/O_QUEUE */ + uint16_t divert; /* O_DIVERT/O_TEE */ + uint16_t skipto; /* skipto, CALLRET */ + uint32_t netgraph; /* O_NETGRAPH/O_NGTEE */ + uint32_t fib; /* O_SETFIB */ + uint32_t nat; /* O_NAT */ + uint32_t nh4; + uint8_t dscp; + uint8_t spare0[3]; + /* -- 32 bytes -- */ + struct in6_addr nh6; + uint32_t limit; /* O_LIMIT */ + uint32_t spare1; + uint64_t refcnt; /* Number of references */ +}; + +int +compare_values(const void *_a, const void *_b) +{ + struct _table_value *a, *b; + + a = (struct _table_value *)_a; + b = (struct _table_value *)_b; + + if (a->spare1 < b->spare1) + return (-1); + else if (a->spare1 > b->spare1) + return (1); + + return (0); +} + +void +ipfw_list_values(int ac, char *av[]) +{ + ipfw_obj_lheader *olh; + struct _table_value *v; + int error, i; + uint32_t vmask; + char buf[128]; + + error = table_do_get_vlist(&olh); + if (error != 0) + err(EX_OSERR, "Unable to request value list"); + + vmask = 0x7FFFFFFF; /* Similar to IPFW_VTYPE_LEGACY */ + + table_print_valheader(buf, sizeof(buf), vmask); + printf("HEADER: %s\n", buf); + v = (struct _table_value *)(olh + 1); + qsort(v, olh->count, olh->objsize, compare_values); + for (i = 0; i < olh->count; i++) { + table_show_value(buf, sizeof(buf), (ipfw_table_value *)v, + vmask, 0); + printf("[%u] refs=%lu %s\n", v->spare1, v->refcnt, buf); + v = (struct _table_value *)((caddr_t)v + olh->objsize); + } + + free(olh); +} + int compare_ntlv(const void *_a, const void *_b) { Modified: projects/ipfw/sys/conf/files ============================================================================== --- projects/ipfw/sys/conf/files Sun Aug 31 23:09:23 2014 (r270905) +++ projects/ipfw/sys/conf/files Sun Aug 31 23:51:09 2014 (r270906) @@ -3494,6 +3494,7 @@ netpfil/ipfw/ip_fw_pfil.c optional inet netpfil/ipfw/ip_fw_sockopt.c optional inet ipfirewall netpfil/ipfw/ip_fw_table.c optional inet ipfirewall netpfil/ipfw/ip_fw_table_algo.c optional inet ipfirewall +netpfil/ipfw/ip_fw_table_value.c optional inet ipfirewall netpfil/ipfw/ip_fw_iface.c optional inet ipfirewall netpfil/ipfw/ip_fw_nat.c optional inet ipfirewall_nat netpfil/pf/if_pflog.c optional pflog pf inet Modified: projects/ipfw/sys/modules/ipfw/Makefile ============================================================================== --- projects/ipfw/sys/modules/ipfw/Makefile Sun Aug 31 23:09:23 2014 (r270905) +++ projects/ipfw/sys/modules/ipfw/Makefile Sun Aug 31 23:51:09 2014 (r270906) @@ -8,6 +8,7 @@ KMOD= ipfw SRCS= ip_fw2.c ip_fw_pfil.c SRCS+= ip_fw_dynamic.c ip_fw_log.c SRCS+= ip_fw_sockopt.c ip_fw_table.c ip_fw_table_algo.c ip_fw_iface.c +SRCS+= ip_fw_table_value.c SRCS+= opt_inet.h opt_inet6.h opt_ipdivert.h opt_ipfw.h opt_ipsec.h CFLAGS+= -DIPFIREWALL Modified: projects/ipfw/sys/netinet/ip_fw.h ============================================================================== --- projects/ipfw/sys/netinet/ip_fw.h Sun Aug 31 23:09:23 2014 (r270905) +++ projects/ipfw/sys/netinet/ip_fw.h Sun Aug 31 23:51:09 2014 (r270906) @@ -96,6 +96,7 @@ typedef struct _ip_fw3_opheader { #define IP_FW_XIFLIST 107 /* list tracked interfaces */ #define IP_FW_TABLES_ALIST 108 /* list table algorithms */ #define IP_FW_TABLE_XSWAP 109 /* swap two tables */ +#define IP_FW_TABLE_VLIST 110 /* dump table value hash */ /* * The kernel representation of ipfw rules is made of a list of @@ -663,11 +664,18 @@ struct _ipfw_dyn_rule { #define IPFW_TABLE_CIDR IPFW_TABLE_ADDR /* compat */ /* Value types */ -#define IPFW_VTYPE_U32 1 /* Skipto/tablearg integer */ - -/* Value format types */ -#define IPFW_VFTYPE_U32 0 /* Skipto/tablearg integer */ -#define IPFW_VFTYPE_IP 1 /* Nexthop IP address */ +#define IPFW_VTYPE_LEGACY 0xFFFFFFFF /* All data is filled in */ +#define IPFW_VTYPE_SKIPTO 0x00000001 /* skipto/call/callreturn */ +#define IPFW_VTYPE_PIPE 0x00000002 /* pipe/queue */ +#define IPFW_VTYPE_FIB 0x00000004 /* setfib */ +#define IPFW_VTYPE_NAT 0x00000008 /* nat */ +#define IPFW_VTYPE_DSCP 0x00000010 /* dscp */ +#define IPFW_VTYPE_TAG 0x00000020 /* tag/untag */ +#define IPFW_VTYPE_DIVERT 0x00000040 /* divert/tee */ +#define IPFW_VTYPE_NETGRAPH 0x00000080 /* netgraph/ngtee */ +#define IPFW_VTYPE_LIMIT 0x00000100 /* IPv6 nexthop */ +#define IPFW_VTYPE_NH4 0x00000200 /* IPv4 nexthop */ +#define IPFW_VTYPE_NH6 0x00000400 /* IPv6 nexthop */ typedef struct _ipfw_table_entry { in_addr_t addr; /* network address */ @@ -751,6 +759,23 @@ struct tflow_entry { } a; }; +typedef struct _ipfw_table_value { + uint32_t tag; /* O_TAG/O_TAGGED */ + uint32_t pipe; /* O_PIPE/O_QUEUE */ + uint16_t divert; /* O_DIVERT/O_TEE */ + uint16_t skipto; /* skipto, CALLRET */ + uint32_t netgraph; /* O_NETGRAPH/O_NGTEE */ + uint32_t fib; /* O_SETFIB */ + uint32_t nat; /* O_NAT */ + uint32_t nh4; + uint8_t dscp; + uint8_t spare0[3]; + struct in6_addr nh6; + uint32_t limit; /* O_LIMIT */ + uint32_t spare1; + uint64_t reserved; +} ipfw_table_value; + /* Table entry TLV */ typedef struct _ipfw_obj_tentry { ipfw_obj_tlv head; /* TLV header */ @@ -769,8 +794,8 @@ typedef struct _ipfw_obj_tentry { struct tflow_entry flow; } k; union { - uint32_t value; /* 32-bit value */ - char storage[64]; /* Future needs */ + ipfw_table_value value; /* value data */ + uint32_t kidx; /* value kernel index */ } v; } ipfw_obj_tentry; #define IPFW_TF_UPDATE 0x01 /* Update record if exists */ @@ -839,10 +864,10 @@ typedef struct _ipfw_ta_tinfo { typedef struct _ipfw_xtable_info { uint8_t type; /* table type (addr,iface,..) */ uint8_t tflags; /* type flags */ - uint8_t vtype; /* value type (u32) */ - uint8_t vftype; /* value format type (ip,number)*/ uint16_t mflags; /* modification flags */ uint16_t flags; /* generic table flags */ + uint16_t spare[3]; + uint32_t vmask; /* bitmask with value types */ uint32_t set; /* set table is in */ uint32_t kidx; /* kernel index */ uint32_t refcnt; /* number of references */ @@ -862,7 +887,6 @@ typedef struct _ipfw_xtable_info { #define IPFW_TFFLAG_DSTPORT 0x08 #define IPFW_TFFLAG_PROTO 0x10 /* Table modification flags */ -#define IPFW_TMFLAGS_FTYPE 0x0001 /* Change ftype field */ #define IPFW_TMFLAGS_LIMIT 0x0002 /* Change limit value */ #define IPFW_TMFLAGS_LOCK 0x0004 /* Change table lock state */ Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw2.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Sun Aug 31 23:09:23 2014 (r270905) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Sun Aug 31 23:51:09 2014 (r270906) @@ -817,7 +817,7 @@ jump_fast(struct ip_fw_chain *chain, str if (num != IP_FW_TARG && f->cached_id == chain->id) f_pos = f->cached_pos; else { - int i = IP_FW_ARG_TABLEARG(num); + int i = IP_FW_ARG_TABLEARG(chain, num, skipto); /* make sure we do not jump backward */ if (jump_backwards == 0 && i <= f->rulenum) i = f->rulenum + 1; @@ -844,7 +844,7 @@ jump_linear(struct ip_fw_chain *chain, s { int f_pos; - num = IP_FW_ARG_TABLEARG(num); + num = IP_FW_ARG_TABLEARG(chain, num, skipto); /* make sure we do not jump backward */ if (jump_backwards == 0 && num <= f->rulenum) num = f->rulenum + 1; @@ -853,6 +853,7 @@ jump_linear(struct ip_fw_chain *chain, s return (f_pos); } +#define TARG(k, f) IP_FW_ARG_TABLEARG(chain, k, f) /* * The main check routine for the firewall. * @@ -1841,7 +1842,7 @@ do { \ } case O_LOG: - ipfw_log(f, hlen, args, m, + ipfw_log(chain, f, hlen, args, m, oif, offset | ip6f_mf, tablearg, ip); match = 1; break; @@ -1963,7 +1964,7 @@ do { \ case O_TAG: { struct m_tag *mtag; - uint32_t tag = IP_FW_ARG_TABLEARG(cmd->arg1); + uint32_t tag = TARG(cmd->arg1, tag); /* Packet is already tagged with this tag? */ mtag = m_tag_locate(m, MTAG_IPFW, tag, NULL); @@ -2044,7 +2045,7 @@ do { \ *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201408312351.s7VNp9Ir047310>
