From owner-svn-src-user@FreeBSD.ORG Mon Apr 27 09:10:34 2015 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 68F386DA; Mon, 27 Apr 2015 09:10:34 +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 5664316CA; Mon, 27 Apr 2015 09:10:34 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t3R9AYe4027589; Mon, 27 Apr 2015 09:10:34 GMT (envelope-from ngie@FreeBSD.org) Received: (from ngie@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t3R9AWX2027580; Mon, 27 Apr 2015 09:10:32 GMT (envelope-from ngie@FreeBSD.org) Message-Id: <201504270910.t3R9AWX2027580@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: ngie set sender to ngie@FreeBSD.org using -f From: Garrett Cooper Date: Mon, 27 Apr 2015 09:10:32 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r282077 - in user/ngie/more-tests: etc/mtree sys/netinet sys/netpfil/ipfw tests/sys tests/sys/kern X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 27 Apr 2015 09:10:34 -0000 Author: ngie Date: Mon Apr 27 09:10:32 2015 New Revision: 282077 URL: https://svnweb.freebsd.org/changeset/base/282077 Log: MFhead @ r282076 Added: user/ngie/more-tests/tests/sys/kern/mmap_test.c - copied unchanged from r282076, head/tests/sys/kern/mmap_test.c Modified: user/ngie/more-tests/etc/mtree/BSD.tests.dist user/ngie/more-tests/sys/netinet/ip_fw.h user/ngie/more-tests/sys/netpfil/ipfw/ip_fw2.c user/ngie/more-tests/sys/netpfil/ipfw/ip_fw_private.h user/ngie/more-tests/sys/netpfil/ipfw/ip_fw_sockopt.c user/ngie/more-tests/sys/netpfil/ipfw/ip_fw_table.c user/ngie/more-tests/sys/netpfil/ipfw/ip_fw_table.h user/ngie/more-tests/tests/sys/Makefile user/ngie/more-tests/tests/sys/kern/Makefile Directory Properties: user/ngie/more-tests/ (props changed) user/ngie/more-tests/etc/ (props changed) user/ngie/more-tests/sys/ (props changed) user/ngie/more-tests/tests/sys/aio/ (props changed) user/ngie/more-tests/tests/sys/mqueue/ (props changed) Modified: user/ngie/more-tests/etc/mtree/BSD.tests.dist ============================================================================== --- user/ngie/more-tests/etc/mtree/BSD.tests.dist Mon Apr 27 09:06:27 2015 (r282076) +++ user/ngie/more-tests/etc/mtree/BSD.tests.dist Mon Apr 27 09:10:32 2015 (r282077) @@ -366,8 +366,6 @@ .. kqueue .. - mmap - .. mqueue .. netinet Modified: user/ngie/more-tests/sys/netinet/ip_fw.h ============================================================================== --- user/ngie/more-tests/sys/netinet/ip_fw.h Mon Apr 27 09:06:27 2015 (r282076) +++ user/ngie/more-tests/sys/netinet/ip_fw.h Mon Apr 27 09:10:32 2015 (r282077) @@ -40,10 +40,12 @@ #define IPFW_MAX_SETS 32 /* Number of sets supported by ipfw*/ /* - * Default number of ipfw tables. + * Compat values for old clients */ +#ifndef _KERNEL #define IPFW_TABLES_MAX 65535 #define IPFW_TABLES_DEFAULT 128 +#endif /* * Most commands (queue, pipe, tag, untag, limit...) can have a 16-bit @@ -963,7 +965,6 @@ typedef struct _ipfw_ta_info { uint64_t spare1; } ipfw_ta_info; -#define IPFW_OBJTYPE_TABLE 1 typedef struct _ipfw_obj_header { ip_fw3_opheader opheader; /* IP_FW3 opcode */ uint32_t spare; Modified: user/ngie/more-tests/sys/netpfil/ipfw/ip_fw2.c ============================================================================== --- user/ngie/more-tests/sys/netpfil/ipfw/ip_fw2.c Mon Apr 27 09:06:27 2015 (r282076) +++ user/ngie/more-tests/sys/netpfil/ipfw/ip_fw2.c Mon Apr 27 09:10:32 2015 (r282077) @@ -2762,6 +2762,10 @@ vnet_ipfw_init(const void *unused) LIST_INIT(&chain->nat); #endif + /* Init shared services hash table */ + ipfw_init_srv(chain); + + ipfw_init_obj_rewriter(); ipfw_init_counters(); /* insert the default rule and create the initial map */ chain->n_rules = 1; @@ -2860,9 +2864,11 @@ vnet_ipfw_uninit(const void *unused) if (reap != NULL) ipfw_reap_rules(reap); vnet_ipfw_iface_destroy(chain); + ipfw_destroy_srv(chain); IPFW_LOCK_DESTROY(chain); ipfw_dyn_uninit(1); /* free the remaining parts */ ipfw_destroy_counters(); + ipfw_destroy_obj_rewriter(); return (0); } Modified: user/ngie/more-tests/sys/netpfil/ipfw/ip_fw_private.h ============================================================================== --- user/ngie/more-tests/sys/netpfil/ipfw/ip_fw_private.h Mon Apr 27 09:06:27 2015 (r282076) +++ user/ngie/more-tests/sys/netpfil/ipfw/ip_fw_private.h Mon Apr 27 09:10:32 2015 (r282077) @@ -264,10 +264,10 @@ struct ip_fw_chain { struct ip_fw **map; /* array of rule ptrs to ease lookup */ uint32_t id; /* ruleset id */ int n_rules; /* number of static rules */ - LIST_HEAD(nat_list, cfg_nat) nat; /* list of nat entries */ void *tablestate; /* runtime table info */ void *valuestate; /* runtime table value info */ int *idxmap; /* skipto array of rules */ + void **srvstate; /* runtime service mappings */ #if defined( __linux__ ) || defined( _WIN32 ) spinlock_t rwmtx; #else @@ -275,10 +275,12 @@ struct ip_fw_chain { #endif int static_len; /* total len of static rules (v0) */ uint32_t gencnt; /* NAT generation count */ + LIST_HEAD(nat_list, cfg_nat) nat; /* list of nat entries */ struct ip_fw *default_rule; struct tables_config *tblcfg; /* tables module data */ void *ifcfg; /* interface module data */ int *idxmap_back; /* standby skipto array of rules */ + struct namedobj_instance *srvmap; /* cfg name->number mappings */ #if defined( __linux__ ) || defined( _WIN32 ) spinlock_t uh_lock; #else @@ -306,16 +308,15 @@ struct table_value { uint64_t refcnt; /* Number of references */ }; -struct namedobj_instance; struct named_object { TAILQ_ENTRY(named_object) nn_next; /* namehash */ TAILQ_ENTRY(named_object) nv_next; /* valuehash */ char *name; /* object name */ - uint8_t type; /* object type */ - uint8_t compat; /* Object name is number */ + uint8_t subtype; /* object subtype within class */ + uint8_t etlv; /* Export TLV id */ + uint16_t spare[2]; uint16_t kidx; /* object kernel index */ - uint16_t uidx; /* userland idx for compat records */ uint32_t set; /* set object belongs to */ uint32_t refcnt; /* number of references */ }; @@ -450,7 +451,7 @@ struct obj_idx { struct rule_check_info { uint16_t flags; /* rule-specific check flags */ - uint16_t table_opcodes; /* count of opcodes referencing table */ + uint16_t object_opcodes; /* num of opcodes referencing objects */ uint16_t urule_numoff; /* offset of rulenum in bytes */ uint8_t version; /* rule version */ uint8_t spare; @@ -507,6 +508,84 @@ struct ip_fw_bcounter0 { (r)->cmd_len * 4 - 4, 8)) #define RULEKSIZE1(r) roundup2((sizeof(struct ip_fw) + (r)->cmd_len*4 - 4), 8) +/* + * Tables/Objects index rewriting code + */ + +/* Default and maximum number of ipfw tables/objects. */ +#define IPFW_TABLES_MAX 65536 +#define IPFW_TABLES_DEFAULT 128 +#define IPFW_OBJECTS_MAX 65536 +#define IPFW_OBJECTS_DEFAULT 128 + +#define CHAIN_TO_SRV(ch) ((ch)->srvmap) + +struct tid_info { + uint32_t set; /* table set */ + uint16_t uidx; /* table index */ + uint8_t type; /* table type */ + uint8_t atype; + uint8_t spare; + int tlen; /* Total TLV size block */ + void *tlvs; /* Pointer to first TLV */ +}; + +/* + * Classifier callback. Checks if @cmd opcode contains kernel object reference. + * If true, returns its index and type. + * Returns 0 if match is found, 1 overwise. + */ +typedef int (ipfw_obj_rw_cl)(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype); +/* + * Updater callback. Sets kernel object reference index to @puidx + */ +typedef void (ipfw_obj_rw_upd)(ipfw_insn *cmd, uint16_t puidx); +/* + * Finder callback. Tries to find named object by name (specified via @ti). + * Stores found named object pointer in @pno. + * If object was not found, NULL is stored. + * + * Return 0 if input data was valid. + */ +typedef int (ipfw_obj_fname_cb)(struct ip_fw_chain *ch, + struct tid_info *ti, struct named_object **pno); +/* + * Another finder callback. Tries to findex named object by kernel index. + * + * Returns pointer to named object or NULL. + */ +typedef struct named_object *(ipfw_obj_fidx_cb)(struct ip_fw_chain *ch, + uint16_t kidx); +/* + * Object creator callback. Tries to create object specified by @ti. + * Stores newly-allocated object index in @pkidx. + * + * Returns 0 on success. + */ +typedef int (ipfw_obj_create_cb)(struct ip_fw_chain *ch, struct tid_info *ti, + uint16_t *pkidx); + + +struct opcode_obj_rewrite { + uint32_t opcode; /* Opcode to act upon */ + uint32_t etlv; /* Relevant export TLV id */ + ipfw_obj_rw_cl *classifier; /* Check if rewrite is needed */ + ipfw_obj_rw_upd *update; /* update cmd with new value */ + ipfw_obj_fname_cb *find_byname; /* Find named object by name */ + ipfw_obj_fidx_cb *find_bykidx; /* Find named object by kidx */ + ipfw_obj_create_cb *create_object; /* Create named object */ +}; + +#define IPFW_ADD_OBJ_REWRITER(f, c) do { \ + if ((f) != 0) \ + ipfw_add_obj_rewriter(c, \ + sizeof(c) / sizeof(c[0])); \ + } while(0) +#define IPFW_DEL_OBJ_REWRITER(l, c) do { \ + if ((l) != 0) \ + ipfw_del_obj_rewriter(c, \ + sizeof(c) / sizeof(c[0])); \ + } while(0) /* In ip_fw_iface.c */ int ipfw_iface_init(void); @@ -562,6 +641,7 @@ caddr_t ipfw_get_sopt_header(struct sock sizeof(c) / sizeof(c[0])); \ } while(0) +struct namedobj_instance; typedef void (objhash_cb_t)(struct namedobj_instance *ni, struct named_object *, void *arg); typedef uint32_t (objhash_hash_f)(struct namedobj_instance *ni, void *key, @@ -578,6 +658,8 @@ void ipfw_objhash_bitmap_free(void *idx, void ipfw_objhash_set_hashf(struct namedobj_instance *ni, objhash_hash_f *f); struct named_object *ipfw_objhash_lookup_name(struct namedobj_instance *ni, uint32_t set, char *name); +struct named_object *ipfw_objhash_lookup_name_type(struct namedobj_instance *ni, + uint32_t set, uint32_t type, char *name); struct named_object *ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, uint16_t idx); int ipfw_objhash_same_name(struct namedobj_instance *ni, struct named_object *a, @@ -591,6 +673,25 @@ int ipfw_objhash_free_idx(struct namedob int ipfw_objhash_alloc_idx(void *n, uint16_t *pidx); void ipfw_objhash_set_funcs(struct namedobj_instance *ni, objhash_hash_f *hash_f, objhash_cmp_f *cmp_f); +void ipfw_init_obj_rewriter(void); +void ipfw_destroy_obj_rewriter(void); +void ipfw_add_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count); +int ipfw_del_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count); + +int ipfw_rewrite_rule_uidx(struct ip_fw_chain *chain, + struct rule_check_info *ci); +int ipfw_mark_object_kidx(struct ip_fw_chain *chain, struct ip_fw *rule, + uint32_t *bmask); +int ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd, struct tid_info *ti, + struct obj_idx *pidx, int *found, int *unresolved); +void unref_oib_objects(struct ip_fw_chain *ch, ipfw_insn *cmd, + struct obj_idx *oib, struct obj_idx *end); +int create_objects_compat(struct ip_fw_chain *ch, ipfw_insn *cmd, + struct obj_idx *oib, struct obj_idx *pidx, struct tid_info *ti); +void update_opcode_kidx(ipfw_insn *cmd, uint16_t idx); +int classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx); +void ipfw_init_srv(struct ip_fw_chain *ch); +void ipfw_destroy_srv(struct ip_fw_chain *ch); /* In ip_fw_table.c */ struct table_info; Modified: user/ngie/more-tests/sys/netpfil/ipfw/ip_fw_sockopt.c ============================================================================== --- user/ngie/more-tests/sys/netpfil/ipfw/ip_fw_sockopt.c Mon Apr 27 09:06:27 2015 (r282076) +++ user/ngie/more-tests/sys/netpfil/ipfw/ip_fw_sockopt.c Mon Apr 27 09:10:32 2015 (r282077) @@ -148,6 +148,21 @@ static struct ipfw_sopt_handler scodes[] { IP_FW_DUMP_SOPTCODES, 0, HDIR_GET, dump_soptcodes }, }; +static int +set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule); +struct opcode_obj_rewrite *ipfw_find_op_rw(uint16_t opcode); +static int mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule, + uint32_t *bmask); +static void unref_rule_objects(struct ip_fw_chain *chain, struct ip_fw *rule); +static int export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx, + struct sockopt_data *sd); + +/* + * Opcode object rewriter variables + */ +struct opcode_obj_rewrite *ctl3_rewriters; +static size_t ctl3_rsize; + /* * static variables followed by global ones */ @@ -646,17 +661,18 @@ commit_rules(struct ip_fw_chain *chain, struct ip_fw *krule; struct ip_fw **map; /* the new array of pointers */ - /* Check if we need to do table remap */ + /* Check if we need to do table/obj index remap */ tcount = 0; for (ci = rci, i = 0; i < count; ci++, i++) { - if (ci->table_opcodes == 0) + if (ci->object_opcodes == 0) continue; /* - * Rule has some table opcodes. - * Reference & allocate needed tables/ + * Rule has some object opcodes. + * We need to find (and create non-existing) + * kernel objects, and reference existing ones. */ - error = ipfw_rewrite_table_uidx(chain, ci); + error = ipfw_rewrite_rule_uidx(chain, ci); if (error != 0) { /* @@ -674,9 +690,9 @@ commit_rules(struct ip_fw_chain *chain, IPFW_UH_WLOCK(chain); while (ci != rci) { ci--; - if (ci->table_opcodes == 0) + if (ci->object_opcodes == 0) continue; - ipfw_unref_rule_tables(chain,ci->krule); + unref_rule_objects(chain,ci->krule); } IPFW_UH_WUNLOCK(chain); @@ -696,10 +712,10 @@ commit_rules(struct ip_fw_chain *chain, /* Unbind tables */ IPFW_UH_WLOCK(chain); for (ci = rci, i = 0; i < count; ci++, i++) { - if (ci->table_opcodes == 0) + if (ci->object_opcodes == 0) continue; - ipfw_unref_rule_tables(chain, ci->krule); + unref_rule_objects(chain, ci->krule); } IPFW_UH_WUNLOCK(chain); } @@ -759,7 +775,7 @@ ipfw_reap_add(struct ip_fw_chain *chain, IPFW_UH_WLOCK_ASSERT(chain); /* Unlink rule from everywhere */ - ipfw_unref_rule_tables(chain, rule); + unref_rule_objects(chain, rule); *((struct ip_fw **)rule) = *head; *head = rule; @@ -1542,7 +1558,7 @@ check_ipfw_rule_body(ipfw_insn *cmd, int cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 && cmdlen != F_INSN_SIZE(ipfw_insn_u32)) goto bad_size; - ci->table_opcodes++; + ci->object_opcodes++; break; case O_IP_FLOW_LOOKUP: if (cmd->arg1 >= V_fw_tables_max) { @@ -1553,7 +1569,7 @@ check_ipfw_rule_body(ipfw_insn *cmd, int if (cmdlen != F_INSN_SIZE(ipfw_insn) && cmdlen != F_INSN_SIZE(ipfw_insn_u32)) goto bad_size; - ci->table_opcodes++; + ci->object_opcodes++; break; case O_MACADDR2: if (cmdlen != F_INSN_SIZE(ipfw_insn_mac)) @@ -1587,7 +1603,7 @@ check_ipfw_rule_body(ipfw_insn *cmd, int case O_XMIT: case O_VIA: if (((ipfw_insn_if *)cmd)->name[0] == '\1') - ci->table_opcodes++; + ci->object_opcodes++; if (cmdlen != F_INSN_SIZE(ipfw_insn_if)) goto bad_size; break; @@ -1631,6 +1647,7 @@ check_ipfw_rule_body(ipfw_insn *cmd, int return EINVAL; if (cmdlen != F_INSN_SIZE(ipfw_insn_nat)) goto bad_size; + ci->object_opcodes++; goto check_action; case O_FORWARD_MAC: /* XXX not implemented yet */ case O_CHECK_STATE: @@ -1788,7 +1805,7 @@ ipfw_getrules(struct ip_fw_chain *chain, l = RULESIZE7(rule); if (bp + l + sizeof(uint32_t) <= ep) { bcopy(rule, bp, l + sizeof(uint32_t)); - error = ipfw_rewrite_table_kidx(chain, + error = set_legacy_obj_kidx(chain, (struct ip_fw_rule0 *)bp); if (error != 0) return (0); @@ -1817,7 +1834,7 @@ ipfw_getrules(struct ip_fw_chain *chain, } dst = (struct ip_fw_rule0 *)bp; export_rule0(rule, dst, l); - error = ipfw_rewrite_table_kidx(chain, dst); + error = set_legacy_obj_kidx(chain, dst); /* * XXX HACK. Store the disable mask in the "next" @@ -1861,6 +1878,34 @@ struct dump_args { }; /* + * Export named object info in instance @ni, identified by @kidx + * to ipfw_obj_ntlv. TLV is allocated from @sd space. + * + * Returns 0 on success. + */ +static int +export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx, + struct sockopt_data *sd) +{ + struct named_object *no; + ipfw_obj_ntlv *ntlv; + + no = ipfw_objhash_lookup_kidx(ni, kidx); + KASSERT(no != NULL, ("invalid object kernel index passed")); + + ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv)); + if (ntlv == NULL) + return (ENOMEM); + + ntlv->head.type = no->etlv; + ntlv->head.length = sizeof(*ntlv); + ntlv->idx = no->kidx; + strlcpy(ntlv->name, no->name, sizeof(ntlv->name)); + + return (0); +} + +/* * Dumps static rules with table TLVs in buffer @sd. * * Returns 0 on success. @@ -1874,6 +1919,7 @@ dump_static_rules(struct ip_fw_chain *ch uint32_t tcount; ipfw_obj_ctlv *ctlv; struct ip_fw *krule; + struct namedobj_instance *ni; caddr_t dst; /* Dump table names first (if any) */ @@ -1891,13 +1937,21 @@ dump_static_rules(struct ip_fw_chain *ch i = 0; tcount = da->tcount; + ni = ipfw_get_table_objhash(chain); while (tcount > 0) { if ((bmask[i / 32] & (1 << (i % 32))) == 0) { i++; continue; } - if ((error = ipfw_export_table_ntlv(chain, i, sd)) != 0) + /* Jump to shared named object bitmask */ + if (i >= IPFW_TABLES_MAX) { + ni = CHAIN_TO_SRV(chain); + i -= IPFW_TABLES_MAX; + bmask += IPFW_TABLES_MAX / 32; + } + + if ((error = export_objhash_ntlv(ni, i, sd)) != 0) return (error); i++; @@ -1929,6 +1983,52 @@ dump_static_rules(struct ip_fw_chain *ch } /* + * Marks every object index used in @rule with bit in @bmask. + * Used to generate bitmask of referenced tables/objects for given ruleset + * or its part. + * + * Returns number of newly-referenced objects. + */ +static int +mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule, + uint32_t *bmask) +{ + int cmdlen, l, count; + ipfw_insn *cmd; + uint16_t kidx; + struct opcode_obj_rewrite *rw; + int bidx; + uint8_t subtype; + + l = rule->cmd_len; + cmd = rule->cmd; + cmdlen = 0; + count = 0; + for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { + cmdlen = F_LEN(cmd); + + rw = ipfw_find_op_rw(cmd->opcode); + if (rw == NULL) + continue; + + if (rw->classifier(cmd, &kidx, &subtype) != 0) + continue; + + bidx = kidx / 32; + /* Maintain separate bitmasks for table and non-table objects */ + if (rw->etlv != IPFW_TLV_TBL_NAME) + bidx += IPFW_TABLES_MAX / 32; + + if ((bmask[bidx] & (1 << (kidx % 32))) == 0) + count++; + + bmask[bidx] |= 1 << (kidx % 32); + } + + return (count); +} + +/* * Dumps requested objects data * Data layout (version 0)(current): * Request: [ ipfw_cfg_lheader ] + IPFW_CFG_GET_* flags @@ -1963,9 +2063,9 @@ dump_config(struct ip_fw_chain *chain, i error = 0; bmask = NULL; - /* Allocate needed state */ + /* Allocate needed state. Note we allocate 2xspace mask, for table&srv */ if (hdr->flags & IPFW_CFG_GET_STATIC) - bmask = malloc(IPFW_TABLES_MAX / 8, M_TEMP, M_WAITOK | M_ZERO); + bmask = malloc(IPFW_TABLES_MAX / 4, M_TEMP, M_WAITOK | M_ZERO); IPFW_UH_RLOCK(chain); @@ -1994,7 +2094,8 @@ dump_config(struct ip_fw_chain *chain, i rule = chain->map[i]; da.rsize += RULEUSIZE1(rule) + sizeof(ipfw_obj_tlv); da.rcount++; - da.tcount += ipfw_mark_table_kidx(chain, rule, bmask); + /* Update bitmask of used objects for given range */ + da.tcount += mark_object_kidx(chain, rule, bmask); } /* Add counters if requested */ if (hdr->flags & IPFW_CFG_GET_COUNTERS) { @@ -2064,6 +2165,241 @@ check_object_name(ipfw_obj_ntlv *ntlv) } /* + * Creates non-existent objects referenced by rule. + * + * Return 0 on success. + */ +int +create_objects_compat(struct ip_fw_chain *ch, ipfw_insn *cmd, + struct obj_idx *oib, struct obj_idx *pidx, struct tid_info *ti) +{ + struct opcode_obj_rewrite *rw; + struct obj_idx *p; + uint16_t kidx; + int error; + + /* + * Compatibility stuff: do actual creation for non-existing, + * but referenced objects. + */ + for (p = oib; p < pidx; p++) { + if (p->kidx != 0) + continue; + + ti->uidx = p->uidx; + ti->type = p->type; + ti->atype = 0; + + rw = ipfw_find_op_rw((cmd + p->off)->opcode); + KASSERT(rw != NULL, ("Unable to find handler for op %d", + (cmd + p->off)->opcode)); + + error = rw->create_object(ch, ti, &kidx); + if (error == 0) { + p->kidx = kidx; + continue; + } + + /* + * Error happened. We have to rollback everything. + * Drop all already acquired references. + */ + IPFW_UH_WLOCK(ch); + unref_oib_objects(ch, cmd, oib, pidx); + IPFW_UH_WUNLOCK(ch); + + return (error); + } + + return (error); +} + +/* + * Compatibility function for old ipfw(8) binaries. + * Rewrites table/nat kernel indices with userland ones. + * Convert tables matching '/^\d+$/' to their atoi() value. + * Use number 65535 for other tables. + * + * Returns 0 on success. + */ +static int +set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule) +{ + int cmdlen, error, l; + ipfw_insn *cmd; + uint16_t kidx, uidx; + struct named_object *no; + struct opcode_obj_rewrite *rw; + uint8_t subtype; + char *end; + long val; + + error = 0; + + l = rule->cmd_len; + cmd = rule->cmd; + cmdlen = 0; + for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { + cmdlen = F_LEN(cmd); + + rw = ipfw_find_op_rw(cmd->opcode); + if (rw == NULL) + continue; + + /* Check if is index in given opcode */ + if (rw->classifier(cmd, &kidx, &subtype) != 0) + continue; + + /* Try to find referenced kernel object */ + no = rw->find_bykidx(ch, kidx); + if (no == NULL) + continue; + + val = strtol(no->name, &end, 10); + if (*end == '\0' && val < 65535) { + uidx = val; + } else { + + /* + * We are called via legacy opcode. + * Save error and show table as fake number + * not to make ipfw(8) hang. + */ + uidx = 65535; + error = 2; + } + + rw->update(cmd, uidx); + } + + return (error); +} + + +/* + * Unreferences all already-referenced objects in given @cmd rule, + * using information in @oib. + * + * Used to rollback partially converted rule on error. + */ +void +unref_oib_objects(struct ip_fw_chain *ch, ipfw_insn *cmd, struct obj_idx *oib, + struct obj_idx *end) +{ + struct opcode_obj_rewrite *rw; + struct named_object *no; + struct obj_idx *p; + + IPFW_UH_WLOCK_ASSERT(ch); + + for (p = oib; p < end; p++) { + if (p->kidx == 0) + continue; + + rw = ipfw_find_op_rw((cmd + p->off)->opcode); + KASSERT(rw != NULL, ("Unable to find handler for op %d", + (cmd + p->off)->opcode)); + + /* Find & unref by existing idx */ + no = rw->find_bykidx(ch, p->kidx); + KASSERT(no != NULL, ("Ref'd object %d disappeared", p->kidx)); + no->refcnt--; + } +} + +/* + * Remove references from every object used in @rule. + * Used at rule removal code. + */ +static void +unref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule) +{ + int cmdlen, l; + ipfw_insn *cmd; + struct named_object *no; + uint16_t kidx; + struct opcode_obj_rewrite *rw; + uint8_t subtype; + + IPFW_UH_WLOCK_ASSERT(ch); + + l = rule->cmd_len; + cmd = rule->cmd; + cmdlen = 0; + for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { + cmdlen = F_LEN(cmd); + + rw = ipfw_find_op_rw(cmd->opcode); + if (rw == NULL) + continue; + if (rw->classifier(cmd, &kidx, &subtype) != 0) + continue; + + no = rw->find_bykidx(ch, kidx); + + KASSERT(no != NULL, ("table id %d not found", kidx)); + KASSERT(no->subtype == subtype, + ("wrong type %d (%d) for table id %d", + no->subtype, subtype, kidx)); + KASSERT(no->refcnt > 0, ("refcount for table %d is %d", + kidx, no->refcnt)); + + no->refcnt--; + } +} + + +/* + * Find and reference object (if any) stored in instruction @cmd. + * + * Saves object info in @pidx, sets + * - @found to 1 if object was found and references + * - @unresolved to 1 if object should exists but not found + * + * Returns non-zero value in case of error. + */ +int +ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd, struct tid_info *ti, + struct obj_idx *pidx, int *found, int *unresolved) +{ + struct named_object *no; + struct opcode_obj_rewrite *rw; + int error; + + *found = 0; + *unresolved = 0; + + /* Check if this opcode is candidate for rewrite */ + rw = ipfw_find_op_rw(cmd->opcode); + if (rw == NULL) + return (0); + + /* Check if we need to rewrite this opcode */ + if (rw->classifier(cmd, &ti->uidx, &ti->type) != 0) + return (0); + + /* Need to rewrite. Save necessary fields */ + pidx->uidx = ti->uidx; + pidx->type = ti->type; + + /* Try to find referenced kernel object */ + error = rw->find_byname(ch, ti, &no); + if (error != 0) + return (error); + if (no == NULL) { + *unresolved = 1; + return (0); + } + + /* Found. bump refcount */ + *found = 1; + no->refcnt++; + pidx->kidx = no->kidx; + + return (0); +} + +/* * Adds one or more rules to ipfw @chain. * Data layout (version 0)(current): * Request: @@ -2315,6 +2651,160 @@ dump_soptcodes(struct ip_fw_chain *chain } /* + * Compares two opcodes. + * Used both in qsort() and bsearch(). + * + * Returns 0 if match is found. + */ +static int +compare_opcodes(const void *_a, const void *_b) +{ + const struct opcode_obj_rewrite *a, *b; + + a = (const struct opcode_obj_rewrite *)_a; + b = (const struct opcode_obj_rewrite *)_b; + + if (a->opcode < b->opcode) + return (-1); + else if (a->opcode > b->opcode) + return (1); + + return (0); +} + +/* + * Finds opcode object rewriter based on @code. + * + * Returns pointer to handler or NULL. + */ +struct opcode_obj_rewrite * +ipfw_find_op_rw(uint16_t opcode) +{ + struct opcode_obj_rewrite *rw, h; + + memset(&h, 0, sizeof(h)); + h.opcode = opcode; + + rw = (struct opcode_obj_rewrite *)bsearch(&h, ctl3_rewriters, + ctl3_rsize, sizeof(h), compare_opcodes); + + return (rw); +} + +int +classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx) +{ + struct opcode_obj_rewrite *rw; + uint8_t subtype; + + rw = ipfw_find_op_rw(cmd->opcode); + if (rw == NULL) + return (1); + + return (rw->classifier(cmd, puidx, &subtype)); +} + +void +update_opcode_kidx(ipfw_insn *cmd, uint16_t idx) +{ + struct opcode_obj_rewrite *rw; + + rw = ipfw_find_op_rw(cmd->opcode); + KASSERT(rw != NULL, ("No handler to update opcode %d", cmd->opcode)); + rw->update(cmd, idx); +} + +void +ipfw_init_obj_rewriter() +{ + + ctl3_rewriters = NULL; + ctl3_rsize = 0; +} + +void +ipfw_destroy_obj_rewriter() +{ + + if (ctl3_rewriters != NULL) + free(ctl3_rewriters, M_IPFW); + ctl3_rewriters = NULL; + ctl3_rsize = 0; +} + +/* + * Adds one or more opcode object rewrite handlers to the global array. + * Function may sleep. + */ +void +ipfw_add_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count) +{ + size_t sz; + struct opcode_obj_rewrite *tmp; + + CTL3_LOCK(); + + for (;;) { + sz = ctl3_rsize + count; + CTL3_UNLOCK(); + tmp = malloc(sizeof(*rw) * sz, M_IPFW, M_WAITOK | M_ZERO); + CTL3_LOCK(); + if (ctl3_rsize + count <= sz) + break; + + /* Retry */ + free(tmp, M_IPFW); + } + + /* Merge old & new arrays */ + sz = ctl3_rsize + count; + memcpy(tmp, ctl3_rewriters, ctl3_rsize * sizeof(*rw)); + memcpy(&tmp[ctl3_rsize], rw, count * sizeof(*rw)); + qsort(tmp, sz, sizeof(*rw), compare_opcodes); + /* Switch new and free old */ + if (ctl3_rewriters != NULL) + free(ctl3_rewriters, M_IPFW); + ctl3_rewriters = tmp; + ctl3_rsize = sz; + + CTL3_UNLOCK(); +} + +/* + * Removes one or more object rewrite handlers from the global array. + */ +int +ipfw_del_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count) +{ + size_t sz; + struct opcode_obj_rewrite *tmp, *h; + int i; + + CTL3_LOCK(); + + for (i = 0; i < count; i++) { + tmp = &rw[i]; + h = ipfw_find_op_rw(tmp->opcode); + if (h == NULL) + continue; + + sz = (ctl3_rewriters + ctl3_rsize - (h + 1)) * sizeof(*h); + memmove(h, h + 1, sz); + ctl3_rsize--; + } + + if (ctl3_rsize == 0) { + if (ctl3_rewriters != NULL) + free(ctl3_rewriters, M_IPFW); + ctl3_rewriters = NULL; + } + + CTL3_UNLOCK(); + + return (0); +} + +/* * Compares two sopt handlers (code, version and handler ptr). * Used both as qsort() and bsearch(). * Does not compare handler for latter case. @@ -3150,6 +3640,23 @@ convert_rule_to_8(struct ip_fw_rule0 *ru * */ +void +ipfw_init_srv(struct ip_fw_chain *ch) +{ + + ch->srvmap = ipfw_objhash_create(IPFW_OBJECTS_DEFAULT); + ch->srvstate = malloc(sizeof(void *) * IPFW_OBJECTS_DEFAULT, + M_IPFW, M_WAITOK | M_ZERO); +} + +void +ipfw_destroy_srv(struct ip_fw_chain *ch) +{ + + free(ch->srvstate, M_IPFW); + ipfw_objhash_destroy(ch->srvmap); +} + /* * Allocate new bitmask which can be used to enlarge/shrink * named instance index. @@ -3323,6 +3830,26 @@ ipfw_objhash_lookup_name(struct namedobj return (NULL); } +/* + * Find named object by name, considering also its TLV type. + */ +struct named_object * +ipfw_objhash_lookup_name_type(struct namedobj_instance *ni, uint32_t set, + uint32_t type, char *name) +{ + struct named_object *no; + uint32_t hash; + + hash = ni->hash_f(ni, name, set) % ni->nn_size; + + TAILQ_FOREACH(no, &ni->names[hash], nn_next) { + if (ni->cmp_f(no, name, set) == 0 && no->etlv == type) + return (no); + } + + return (NULL); +} + struct named_object * ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, uint16_t kidx) { Modified: user/ngie/more-tests/sys/netpfil/ipfw/ip_fw_table.c ============================================================================== --- user/ngie/more-tests/sys/netpfil/ipfw/ip_fw_table.c Mon Apr 27 09:06:27 2015 (r282076) +++ user/ngie/more-tests/sys/netpfil/ipfw/ip_fw_table.c Mon Apr 27 09:10:32 2015 (r282077) @@ -89,6 +89,8 @@ struct table_config { struct namedobj_instance *vi; }; +static int find_table_err(struct namedobj_instance *ni, struct tid_info *ti, + struct table_config **tc); static struct table_config *find_table(struct namedobj_instance *ni, struct tid_info *ti); static struct table_config *alloc_table_config(struct ip_fw_chain *ch, @@ -122,7 +124,6 @@ static struct table_algo *find_table_alg static void objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti); static void ntlv_to_ti(struct _ipfw_obj_ntlv *ntlv, struct tid_info *ti); -static int classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype); #define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash) #define KIDX_TO_TI(ch, k) (&(((struct table_info *)(ch)->tablestate)[k])) @@ -297,7 +298,7 @@ find_ref_table(struct ip_fw_chain *ch, s tc = NULL; if ((tc = find_table(ni, ti)) != NULL) { /* check table type */ - if (tc->no.type != ti->type) + if (tc->no.subtype != ti->type) return (EINVAL); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***