From owner-svn-src-projects@FreeBSD.ORG Wed Jul 30 14:52:28 2014 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id EB5D49FB; Wed, 30 Jul 2014 14:52:27 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id D7AC928F8; Wed, 30 Jul 2014 14:52:27 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s6UEqRwb064643; Wed, 30 Jul 2014 14:52:27 GMT (envelope-from melifaro@svn.freebsd.org) Received: (from melifaro@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s6UEqQxm064634; Wed, 30 Jul 2014 14:52:26 GMT (envelope-from melifaro@svn.freebsd.org) Message-Id: <201407301452.s6UEqQxm064634@svn.freebsd.org> From: "Alexander V. Chernikov" Date: Wed, 30 Jul 2014 14:52:26 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r269304 - in projects/ipfw: sbin/ipfw sys/netinet sys/netpfil/ipfw X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 30 Jul 2014 14:52:28 -0000 Author: melifaro Date: Wed Jul 30 14:52:26 2014 New Revision: 269304 URL: http://svnweb.freebsd.org/changeset/base/269304 Log: * Add number:array algorithm lookup method. Kernel changes: * s/IPFW_TABLE_U32/IPFW_TABLE_NUMBER/ * Force "lookup " to be IPFW_TABLE_NUMBER * Support "lookup" method for number tables * Add number:array algorihm (i32 as key, auto-growing). Userland changes: * Support named tables in "lookup Table" * Fix handling of "table(NAME,val)" case * Support printing "number" table data. Modified: projects/ipfw/sbin/ipfw/ipfw2.c projects/ipfw/sbin/ipfw/tables.c projects/ipfw/sys/netinet/ip_fw.h projects/ipfw/sys/netpfil/ipfw/ip_fw2.c projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Modified: projects/ipfw/sbin/ipfw/ipfw2.c ============================================================================== --- projects/ipfw/sbin/ipfw/ipfw2.c Wed Jul 30 14:52:04 2014 (r269303) +++ projects/ipfw/sbin/ipfw/ipfw2.c Wed Jul 30 14:52:26 2014 (r269304) @@ -1096,6 +1096,7 @@ print_ip(struct format_opts *fo, ipfw_in struct hostent *he = NULL; uint32_t len = F_LEN((ipfw_insn *)cmd); uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; + char *t; if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) { uint32_t d = a[1]; @@ -1103,8 +1104,9 @@ print_ip(struct format_opts *fo, ipfw_in if (d < sizeof(lookup_key)/sizeof(lookup_key[0])) arg = match_value(rule_options, lookup_key[d]); - printf("%s lookup %s %d", cmd->o.len & F_NOT ? " not": "", - arg, cmd->o.arg1); + t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1); + printf("%s lookup %s %s", cmd->o.len & F_NOT ? " not": "", + arg, t); return; } printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); @@ -1115,7 +1117,6 @@ print_ip(struct format_opts *fo, ipfw_in } if (cmd->o.opcode == O_IP_SRC_LOOKUP || cmd->o.opcode == O_IP_DST_LOOKUP) { - char *t; t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1); printf("table(%s", t); if (len == F_INSN_SIZE(ipfw_insn_u32)) @@ -2624,14 +2625,9 @@ struct tidx { static uint16_t pack_table(struct tidx *tstate, char *name, uint32_t set) { - char *p; int i; ipfw_obj_ntlv *ntlv; - if ((p = strchr(name, ')')) == NULL) - return (0); - *p = '\0'; - if (table_check_name(name) != 0) return (0); @@ -2694,6 +2690,9 @@ fill_ip(ipfw_insn_ip *cmd, char *av, int } if (strncmp(av, "table(", 6) == 0) { + if ((p = strchr(av + 6, ')')) == NULL) + errx(EX_DATAERR, "forgotten parenthesis: '%s'", av); + *p = '\0'; p = strchr(av + 6, ','); if (p) *p++ = '\0'; @@ -2983,6 +2982,7 @@ ipfw_delete(char *av[]) static void fill_iface(ipfw_insn_if *cmd, char *arg, int cblen, struct tidx *tstate) { + char *p; uint16_t uidx; cmd->name[0] = '\0'; @@ -2994,7 +2994,10 @@ fill_iface(ipfw_insn_if *cmd, char *arg, if (strcmp(arg, "any") == 0) cmd->o.len = 0; /* effectively ignore this command */ else if (strncmp(arg, "table(", 6) == 0) { - char *p = strchr(arg + 6, ','); + if ((p = strchr(arg + 6, ')')) == NULL) + errx(EX_DATAERR, "forgotten parenthesis: '%s'", arg); + *p = '\0'; + p = strchr(arg + 6, ','); if (p) *p++ = '\0'; if ((uidx = pack_table(tstate, arg + 6, 0)) == 0) @@ -4381,7 +4384,6 @@ read_options: case TOK_LOOKUP: { ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd; - char *p; int j; if (!av[0] || !av[1]) @@ -4397,9 +4399,11 @@ read_options: errx(EX_USAGE, "format: cannot lookup on %s", *av); __PAST_END(c->d, 1) = j; // i converted to option av++; - cmd->arg1 = strtoul(*av, &p, 0); - if (p && *p) - errx(EX_USAGE, "format: lookup argument tablenum"); + + if ((j = pack_table(tstate, *av, 0)) == 0) + errx(EX_DATAERR, "Invalid table name: %s", *av); + + cmd->arg1 = j; av++; } break; Modified: projects/ipfw/sbin/ipfw/tables.c ============================================================================== --- projects/ipfw/sbin/ipfw/tables.c Wed Jul 30 14:52:04 2014 (r269303) +++ projects/ipfw/sbin/ipfw/tables.c Wed Jul 30 14:52:26 2014 (r269304) @@ -82,7 +82,7 @@ static int tables_foreach(table_cb_t *f, static struct _s_x tabletypes[] = { { "cidr", IPFW_TABLE_CIDR }, { "iface", IPFW_TABLE_INTERFACE }, - { "u32", IPFW_TABLE_U32 }, + { "number", IPFW_TABLE_NUMBER }, { NULL, 0 } }; @@ -654,7 +654,7 @@ tentry_fill_key_type(char *arg, ipfw_obj /* Set mask to exact match */ masklen = 8 * IF_NAMESIZE; break; - case IPFW_TABLE_U32: + case IPFW_TABLE_NUMBER: /* Port or any other key */ key = strtol(arg, &p, 10); if (*p != '\0') @@ -899,6 +899,16 @@ table_show_entry(ipfw_xtable_info *i, ip inet_ntoa(*(struct in_addr *)&tval)); } else printf("%s %u\n", tent->k.iface, tval); + break; + case IPFW_TABLE_NUMBER: + /* numbers */ + if (co.do_value_as_ip) { + tval = htonl(tval); + printf("%u %s\n", tent->k.key, + inet_ntoa(*(struct in_addr *)&tval)); + } else + printf("%u %u\n", tent->k.key, tval); + break; } } Modified: projects/ipfw/sys/netinet/ip_fw.h ============================================================================== --- projects/ipfw/sys/netinet/ip_fw.h Wed Jul 30 14:52:04 2014 (r269303) +++ projects/ipfw/sys/netinet/ip_fw.h Wed Jul 30 14:52:26 2014 (r269304) @@ -674,7 +674,7 @@ struct _ipfw_dyn_rule { #define IPFW_TABLE_CIDR 1 /* Table for holding IPv4/IPv6 prefixes */ #define IPFW_TABLE_INTERFACE 2 /* Table for holding interface names */ -#define IPFW_TABLE_U32 3 /* Table for holidng ports/uid/gid/etc */ +#define IPFW_TABLE_NUMBER 3 /* Table for holding ports/uid/gid/etc */ #define IPFW_TABLE_MAXTYPE 3 /* Maximum valid number */ #define IPFW_VTYPE_U32 1 /* Skipto/tablearg integer */ Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw2.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Wed Jul 30 14:52:04 2014 (r269303) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Wed Jul 30 14:52:26 2014 (r269304) @@ -1473,9 +1473,9 @@ do { \ proto != IPPROTO_UDP) break; else if (v == 2) - key = htonl(dst_port); + key = dst_port; else if (v == 3) - key = htonl(src_port); + key = src_port; #ifndef USERSPACE else if (v == 4 || v == 5) { check_uidgid( @@ -1494,7 +1494,6 @@ do { \ else if (v == 5 /* O_JAIL */) key = ucred_cache.xid; #endif /* !__FreeBSD__ */ - key = htonl(key); } else #endif /* !USERSPACE */ break; Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Wed Jul 30 14:52:04 2014 (r269303) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Wed Jul 30 14:52:26 2014 (r269304) @@ -593,6 +593,9 @@ ipfw_find_table_entry(struct ip_fw_chain IPFW_UH_RUNLOCK(ch); return (EINVAL); } + case IPFW_TABLE_NUMBER: + plen = sizeof(uint32_t); + break; break; default: @@ -1744,17 +1747,19 @@ classify_table_opcode(ipfw_insn *cmd, ui case 2: case 3: /* src/dst port */ - //type = IPFW_TABLE_U16; + *ptype = IPFW_TABLE_NUMBER; break; case 4: /* uid/gid */ - //type = IPFW_TABLE_U32; + *ptype = IPFW_TABLE_NUMBER; + break; case 5: - //type = IPFW_TABLE_U32; /* jid */ + *ptype = IPFW_TABLE_NUMBER; + break; case 6: - //type = IPFW_TABLE_U16; /* dscp */ + *ptype = IPFW_TABLE_NUMBER; break; } } Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Wed Jul 30 14:52:04 2014 (r269303) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Wed Jul 30 14:52:26 2014 (r269304) @@ -1376,7 +1376,7 @@ struct table_algo cidr_hash = { * * Runtime part: * - sorted array of "struct ifidx" pointed by ti->state. - * Array is allocated with routing up to IFIDX_CHUNK. Only existing + * Array is allocated with rounding up to IFIDX_CHUNK. Only existing * interfaces are stored in array, however its allocated size is * sufficient to hold all table records if needed. * - current array size is stored in ti->data @@ -2025,6 +2025,368 @@ struct table_algo iface_idx = { .change_ti = ta_change_ti_ifidx, }; +/* + * Number array cmds. + * + * Implementation: + * + * Runtime part: + * - sorted array of "struct numarray" pointed by ti->state. + * Array is allocated with rounding up to NUMARRAY_CHUNK. + * - current array size is stored in ti->data + * + */ + +struct numarray { + uint32_t number; + uint32_t value; +}; + +struct numarray_cfg { + void *main_ptr; + size_t size; /* Number of items allocated in array */ + size_t used; /* Number of items _active_ now */ +}; + +#define NUMARRAY_CHUNK 16 + +int compare_numarray(const void *k, const void *v); + +int +compare_numarray(const void *k, const void *v) +{ + struct numarray *na; + uint32_t key; + + key = *((uint32_t *)k); + na = (struct numarray *)v; + + if (key < na->number) + return (-1); + else if (key > na->number) + return (1); + + return (0); +} + +static struct numarray * +numarray_find(struct table_info *ti, void *key) +{ + struct numarray *ri; + + ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray), + compare_ifidx); + + return (ri); +} + +static int +ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen, + uint32_t *val) +{ + struct numarray *ri; + + ri = numarray_find(ti, key); + + if (ri != NULL) { + *val = ri->value; + return (1); + } + + return (0); +} + +static int +ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, + char *data) +{ + struct numarray_cfg *cfg; + + cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO); + + cfg->size = NUMARRAY_CHUNK; + cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW, + M_WAITOK | M_ZERO); + + *ta_state = cfg; + ti->state = cfg->main_ptr; + ti->lookup = ta_lookup_numarray; + + return (0); +} + +/* + * Destroys table @ti + */ +static void +ta_destroy_numarray(void *ta_state, struct table_info *ti) +{ + struct numarray_cfg *cfg; + + cfg = (struct numarray_cfg *)ta_state; + + if (cfg->main_ptr != NULL) + free(cfg->main_ptr, M_IPFW); + + free(cfg, M_IPFW); +} + +struct ta_buf_numarray +{ + struct numarray na; +}; + +/* + * Prepare for addition/deletion to an array. + */ +static int +ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei, + void *ta_buf) +{ + struct ta_buf_numarray *tb; + + tb = (struct ta_buf_numarray *)ta_buf; + memset(tb, 0, sizeof(*tb)); + + tb->na.number = *((uint32_t *)tei->paddr); + tb->na.value = tei->value; + + return (0); +} + +static int +ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, + void *ta_buf, uint64_t *pflags, uint32_t *pnum) +{ + struct numarray_cfg *cfg; + struct ta_buf_numarray *tb; + struct numarray *ri; + int res; + + tb = (struct ta_buf_numarray*)ta_buf; + cfg = (struct numarray_cfg *)ta_state; + + ri = numarray_find(ti, &tb->na.number); + + if (ri != NULL) { + if ((tei->flags & TEI_FLAGS_UPDATE) == 0) + return (EEXIST); + + /* We need to update value */ + ri->value = tb->na.value; + /* Indicate that update has happened instead of addition */ + tei->flags |= TEI_FLAGS_UPDATED; + *pnum = 0; + return (0); + } + + res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used, + sizeof(struct numarray), compare_numarray); + + KASSERT(res == 1, ("number %d already exists", tb->na.number)); + cfg->used++; + ti->data = cfg->used; + + if (cfg->used + 1 == cfg->size) { + /* Notify core we need to grow */ + *pflags = cfg->size + NUMARRAY_CHUNK; + } + *pnum = 1; + + return (0); +} + +/* + * Remove key from both configuration list and + * runtime array. Removed interface notification. + */ +static int +ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, + void *ta_buf, uint64_t *pflags, uint32_t *pnum) +{ + struct numarray_cfg *cfg; + struct ta_buf_numarray *tb; + struct numarray *ri; + int res; + + tb = (struct ta_buf_numarray *)ta_buf; + cfg = (struct numarray_cfg *)ta_state; + + ri = numarray_find(ti, &tb->na.number); + if (ri == NULL) + return (ENOENT); + + res = bdel(&tb->na.number, cfg->main_ptr, cfg->used, + sizeof(struct numarray), compare_numarray); + + KASSERT(res == 1, ("number %u does not exist", tb->na.number)); + cfg->used--; + ti->data = cfg->used; + + *pnum = 1; + + return (0); +} + +static void +ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei, + void *ta_buf) +{ + + /* Do nothing */ +} + + +/* + * Table growing callbacks. + */ + +/* + * Allocate ned, larger runtime numarray array. + */ +static int +ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags) +{ + struct mod_item *mi; + + mi = (struct mod_item *)ta_buf; + + memset(mi, 0, sizeof(struct mod_item)); + mi->size = *pflags; + mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW, + M_WAITOK | M_ZERO); + + return (0); +} + +/* + * Copy data from old runtime array to new one. + */ +static int +ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf, + uint64_t *pflags) +{ + struct mod_item *mi; + struct numarray_cfg *cfg; + + mi = (struct mod_item *)ta_buf; + cfg = (struct numarray_cfg *)ta_state; + + /* Check if we still need to grow array */ + if (cfg->size >= mi->size) { + *pflags = 0; + return (0); + } + + memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray)); + + return (0); +} + +/* + * Switch old & new arrays. + */ +static int +ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf, + uint64_t pflags) +{ + struct mod_item *mi; + struct numarray_cfg *cfg; + void *old_ptr; + + mi = (struct mod_item *)ta_buf; + cfg = (struct numarray_cfg *)ta_state; + + old_ptr = cfg->main_ptr; + cfg->main_ptr = mi->main_ptr; + cfg->size = mi->size; + ti->state = cfg->main_ptr; + + mi->main_ptr = old_ptr; + + return (0); +} + +/* + * Free unneded array. + */ +static void +ta_flush_mod_numarray(void *ta_buf) +{ + struct mod_item *mi; + + mi = (struct mod_item *)ta_buf; + if (mi->main_ptr != NULL) + free(mi->main_ptr, M_IPFW); +} + +static int +ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e, + ipfw_obj_tentry *tent) +{ + struct numarray *na; + + na = (struct numarray *)e; + + tent->k.key = na->number; + tent->value = na->value; + + return (0); +} + +static int +ta_find_numarray_tentry(void *ta_state, struct table_info *ti, void *key, + uint32_t keylen, ipfw_obj_tentry *tent) +{ + struct numarray_cfg *cfg; + struct numarray *ri; + + cfg = (struct numarray_cfg *)ta_state; + + ri = numarray_find(ti, key); + + if (ri != NULL) { + ta_dump_numarray_tentry(ta_state, ti, ri, tent); + return (0); + } + + return (ENOENT); +} + +static void +ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f, + void *arg) +{ + struct numarray_cfg *cfg; + struct numarray *array; + int i; + + cfg = (struct numarray_cfg *)ta_state; + array = cfg->main_ptr; + + for (i = 0; i < cfg->used; i++) + f(&array[i], arg); +} + +struct table_algo number_array = { + .name = "number:array", + .type = IPFW_TABLE_NUMBER, + .init = ta_init_numarray, + .destroy = ta_destroy_numarray, + .prepare_add = ta_prepare_add_numarray, + .prepare_del = ta_prepare_add_numarray, + .add = ta_add_numarray, + .del = ta_del_numarray, + .flush_entry = ta_flush_numarray_entry, + .foreach = ta_foreach_numarray, + .dump_tentry = ta_dump_numarray_tentry, + .find_tentry = ta_find_numarray_tentry, + .prepare_mod = ta_prepare_mod_numarray, + .fill_mod = ta_fill_mod_numarray, + .modify = ta_modify_numarray, + .flush_mod = ta_flush_mod_numarray, +}; + void ipfw_table_algo_init(struct ip_fw_chain *ch) { @@ -2037,6 +2399,7 @@ ipfw_table_algo_init(struct ip_fw_chain ipfw_add_table_algo(ch, &cidr_radix, sz, &cidr_radix.idx); ipfw_add_table_algo(ch, &cidr_hash, sz, &cidr_hash.idx); ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx); + ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx); } void @@ -2046,6 +2409,7 @@ ipfw_table_algo_destroy(struct ip_fw_cha ipfw_del_table_algo(ch, cidr_radix.idx); ipfw_del_table_algo(ch, cidr_hash.idx); ipfw_del_table_algo(ch, iface_idx.idx); + ipfw_del_table_algo(ch, number_array.idx); }