From owner-svn-src-projects@FreeBSD.ORG Sat Jun 14 10:58:40 2014 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id DDFFDB67; Sat, 14 Jun 2014 10:58:40 +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 C96802562; Sat, 14 Jun 2014 10:58:40 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s5EAwexI008544; Sat, 14 Jun 2014 10:58:40 GMT (envelope-from melifaro@svn.freebsd.org) Received: (from melifaro@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s5EAwdkp008536; Sat, 14 Jun 2014 10:58:39 GMT (envelope-from melifaro@svn.freebsd.org) Message-Id: <201406141058.s5EAwdkp008536@svn.freebsd.org> From: "Alexander V. Chernikov" Date: Sat, 14 Jun 2014 10:58:39 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r267467 - in projects/ipfw: sbin/ipfw sys/conf 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: Sat, 14 Jun 2014 10:58:41 -0000 Author: melifaro Date: Sat Jun 14 10:58:39 2014 New Revision: 267467 URL: http://svnweb.freebsd.org/changeset/base/267467 Log: Add API to ease adding new algorithms/new tabletypes to ipfw. Kernel-side changelog: * Split general tables code and algorithm-specific table data. Current algorithms (IPv4/IPv6 radix and interface tables radix) moved to new ip_fw_table_algo.c file. Tables code now supports any algorithm implementing the following callbacks: +struct table_algo { + char name[64]; + int idx; + ta_init *init; + ta_destroy *destroy; + table_lookup_t *lookup; + ta_prepare_add *prepare_add; + ta_prepare_del *prepare_del; + ta_add *add; + ta_del *del; + ta_flush_entry *flush_entry; + ta_foreach *foreach; + ta_dump_entry *dump_entry; + ta_dump_xentry *dump_xentry; +}; * Change ->state, ->xstate, ->tabletype fields of ip_fw_chain to ->tablestate pointer (array of 32 bytes structures necessary for runtime lookups (can be probably shrinked to 16 bytes later): +struct table_info { + table_lookup_t *lookup; /* Lookup function */ + void *state; /* Lookup radix/other structure */ + void *xstate; /* eXtended state */ + u_long data; /* Hints for given func */ +}; * Add count method for namedobj instance to ease size calculations * Bump ip_fw3 buffer in ipfw_clt 128->256 bytes. * Improve bitmask resizing on tables_max change. * Remove table numbers checking from most places. * Fix wrong nesting in ipfw_rewrite_table_uidx(). * Add IP_FW_OBJ_LIST opcode (list all objects of given type, currently implemented for IPFW_OBJTYPE_TABLE). * Add IP_FW_OBJ_LISTSIZE (get buffer size to hold IP_FW_OBJ_LIST data, currenly implemented for IPFW_OBJTYPE_TABLE). * Add IP_FW_OBJ_INFO (requests info for one object of given type). Some name changes: s/ipfw_xtable_tlv/ipfw_obj_tlv/ (no table specifics) s/ipfw_xtable_ntlv/ipfw_obj_ntlv/ (no table specifics) Userland changes: * Add do_set3() cmd to ipfw2 to ease dealing with op3-embeded opcodes. * Add/improve support for destroy/info cmds. Added: projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Modified: projects/ipfw/sbin/ipfw/ipfw2.c projects/ipfw/sys/conf/files 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 Modified: projects/ipfw/sbin/ipfw/ipfw2.c ============================================================================== --- projects/ipfw/sbin/ipfw/ipfw2.c Sat Jun 14 06:54:03 2014 (r267466) +++ projects/ipfw/sbin/ipfw/ipfw2.c Sat Jun 14 10:58:39 2014 (r267467) @@ -448,6 +448,33 @@ do_cmd(int optname, void *optval, uintpt } /* + * do_set3 - pass ipfw control cmd to kernel + * @optname: option name + * @optval: pointer to option data + * @optlen: option length + * + * Assumes op3 header is already embedded. + * Calls setsockopt() with IP_FW3 as kernel-visible opcode. + * Returns 0 on success or -1 otherwise. + */ +static int +do_set3(int optname, ip_fw3_opheader *op3, socklen_t optlen) +{ + + if (co.test_only) + return (0); + + if (ipfw_socket == -1) + ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + if (ipfw_socket < 0) + err(EX_UNAVAILABLE, "socket"); + + op3->opcode = optname; + + return (setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, optlen)); +} + +/* * do_setcmd3 - pass ipfw control cmd to kernel * @optname: option name * @optval: pointer to option data @@ -4124,6 +4151,10 @@ ipfw_flush(int force) static void table_list(uint16_t num, int need_header); static void table_fill_xentry(char *arg, ipfw_table_xentry *xent); +static int table_destroy(char *name, uint32_t set); +static int table_get_info(char *name, uint32_t set, ipfw_xtable_info *i); +static void table_show_info(ipfw_xtable_info *i); +static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint16_t uidx); /* * Retrieve maximum number of tables supported by ipfw(4) module. @@ -4167,12 +4198,17 @@ ipfw_table_handler(int ac, char *av[]) int is_all; uint32_t a; uint32_t tables_max; + uint32_t set; + int error; + char *tablename; tables_max = ipfw_get_tables_max(); memset(&xent, 0, sizeof(xent)); ac--; av++; + tablename = *av; + set = 0; if (ac && isdigit(**av)) { xent.tbl = atoi(*av); is_all = 0; @@ -4244,22 +4280,13 @@ ipfw_table_handler(int ac, char *av[]) table_list(xent.tbl, is_all); } while (++xent.tbl < a); } else if (_substrcmp(*av, "destroy") == 0) { - char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_ntlv)]; - ipfw_obj_header *oh; - ipfw_xtable_ntlv *ntlv; - - memset(xbuf, 0, sizeof(xbuf)); - oh = (ipfw_obj_header *)xbuf; - ntlv = (ipfw_xtable_ntlv *)(oh + 1); - - ntlv->head.type = IPFW_TLV_NAME; - ntlv->head.length = sizeof(*ntlv); - ntlv->idx = 1; - snprintf(ntlv->name, sizeof(ntlv->name), "%d", xent.tbl); - oh->idx = 1; - oh->objtype = IPFW_OBJTYPE_TABLE; - if (do_setcmd3(IP_FW_OBJ_DEL, xbuf, sizeof(xbuf)) != 0) - err(EX_OSERR, "setsockopt(IP_FW_OBJ_DEL)"); + if (table_destroy(tablename, set) != 0) + err(EX_OSERR, "failed to destroy table %s", tablename); + } else if (_substrcmp(*av, "info") == 0) { + ipfw_xtable_info i; + if ((error = table_get_info(tablename, set, &i)) != 0) + err(EX_OSERR, "failed to request table info"); + table_show_info(&i); } else errx(EX_USAGE, "invalid table command %s", *av); } @@ -4363,6 +4390,93 @@ table_fill_xentry(char *arg, ipfw_table_ } static void +table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint16_t uidx) +{ + + ntlv->head.type = IPFW_TLV_NAME; + ntlv->head.length = sizeof(ipfw_obj_ntlv); + ntlv->idx = uidx; + strlcpy(ntlv->name, name, sizeof(ntlv->name)); +} + +/* + * Destroys given table @name in given @set. + * Returns 0 on success. + */ +static int +table_destroy(char *name, uint32_t set) +{ + ipfw_obj_header oh; + + memset(&oh, 0, sizeof(oh)); + oh.idx = 1; + oh.objtype = IPFW_OBJTYPE_TABLE; + table_fill_ntlv(&oh.ntlv, name, 1); + if (do_set3(IP_FW_OBJ_DEL, &oh.opheader, sizeof(oh)) != 0) + return (-1); + + return (0); +} + +/* + * Retrieves info for given table @name in given @set and stores + * it inside @i. + * Returns 0 on success. + */ +static int +table_get_info(char *name, uint32_t set, ipfw_xtable_info *i) +{ + char tbuf[sizeof(ipfw_obj_header)+sizeof(ipfw_xtable_info)]; + ipfw_obj_header *oh; + size_t sz; + + sz = sizeof(tbuf); + memset(tbuf, 0, sizeof(tbuf)); + oh = (ipfw_obj_header *)tbuf; + + oh->opheader.opcode = IP_FW_OBJ_INFO; + oh->set = set; + oh->idx = 1; + oh->objtype = IPFW_OBJTYPE_TABLE; + table_fill_ntlv(&oh->ntlv, name, 1); + + if (do_cmd(IP_FW3, oh, (uintptr_t)&sz) < 0) + return (-1); + + if (sz < sizeof(tbuf)) + return (-1); + + *i = *(ipfw_xtable_info *)(oh + 1); + + return (0); +} + +/* + * Prints table info struct @i in human-readable form. + */ +static void +table_show_info(ipfw_xtable_info *i) +{ + char *type; + + printf("--- table %s, set %u ---\n", i->tablename, i->set); + switch (i->type) { + case IPFW_TABLE_CIDR: + type = "cidr"; + break; + case IPFW_TABLE_INTERFACE: + type = "iface"; + break; + default: + type = "unknown"; + } + printf("type: %s, kindex: %d\n", type, i->kidx); + printf("ftype: %d, algorithm: %d\n", i->ftype, i->atype); + printf("references: %u\n", i->refcnt); + printf("items: %u, size: %u\n", i->count, i->size); +} + +static void table_list(uint16_t num, int need_header) { ipfw_xtable *tbl; Modified: projects/ipfw/sys/conf/files ============================================================================== --- projects/ipfw/sys/conf/files Sat Jun 14 06:54:03 2014 (r267466) +++ projects/ipfw/sys/conf/files Sat Jun 14 10:58:39 2014 (r267467) @@ -3449,6 +3449,7 @@ netpfil/ipfw/ip_fw_log.c optional inet i netpfil/ipfw/ip_fw_pfil.c optional inet ipfirewall 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_nat.c optional inet ipfirewall_nat netpfil/pf/if_pflog.c optional pflog pf inet netpfil/pf/if_pfsync.c optional pfsync pf inet Modified: projects/ipfw/sys/netinet/ip_fw.h ============================================================================== --- projects/ipfw/sys/netinet/ip_fw.h Sat Jun 14 06:54:03 2014 (r267466) +++ projects/ipfw/sys/netinet/ip_fw.h Sat Jun 14 10:58:39 2014 (r267467) @@ -80,6 +80,9 @@ typedef struct _ip_fw3_opheader { #define IP_FW_TABLE_XGETSIZE 88 /* get table size */ #define IP_FW_TABLE_XLIST 89 /* list table contents */ #define IP_FW_OBJ_DEL 90 /* del table/pipe/etc */ +#define IP_FW_OBJ_LISTSIZE 91 /* get size for table/etc list */ +#define IP_FW_OBJ_LIST 92 /* list all objects of given type */ +#define IP_FW_OBJ_INFO 93 /* request info for one object */ /* * The kernel representation of ipfw rules is made of a list of @@ -646,26 +649,53 @@ typedef struct _ipfw_xtable { ipfw_table_xentry xent[0]; /* entries */ } ipfw_xtable; -typedef struct _ipfw_xtable_tlv { +typedef struct _ipfw_obj_tlv { uint16_t type; /* TLV type */ uint16_t length; /* Total length, aligned to u32 */ -} ipfw_xtable_tlv; +} ipfw_obj_tlv; #define IPFW_TLV_NAME 1 /* Object name TLV */ -typedef struct _ipfw_xtable_ntlv { - ipfw_xtable_tlv head; /* TLV header */ +typedef struct _ipfw_obj_ntlv { + ipfw_obj_tlv head; /* TLV header */ uint16_t idx; /* Name index */ uint16_t spare; /* unused */ char name[64]; /* Null-terminated name */ -} ipfw_xtable_ntlv; +} ipfw_obj_ntlv; +typedef struct _ipfw_xtable_info { + uint8_t type; /* table type (cidr,iface,..) */ + uint8_t ftype; /* format table type */ + uint8_t atype; /* algorithm type */ + uint8_t spare0; + uint32_t set; /* set table is in */ + uint32_t kidx; /* kernel index */ + uint32_t refcnt; /* number of references */ + uint32_t count; /* Number of records */ + uint32_t size; /* Total size of records */ + char tablename[64]; /* table name */ +} ipfw_xtable_info; + +#define IPFW_OBJTYPE_TABLE 1 +/* IP_FW_OBJ_DEL, IP_FW_OBJ_INFO (followed by ipfw_xtable_info) */ typedef struct _ipfw_obj_header { ip_fw3_opheader opheader; /* IP_FW3 opcode */ uint32_t set; /* Set we're operating */ uint16_t idx; /* object name index */ - uint16_t objtype; /* object type */ + uint8_t objtype; /* object type */ + uint8_t objsubtype; /* object subtype */ + ipfw_obj_ntlv ntlv; /* object name tlv */ } ipfw_obj_header; -#define IPFW_OBJTYPE_TABLE 1 + +/* IP_FW_OBJ_LISTSIZE, IP_FW_OBJ_LIST (followd by ipfw_xtable_info) */ +typedef struct _ipfw_obj_lheader { + ip_fw3_opheader opheader; /* IP_FW3 opcode */ + uint8_t objtype; /* object type */ + uint8_t spare0; + uint16_t spare1; + uint32_t count; /* Total objects count */ + uint32_t size; /* Total objects size */ + uint32_t objsize; /* Size of one object */ +} ipfw_obj_lheader; #endif /* _IPFW2_H */ Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw2.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Sat Jun 14 06:54:03 2014 (r267466) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw2.c Sat Jun 14 10:58:39 2014 (r267467) @@ -360,8 +360,8 @@ iface_match(struct ifnet *ifp, ipfw_insn /* Check by name or by IP address */ if (cmd->name[0] != '\0') { /* match by name */ if (cmd->name[0] == '\1') /* use tablearg to match */ - return ipfw_lookup_table_extended(chain, cmd->p.glob, - ifp->if_xname, tablearg, IPFW_TABLE_INTERFACE); + return ipfw_lookup_table_extended(chain, cmd->p.glob, 0, + ifp->if_xname, tablearg); /* Check name */ if (cmd->p.glob) { if (fnmatch(cmd->name, ifp->if_xname, 0) == 0) @@ -1506,8 +1506,9 @@ do { \ void *pkey = (cmd->opcode == O_IP_DST_LOOKUP) ? &args->f_id.dst_ip6: &args->f_id.src_ip6; match = ipfw_lookup_table_extended(chain, - cmd->arg1, pkey, &v, - IPFW_TABLE_CIDR); + cmd->arg1, + sizeof(struct in6_addr), + pkey, &v); if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) match = ((ipfw_insn_u32 *)cmd)->d[0] == v; if (match) Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h Sat Jun 14 06:54:03 2014 (r267466) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h Sat Jun 14 10:58:39 2014 (r267467) @@ -222,8 +222,7 @@ struct ip_fw_chain { uint32_t id; /* ruleset id */ int n_rules; /* number of static rules */ LIST_HEAD(nat_list, cfg_nat) nat; /* list of nat entries */ - struct radix_node_head **tables; /* IPv4 tables */ - struct radix_node_head **xtables; /* extended tables */ + void *tablestate; /* runtime table info */ #if defined( __linux__ ) || defined( _WIN32 ) spinlock_t rwmtx; #else @@ -304,7 +303,7 @@ struct tid_info { uint32_t set; /* table set */ uint16_t uidx; /* table index */ uint8_t type; /* table type */ - uint8_t spare; + uint8_t atype; void *tlvs; /* Pointer to first TLV */ int tlen; /* Total TLV size block */ }; @@ -363,7 +362,9 @@ typedef void (objhash_cb_t)(struct named struct namedobj_instance *ipfw_objhash_create(uint32_t items); void ipfw_objhash_destroy(struct namedobj_instance *); void ipfw_objhash_bitmap_alloc(uint32_t items, void **idx, int *pblocks); -int ipfw_objhash_bitmap_merge(struct namedobj_instance *ni, +void ipfw_objhash_bitmap_merge(struct namedobj_instance *ni, + void **idx, int *blocks); +void ipfw_objhash_bitmap_swap(struct namedobj_instance *ni, void **idx, int *blocks); void ipfw_objhash_bitmap_free(void *idx, int blocks); struct named_object *ipfw_objhash_lookup_name(struct namedobj_instance *ni, @@ -372,6 +373,7 @@ struct named_object *ipfw_objhash_lookup uint32_t set, uint16_t idx); void ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no); void ipfw_objhash_del(struct namedobj_instance *ni, struct named_object *no); +uint32_t ipfw_objhash_count(struct namedobj_instance *ni); void ipfw_objhash_foreach(struct namedobj_instance *ni, objhash_cb_t *f, void *arg); int ipfw_objhash_free_idx(struct namedobj_instance *ni, uint32_t set, @@ -379,13 +381,60 @@ int ipfw_objhash_free_idx(struct namedob int ipfw_objhash_alloc_idx(void *n, uint32_t set, uint16_t *pidx); /* In ip_fw_table.c */ +struct table_info; + +typedef int (table_lookup_t)(struct table_info *ti, void *key, uint32_t keylen, + uint32_t *val); +struct table_info { + table_lookup_t *lookup; /* Lookup function */ + void *state; /* Lookup radix/other structure */ + void *xstate; /* eXtended state */ + u_long data; /* Hints for given func */ +}; + +typedef int (ta_init)(void **ta_state, struct table_info *ti); +typedef void (ta_destroy)(void *ta_state, struct table_info *ti); +typedef int (ta_prepare_add)(struct tentry_info *tei, void *ta_buf); +typedef int (ta_prepare_del)(struct tentry_info *tei, void *ta_buf); +typedef int (ta_add)(void *ta_state, struct table_info *ti, + struct tentry_info *tei, void *ta_buf); +typedef int (ta_del)(void *ta_state, struct table_info *ti, + struct tentry_info *tei, void *ta_buf); +typedef void (ta_flush_entry)(struct tentry_info *tei, void *ta_buf); + +typedef int ta_foreach_f(void *node, void *arg); +typedef void ta_foreach(void *ta_state, struct table_info *ti, ta_foreach_f *f, + void *arg); +typedef int ta_dump_entry(void *ta_state, struct table_info *ti, void *e, + ipfw_table_entry *ent); +typedef int ta_dump_xentry(void *ta_state, struct table_info *ti, void *e, + ipfw_table_xentry *xent); + +struct table_algo { + char name[64]; + int idx; + ta_init *init; + ta_destroy *destroy; + table_lookup_t *lookup; + ta_prepare_add *prepare_add; + ta_prepare_del *prepare_del; + ta_add *add; + ta_del *del; + ta_flush_entry *flush_entry; + ta_foreach *foreach; + ta_dump_entry *dump_entry; + ta_dump_xentry *dump_xentry; +}; +void ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta); +extern struct table_algo radix_cidr, radix_iface; + struct radix_node; int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, uint32_t *val); -int ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr, - uint32_t *val, int type); +int ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen, + void *paddr, uint32_t *val); int ipfw_init_tables(struct ip_fw_chain *ch); -int ipfw_destroy_table(struct ip_fw_chain *ch, struct tid_info *ti, int force); +int ipfw_destroy_table(struct ip_fw_chain *ch, struct tid_info *ti); void ipfw_destroy_tables(struct ip_fw_chain *ch); int ipfw_flush_table(struct ip_fw_chain *ch, struct tid_info *ti); int ipfw_add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, @@ -394,13 +443,17 @@ int ipfw_del_table_entry(struct ip_fw_ch struct tentry_info *tei); int ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt); -int ipfw_dump_table_entry(struct radix_node *rn, void *arg); -int ipfw_dump_table(struct ip_fw_chain *ch, struct tid_info *ti, - ipfw_table *tbl); int ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt); +int ipfw_dump_table(struct ip_fw_chain *ch, struct tid_info *ti, + ipfw_table *tbl); int ipfw_dump_xtable(struct ip_fw_chain *ch, struct tid_info *ti, ipfw_xtable *tbl); +int ipfw_describe_table(struct ip_fw_chain *ch, struct tid_info *ti, + ipfw_xtable_info *i); +int ipfw_count_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh); +int ipfw_list_tables(struct ip_fw_chain *ch, struct tid_info *ti, + ipfw_obj_lheader *olh); int ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables); int ipfw_rewrite_table_uidx(struct ip_fw_chain *chain, struct rule_check_info *ci); @@ -408,6 +461,9 @@ int ipfw_rewrite_table_kidx(struct ip_fw void ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule); void ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head); +void ipfw_table_algo_init(struct ip_fw_chain *chain); +void ipfw_table_algo_destroy(struct ip_fw_chain *chain); + /* In ip_fw_nat.c -- XXX to be moved to ip_var.h */ extern struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int); Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Sat Jun 14 06:54:03 2014 (r267466) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c Sat Jun 14 10:58:39 2014 (r267467) @@ -77,6 +77,7 @@ struct namedobj_instance { uint32_t nv_size; /* number hash size */ u_long *idx_mask; /* used items bitmask */ uint32_t max_blocks; /* number of "long" blocks in bitmask */ + uint32_t count; /* number of items */ uint16_t free_off[IPFW_MAX_SETS]; /* first possible free offset */ }; #define BLOCK_ITEMS (8 * sizeof(u_long)) /* Number of items for ffsl() */ @@ -1000,7 +1001,7 @@ ipfw_ctl(struct sockopt *sopt) struct ip_fw_chain *chain; u_int32_t rulenum[2]; uint32_t opt; - char xbuf[128]; + char xbuf[256]; ip_fw3_opheader *op3 = NULL; struct rule_check_info ci; @@ -1171,6 +1172,7 @@ ipfw_ctl(struct sockopt *sopt) /*--- TABLE manipulations are protected by the IPFW_LOCK ---*/ case IP_FW_OBJ_DEL: /* IP_FW3 */ + case IP_FW_OBJ_INFO: /* IP_FW3 */ { struct _ipfw_obj_header *oh; struct tid_info ti; @@ -1180,16 +1182,31 @@ ipfw_ctl(struct sockopt *sopt) break; } - oh = (struct _ipfw_obj_header *)(op3 + 1); + oh = (struct _ipfw_obj_header *)op3; switch (oh->objtype) { case IPFW_OBJTYPE_TABLE: memset(&ti, 0, sizeof(ti)); ti.set = oh->set; ti.uidx = oh->idx; - ti.tlvs = (oh + 1); - ti.tlen = sopt->sopt_valsize - sizeof(*oh); - error = ipfw_destroy_table(chain, &ti, 0); + ti.tlvs = &oh->ntlv; + ti.tlen = oh->ntlv.head.length; + if (opt == IP_FW_OBJ_DEL) + error = ipfw_destroy_table(chain, &ti); + else { + /* IP_FW_OBJ_INFO */ + if (sopt->sopt_valsize < sizeof(*oh) + + sizeof(ipfw_xtable_info)) { + error = EINVAL; + break; + } + + error = ipfw_describe_table(chain, &ti, + (ipfw_xtable_info *)(oh + 1)); + if (error == 0) + error = sooptcopyout(sopt, oh, + sopt->sopt_valsize); + } break; default: error = ENOTSUP; @@ -1563,6 +1580,10 @@ convert_rule_to_8(struct ip_fw *rule) * */ +/* + * Allocate new bitmask which can be used to enlarge/shrink + * named instance index. + */ void ipfw_objhash_bitmap_alloc(uint32_t items, void **idx, int *pblocks) { @@ -1581,7 +1602,10 @@ ipfw_objhash_bitmap_alloc(uint32_t items *pblocks = max_blocks; } -int +/* + * Copy current bitmask index to new one. + */ +void ipfw_objhash_bitmap_merge(struct namedobj_instance *ni, void **idx, int *blocks) { int old_blocks, new_blocks; @@ -1593,25 +1617,30 @@ ipfw_objhash_bitmap_merge(struct namedob new_idx = *idx; new_blocks = *blocks; - /* - * FIXME: Permit reducing total amount of tables - */ - if (old_blocks > new_blocks) - return (1); - for (i = 0; i < IPFW_MAX_SETS; i++) { memcpy(&new_idx[new_blocks * i], &old_idx[old_blocks * i], old_blocks * sizeof(u_long)); } +} + +/* + * Swaps current @ni index with new one. + */ +void +ipfw_objhash_bitmap_swap(struct namedobj_instance *ni, void **idx, int *blocks) +{ + int old_blocks; + u_long *old_idx; - ni->idx_mask = new_idx; - ni->max_blocks = new_blocks; + old_idx = ni->idx_mask; + old_blocks = ni->max_blocks; + + ni->idx_mask = *idx; + ni->max_blocks = *blocks; /* Save old values */ *idx = old_idx; *blocks = old_blocks; - - return (0); } void @@ -1727,6 +1756,8 @@ ipfw_objhash_add(struct namedobj_instanc hash = objhash_hash_val(ni, no->set, no->kidx); TAILQ_INSERT_HEAD(&ni->values[hash], no, nv_next); + + ni->count++; } void @@ -1739,6 +1770,15 @@ ipfw_objhash_del(struct namedobj_instanc hash = objhash_hash_val(ni, no->set, no->kidx); TAILQ_REMOVE(&ni->values[hash], no, nv_next); + + ni->count--; +} + +uint32_t +ipfw_objhash_count(struct namedobj_instance *ni) +{ + + return (ni->count); } /* Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Sat Jun 14 06:54:03 2014 (r267466) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Sat Jun 14 10:58:39 2014 (r267467) @@ -65,252 +65,133 @@ __FBSDID("$FreeBSD$"); #include -#ifdef MAC -#include -#endif - -static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables"); - -struct table_entry { - struct radix_node rn[2]; - struct sockaddr_in addr, mask; - u_int32_t value; -}; - -struct xaddr_iface { - uint8_t if_len; /* length of this struct */ - uint8_t pad[7]; /* Align name */ - char ifname[IF_NAMESIZE]; /* Interface name */ -}; - -struct table_xentry { - struct radix_node rn[2]; - union { -#ifdef INET6 - struct sockaddr_in6 addr6; -#endif - struct xaddr_iface iface; - } a; - union { -#ifdef INET6 - struct sockaddr_in6 mask6; -#endif - struct xaddr_iface ifmask; - } m; - u_int32_t value; -}; /* * Table has the following `type` concepts: * - * `type` represents lookup key type (cidr, ifp, uid, etc..) - * `ftype` is pure userland field helping to properly format table data - * `atype` represents exact lookup algorithm for given tabletype. + * `no.type` represents lookup key type (cidr, ifp, uid, etc..) + * `ta->atype` represents exact lookup algorithm. * For example, we can use more efficient search schemes if we plan * to use some specific table for storing host-routes only. + * `ftype` is pure userland field helping to properly format table data + * e.g. "value is IPv4 nexthop" or "key is port number" * */ struct table_config { struct named_object no; uint8_t ftype; /* format table type */ - uint8_t atype; /* algorith type */ uint8_t linked; /* 1 if already linked */ - uint8_t spare0; + uint16_t spare0; uint32_t count; /* Number of records */ char tablename[64]; /* table name */ - void *state; /* Store some state if needed */ - void *xstate; + struct table_algo *ta; /* Callbacks for given algo */ + void *astate; /* algorithm state */ + struct table_info ti; /* data to put to table_info */ }; #define TABLE_SET(set) ((V_fw_tables_sets != 0) ? set : 0) struct tables_config { struct namedobj_instance *namehash; + int algo_count; + struct table_algo *algo[256]; }; static struct table_config *find_table(struct namedobj_instance *ni, struct tid_info *ti); static struct table_config *alloc_table_config(struct namedobj_instance *ni, - struct tid_info *ti); + struct tid_info *ti, struct table_algo *ta); static void free_table_config(struct namedobj_instance *ni, struct table_config *tc); static void link_table(struct ip_fw_chain *chain, struct table_config *tc); static void unlink_table(struct ip_fw_chain *chain, struct table_config *tc); -static int alloc_table_state(void **state, void **xstate, uint8_t type); static void free_table_state(void **state, void **xstate, uint8_t type); +static struct table_algo *find_table_algo(struct tables_config *tableconf, + struct tid_info *ti); #define CHAIN_TO_TCFG(chain) ((struct tables_config *)(chain)->tblcfg) #define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash) +#define KIDX_TO_TI(ch, k) (&(((struct table_info *)(ch)->tablestate)[k])) -/* - * The radix code expects addr and mask to be array of bytes, - * with the first byte being the length of the array. rn_inithead - * is called with the offset in bits of the lookup key within the - * array. If we use a sockaddr_in as the underlying type, - * sin_len is conveniently located at offset 0, sin_addr is at - * offset 4 and normally aligned. - * But for portability, let's avoid assumption and make the code explicit - */ -#define KEY_LEN(v) *((uint8_t *)&(v)) -#define KEY_OFS (8*offsetof(struct sockaddr_in, sin_addr)) -/* - * Do not require radix to compare more than actual IPv4/IPv6 address - */ -#define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t)) -#define KEY_LEN_INET6 (offsetof(struct sockaddr_in6, sin6_addr) + sizeof(struct in6_addr)) -#define KEY_LEN_IFACE (offsetof(struct xaddr_iface, ifname)) - -#define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr)) -#define OFF_LEN_INET6 (8 * offsetof(struct sockaddr_in6, sin6_addr)) -#define OFF_LEN_IFACE (8 * offsetof(struct xaddr_iface, ifname)) - - -#ifdef INET6 -static inline void -ipv6_writemask(struct in6_addr *addr6, uint8_t mask) -{ - uint32_t *cp; - - for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32) - *cp++ = 0xFFFFFFFF; - *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0); -} -#endif int ipfw_add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, struct tentry_info *tei) { - struct radix_node_head *rnh; - struct table_entry *ent; - struct table_xentry *xent; - struct radix_node *rn; - in_addr_t addr; - int offset; - void *ent_ptr; - struct sockaddr *addr_ptr, *mask_ptr; struct table_config *tc, *tc_new; + struct table_algo *ta; struct namedobj_instance *ni; - char c; - uint8_t mlen; uint16_t kidx; + int error; + char ta_buf[128]; +#if 0 if (ti->uidx >= V_fw_tables_max) return (EINVAL); +#endif - mlen = tei->masklen; + IPFW_UH_WLOCK(ch); + ni = CHAIN_TO_NI(ch); - switch (ti->type) { - case IPFW_TABLE_CIDR: - if (tei->plen == sizeof(in_addr_t)) { -#ifdef INET - /* IPv4 case */ - if (mlen > 32) - return (EINVAL); - ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); - ent->value = tei->value; - /* Set 'total' structure length */ - KEY_LEN(ent->addr) = KEY_LEN_INET; - KEY_LEN(ent->mask) = KEY_LEN_INET; - /* Set offset of IPv4 address in bits */ - offset = OFF_LEN_INET; - ent->mask.sin_addr.s_addr = - htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); - addr = *((in_addr_t *)tei->paddr); - ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr; - /* Set pointers */ - ent_ptr = ent; - addr_ptr = (struct sockaddr *)&ent->addr; - mask_ptr = (struct sockaddr *)&ent->mask; -#endif -#ifdef INET6 - } else if (tei->plen == sizeof(struct in6_addr)) { - /* IPv6 case */ - if (mlen > 128) - return (EINVAL); - xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO); - xent->value = tei->value; - /* Set 'total' structure length */ - KEY_LEN(xent->a.addr6) = KEY_LEN_INET6; - KEY_LEN(xent->m.mask6) = KEY_LEN_INET6; - /* Set offset of IPv6 address in bits */ - offset = OFF_LEN_INET6; - ipv6_writemask(&xent->m.mask6.sin6_addr, mlen); - memcpy(&xent->a.addr6.sin6_addr, tei->paddr, - sizeof(struct in6_addr)); - APPLY_MASK(&xent->a.addr6.sin6_addr, &xent->m.mask6.sin6_addr); - /* Set pointers */ - ent_ptr = xent; - addr_ptr = (struct sockaddr *)&xent->a.addr6; - mask_ptr = (struct sockaddr *)&xent->m.mask6; -#endif - } else { - /* Unknown CIDR type */ + /* + * Find and reference existing table. + */ + ta = NULL; + if ((tc = find_table(ni, ti)) != NULL) { + /* check table type */ + if (tc->no.type != ti->type) { + IPFW_UH_WUNLOCK(ch); return (EINVAL); } - break; - - case IPFW_TABLE_INTERFACE: - /* Check if string is terminated */ - c = ((char *)tei->paddr)[IF_NAMESIZE - 1]; - ((char *)tei->paddr)[IF_NAMESIZE - 1] = '\0'; - mlen = strlen((char *)tei->paddr); - if ((mlen == IF_NAMESIZE - 1) && (c != '\0')) - return (EINVAL); - /* Include last \0 into comparison */ - mlen++; - - xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO); - xent->value = tei->value; - /* Set 'total' structure length */ - KEY_LEN(xent->a.iface) = KEY_LEN_IFACE + mlen; - KEY_LEN(xent->m.ifmask) = KEY_LEN_IFACE + mlen; - /* Set offset of interface name in bits */ - offset = OFF_LEN_IFACE; - memcpy(xent->a.iface.ifname, tei->paddr, mlen); - /* Assume direct match */ - /* TODO: Add interface pattern matching */ -#if 0 - memset(xent->m.ifmask.ifname, 0xFF, IF_NAMESIZE); - mask_ptr = (struct sockaddr *)&xent->m.ifmask; -#endif - /* Set pointers */ - ent_ptr = xent; - addr_ptr = (struct sockaddr *)&xent->a.iface; - mask_ptr = NULL; - break; - - default: - return (EINVAL); + /* Reference and unlock */ + tc->no.refcnt++; + ta = tc->ta; } - - IPFW_UH_WLOCK(ch); - - ni = CHAIN_TO_NI(ch); + IPFW_UH_WUNLOCK(ch); tc_new = NULL; - if ((tc = find_table(ni, ti)) == NULL) { - /* Not found. We have to create new one */ - IPFW_UH_WUNLOCK(ch); + if (ta == NULL) { + /* Table not found. We have to create new one */ + if ((ta = find_table_algo(CHAIN_TO_TCFG(ch), ti)) == NULL) + return (ENOTSUP); - tc_new = alloc_table_config(ni, ti); + tc_new = alloc_table_config(ni, ti, ta); if (tc_new == NULL) return (ENOMEM); + } - IPFW_UH_WLOCK(ch); + /* Prepare record (allocate memory) */ + memset(&ta_buf, 0, sizeof(ta_buf)); + error = ta->prepare_add(tei, &ta_buf); + if (error != 0) { + if (tc_new != NULL) + free_table_config(ni, tc_new); + return (error); + } + + IPFW_UH_WLOCK(ch); - /* Check if table has already allocated by other thread */ + ni = CHAIN_TO_NI(ch); + + if (tc == NULL) { + /* Check if another table was allocated by other thread */ if ((tc = find_table(ni, ti)) != NULL) { - if (tc->no.type != ti->type) { + + /* + * Check if algoritm is the same since we've + * already allocated state using @ta algoritm + * callbacks. + */ + if (tc->ta != ta) { IPFW_UH_WUNLOCK(ch); free_table_config(ni, tc); return (EINVAL); } } else { /* - * New table. + * We're first to create this table. * Set tc_new to zero not to free it afterwards. */ tc = tc_new; @@ -331,212 +212,103 @@ ipfw_add_table_entry(struct ip_fw_chain tc->no.kidx = kidx; } } else { - /* We still have to check table type */ - if (tc->no.type != ti->type) { - IPFW_UH_WUNLOCK(ch); - return (EINVAL); - } + /* Drop reference we've used in first search */ + tc->no.refcnt--; } + + /* We've got valid table in @tc. Let's add data */ kidx = tc->no.kidx; + ta = tc->ta; - /* We've got valid table in @tc. Let's add data */ IPFW_WLOCK(ch); if (tc->linked == 0) { link_table(ch, tc); } - /* XXX: Temporary until splitting add/del to per-type functions */ - rnh = NULL; - switch (ti->type) { - case IPFW_TABLE_CIDR: - if (tei->plen == sizeof(in_addr_t)) - rnh = ch->tables[kidx]; - else - rnh = ch->xtables[kidx]; - break; - case IPFW_TABLE_INTERFACE: - rnh = ch->xtables[kidx]; - break; - } + error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf); - rn = rnh->rnh_addaddr(addr_ptr, mask_ptr, rnh, ent_ptr); IPFW_WUNLOCK(ch); + + if (error == 0) + tc->count++; + IPFW_UH_WUNLOCK(ch); if (tc_new != NULL) free_table_config(ni, tc); - if (rn == NULL) { - free(ent_ptr, M_IPFW_TBL); - return (EEXIST); - } + if (error != 0) + ta->flush_entry(tei, &ta_buf); - return (0); + return (error); } int ipfw_del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, struct tentry_info *tei) { - struct radix_node_head *rnh; - struct table_entry *ent; - in_addr_t addr; - struct sockaddr_in sa, mask; - struct sockaddr *sa_ptr, *mask_ptr; struct table_config *tc; + struct table_algo *ta; struct namedobj_instance *ni; - char c; - uint8_t mlen; uint16_t kidx; + int error; + char ta_buf[128]; - if (ti->uidx >= V_fw_tables_max) - return (EINVAL); - - mlen = tei->masklen; - - switch (ti->type) { - case IPFW_TABLE_CIDR: - if (tei->plen == sizeof(in_addr_t)) { - /* Set 'total' structure length */ - KEY_LEN(sa) = KEY_LEN_INET; - KEY_LEN(mask) = KEY_LEN_INET; - mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); - addr = *((in_addr_t *)tei->paddr); - sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr; - sa_ptr = (struct sockaddr *)&sa; - mask_ptr = (struct sockaddr *)&mask; -#ifdef INET6 - } else if (tei->plen == sizeof(struct in6_addr)) { - /* IPv6 case */ - if (mlen > 128) - return (EINVAL); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***