19f7d47b0SAlexander V. Chernikov /*- 21a33e799SAlexander V. Chernikov * Copyright (c) 2014 Yandex LLC 31a33e799SAlexander V. Chernikov * Copyright (c) 2014 Alexander V. Chernikov 49f7d47b0SAlexander V. Chernikov * 59f7d47b0SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 69f7d47b0SAlexander V. Chernikov * modification, are permitted provided that the following conditions 79f7d47b0SAlexander V. Chernikov * are met: 89f7d47b0SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 99f7d47b0SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 109f7d47b0SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 119f7d47b0SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 129f7d47b0SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 139f7d47b0SAlexander V. Chernikov * 149f7d47b0SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 159f7d47b0SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 169f7d47b0SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 179f7d47b0SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 189f7d47b0SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 199f7d47b0SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 209f7d47b0SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 219f7d47b0SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 229f7d47b0SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 239f7d47b0SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 249f7d47b0SAlexander V. Chernikov * SUCH DAMAGE. 259f7d47b0SAlexander V. Chernikov */ 269f7d47b0SAlexander V. Chernikov 279f7d47b0SAlexander V. Chernikov #include <sys/cdefs.h> 28a13a8216SAlexander V. Chernikov __FBSDID("$FreeBSD$"); 299f7d47b0SAlexander V. Chernikov 309f7d47b0SAlexander V. Chernikov /* 319f7d47b0SAlexander V. Chernikov * Lookup table algorithms. 329f7d47b0SAlexander V. Chernikov * 339f7d47b0SAlexander V. Chernikov */ 349f7d47b0SAlexander V. Chernikov 359f7d47b0SAlexander V. Chernikov #include "opt_ipfw.h" 369f7d47b0SAlexander V. Chernikov #include "opt_inet.h" 379f7d47b0SAlexander V. Chernikov #ifndef INET 389f7d47b0SAlexander V. Chernikov #error IPFIREWALL requires INET. 399f7d47b0SAlexander V. Chernikov #endif /* INET */ 409f7d47b0SAlexander V. Chernikov #include "opt_inet6.h" 419f7d47b0SAlexander V. Chernikov 429f7d47b0SAlexander V. Chernikov #include <sys/param.h> 439f7d47b0SAlexander V. Chernikov #include <sys/systm.h> 449f7d47b0SAlexander V. Chernikov #include <sys/malloc.h> 459f7d47b0SAlexander V. Chernikov #include <sys/kernel.h> 469f7d47b0SAlexander V. Chernikov #include <sys/lock.h> 479f7d47b0SAlexander V. Chernikov #include <sys/rwlock.h> 48d4e1b515SAlexander V. Chernikov #include <sys/rmlock.h> 499f7d47b0SAlexander V. Chernikov #include <sys/socket.h> 509f7d47b0SAlexander V. Chernikov #include <sys/queue.h> 519f7d47b0SAlexander V. Chernikov #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */ 529f7d47b0SAlexander V. Chernikov #include <net/radix.h> 53d3b00c08SAlexander V. Chernikov #include <net/route.h> 549f7d47b0SAlexander V. Chernikov 559f7d47b0SAlexander V. Chernikov #include <netinet/in.h> 569f7d47b0SAlexander V. Chernikov #include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 579f7d47b0SAlexander V. Chernikov #include <netinet/ip_fw.h> 589f7d47b0SAlexander V. Chernikov 599f7d47b0SAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_private.h> 60ea761a5dSAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_table.h> 619f7d47b0SAlexander V. Chernikov 62301290bcSAlexander V. Chernikov 63301290bcSAlexander V. Chernikov /* 64301290bcSAlexander V. Chernikov * IPFW table lookup algorithms. 65301290bcSAlexander V. Chernikov * 66301290bcSAlexander V. Chernikov * What is needed to add another table algo? 67301290bcSAlexander V. Chernikov * 68301290bcSAlexander V. Chernikov * Algo init: 69301290bcSAlexander V. Chernikov * * struct table_algo has to be filled with: 70c21034b7SAlexander V. Chernikov * name: "type:algoname" format, e.g. "addr:radix". Currently 71c21034b7SAlexander V. Chernikov * there are the following types: "addr", "iface", "number" and "flow". 72301290bcSAlexander V. Chernikov * type: one of IPFW_TABLE_* types 73301290bcSAlexander V. Chernikov * flags: one or more TA_FLAGS_* 74301290bcSAlexander V. Chernikov * ta_buf_size: size of structure used to store add/del item state. 75301290bcSAlexander V. Chernikov * Needs to be less than TA_BUF_SZ. 76301290bcSAlexander V. Chernikov * callbacks: see below for description. 77301290bcSAlexander V. Chernikov * * ipfw_add_table_algo / ipfw_del_table_algo has to be called 78301290bcSAlexander V. Chernikov * 79301290bcSAlexander V. Chernikov * Callbacks description: 80301290bcSAlexander V. Chernikov * 81301290bcSAlexander V. Chernikov * -init: request to initialize new table instance. 82301290bcSAlexander V. Chernikov * typedef int (ta_init)(struct ip_fw_chain *ch, void **ta_state, 83301290bcSAlexander V. Chernikov * struct table_info *ti, char *data, uint8_t tflags); 84301290bcSAlexander V. Chernikov * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success. 85301290bcSAlexander V. Chernikov * 86301290bcSAlexander V. Chernikov * Allocate all structures needed for normal operations. 87301290bcSAlexander V. Chernikov * * Caller may want to parse @data for some algo-specific 88301290bcSAlexander V. Chernikov * options provided by userland. 89301290bcSAlexander V. Chernikov * * Caller may want to save configuration state pointer to @ta_state 90301290bcSAlexander V. Chernikov * * Caller needs to save desired runtime structure pointer(s) 91301290bcSAlexander V. Chernikov * inside @ti fields. Note that it is not correct to save 92301290bcSAlexander V. Chernikov * @ti pointer at this moment. Use -change_ti hook for that. 93301290bcSAlexander V. Chernikov * * Caller has to fill in ti->lookup to appropriate function 94301290bcSAlexander V. Chernikov * pointer. 95301290bcSAlexander V. Chernikov * 96301290bcSAlexander V. Chernikov * 97301290bcSAlexander V. Chernikov * 98301290bcSAlexander V. Chernikov * -destroy: request to destroy table instance. 99301290bcSAlexander V. Chernikov * typedef void (ta_destroy)(void *ta_state, struct table_info *ti); 100301290bcSAlexander V. Chernikov * MANDATORY, may be locked (UH+WLOCK). (M_NOWAIT). 101301290bcSAlexander V. Chernikov * 102301290bcSAlexander V. Chernikov * Frees all table entries and all tables structures allocated by -init. 103301290bcSAlexander V. Chernikov * 104301290bcSAlexander V. Chernikov * 105301290bcSAlexander V. Chernikov * 106301290bcSAlexander V. Chernikov * -prepare_add: request to allocate state for adding new entry. 107301290bcSAlexander V. Chernikov * typedef int (ta_prepare_add)(struct ip_fw_chain *ch, struct tentry_info *tei, 108301290bcSAlexander V. Chernikov * void *ta_buf); 109301290bcSAlexander V. Chernikov * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success. 110301290bcSAlexander V. Chernikov * 11113263632SAlexander V. Chernikov * Allocates state and fills it in with all necessary data (EXCEPT value) 11213263632SAlexander V. Chernikov * from @tei to minimize operations needed to be done under WLOCK. 11313263632SAlexander V. Chernikov * "value" field has to be copied to new entry in @add callback. 114301290bcSAlexander V. Chernikov * Buffer ta_buf of size ta->ta_buf_sz may be used to store 115301290bcSAlexander V. Chernikov * allocated state. 116301290bcSAlexander V. Chernikov * 117301290bcSAlexander V. Chernikov * 118301290bcSAlexander V. Chernikov * 119301290bcSAlexander V. Chernikov * -prepare_del: request to set state for deleting existing entry. 120301290bcSAlexander V. Chernikov * typedef int (ta_prepare_del)(struct ip_fw_chain *ch, struct tentry_info *tei, 121301290bcSAlexander V. Chernikov * void *ta_buf); 122301290bcSAlexander V. Chernikov * MANDATORY, locked, UH. (M_NOWAIT). Returns 0 on success. 123301290bcSAlexander V. Chernikov * 124301290bcSAlexander V. Chernikov * Buffer ta_buf of size ta->ta_buf_sz may be used to store 125301290bcSAlexander V. Chernikov * allocated state. Caller should use on-stack ta_buf allocation 126301290bcSAlexander V. Chernikov * instead of doing malloc(). 127301290bcSAlexander V. Chernikov * 128301290bcSAlexander V. Chernikov * 129301290bcSAlexander V. Chernikov * 130301290bcSAlexander V. Chernikov * -add: request to insert new entry into runtime/config structures. 131301290bcSAlexander V. Chernikov * typedef int (ta_add)(void *ta_state, struct table_info *ti, 132301290bcSAlexander V. Chernikov * struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 133301290bcSAlexander V. Chernikov * MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success. 134301290bcSAlexander V. Chernikov * 135301290bcSAlexander V. Chernikov * Insert new entry using previously-allocated state in @ta_buf. 136301290bcSAlexander V. Chernikov * * @tei may have the following flags: 137301290bcSAlexander V. Chernikov * TEI_FLAGS_UPDATE: request to add or update entry. 138301290bcSAlexander V. Chernikov * TEI_FLAGS_DONTADD: request to update (but not add) entry. 139301290bcSAlexander V. Chernikov * * Caller is required to do the following: 14013263632SAlexander V. Chernikov * copy real entry value from @tei 141301290bcSAlexander V. Chernikov * entry added: return 0, set 1 to @pnum 142301290bcSAlexander V. Chernikov * entry updated: return 0, store 0 to @pnum, store old value in @tei, 143301290bcSAlexander V. Chernikov * add TEI_FLAGS_UPDATED flag to @tei. 144301290bcSAlexander V. Chernikov * entry exists: return EEXIST 145301290bcSAlexander V. Chernikov * entry not found: return ENOENT 146301290bcSAlexander V. Chernikov * other error: return non-zero error code. 147301290bcSAlexander V. Chernikov * 148301290bcSAlexander V. Chernikov * 149301290bcSAlexander V. Chernikov * 150301290bcSAlexander V. Chernikov * -del: request to delete existing entry from runtime/config structures. 151301290bcSAlexander V. Chernikov * typedef int (ta_del)(void *ta_state, struct table_info *ti, 152301290bcSAlexander V. Chernikov * struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 153301290bcSAlexander V. Chernikov * MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success. 154301290bcSAlexander V. Chernikov * 155301290bcSAlexander V. Chernikov * Delete entry using previously set up in @ta_buf. 156301290bcSAlexander V. Chernikov * * Caller is required to do the following: 15713263632SAlexander V. Chernikov * entry deleted: return 0, set 1 to @pnum, store old value in @tei. 158301290bcSAlexander V. Chernikov * entry not found: return ENOENT 159301290bcSAlexander V. Chernikov * other error: return non-zero error code. 160301290bcSAlexander V. Chernikov * 161301290bcSAlexander V. Chernikov * 162301290bcSAlexander V. Chernikov * 163301290bcSAlexander V. Chernikov * -flush_entry: flush entry state created by -prepare_add / -del / others 164301290bcSAlexander V. Chernikov * typedef void (ta_flush_entry)(struct ip_fw_chain *ch, 165301290bcSAlexander V. Chernikov * struct tentry_info *tei, void *ta_buf); 166301290bcSAlexander V. Chernikov * MANDATORY, may be locked. (M_NOWAIT). 167301290bcSAlexander V. Chernikov * 168301290bcSAlexander V. Chernikov * Delete state allocated by: 169301290bcSAlexander V. Chernikov * -prepare_add (-add returned EEXIST|UPDATED) 170301290bcSAlexander V. Chernikov * -prepare_del (if any) 171301290bcSAlexander V. Chernikov * -del 172301290bcSAlexander V. Chernikov * * Caller is required to handle empty @ta_buf correctly. 173301290bcSAlexander V. Chernikov * 174301290bcSAlexander V. Chernikov * 175301290bcSAlexander V. Chernikov * -find_tentry: finds entry specified by key @tei 176301290bcSAlexander V. Chernikov * typedef int ta_find_tentry(void *ta_state, struct table_info *ti, 177301290bcSAlexander V. Chernikov * ipfw_obj_tentry *tent); 178301290bcSAlexander V. Chernikov * OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 on success. 179301290bcSAlexander V. Chernikov * 180301290bcSAlexander V. Chernikov * Finds entry specified by given key. 181301290bcSAlexander V. Chernikov * * Caller is requred to do the following: 182301290bcSAlexander V. Chernikov * entry found: returns 0, export entry to @tent 183301290bcSAlexander V. Chernikov * entry not found: returns ENOENT 184301290bcSAlexander V. Chernikov * 185301290bcSAlexander V. Chernikov * 186301290bcSAlexander V. Chernikov * -need_modify: checks if @ti has enough space to hold another @count items. 187301290bcSAlexander V. Chernikov * typedef int (ta_need_modify)(void *ta_state, struct table_info *ti, 188301290bcSAlexander V. Chernikov * uint32_t count, uint64_t *pflags); 189fd0869d5SAlexander V. Chernikov * OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 if has. 190301290bcSAlexander V. Chernikov * 191301290bcSAlexander V. Chernikov * Checks if given table has enough space to add @count items without 192301290bcSAlexander V. Chernikov * resize. Caller may use @pflags to store desired modification data. 193301290bcSAlexander V. Chernikov * 194301290bcSAlexander V. Chernikov * 195301290bcSAlexander V. Chernikov * 196301290bcSAlexander V. Chernikov * -prepare_mod: allocate structures for table modification. 197301290bcSAlexander V. Chernikov * typedef int (ta_prepare_mod)(void *ta_buf, uint64_t *pflags); 198fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), unlocked. (M_WAITOK). Returns 0 on success. 199301290bcSAlexander V. Chernikov * 200301290bcSAlexander V. Chernikov * Allocate all needed state for table modification. Caller 201301290bcSAlexander V. Chernikov * should use `struct mod_item` to store new state in @ta_buf. 202301290bcSAlexander V. Chernikov * Up to TA_BUF_SZ (128 bytes) can be stored in @ta_buf. 203301290bcSAlexander V. Chernikov * 204301290bcSAlexander V. Chernikov * 205301290bcSAlexander V. Chernikov * 206301290bcSAlexander V. Chernikov * -fill_mod: copy some data to new state/ 207301290bcSAlexander V. Chernikov * typedef int (ta_fill_mod)(void *ta_state, struct table_info *ti, 208301290bcSAlexander V. Chernikov * void *ta_buf, uint64_t *pflags); 209fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), locked (UH). (M_NOWAIT). Returns 0 on success. 210301290bcSAlexander V. Chernikov * 211301290bcSAlexander V. Chernikov * Copy as much data as we can to minimize changes under WLOCK. 212301290bcSAlexander V. Chernikov * For example, array can be merged inside this callback. 213301290bcSAlexander V. Chernikov * 214301290bcSAlexander V. Chernikov * 215301290bcSAlexander V. Chernikov * 216301290bcSAlexander V. Chernikov * -modify: perform final modification. 217301290bcSAlexander V. Chernikov * typedef void (ta_modify)(void *ta_state, struct table_info *ti, 218301290bcSAlexander V. Chernikov * void *ta_buf, uint64_t pflags); 219fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), locked (UH+WLOCK). (M_NOWAIT). 220301290bcSAlexander V. Chernikov * 221301290bcSAlexander V. Chernikov * Performs all changes necessary to switch to new structures. 222301290bcSAlexander V. Chernikov * * Caller should save old pointers to @ta_buf storage. 223301290bcSAlexander V. Chernikov * 224301290bcSAlexander V. Chernikov * 225301290bcSAlexander V. Chernikov * 226301290bcSAlexander V. Chernikov * -flush_mod: flush table modification state. 227301290bcSAlexander V. Chernikov * typedef void (ta_flush_mod)(void *ta_buf); 228fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), unlocked. (M_WAITOK). 229301290bcSAlexander V. Chernikov * 230301290bcSAlexander V. Chernikov * Performs flush for the following: 231301290bcSAlexander V. Chernikov * - prepare_mod (modification was not necessary) 232301290bcSAlexander V. Chernikov * - modify (for the old state) 233301290bcSAlexander V. Chernikov * 234301290bcSAlexander V. Chernikov * 235301290bcSAlexander V. Chernikov * 236301290bcSAlexander V. Chernikov * -change_gi: monitor table info pointer changes 237301290bcSAlexander V. Chernikov * typedef void (ta_change_ti)(void *ta_state, struct table_info *ti); 238301290bcSAlexander V. Chernikov * OPTIONAL, locked (UH). (M_NOWAIT). 239301290bcSAlexander V. Chernikov * 240301290bcSAlexander V. Chernikov * Called on @ti pointer changed. Called immediately after -init 241301290bcSAlexander V. Chernikov * to set initial state. 242301290bcSAlexander V. Chernikov * 243301290bcSAlexander V. Chernikov * 244301290bcSAlexander V. Chernikov * 245301290bcSAlexander V. Chernikov * -foreach: calls @f for each table entry 246301290bcSAlexander V. Chernikov * typedef void ta_foreach(void *ta_state, struct table_info *ti, 247301290bcSAlexander V. Chernikov * ta_foreach_f *f, void *arg); 248301290bcSAlexander V. Chernikov * MANDATORY, locked(UH). (M_NOWAIT). 249301290bcSAlexander V. Chernikov * 250301290bcSAlexander V. Chernikov * Runs callback with specified argument for each table entry, 251301290bcSAlexander V. Chernikov * Typically used for dumping table entries. 252301290bcSAlexander V. Chernikov * 253301290bcSAlexander V. Chernikov * 254301290bcSAlexander V. Chernikov * 255301290bcSAlexander V. Chernikov * -dump_tentry: dump table entry in current @tentry format. 256301290bcSAlexander V. Chernikov * typedef int ta_dump_tentry(void *ta_state, struct table_info *ti, void *e, 257301290bcSAlexander V. Chernikov * ipfw_obj_tentry *tent); 258301290bcSAlexander V. Chernikov * MANDATORY, locked(UH). (M_NOWAIT). Returns 0 on success. 259301290bcSAlexander V. Chernikov * 260301290bcSAlexander V. Chernikov * Dumps entry @e to @tent. 261301290bcSAlexander V. Chernikov * 262301290bcSAlexander V. Chernikov * 263301290bcSAlexander V. Chernikov * -print_config: prints custom algoritm options into buffer. 264301290bcSAlexander V. Chernikov * typedef void (ta_print_config)(void *ta_state, struct table_info *ti, 265301290bcSAlexander V. Chernikov * char *buf, size_t bufsize); 266301290bcSAlexander V. Chernikov * OPTIONAL. locked(UH). (M_NOWAIT). 267301290bcSAlexander V. Chernikov * 268301290bcSAlexander V. Chernikov * Prints custom algorithm options in the format suitable to pass 269301290bcSAlexander V. Chernikov * back to -init callback. 270301290bcSAlexander V. Chernikov * 271301290bcSAlexander V. Chernikov * 272301290bcSAlexander V. Chernikov * 273301290bcSAlexander V. Chernikov * -dump_tinfo: dumps algo-specific info. 274301290bcSAlexander V. Chernikov * typedef void ta_dump_tinfo(void *ta_state, struct table_info *ti, 275301290bcSAlexander V. Chernikov * ipfw_ta_tinfo *tinfo); 276301290bcSAlexander V. Chernikov * OPTIONAL. locked(UH). (M_NOWAIT). 277301290bcSAlexander V. Chernikov * 278301290bcSAlexander V. Chernikov * Dumps options like items size/hash size, etc. 279301290bcSAlexander V. Chernikov */ 280301290bcSAlexander V. Chernikov 281b1d105bcSAlexander V. Chernikov MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables"); 2829f7d47b0SAlexander V. Chernikov 2830bce0c23SAlexander V. Chernikov /* 2840bce0c23SAlexander V. Chernikov * Utility structures/functions common to more than one algo 2850bce0c23SAlexander V. Chernikov */ 2860bce0c23SAlexander V. Chernikov 2870bce0c23SAlexander V. Chernikov struct mod_item { 2880bce0c23SAlexander V. Chernikov void *main_ptr; 2890bce0c23SAlexander V. Chernikov size_t size; 2900bce0c23SAlexander V. Chernikov void *main_ptr6; 2910bce0c23SAlexander V. Chernikov size_t size6; 2920bce0c23SAlexander V. Chernikov }; 2930bce0c23SAlexander V. Chernikov 29468394ec8SAlexander V. Chernikov static int badd(const void *key, void *item, void *base, size_t nmemb, 29568394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *)); 29668394ec8SAlexander V. Chernikov static int bdel(const void *key, void *base, size_t nmemb, size_t size, 29768394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *)); 29868394ec8SAlexander V. Chernikov 29968394ec8SAlexander V. Chernikov 30068394ec8SAlexander V. Chernikov /* 301c21034b7SAlexander V. Chernikov * ADDR implementation using radix 30268394ec8SAlexander V. Chernikov * 30368394ec8SAlexander V. Chernikov */ 30468394ec8SAlexander V. Chernikov 3059f7d47b0SAlexander V. Chernikov /* 3069f7d47b0SAlexander V. Chernikov * The radix code expects addr and mask to be array of bytes, 3079f7d47b0SAlexander V. Chernikov * with the first byte being the length of the array. rn_inithead 3089f7d47b0SAlexander V. Chernikov * is called with the offset in bits of the lookup key within the 3099f7d47b0SAlexander V. Chernikov * array. If we use a sockaddr_in as the underlying type, 3109f7d47b0SAlexander V. Chernikov * sin_len is conveniently located at offset 0, sin_addr is at 3119f7d47b0SAlexander V. Chernikov * offset 4 and normally aligned. 3129f7d47b0SAlexander V. Chernikov * But for portability, let's avoid assumption and make the code explicit 3139f7d47b0SAlexander V. Chernikov */ 3149f7d47b0SAlexander V. Chernikov #define KEY_LEN(v) *((uint8_t *)&(v)) 3159f7d47b0SAlexander V. Chernikov /* 3169f7d47b0SAlexander V. Chernikov * Do not require radix to compare more than actual IPv4/IPv6 address 3179f7d47b0SAlexander V. Chernikov */ 3189f7d47b0SAlexander V. Chernikov #define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t)) 319e0a8b9eeSAlexander V. Chernikov #define KEY_LEN_INET6 (offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr)) 3209f7d47b0SAlexander V. Chernikov 3219f7d47b0SAlexander V. Chernikov #define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr)) 322e0a8b9eeSAlexander V. Chernikov #define OFF_LEN_INET6 (8 * offsetof(struct sa_in6, sin6_addr)) 3239f7d47b0SAlexander V. Chernikov 324c21034b7SAlexander V. Chernikov struct radix_addr_entry { 3259f7d47b0SAlexander V. Chernikov struct radix_node rn[2]; 326e0a8b9eeSAlexander V. Chernikov struct sockaddr_in addr; 327e0a8b9eeSAlexander V. Chernikov uint32_t value; 328e0a8b9eeSAlexander V. Chernikov uint8_t masklen; 329e0a8b9eeSAlexander V. Chernikov }; 330e0a8b9eeSAlexander V. Chernikov 331e0a8b9eeSAlexander V. Chernikov struct sa_in6 { 332e0a8b9eeSAlexander V. Chernikov uint8_t sin6_len; 333e0a8b9eeSAlexander V. Chernikov uint8_t sin6_family; 334e0a8b9eeSAlexander V. Chernikov uint8_t pad[2]; 335e0a8b9eeSAlexander V. Chernikov struct in6_addr sin6_addr; 336e0a8b9eeSAlexander V. Chernikov }; 337e0a8b9eeSAlexander V. Chernikov 338c21034b7SAlexander V. Chernikov struct radix_addr_xentry { 339e0a8b9eeSAlexander V. Chernikov struct radix_node rn[2]; 340e0a8b9eeSAlexander V. Chernikov struct sa_in6 addr6; 341e0a8b9eeSAlexander V. Chernikov uint32_t value; 342e0a8b9eeSAlexander V. Chernikov uint8_t masklen; 3439f7d47b0SAlexander V. Chernikov }; 3449f7d47b0SAlexander V. Chernikov 3455f379342SAlexander V. Chernikov struct radix_cfg { 3465f379342SAlexander V. Chernikov struct radix_node_head *head4; 3475f379342SAlexander V. Chernikov struct radix_node_head *head6; 3485f379342SAlexander V. Chernikov size_t count4; 3495f379342SAlexander V. Chernikov size_t count6; 3505f379342SAlexander V. Chernikov }; 3515f379342SAlexander V. Chernikov 352c21034b7SAlexander V. Chernikov struct ta_buf_radix 3530bce0c23SAlexander V. Chernikov { 3540bce0c23SAlexander V. Chernikov void *ent_ptr; 3550bce0c23SAlexander V. Chernikov struct sockaddr *addr_ptr; 3560bce0c23SAlexander V. Chernikov struct sockaddr *mask_ptr; 3570bce0c23SAlexander V. Chernikov union { 3580bce0c23SAlexander V. Chernikov struct { 3590bce0c23SAlexander V. Chernikov struct sockaddr_in sa; 3600bce0c23SAlexander V. Chernikov struct sockaddr_in ma; 3610bce0c23SAlexander V. Chernikov } a4; 3620bce0c23SAlexander V. Chernikov struct { 3630bce0c23SAlexander V. Chernikov struct sa_in6 sa; 3640bce0c23SAlexander V. Chernikov struct sa_in6 ma; 3650bce0c23SAlexander V. Chernikov } a6; 3660bce0c23SAlexander V. Chernikov } addr; 3670bce0c23SAlexander V. Chernikov }; 3680bce0c23SAlexander V. Chernikov 369*9fe15d06SAlexander V. Chernikov static int ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen, 370*9fe15d06SAlexander V. Chernikov uint32_t *val); 371*9fe15d06SAlexander V. Chernikov static int ta_init_radix(struct ip_fw_chain *ch, void **ta_state, 372*9fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 373*9fe15d06SAlexander V. Chernikov static int flush_radix_entry(struct radix_node *rn, void *arg); 374*9fe15d06SAlexander V. Chernikov static void ta_destroy_radix(void *ta_state, struct table_info *ti); 375*9fe15d06SAlexander V. Chernikov static void ta_dump_radix_tinfo(void *ta_state, struct table_info *ti, 376*9fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 377*9fe15d06SAlexander V. Chernikov static int ta_dump_radix_tentry(void *ta_state, struct table_info *ti, 378*9fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent); 379*9fe15d06SAlexander V. Chernikov static int ta_find_radix_tentry(void *ta_state, struct table_info *ti, 380*9fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 381*9fe15d06SAlexander V. Chernikov static void ta_foreach_radix(void *ta_state, struct table_info *ti, 382*9fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 383*9fe15d06SAlexander V. Chernikov static inline void ipv6_writemask(struct in6_addr *addr6, uint8_t mask); 384*9fe15d06SAlexander V. Chernikov static void tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa, 385*9fe15d06SAlexander V. Chernikov struct sockaddr *ma, int *set_mask); 386*9fe15d06SAlexander V. Chernikov static int ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 387*9fe15d06SAlexander V. Chernikov void *ta_buf); 388*9fe15d06SAlexander V. Chernikov static int ta_add_radix(void *ta_state, struct table_info *ti, 389*9fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 390*9fe15d06SAlexander V. Chernikov static int ta_prepare_del_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 391*9fe15d06SAlexander V. Chernikov void *ta_buf); 392*9fe15d06SAlexander V. Chernikov static int ta_del_radix(void *ta_state, struct table_info *ti, 393*9fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 394*9fe15d06SAlexander V. Chernikov static void ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 395*9fe15d06SAlexander V. Chernikov void *ta_buf); 396*9fe15d06SAlexander V. Chernikov static int ta_need_modify_radix(void *ta_state, struct table_info *ti, 397*9fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 398*9fe15d06SAlexander V. Chernikov 3999f7d47b0SAlexander V. Chernikov static int 4009f7d47b0SAlexander V. Chernikov ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen, 4019f7d47b0SAlexander V. Chernikov uint32_t *val) 4029f7d47b0SAlexander V. Chernikov { 4039f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 4049f7d47b0SAlexander V. Chernikov 4059f7d47b0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 406c21034b7SAlexander V. Chernikov struct radix_addr_entry *ent; 4079f7d47b0SAlexander V. Chernikov struct sockaddr_in sa; 4089f7d47b0SAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 4099f7d47b0SAlexander V. Chernikov sa.sin_addr.s_addr = *((in_addr_t *)key); 4109f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 411c21034b7SAlexander V. Chernikov ent = (struct radix_addr_entry *)(rnh->rnh_matchaddr(&sa, rnh)); 4129f7d47b0SAlexander V. Chernikov if (ent != NULL) { 4139f7d47b0SAlexander V. Chernikov *val = ent->value; 4149f7d47b0SAlexander V. Chernikov return (1); 4159f7d47b0SAlexander V. Chernikov } 4169f7d47b0SAlexander V. Chernikov } else { 417c21034b7SAlexander V. Chernikov struct radix_addr_xentry *xent; 418e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 4199f7d47b0SAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 4209f7d47b0SAlexander V. Chernikov memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr)); 4219f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 422c21034b7SAlexander V. Chernikov xent = (struct radix_addr_xentry *)(rnh->rnh_matchaddr(&sa6, rnh)); 4239f7d47b0SAlexander V. Chernikov if (xent != NULL) { 4249f7d47b0SAlexander V. Chernikov *val = xent->value; 4259f7d47b0SAlexander V. Chernikov return (1); 4269f7d47b0SAlexander V. Chernikov } 4279f7d47b0SAlexander V. Chernikov } 4289f7d47b0SAlexander V. Chernikov 4299f7d47b0SAlexander V. Chernikov return (0); 4309f7d47b0SAlexander V. Chernikov } 4319f7d47b0SAlexander V. Chernikov 4329f7d47b0SAlexander V. Chernikov /* 4339f7d47b0SAlexander V. Chernikov * New table 4349f7d47b0SAlexander V. Chernikov */ 4359f7d47b0SAlexander V. Chernikov static int 43668394ec8SAlexander V. Chernikov ta_init_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 437914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 4389f7d47b0SAlexander V. Chernikov { 4395f379342SAlexander V. Chernikov struct radix_cfg *cfg; 4409f7d47b0SAlexander V. Chernikov 4419f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->state, OFF_LEN_INET)) 4429f7d47b0SAlexander V. Chernikov return (ENOMEM); 4439f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) { 4449f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 4459f7d47b0SAlexander V. Chernikov return (ENOMEM); 4469f7d47b0SAlexander V. Chernikov } 4479f7d47b0SAlexander V. Chernikov 4485f379342SAlexander V. Chernikov cfg = malloc(sizeof(struct radix_cfg), M_IPFW, M_WAITOK | M_ZERO); 4495f379342SAlexander V. Chernikov 4505f379342SAlexander V. Chernikov *ta_state = cfg; 4519f7d47b0SAlexander V. Chernikov ti->lookup = ta_lookup_radix; 4529f7d47b0SAlexander V. Chernikov 4539f7d47b0SAlexander V. Chernikov return (0); 4549f7d47b0SAlexander V. Chernikov } 4559f7d47b0SAlexander V. Chernikov 4569f7d47b0SAlexander V. Chernikov static int 457a399f8beSAlexander V. Chernikov flush_radix_entry(struct radix_node *rn, void *arg) 4589f7d47b0SAlexander V. Chernikov { 4599f7d47b0SAlexander V. Chernikov struct radix_node_head * const rnh = arg; 460c21034b7SAlexander V. Chernikov struct radix_addr_entry *ent; 4619f7d47b0SAlexander V. Chernikov 462c21034b7SAlexander V. Chernikov ent = (struct radix_addr_entry *) 4639f7d47b0SAlexander V. Chernikov rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 4649f7d47b0SAlexander V. Chernikov if (ent != NULL) 4659f7d47b0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 4669f7d47b0SAlexander V. Chernikov return (0); 4679f7d47b0SAlexander V. Chernikov } 4689f7d47b0SAlexander V. Chernikov 4699f7d47b0SAlexander V. Chernikov static void 4709f7d47b0SAlexander V. Chernikov ta_destroy_radix(void *ta_state, struct table_info *ti) 4719f7d47b0SAlexander V. Chernikov { 4725f379342SAlexander V. Chernikov struct radix_cfg *cfg; 4739f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 4749f7d47b0SAlexander V. Chernikov 4755f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 4765f379342SAlexander V. Chernikov 4779f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 478a399f8beSAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_radix_entry, rnh); 4799f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 4809f7d47b0SAlexander V. Chernikov 4819f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 482a399f8beSAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_radix_entry, rnh); 4839f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->xstate); 4845f379342SAlexander V. Chernikov 4855f379342SAlexander V. Chernikov free(cfg, M_IPFW); 4865f379342SAlexander V. Chernikov } 4875f379342SAlexander V. Chernikov 4885f379342SAlexander V. Chernikov /* 4895f379342SAlexander V. Chernikov * Provide algo-specific table info 4905f379342SAlexander V. Chernikov */ 4915f379342SAlexander V. Chernikov static void 4925f379342SAlexander V. Chernikov ta_dump_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 4935f379342SAlexander V. Chernikov { 4945f379342SAlexander V. Chernikov struct radix_cfg *cfg; 4955f379342SAlexander V. Chernikov 4965f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 4975f379342SAlexander V. Chernikov 4985f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM; 4995f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_RADIX; 5005f379342SAlexander V. Chernikov tinfo->count4 = cfg->count4; 501c21034b7SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct radix_addr_entry); 5025f379342SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_RADIX; 5035f379342SAlexander V. Chernikov tinfo->count6 = cfg->count6; 504c21034b7SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct radix_addr_xentry); 5059f7d47b0SAlexander V. Chernikov } 5069f7d47b0SAlexander V. Chernikov 5079f7d47b0SAlexander V. Chernikov static int 50881d3153dSAlexander V. Chernikov ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e, 50981d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 5109f7d47b0SAlexander V. Chernikov { 511c21034b7SAlexander V. Chernikov struct radix_addr_entry *n; 512*9fe15d06SAlexander V. Chernikov #ifdef INET6 513c21034b7SAlexander V. Chernikov struct radix_addr_xentry *xn; 514*9fe15d06SAlexander V. Chernikov #endif 5159f7d47b0SAlexander V. Chernikov 516c21034b7SAlexander V. Chernikov n = (struct radix_addr_entry *)e; 5179f7d47b0SAlexander V. Chernikov 5189f7d47b0SAlexander V. Chernikov /* Guess IPv4/IPv6 radix by sockaddr family */ 5199f7d47b0SAlexander V. Chernikov if (n->addr.sin_family == AF_INET) { 52081d3153dSAlexander V. Chernikov tent->k.addr.s_addr = n->addr.sin_addr.s_addr; 521e0a8b9eeSAlexander V. Chernikov tent->masklen = n->masklen; 52281d3153dSAlexander V. Chernikov tent->subtype = AF_INET; 5230cba2b28SAlexander V. Chernikov tent->v.kidx = n->value; 5249f7d47b0SAlexander V. Chernikov #ifdef INET6 5259f7d47b0SAlexander V. Chernikov } else { 526c21034b7SAlexander V. Chernikov xn = (struct radix_addr_xentry *)e; 527e0a8b9eeSAlexander V. Chernikov memcpy(&tent->k, &xn->addr6.sin6_addr, sizeof(struct in6_addr)); 528e0a8b9eeSAlexander V. Chernikov tent->masklen = xn->masklen; 52981d3153dSAlexander V. Chernikov tent->subtype = AF_INET6; 5300cba2b28SAlexander V. Chernikov tent->v.kidx = xn->value; 5319f7d47b0SAlexander V. Chernikov #endif 5329f7d47b0SAlexander V. Chernikov } 5339f7d47b0SAlexander V. Chernikov 5349f7d47b0SAlexander V. Chernikov return (0); 5359f7d47b0SAlexander V. Chernikov } 5369f7d47b0SAlexander V. Chernikov 53781d3153dSAlexander V. Chernikov static int 538914bffb6SAlexander V. Chernikov ta_find_radix_tentry(void *ta_state, struct table_info *ti, 539914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 54081d3153dSAlexander V. Chernikov { 54181d3153dSAlexander V. Chernikov struct radix_node_head *rnh; 54281d3153dSAlexander V. Chernikov void *e; 54381d3153dSAlexander V. Chernikov 54481d3153dSAlexander V. Chernikov e = NULL; 545914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) { 54681d3153dSAlexander V. Chernikov struct sockaddr_in sa; 54781d3153dSAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 548914bffb6SAlexander V. Chernikov sa.sin_addr.s_addr = tent->k.addr.s_addr; 54981d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 55081d3153dSAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa, rnh); 55181d3153dSAlexander V. Chernikov } else { 552e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 55381d3153dSAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 554914bffb6SAlexander V. Chernikov memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr)); 55581d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 55681d3153dSAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa6, rnh); 55781d3153dSAlexander V. Chernikov } 55881d3153dSAlexander V. Chernikov 55981d3153dSAlexander V. Chernikov if (e != NULL) { 56081d3153dSAlexander V. Chernikov ta_dump_radix_tentry(ta_state, ti, e, tent); 56181d3153dSAlexander V. Chernikov return (0); 56281d3153dSAlexander V. Chernikov } 56381d3153dSAlexander V. Chernikov 56481d3153dSAlexander V. Chernikov return (ENOENT); 56581d3153dSAlexander V. Chernikov } 56681d3153dSAlexander V. Chernikov 5679f7d47b0SAlexander V. Chernikov static void 5689f7d47b0SAlexander V. Chernikov ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f, 5699f7d47b0SAlexander V. Chernikov void *arg) 5709f7d47b0SAlexander V. Chernikov { 5719f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 5729f7d47b0SAlexander V. Chernikov 5739f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 5749f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 5759f7d47b0SAlexander V. Chernikov 5769f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 5779f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 5789f7d47b0SAlexander V. Chernikov } 5799f7d47b0SAlexander V. Chernikov 5809f7d47b0SAlexander V. Chernikov 5819f7d47b0SAlexander V. Chernikov #ifdef INET6 5829f7d47b0SAlexander V. Chernikov static inline void 5839f7d47b0SAlexander V. Chernikov ipv6_writemask(struct in6_addr *addr6, uint8_t mask) 5849f7d47b0SAlexander V. Chernikov { 5859f7d47b0SAlexander V. Chernikov uint32_t *cp; 5869f7d47b0SAlexander V. Chernikov 5879f7d47b0SAlexander V. Chernikov for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32) 5889f7d47b0SAlexander V. Chernikov *cp++ = 0xFFFFFFFF; 5899f7d47b0SAlexander V. Chernikov *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0); 5909f7d47b0SAlexander V. Chernikov } 5919f7d47b0SAlexander V. Chernikov #endif 5929f7d47b0SAlexander V. Chernikov 5932e324d29SAlexander V. Chernikov static void 5942e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa, 5952e324d29SAlexander V. Chernikov struct sockaddr *ma, int *set_mask) 5962e324d29SAlexander V. Chernikov { 5972e324d29SAlexander V. Chernikov int mlen; 598*9fe15d06SAlexander V. Chernikov #ifdef INET 5992e324d29SAlexander V. Chernikov struct sockaddr_in *addr, *mask; 600*9fe15d06SAlexander V. Chernikov #endif 601*9fe15d06SAlexander V. Chernikov #ifdef INET6 602720ee730SAlexander V. Chernikov struct sa_in6 *addr6, *mask6; 603*9fe15d06SAlexander V. Chernikov #endif 6042e324d29SAlexander V. Chernikov in_addr_t a4; 6052e324d29SAlexander V. Chernikov 6062e324d29SAlexander V. Chernikov mlen = tei->masklen; 6072e324d29SAlexander V. Chernikov 6082e324d29SAlexander V. Chernikov if (tei->subtype == AF_INET) { 6092e324d29SAlexander V. Chernikov #ifdef INET 6102e324d29SAlexander V. Chernikov addr = (struct sockaddr_in *)sa; 6112e324d29SAlexander V. Chernikov mask = (struct sockaddr_in *)ma; 6122e324d29SAlexander V. Chernikov /* Set 'total' structure length */ 6132e324d29SAlexander V. Chernikov KEY_LEN(*addr) = KEY_LEN_INET; 6142e324d29SAlexander V. Chernikov KEY_LEN(*mask) = KEY_LEN_INET; 6152e324d29SAlexander V. Chernikov addr->sin_family = AF_INET; 6162e324d29SAlexander V. Chernikov mask->sin_addr.s_addr = 6172e324d29SAlexander V. Chernikov htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 6182e324d29SAlexander V. Chernikov a4 = *((in_addr_t *)tei->paddr); 6192e324d29SAlexander V. Chernikov addr->sin_addr.s_addr = a4 & mask->sin_addr.s_addr; 6202e324d29SAlexander V. Chernikov if (mlen != 32) 6212e324d29SAlexander V. Chernikov *set_mask = 1; 6222e324d29SAlexander V. Chernikov else 6232e324d29SAlexander V. Chernikov *set_mask = 0; 6242e324d29SAlexander V. Chernikov #endif 6252e324d29SAlexander V. Chernikov #ifdef INET6 6262e324d29SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 6272e324d29SAlexander V. Chernikov /* IPv6 case */ 628720ee730SAlexander V. Chernikov addr6 = (struct sa_in6 *)sa; 629720ee730SAlexander V. Chernikov mask6 = (struct sa_in6 *)ma; 6302e324d29SAlexander V. Chernikov /* Set 'total' structure length */ 6312e324d29SAlexander V. Chernikov KEY_LEN(*addr6) = KEY_LEN_INET6; 6322e324d29SAlexander V. Chernikov KEY_LEN(*mask6) = KEY_LEN_INET6; 6332e324d29SAlexander V. Chernikov addr6->sin6_family = AF_INET6; 6342e324d29SAlexander V. Chernikov ipv6_writemask(&mask6->sin6_addr, mlen); 6352e324d29SAlexander V. Chernikov memcpy(&addr6->sin6_addr, tei->paddr, sizeof(struct in6_addr)); 6362e324d29SAlexander V. Chernikov APPLY_MASK(&addr6->sin6_addr, &mask6->sin6_addr); 6372e324d29SAlexander V. Chernikov if (mlen != 128) 6382e324d29SAlexander V. Chernikov *set_mask = 1; 6392e324d29SAlexander V. Chernikov else 6402e324d29SAlexander V. Chernikov *set_mask = 0; 6412e324d29SAlexander V. Chernikov } 6422e324d29SAlexander V. Chernikov #endif 6432e324d29SAlexander V. Chernikov } 6449f7d47b0SAlexander V. Chernikov 6459f7d47b0SAlexander V. Chernikov static int 646a399f8beSAlexander V. Chernikov ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 64768394ec8SAlexander V. Chernikov void *ta_buf) 6489f7d47b0SAlexander V. Chernikov { 649c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 650c21034b7SAlexander V. Chernikov struct radix_addr_entry *ent; 651c21034b7SAlexander V. Chernikov struct radix_addr_xentry *xent; 6522e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask; 6532e324d29SAlexander V. Chernikov int mlen, set_mask; 6549f7d47b0SAlexander V. Chernikov 655c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 6569f7d47b0SAlexander V. Chernikov 6579f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 6582e324d29SAlexander V. Chernikov set_mask = 0; 6599f7d47b0SAlexander V. Chernikov 660ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 6619f7d47b0SAlexander V. Chernikov #ifdef INET 6629f7d47b0SAlexander V. Chernikov if (mlen > 32) 6639f7d47b0SAlexander V. Chernikov return (EINVAL); 6649f7d47b0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 665e0a8b9eeSAlexander V. Chernikov ent->masklen = mlen; 6662e324d29SAlexander V. Chernikov 6672e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&ent->addr; 6682e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma; 6699f7d47b0SAlexander V. Chernikov tb->ent_ptr = ent; 6709f7d47b0SAlexander V. Chernikov #endif 6719f7d47b0SAlexander V. Chernikov #ifdef INET6 672ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 6739f7d47b0SAlexander V. Chernikov /* IPv6 case */ 6749f7d47b0SAlexander V. Chernikov if (mlen > 128) 6759f7d47b0SAlexander V. Chernikov return (EINVAL); 6769f7d47b0SAlexander V. Chernikov xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO); 677e0a8b9eeSAlexander V. Chernikov xent->masklen = mlen; 6782e324d29SAlexander V. Chernikov 6792e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&xent->addr6; 6802e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma; 6819f7d47b0SAlexander V. Chernikov tb->ent_ptr = xent; 6829f7d47b0SAlexander V. Chernikov #endif 6839f7d47b0SAlexander V. Chernikov } else { 6849f7d47b0SAlexander V. Chernikov /* Unknown CIDR type */ 6859f7d47b0SAlexander V. Chernikov return (EINVAL); 6869f7d47b0SAlexander V. Chernikov } 6879f7d47b0SAlexander V. Chernikov 6882e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(tei, addr, mask, &set_mask); 6892e324d29SAlexander V. Chernikov /* Set pointers */ 6902e324d29SAlexander V. Chernikov tb->addr_ptr = addr; 6912e324d29SAlexander V. Chernikov if (set_mask != 0) 6922e324d29SAlexander V. Chernikov tb->mask_ptr = mask; 6932e324d29SAlexander V. Chernikov 6949f7d47b0SAlexander V. Chernikov return (0); 6959f7d47b0SAlexander V. Chernikov } 6969f7d47b0SAlexander V. Chernikov 6979f7d47b0SAlexander V. Chernikov static int 698a399f8beSAlexander V. Chernikov ta_add_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, 699b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 7009f7d47b0SAlexander V. Chernikov { 7015f379342SAlexander V. Chernikov struct radix_cfg *cfg; 7029f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 7039f7d47b0SAlexander V. Chernikov struct radix_node *rn; 704c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 705648e8380SAlexander V. Chernikov uint32_t *old_value, value; 7069f7d47b0SAlexander V. Chernikov 7075f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 708c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 7099f7d47b0SAlexander V. Chernikov 71013263632SAlexander V. Chernikov /* Save current entry value from @tei */ 71113263632SAlexander V. Chernikov if (tei->subtype == AF_INET) { 7129f7d47b0SAlexander V. Chernikov rnh = ti->state; 71313263632SAlexander V. Chernikov ((struct radix_addr_entry *)tb->ent_ptr)->value = tei->value; 71413263632SAlexander V. Chernikov } else { 7159f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 71613263632SAlexander V. Chernikov ((struct radix_addr_xentry *)tb->ent_ptr)->value = tei->value; 71713263632SAlexander V. Chernikov } 7189f7d47b0SAlexander V. Chernikov 7194c0c07a5SAlexander V. Chernikov /* Search for an entry first */ 7204c0c07a5SAlexander V. Chernikov rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, rnh); 7214c0c07a5SAlexander V. Chernikov if (rn != NULL) { 722ac35ff17SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 7239f7d47b0SAlexander V. Chernikov return (EEXIST); 724ac35ff17SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 725648e8380SAlexander V. Chernikov if (tei->subtype == AF_INET) 726c21034b7SAlexander V. Chernikov old_value = &((struct radix_addr_entry *)rn)->value; 727648e8380SAlexander V. Chernikov else 728c21034b7SAlexander V. Chernikov old_value = &((struct radix_addr_xentry *)rn)->value; 729648e8380SAlexander V. Chernikov 730648e8380SAlexander V. Chernikov value = *old_value; 731648e8380SAlexander V. Chernikov *old_value = tei->value; 732648e8380SAlexander V. Chernikov tei->value = value; 733ac35ff17SAlexander V. Chernikov 734ac35ff17SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 735ac35ff17SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 736adea6201SAlexander V. Chernikov *pnum = 0; 737e0a8b9eeSAlexander V. Chernikov 738e0a8b9eeSAlexander V. Chernikov return (0); 739ac35ff17SAlexander V. Chernikov } 740ac35ff17SAlexander V. Chernikov 7414c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 7424c0c07a5SAlexander V. Chernikov return (EFBIG); 7434c0c07a5SAlexander V. Chernikov 7444c0c07a5SAlexander V. Chernikov rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr); 7454c0c07a5SAlexander V. Chernikov if (rn == NULL) { 7464c0c07a5SAlexander V. Chernikov /* Unknown error */ 7474c0c07a5SAlexander V. Chernikov return (EINVAL); 7484c0c07a5SAlexander V. Chernikov } 7494c0c07a5SAlexander V. Chernikov 7505f379342SAlexander V. Chernikov if (tei->subtype == AF_INET) 7515f379342SAlexander V. Chernikov cfg->count4++; 7525f379342SAlexander V. Chernikov else 7535f379342SAlexander V. Chernikov cfg->count6++; 754ac35ff17SAlexander V. Chernikov tb->ent_ptr = NULL; 755adea6201SAlexander V. Chernikov *pnum = 1; 7569f7d47b0SAlexander V. Chernikov 7579f7d47b0SAlexander V. Chernikov return (0); 7589f7d47b0SAlexander V. Chernikov } 7599f7d47b0SAlexander V. Chernikov 7609f7d47b0SAlexander V. Chernikov static int 761a399f8beSAlexander V. Chernikov ta_prepare_del_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 76268394ec8SAlexander V. Chernikov void *ta_buf) 7639f7d47b0SAlexander V. Chernikov { 764c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 7652e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask; 7662e324d29SAlexander V. Chernikov int mlen, set_mask; 7679f7d47b0SAlexander V. Chernikov 768c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 7699f7d47b0SAlexander V. Chernikov 7709f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 7712e324d29SAlexander V. Chernikov set_mask = 0; 7729f7d47b0SAlexander V. Chernikov 773ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 774e0a8b9eeSAlexander V. Chernikov if (mlen > 32) 775e0a8b9eeSAlexander V. Chernikov return (EINVAL); 7762e324d29SAlexander V. Chernikov 7772e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a4.sa; 7782e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma; 7799f7d47b0SAlexander V. Chernikov #ifdef INET6 780ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 7819f7d47b0SAlexander V. Chernikov if (mlen > 128) 7829f7d47b0SAlexander V. Chernikov return (EINVAL); 7832e324d29SAlexander V. Chernikov 7842e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a6.sa; 7852e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma; 7869f7d47b0SAlexander V. Chernikov #endif 7879f7d47b0SAlexander V. Chernikov } else 7889f7d47b0SAlexander V. Chernikov return (EINVAL); 7899f7d47b0SAlexander V. Chernikov 7902e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(tei, addr, mask, &set_mask); 7912e324d29SAlexander V. Chernikov tb->addr_ptr = addr; 7922e324d29SAlexander V. Chernikov if (set_mask != 0) 7932e324d29SAlexander V. Chernikov tb->mask_ptr = mask; 7942e324d29SAlexander V. Chernikov 7959f7d47b0SAlexander V. Chernikov return (0); 7969f7d47b0SAlexander V. Chernikov } 7979f7d47b0SAlexander V. Chernikov 7989f7d47b0SAlexander V. Chernikov static int 799a399f8beSAlexander V. Chernikov ta_del_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, 800b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 8019f7d47b0SAlexander V. Chernikov { 8025f379342SAlexander V. Chernikov struct radix_cfg *cfg; 8039f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 8049f7d47b0SAlexander V. Chernikov struct radix_node *rn; 805c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 8069f7d47b0SAlexander V. Chernikov 8075f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 808c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 8099f7d47b0SAlexander V. Chernikov 810ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) 8119f7d47b0SAlexander V. Chernikov rnh = ti->state; 8129f7d47b0SAlexander V. Chernikov else 8139f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 8149f7d47b0SAlexander V. Chernikov 8159f7d47b0SAlexander V. Chernikov rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh); 8169f7d47b0SAlexander V. Chernikov 8173a845e10SAlexander V. Chernikov if (rn == NULL) 8183a845e10SAlexander V. Chernikov return (ENOENT); 8193a845e10SAlexander V. Chernikov 820648e8380SAlexander V. Chernikov /* Save entry value to @tei */ 821648e8380SAlexander V. Chernikov if (tei->subtype == AF_INET) 822c21034b7SAlexander V. Chernikov tei->value = ((struct radix_addr_entry *)rn)->value; 823648e8380SAlexander V. Chernikov else 824c21034b7SAlexander V. Chernikov tei->value = ((struct radix_addr_xentry *)rn)->value; 825648e8380SAlexander V. Chernikov 8269f7d47b0SAlexander V. Chernikov tb->ent_ptr = rn; 8279f7d47b0SAlexander V. Chernikov 8285f379342SAlexander V. Chernikov if (tei->subtype == AF_INET) 8295f379342SAlexander V. Chernikov cfg->count4--; 8305f379342SAlexander V. Chernikov else 8315f379342SAlexander V. Chernikov cfg->count6--; 832adea6201SAlexander V. Chernikov *pnum = 1; 833adea6201SAlexander V. Chernikov 8349f7d47b0SAlexander V. Chernikov return (0); 8359f7d47b0SAlexander V. Chernikov } 8369f7d47b0SAlexander V. Chernikov 8379f7d47b0SAlexander V. Chernikov static void 838a399f8beSAlexander V. Chernikov ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 83968394ec8SAlexander V. Chernikov void *ta_buf) 8409f7d47b0SAlexander V. Chernikov { 841c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 8429f7d47b0SAlexander V. Chernikov 843c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 8449f7d47b0SAlexander V. Chernikov 845ac35ff17SAlexander V. Chernikov if (tb->ent_ptr != NULL) 8469f7d47b0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 8479f7d47b0SAlexander V. Chernikov } 8489f7d47b0SAlexander V. Chernikov 849b6ee846eSAlexander V. Chernikov static int 850301290bcSAlexander V. Chernikov ta_need_modify_radix(void *ta_state, struct table_info *ti, uint32_t count, 851b6ee846eSAlexander V. Chernikov uint64_t *pflags) 852b6ee846eSAlexander V. Chernikov { 853b6ee846eSAlexander V. Chernikov 854b6ee846eSAlexander V. Chernikov /* 8550bce0c23SAlexander V. Chernikov * radix does not require additional memory allocations 856b6ee846eSAlexander V. Chernikov * other than nodes itself. Adding new masks to the tree do 857b6ee846eSAlexander V. Chernikov * but we don't have any API to call (and we don't known which 858b6ee846eSAlexander V. Chernikov * sizes do we need). 859b6ee846eSAlexander V. Chernikov */ 860301290bcSAlexander V. Chernikov return (0); 861b6ee846eSAlexander V. Chernikov } 862b6ee846eSAlexander V. Chernikov 863c21034b7SAlexander V. Chernikov struct table_algo addr_radix = { 864c21034b7SAlexander V. Chernikov .name = "addr:radix", 865c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR, 86657a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 867c21034b7SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_radix), 8689f7d47b0SAlexander V. Chernikov .init = ta_init_radix, 8699f7d47b0SAlexander V. Chernikov .destroy = ta_destroy_radix, 870a399f8beSAlexander V. Chernikov .prepare_add = ta_prepare_add_radix, 871a399f8beSAlexander V. Chernikov .prepare_del = ta_prepare_del_radix, 872a399f8beSAlexander V. Chernikov .add = ta_add_radix, 873a399f8beSAlexander V. Chernikov .del = ta_del_radix, 874a399f8beSAlexander V. Chernikov .flush_entry = ta_flush_radix_entry, 8759f7d47b0SAlexander V. Chernikov .foreach = ta_foreach_radix, 87681d3153dSAlexander V. Chernikov .dump_tentry = ta_dump_radix_tentry, 87781d3153dSAlexander V. Chernikov .find_tentry = ta_find_radix_tentry, 8785f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_radix_tinfo, 879301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_radix, 8809f7d47b0SAlexander V. Chernikov }; 8819f7d47b0SAlexander V. Chernikov 8829f7d47b0SAlexander V. Chernikov 8839f7d47b0SAlexander V. Chernikov /* 884c21034b7SAlexander V. Chernikov * addr:hash cmds 88574b941f0SAlexander V. Chernikov * 88674b941f0SAlexander V. Chernikov * 88774b941f0SAlexander V. Chernikov * ti->data: 88874b941f0SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6] 88974b941f0SAlexander V. Chernikov * [ 8][ 8[ 8][ 8] 89074b941f0SAlexander V. Chernikov * 89174b941f0SAlexander V. Chernikov * inv.mask4: 32 - mask 89274b941f0SAlexander V. Chernikov * inv.mask6: 89374b941f0SAlexander V. Chernikov * 1) _slow lookup: mask 89474b941f0SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8 89574b941f0SAlexander V. Chernikov * 3) _64: 8 896ce2817b5SAlexander V. Chernikov * 897ce2817b5SAlexander V. Chernikov * 898ce2817b5SAlexander V. Chernikov * pflags: 899ce2817b5SAlexander V. Chernikov * [v4=1/v6=0][hsize] 900ce2817b5SAlexander V. Chernikov * [ 32][ 32] 90174b941f0SAlexander V. Chernikov */ 90274b941f0SAlexander V. Chernikov 90374b941f0SAlexander V. Chernikov struct chashentry; 90474b941f0SAlexander V. Chernikov 90574b941f0SAlexander V. Chernikov SLIST_HEAD(chashbhead, chashentry); 90674b941f0SAlexander V. Chernikov 90774b941f0SAlexander V. Chernikov struct chash_cfg { 90874b941f0SAlexander V. Chernikov struct chashbhead *head4; 90974b941f0SAlexander V. Chernikov struct chashbhead *head6; 91074b941f0SAlexander V. Chernikov size_t size4; 91174b941f0SAlexander V. Chernikov size_t size6; 912ce2817b5SAlexander V. Chernikov size_t items4; 913ce2817b5SAlexander V. Chernikov size_t items6; 91474b941f0SAlexander V. Chernikov uint8_t mask4; 91574b941f0SAlexander V. Chernikov uint8_t mask6; 91674b941f0SAlexander V. Chernikov }; 91774b941f0SAlexander V. Chernikov 91874b941f0SAlexander V. Chernikov struct chashentry { 91974b941f0SAlexander V. Chernikov SLIST_ENTRY(chashentry) next; 92074b941f0SAlexander V. Chernikov uint32_t value; 92174b941f0SAlexander V. Chernikov uint32_t type; 92274b941f0SAlexander V. Chernikov union { 92374b941f0SAlexander V. Chernikov uint32_t a4; /* Host format */ 92474b941f0SAlexander V. Chernikov struct in6_addr a6; /* Network format */ 92574b941f0SAlexander V. Chernikov } a; 92674b941f0SAlexander V. Chernikov }; 92774b941f0SAlexander V. Chernikov 9280bce0c23SAlexander V. Chernikov struct ta_buf_chash 9290bce0c23SAlexander V. Chernikov { 9300bce0c23SAlexander V. Chernikov void *ent_ptr; 9310bce0c23SAlexander V. Chernikov struct chashentry ent; 9320bce0c23SAlexander V. Chernikov }; 9330bce0c23SAlexander V. Chernikov 934*9fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip(uint32_t addr, int hsize); 935*9fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip6(struct in6_addr *addr6, int hsize); 936*9fe15d06SAlexander V. Chernikov static __inline uint16_t hash_ip64(struct in6_addr *addr6, int hsize); 937*9fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip6_slow(struct in6_addr *addr6, void *key, 938*9fe15d06SAlexander V. Chernikov int mask, int hsize); 939*9fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip6_al(struct in6_addr *addr6, void *key, int mask, 940*9fe15d06SAlexander V. Chernikov int hsize); 941*9fe15d06SAlexander V. Chernikov static int ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen, 942*9fe15d06SAlexander V. Chernikov uint32_t *val); 943*9fe15d06SAlexander V. Chernikov static int ta_lookup_chash_aligned(struct table_info *ti, void *key, 944*9fe15d06SAlexander V. Chernikov uint32_t keylen, uint32_t *val); 945*9fe15d06SAlexander V. Chernikov static int ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen, 946*9fe15d06SAlexander V. Chernikov uint32_t *val); 947*9fe15d06SAlexander V. Chernikov static int chash_parse_opts(struct chash_cfg *cfg, char *data); 948*9fe15d06SAlexander V. Chernikov static void ta_print_chash_config(void *ta_state, struct table_info *ti, 949*9fe15d06SAlexander V. Chernikov char *buf, size_t bufsize); 950*9fe15d06SAlexander V. Chernikov static int log2(uint32_t v); 951*9fe15d06SAlexander V. Chernikov static int ta_init_chash(struct ip_fw_chain *ch, void **ta_state, 952*9fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 953*9fe15d06SAlexander V. Chernikov static void ta_destroy_chash(void *ta_state, struct table_info *ti); 954*9fe15d06SAlexander V. Chernikov static void ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, 955*9fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 956*9fe15d06SAlexander V. Chernikov static int ta_dump_chash_tentry(void *ta_state, struct table_info *ti, 957*9fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent); 958*9fe15d06SAlexander V. Chernikov static uint32_t hash_ent(struct chashentry *ent, int af, int mlen, 959*9fe15d06SAlexander V. Chernikov uint32_t size); 960*9fe15d06SAlexander V. Chernikov static int tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent); 961*9fe15d06SAlexander V. Chernikov static int ta_find_chash_tentry(void *ta_state, struct table_info *ti, 962*9fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 963*9fe15d06SAlexander V. Chernikov static void ta_foreach_chash(void *ta_state, struct table_info *ti, 964*9fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 965*9fe15d06SAlexander V. Chernikov static int ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 966*9fe15d06SAlexander V. Chernikov void *ta_buf); 967*9fe15d06SAlexander V. Chernikov static int ta_add_chash(void *ta_state, struct table_info *ti, 968*9fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 969*9fe15d06SAlexander V. Chernikov static int ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 970*9fe15d06SAlexander V. Chernikov void *ta_buf); 971*9fe15d06SAlexander V. Chernikov static int ta_del_chash(void *ta_state, struct table_info *ti, 972*9fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 973*9fe15d06SAlexander V. Chernikov static void ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 974*9fe15d06SAlexander V. Chernikov void *ta_buf); 975*9fe15d06SAlexander V. Chernikov static int ta_need_modify_chash(void *ta_state, struct table_info *ti, 976*9fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 977*9fe15d06SAlexander V. Chernikov static int ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags); 978*9fe15d06SAlexander V. Chernikov static int ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf, 979*9fe15d06SAlexander V. Chernikov uint64_t *pflags); 980*9fe15d06SAlexander V. Chernikov static void ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf, 981*9fe15d06SAlexander V. Chernikov uint64_t pflags); 982*9fe15d06SAlexander V. Chernikov static void ta_flush_mod_chash(void *ta_buf); 983*9fe15d06SAlexander V. Chernikov 9840bce0c23SAlexander V. Chernikov 98574b941f0SAlexander V. Chernikov static __inline uint32_t 98674b941f0SAlexander V. Chernikov hash_ip(uint32_t addr, int hsize) 98774b941f0SAlexander V. Chernikov { 98874b941f0SAlexander V. Chernikov 98974b941f0SAlexander V. Chernikov return (addr % (hsize - 1)); 99074b941f0SAlexander V. Chernikov } 99174b941f0SAlexander V. Chernikov 99274b941f0SAlexander V. Chernikov static __inline uint32_t 99374b941f0SAlexander V. Chernikov hash_ip6(struct in6_addr *addr6, int hsize) 99474b941f0SAlexander V. Chernikov { 99574b941f0SAlexander V. Chernikov uint32_t i; 99674b941f0SAlexander V. Chernikov 99774b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^ 99874b941f0SAlexander V. Chernikov addr6->s6_addr32[2] ^ addr6->s6_addr32[3]; 99974b941f0SAlexander V. Chernikov 100074b941f0SAlexander V. Chernikov return (i % (hsize - 1)); 100174b941f0SAlexander V. Chernikov } 100274b941f0SAlexander V. Chernikov 100374b941f0SAlexander V. Chernikov 100474b941f0SAlexander V. Chernikov static __inline uint16_t 100574b941f0SAlexander V. Chernikov hash_ip64(struct in6_addr *addr6, int hsize) 100674b941f0SAlexander V. Chernikov { 100774b941f0SAlexander V. Chernikov uint32_t i; 100874b941f0SAlexander V. Chernikov 100974b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1]; 101074b941f0SAlexander V. Chernikov 101174b941f0SAlexander V. Chernikov return (i % (hsize - 1)); 101274b941f0SAlexander V. Chernikov } 101374b941f0SAlexander V. Chernikov 101474b941f0SAlexander V. Chernikov 101574b941f0SAlexander V. Chernikov static __inline uint32_t 101674b941f0SAlexander V. Chernikov hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize) 101774b941f0SAlexander V. Chernikov { 101874b941f0SAlexander V. Chernikov struct in6_addr mask6; 101974b941f0SAlexander V. Chernikov 102074b941f0SAlexander V. Chernikov ipv6_writemask(&mask6, mask); 102174b941f0SAlexander V. Chernikov memcpy(addr6, key, sizeof(struct in6_addr)); 102274b941f0SAlexander V. Chernikov APPLY_MASK(addr6, &mask6); 102374b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize)); 102474b941f0SAlexander V. Chernikov } 102574b941f0SAlexander V. Chernikov 102674b941f0SAlexander V. Chernikov static __inline uint32_t 102774b941f0SAlexander V. Chernikov hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize) 102874b941f0SAlexander V. Chernikov { 102974b941f0SAlexander V. Chernikov uint64_t *paddr; 103074b941f0SAlexander V. Chernikov 103174b941f0SAlexander V. Chernikov paddr = (uint64_t *)addr6; 103274b941f0SAlexander V. Chernikov *paddr = 0; 103374b941f0SAlexander V. Chernikov *(paddr + 1) = 0; 103474b941f0SAlexander V. Chernikov memcpy(addr6, key, mask); 103574b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize)); 103674b941f0SAlexander V. Chernikov } 103774b941f0SAlexander V. Chernikov 103874b941f0SAlexander V. Chernikov static int 103974b941f0SAlexander V. Chernikov ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen, 104074b941f0SAlexander V. Chernikov uint32_t *val) 104174b941f0SAlexander V. Chernikov { 104274b941f0SAlexander V. Chernikov struct chashbhead *head; 104374b941f0SAlexander V. Chernikov struct chashentry *ent; 104474b941f0SAlexander V. Chernikov uint16_t hash, hsize; 104574b941f0SAlexander V. Chernikov uint8_t imask; 104674b941f0SAlexander V. Chernikov 104774b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 104874b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 104974b941f0SAlexander V. Chernikov imask = ti->data >> 24; 105074b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 105174b941f0SAlexander V. Chernikov uint32_t a; 105274b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 105374b941f0SAlexander V. Chernikov a = a >> imask; 105474b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 105574b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 105674b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 105774b941f0SAlexander V. Chernikov *val = ent->value; 105874b941f0SAlexander V. Chernikov return (1); 105974b941f0SAlexander V. Chernikov } 106074b941f0SAlexander V. Chernikov } 106174b941f0SAlexander V. Chernikov } else { 106274b941f0SAlexander V. Chernikov /* IPv6: worst scenario: non-round mask */ 106374b941f0SAlexander V. Chernikov struct in6_addr addr6; 106474b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 106574b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16; 106674b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 106774b941f0SAlexander V. Chernikov hash = hash_ip6_slow(&addr6, key, imask, hsize); 106874b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 106974b941f0SAlexander V. Chernikov if (memcmp(&ent->a.a6, &addr6, 16) == 0) { 107074b941f0SAlexander V. Chernikov *val = ent->value; 107174b941f0SAlexander V. Chernikov return (1); 107274b941f0SAlexander V. Chernikov } 107374b941f0SAlexander V. Chernikov } 107474b941f0SAlexander V. Chernikov } 107574b941f0SAlexander V. Chernikov 107674b941f0SAlexander V. Chernikov return (0); 107774b941f0SAlexander V. Chernikov } 107874b941f0SAlexander V. Chernikov 107974b941f0SAlexander V. Chernikov static int 108074b941f0SAlexander V. Chernikov ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen, 108174b941f0SAlexander V. Chernikov uint32_t *val) 108274b941f0SAlexander V. Chernikov { 108374b941f0SAlexander V. Chernikov struct chashbhead *head; 108474b941f0SAlexander V. Chernikov struct chashentry *ent; 108574b941f0SAlexander V. Chernikov uint16_t hash, hsize; 108674b941f0SAlexander V. Chernikov uint8_t imask; 108774b941f0SAlexander V. Chernikov 108874b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 108974b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 109074b941f0SAlexander V. Chernikov imask = ti->data >> 24; 109174b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 109274b941f0SAlexander V. Chernikov uint32_t a; 109374b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 109474b941f0SAlexander V. Chernikov a = a >> imask; 109574b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 109674b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 109774b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 109874b941f0SAlexander V. Chernikov *val = ent->value; 109974b941f0SAlexander V. Chernikov return (1); 110074b941f0SAlexander V. Chernikov } 110174b941f0SAlexander V. Chernikov } 110274b941f0SAlexander V. Chernikov } else { 110374b941f0SAlexander V. Chernikov /* IPv6: aligned to 8bit mask */ 110474b941f0SAlexander V. Chernikov struct in6_addr addr6; 110574b941f0SAlexander V. Chernikov uint64_t *paddr, *ptmp; 110674b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 110774b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16; 110874b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 110974b941f0SAlexander V. Chernikov 111074b941f0SAlexander V. Chernikov hash = hash_ip6_al(&addr6, key, imask, hsize); 111174b941f0SAlexander V. Chernikov paddr = (uint64_t *)&addr6; 111274b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 111374b941f0SAlexander V. Chernikov ptmp = (uint64_t *)&ent->a.a6; 111474b941f0SAlexander V. Chernikov if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) { 111574b941f0SAlexander V. Chernikov *val = ent->value; 111674b941f0SAlexander V. Chernikov return (1); 111774b941f0SAlexander V. Chernikov } 111874b941f0SAlexander V. Chernikov } 111974b941f0SAlexander V. Chernikov } 112074b941f0SAlexander V. Chernikov 112174b941f0SAlexander V. Chernikov return (0); 112274b941f0SAlexander V. Chernikov } 112374b941f0SAlexander V. Chernikov 112474b941f0SAlexander V. Chernikov static int 112574b941f0SAlexander V. Chernikov ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen, 112674b941f0SAlexander V. Chernikov uint32_t *val) 112774b941f0SAlexander V. Chernikov { 112874b941f0SAlexander V. Chernikov struct chashbhead *head; 112974b941f0SAlexander V. Chernikov struct chashentry *ent; 113074b941f0SAlexander V. Chernikov uint16_t hash, hsize; 113174b941f0SAlexander V. Chernikov uint8_t imask; 113274b941f0SAlexander V. Chernikov 113374b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 113474b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 113574b941f0SAlexander V. Chernikov imask = ti->data >> 24; 113674b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 113774b941f0SAlexander V. Chernikov uint32_t a; 113874b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 113974b941f0SAlexander V. Chernikov a = a >> imask; 114074b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 114174b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 114274b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 114374b941f0SAlexander V. Chernikov *val = ent->value; 114474b941f0SAlexander V. Chernikov return (1); 114574b941f0SAlexander V. Chernikov } 114674b941f0SAlexander V. Chernikov } 114774b941f0SAlexander V. Chernikov } else { 114874b941f0SAlexander V. Chernikov /* IPv6: /64 */ 114974b941f0SAlexander V. Chernikov uint64_t a6, *paddr; 115074b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 115174b941f0SAlexander V. Chernikov paddr = (uint64_t *)key; 115274b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 115374b941f0SAlexander V. Chernikov a6 = *paddr; 115474b941f0SAlexander V. Chernikov hash = hash_ip64((struct in6_addr *)key, hsize); 115574b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 115674b941f0SAlexander V. Chernikov paddr = (uint64_t *)&ent->a.a6; 115774b941f0SAlexander V. Chernikov if (a6 == *paddr) { 115874b941f0SAlexander V. Chernikov *val = ent->value; 115974b941f0SAlexander V. Chernikov return (1); 116074b941f0SAlexander V. Chernikov } 116174b941f0SAlexander V. Chernikov } 116274b941f0SAlexander V. Chernikov } 116374b941f0SAlexander V. Chernikov 116474b941f0SAlexander V. Chernikov return (0); 116574b941f0SAlexander V. Chernikov } 116674b941f0SAlexander V. Chernikov 116774b941f0SAlexander V. Chernikov static int 11680bce0c23SAlexander V. Chernikov chash_parse_opts(struct chash_cfg *cfg, char *data) 116974b941f0SAlexander V. Chernikov { 117074b941f0SAlexander V. Chernikov char *pdel, *pend, *s; 117174b941f0SAlexander V. Chernikov int mask4, mask6; 117274b941f0SAlexander V. Chernikov 11730bce0c23SAlexander V. Chernikov mask4 = cfg->mask4; 11740bce0c23SAlexander V. Chernikov mask6 = cfg->mask6; 117574b941f0SAlexander V. Chernikov 117674b941f0SAlexander V. Chernikov if (data == NULL) 117774b941f0SAlexander V. Chernikov return (0); 117874b941f0SAlexander V. Chernikov if ((pdel = strchr(data, ' ')) == NULL) 117974b941f0SAlexander V. Chernikov return (0); 118074b941f0SAlexander V. Chernikov while (*pdel == ' ') 118174b941f0SAlexander V. Chernikov pdel++; 118274b941f0SAlexander V. Chernikov if (strncmp(pdel, "masks=", 6) != 0) 118374b941f0SAlexander V. Chernikov return (EINVAL); 118474b941f0SAlexander V. Chernikov if ((s = strchr(pdel, ' ')) != NULL) 118574b941f0SAlexander V. Chernikov *s++ = '\0'; 118674b941f0SAlexander V. Chernikov 118774b941f0SAlexander V. Chernikov pdel += 6; 118874b941f0SAlexander V. Chernikov /* Need /XX[,/YY] */ 118974b941f0SAlexander V. Chernikov if (*pdel++ != '/') 119074b941f0SAlexander V. Chernikov return (EINVAL); 119174b941f0SAlexander V. Chernikov mask4 = strtol(pdel, &pend, 10); 119274b941f0SAlexander V. Chernikov if (*pend == ',') { 119374b941f0SAlexander V. Chernikov /* ,/YY */ 119474b941f0SAlexander V. Chernikov pdel = pend + 1; 119574b941f0SAlexander V. Chernikov if (*pdel++ != '/') 119674b941f0SAlexander V. Chernikov return (EINVAL); 119774b941f0SAlexander V. Chernikov mask6 = strtol(pdel, &pend, 10); 119874b941f0SAlexander V. Chernikov if (*pend != '\0') 119974b941f0SAlexander V. Chernikov return (EINVAL); 120074b941f0SAlexander V. Chernikov } else if (*pend != '\0') 120174b941f0SAlexander V. Chernikov return (EINVAL); 120274b941f0SAlexander V. Chernikov 120374b941f0SAlexander V. Chernikov if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128) 120474b941f0SAlexander V. Chernikov return (EINVAL); 120574b941f0SAlexander V. Chernikov 12060bce0c23SAlexander V. Chernikov cfg->mask4 = mask4; 12070bce0c23SAlexander V. Chernikov cfg->mask6 = mask6; 120874b941f0SAlexander V. Chernikov 120974b941f0SAlexander V. Chernikov return (0); 121074b941f0SAlexander V. Chernikov } 121174b941f0SAlexander V. Chernikov 121274b941f0SAlexander V. Chernikov static void 121374b941f0SAlexander V. Chernikov ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf, 121474b941f0SAlexander V. Chernikov size_t bufsize) 121574b941f0SAlexander V. Chernikov { 12160bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 121774b941f0SAlexander V. Chernikov 12180bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 121974b941f0SAlexander V. Chernikov 12200bce0c23SAlexander V. Chernikov if (cfg->mask4 != 32 || cfg->mask6 != 128) 1221c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s masks=/%d,/%d", "addr:hash", 12220bce0c23SAlexander V. Chernikov cfg->mask4, cfg->mask6); 122374b941f0SAlexander V. Chernikov else 1224c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s", "addr:hash"); 122574b941f0SAlexander V. Chernikov } 122674b941f0SAlexander V. Chernikov 1227914bffb6SAlexander V. Chernikov static int 1228914bffb6SAlexander V. Chernikov log2(uint32_t v) 1229914bffb6SAlexander V. Chernikov { 1230914bffb6SAlexander V. Chernikov uint32_t r; 1231914bffb6SAlexander V. Chernikov 1232914bffb6SAlexander V. Chernikov r = 0; 1233914bffb6SAlexander V. Chernikov while (v >>= 1) 1234914bffb6SAlexander V. Chernikov r++; 1235914bffb6SAlexander V. Chernikov 1236914bffb6SAlexander V. Chernikov return (r); 1237914bffb6SAlexander V. Chernikov } 123874b941f0SAlexander V. Chernikov 123974b941f0SAlexander V. Chernikov /* 124074b941f0SAlexander V. Chernikov * New table. 124174b941f0SAlexander V. Chernikov * We assume 'data' to be either NULL or the following format: 1242c21034b7SAlexander V. Chernikov * 'addr:hash [masks=/32[,/128]]' 124374b941f0SAlexander V. Chernikov */ 124474b941f0SAlexander V. Chernikov static int 124574b941f0SAlexander V. Chernikov ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 1246914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 124774b941f0SAlexander V. Chernikov { 124874b941f0SAlexander V. Chernikov int error, i; 1249914bffb6SAlexander V. Chernikov uint32_t hsize; 12500bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 125174b941f0SAlexander V. Chernikov 12520bce0c23SAlexander V. Chernikov cfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO); 125374b941f0SAlexander V. Chernikov 12540bce0c23SAlexander V. Chernikov cfg->mask4 = 32; 12550bce0c23SAlexander V. Chernikov cfg->mask6 = 128; 125674b941f0SAlexander V. Chernikov 12570bce0c23SAlexander V. Chernikov if ((error = chash_parse_opts(cfg, data)) != 0) { 12580bce0c23SAlexander V. Chernikov free(cfg, M_IPFW); 125974b941f0SAlexander V. Chernikov return (error); 126074b941f0SAlexander V. Chernikov } 126174b941f0SAlexander V. Chernikov 12620bce0c23SAlexander V. Chernikov cfg->size4 = 128; 12630bce0c23SAlexander V. Chernikov cfg->size6 = 128; 126474b941f0SAlexander V. Chernikov 12650bce0c23SAlexander V. Chernikov cfg->head4 = malloc(sizeof(struct chashbhead) * cfg->size4, M_IPFW, 126674b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO); 12670bce0c23SAlexander V. Chernikov cfg->head6 = malloc(sizeof(struct chashbhead) * cfg->size6, M_IPFW, 126874b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO); 12690bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 12700bce0c23SAlexander V. Chernikov SLIST_INIT(&cfg->head4[i]); 12710bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 12720bce0c23SAlexander V. Chernikov SLIST_INIT(&cfg->head6[i]); 127374b941f0SAlexander V. Chernikov 127474b941f0SAlexander V. Chernikov 12750bce0c23SAlexander V. Chernikov *ta_state = cfg; 12760bce0c23SAlexander V. Chernikov ti->state = cfg->head4; 12770bce0c23SAlexander V. Chernikov ti->xstate = cfg->head6; 127874b941f0SAlexander V. Chernikov 127974b941f0SAlexander V. Chernikov /* Store data depending on v6 mask length */ 12800bce0c23SAlexander V. Chernikov hsize = log2(cfg->size4) << 8 | log2(cfg->size6); 12810bce0c23SAlexander V. Chernikov if (cfg->mask6 == 64) { 12820bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | (128 - cfg->mask6) << 16| 1283914bffb6SAlexander V. Chernikov hsize; 128474b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_64; 12850bce0c23SAlexander V. Chernikov } else if ((cfg->mask6 % 8) == 0) { 12860bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | 12870bce0c23SAlexander V. Chernikov cfg->mask6 << 13 | hsize; 128874b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_aligned; 128974b941f0SAlexander V. Chernikov } else { 129074b941f0SAlexander V. Chernikov /* don't do that! */ 12910bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | 12920bce0c23SAlexander V. Chernikov cfg->mask6 << 16 | hsize; 129374b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_slow; 129474b941f0SAlexander V. Chernikov } 129574b941f0SAlexander V. Chernikov 129674b941f0SAlexander V. Chernikov return (0); 129774b941f0SAlexander V. Chernikov } 129874b941f0SAlexander V. Chernikov 129974b941f0SAlexander V. Chernikov static void 130074b941f0SAlexander V. Chernikov ta_destroy_chash(void *ta_state, struct table_info *ti) 130174b941f0SAlexander V. Chernikov { 13020bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 130374b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next; 130474b941f0SAlexander V. Chernikov int i; 130574b941f0SAlexander V. Chernikov 13060bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 130774b941f0SAlexander V. Chernikov 13080bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 13090bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next) 131074b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 131174b941f0SAlexander V. Chernikov 13120bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 13130bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next) 131474b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 131574b941f0SAlexander V. Chernikov 13160bce0c23SAlexander V. Chernikov free(cfg->head4, M_IPFW); 13170bce0c23SAlexander V. Chernikov free(cfg->head6, M_IPFW); 1318ce2817b5SAlexander V. Chernikov 13190bce0c23SAlexander V. Chernikov free(cfg, M_IPFW); 132074b941f0SAlexander V. Chernikov } 132174b941f0SAlexander V. Chernikov 13225f379342SAlexander V. Chernikov static void 13235f379342SAlexander V. Chernikov ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 13245f379342SAlexander V. Chernikov { 13255f379342SAlexander V. Chernikov struct chash_cfg *cfg; 13265f379342SAlexander V. Chernikov 13275f379342SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 13285f379342SAlexander V. Chernikov 13295f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM; 13305f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_HASH; 13315f379342SAlexander V. Chernikov tinfo->size4 = cfg->size4; 13325f379342SAlexander V. Chernikov tinfo->count4 = cfg->items4; 13335f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct chashentry); 13345f379342SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_HASH; 13355f379342SAlexander V. Chernikov tinfo->size6 = cfg->size6; 13365f379342SAlexander V. Chernikov tinfo->count6 = cfg->items6; 13375f379342SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct chashentry); 13385f379342SAlexander V. Chernikov } 13395f379342SAlexander V. Chernikov 134074b941f0SAlexander V. Chernikov static int 134174b941f0SAlexander V. Chernikov ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e, 134274b941f0SAlexander V. Chernikov ipfw_obj_tentry *tent) 134374b941f0SAlexander V. Chernikov { 13440bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 134574b941f0SAlexander V. Chernikov struct chashentry *ent; 134674b941f0SAlexander V. Chernikov 13470bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 134874b941f0SAlexander V. Chernikov ent = (struct chashentry *)e; 134974b941f0SAlexander V. Chernikov 135074b941f0SAlexander V. Chernikov if (ent->type == AF_INET) { 13510bce0c23SAlexander V. Chernikov tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - cfg->mask4)); 13520bce0c23SAlexander V. Chernikov tent->masklen = cfg->mask4; 135374b941f0SAlexander V. Chernikov tent->subtype = AF_INET; 13540cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value; 135574b941f0SAlexander V. Chernikov #ifdef INET6 135674b941f0SAlexander V. Chernikov } else { 135774b941f0SAlexander V. Chernikov memcpy(&tent->k, &ent->a.a6, sizeof(struct in6_addr)); 13580bce0c23SAlexander V. Chernikov tent->masklen = cfg->mask6; 135974b941f0SAlexander V. Chernikov tent->subtype = AF_INET6; 13600cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value; 136174b941f0SAlexander V. Chernikov #endif 136274b941f0SAlexander V. Chernikov } 136374b941f0SAlexander V. Chernikov 136474b941f0SAlexander V. Chernikov return (0); 136574b941f0SAlexander V. Chernikov } 136674b941f0SAlexander V. Chernikov 1367ce2817b5SAlexander V. Chernikov static uint32_t 1368ce2817b5SAlexander V. Chernikov hash_ent(struct chashentry *ent, int af, int mlen, uint32_t size) 1369ce2817b5SAlexander V. Chernikov { 1370ce2817b5SAlexander V. Chernikov uint32_t hash; 1371ce2817b5SAlexander V. Chernikov 1372ce2817b5SAlexander V. Chernikov if (af == AF_INET) { 1373ce2817b5SAlexander V. Chernikov hash = hash_ip(ent->a.a4, size); 1374ce2817b5SAlexander V. Chernikov } else { 1375ce2817b5SAlexander V. Chernikov if (mlen == 64) 1376ce2817b5SAlexander V. Chernikov hash = hash_ip64(&ent->a.a6, size); 1377ce2817b5SAlexander V. Chernikov else 1378ce2817b5SAlexander V. Chernikov hash = hash_ip6(&ent->a.a6, size); 1379ce2817b5SAlexander V. Chernikov } 1380ce2817b5SAlexander V. Chernikov 1381ce2817b5SAlexander V. Chernikov return (hash); 1382ce2817b5SAlexander V. Chernikov } 1383ce2817b5SAlexander V. Chernikov 1384ce2817b5SAlexander V. Chernikov static int 1385ce2817b5SAlexander V. Chernikov tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent) 1386ce2817b5SAlexander V. Chernikov { 1387ce2817b5SAlexander V. Chernikov struct in6_addr mask6; 1388ce2817b5SAlexander V. Chernikov int mlen; 1389ce2817b5SAlexander V. Chernikov 1390ce2817b5SAlexander V. Chernikov 1391ce2817b5SAlexander V. Chernikov mlen = tei->masklen; 1392ce2817b5SAlexander V. Chernikov 1393ce2817b5SAlexander V. Chernikov if (tei->subtype == AF_INET) { 1394ce2817b5SAlexander V. Chernikov #ifdef INET 1395ce2817b5SAlexander V. Chernikov if (mlen > 32) 1396ce2817b5SAlexander V. Chernikov return (EINVAL); 1397ce2817b5SAlexander V. Chernikov ent->type = AF_INET; 1398ce2817b5SAlexander V. Chernikov 1399ce2817b5SAlexander V. Chernikov /* Calculate masked address */ 1400ce2817b5SAlexander V. Chernikov ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen); 1401ce2817b5SAlexander V. Chernikov #endif 1402ce2817b5SAlexander V. Chernikov #ifdef INET6 1403ce2817b5SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 1404ce2817b5SAlexander V. Chernikov /* IPv6 case */ 1405ce2817b5SAlexander V. Chernikov if (mlen > 128) 1406ce2817b5SAlexander V. Chernikov return (EINVAL); 1407ce2817b5SAlexander V. Chernikov ent->type = AF_INET6; 1408ce2817b5SAlexander V. Chernikov 1409ce2817b5SAlexander V. Chernikov ipv6_writemask(&mask6, mlen); 1410ce2817b5SAlexander V. Chernikov memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr)); 1411ce2817b5SAlexander V. Chernikov APPLY_MASK(&ent->a.a6, &mask6); 1412ce2817b5SAlexander V. Chernikov #endif 1413ce2817b5SAlexander V. Chernikov } else { 1414ce2817b5SAlexander V. Chernikov /* Unknown CIDR type */ 1415ce2817b5SAlexander V. Chernikov return (EINVAL); 1416ce2817b5SAlexander V. Chernikov } 1417ce2817b5SAlexander V. Chernikov 1418ce2817b5SAlexander V. Chernikov return (0); 1419ce2817b5SAlexander V. Chernikov } 1420ce2817b5SAlexander V. Chernikov 142174b941f0SAlexander V. Chernikov static int 1422914bffb6SAlexander V. Chernikov ta_find_chash_tentry(void *ta_state, struct table_info *ti, 1423914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 142474b941f0SAlexander V. Chernikov { 14250bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 1426ce2817b5SAlexander V. Chernikov struct chashbhead *head; 1427ce2817b5SAlexander V. Chernikov struct chashentry ent, *tmp; 1428ce2817b5SAlexander V. Chernikov struct tentry_info tei; 1429ce2817b5SAlexander V. Chernikov int error; 1430ce2817b5SAlexander V. Chernikov uint32_t hash; 143174b941f0SAlexander V. Chernikov 14320bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1433ce2817b5SAlexander V. Chernikov 1434ce2817b5SAlexander V. Chernikov memset(&ent, 0, sizeof(ent)); 1435ce2817b5SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 1436ce2817b5SAlexander V. Chernikov 1437914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) { 1438914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr; 14390bce0c23SAlexander V. Chernikov tei.masklen = cfg->mask4; 1440ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET; 144174b941f0SAlexander V. Chernikov 1442ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0) 1443ce2817b5SAlexander V. Chernikov return (error); 1444ce2817b5SAlexander V. Chernikov 14450bce0c23SAlexander V. Chernikov head = cfg->head4; 14460bce0c23SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET, cfg->mask4, cfg->size4); 1447ce2817b5SAlexander V. Chernikov /* Check for existence */ 1448ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1449ce2817b5SAlexander V. Chernikov if (tmp->a.a4 != ent.a.a4) 1450ce2817b5SAlexander V. Chernikov continue; 1451ce2817b5SAlexander V. Chernikov 1452ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent); 145374b941f0SAlexander V. Chernikov return (0); 145474b941f0SAlexander V. Chernikov } 1455ce2817b5SAlexander V. Chernikov } else { 1456914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr6; 14570bce0c23SAlexander V. Chernikov tei.masklen = cfg->mask6; 1458ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET6; 1459ce2817b5SAlexander V. Chernikov 1460ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0) 1461ce2817b5SAlexander V. Chernikov return (error); 1462ce2817b5SAlexander V. Chernikov 14630bce0c23SAlexander V. Chernikov head = cfg->head6; 14640bce0c23SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET6, cfg->mask6, cfg->size6); 1465ce2817b5SAlexander V. Chernikov /* Check for existence */ 1466ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1467ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0) 1468ce2817b5SAlexander V. Chernikov continue; 1469ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent); 1470ce2817b5SAlexander V. Chernikov return (0); 1471ce2817b5SAlexander V. Chernikov } 1472ce2817b5SAlexander V. Chernikov } 1473ce2817b5SAlexander V. Chernikov 147474b941f0SAlexander V. Chernikov return (ENOENT); 147574b941f0SAlexander V. Chernikov } 147674b941f0SAlexander V. Chernikov 147774b941f0SAlexander V. Chernikov static void 147874b941f0SAlexander V. Chernikov ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f, 147974b941f0SAlexander V. Chernikov void *arg) 148074b941f0SAlexander V. Chernikov { 14810bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 148274b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next; 148374b941f0SAlexander V. Chernikov int i; 148474b941f0SAlexander V. Chernikov 14850bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 148674b941f0SAlexander V. Chernikov 14870bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 14880bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next) 148974b941f0SAlexander V. Chernikov f(ent, arg); 149074b941f0SAlexander V. Chernikov 14910bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 14920bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next) 149374b941f0SAlexander V. Chernikov f(ent, arg); 149474b941f0SAlexander V. Chernikov } 149574b941f0SAlexander V. Chernikov 149674b941f0SAlexander V. Chernikov static int 149774b941f0SAlexander V. Chernikov ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 149874b941f0SAlexander V. Chernikov void *ta_buf) 149974b941f0SAlexander V. Chernikov { 150074b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 150174b941f0SAlexander V. Chernikov struct chashentry *ent; 1502ce2817b5SAlexander V. Chernikov int error; 150374b941f0SAlexander V. Chernikov 150474b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 150574b941f0SAlexander V. Chernikov 150674b941f0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 150774b941f0SAlexander V. Chernikov 1508ce2817b5SAlexander V. Chernikov error = tei_to_chash_ent(tei, ent); 1509ce2817b5SAlexander V. Chernikov if (error != 0) { 1510ce2817b5SAlexander V. Chernikov free(ent, M_IPFW_TBL); 1511ce2817b5SAlexander V. Chernikov return (error); 151274b941f0SAlexander V. Chernikov } 1513ce2817b5SAlexander V. Chernikov tb->ent_ptr = ent; 151474b941f0SAlexander V. Chernikov 151574b941f0SAlexander V. Chernikov return (0); 151674b941f0SAlexander V. Chernikov } 151774b941f0SAlexander V. Chernikov 151874b941f0SAlexander V. Chernikov static int 151974b941f0SAlexander V. Chernikov ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1520b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 152174b941f0SAlexander V. Chernikov { 15220bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 152374b941f0SAlexander V. Chernikov struct chashbhead *head; 152474b941f0SAlexander V. Chernikov struct chashentry *ent, *tmp; 152574b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 152674b941f0SAlexander V. Chernikov int exists; 1527648e8380SAlexander V. Chernikov uint32_t hash, value; 152874b941f0SAlexander V. Chernikov 15290bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 153074b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 153174b941f0SAlexander V. Chernikov ent = (struct chashentry *)tb->ent_ptr; 153274b941f0SAlexander V. Chernikov hash = 0; 153374b941f0SAlexander V. Chernikov exists = 0; 153474b941f0SAlexander V. Chernikov 153513263632SAlexander V. Chernikov /* Read current value from @tei */ 153613263632SAlexander V. Chernikov ent->value = tei->value; 153713263632SAlexander V. Chernikov 153813263632SAlexander V. Chernikov /* Read cuurrent value */ 153974b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) { 15400bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask4) 154174b941f0SAlexander V. Chernikov return (EINVAL); 15420bce0c23SAlexander V. Chernikov head = cfg->head4; 15430bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4); 1544ce2817b5SAlexander V. Chernikov 154574b941f0SAlexander V. Chernikov /* Check for existence */ 154674b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 154774b941f0SAlexander V. Chernikov if (tmp->a.a4 == ent->a.a4) { 154874b941f0SAlexander V. Chernikov exists = 1; 154974b941f0SAlexander V. Chernikov break; 155074b941f0SAlexander V. Chernikov } 155174b941f0SAlexander V. Chernikov } 155274b941f0SAlexander V. Chernikov } else { 15530bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask6) 155474b941f0SAlexander V. Chernikov return (EINVAL); 15550bce0c23SAlexander V. Chernikov head = cfg->head6; 15560bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6); 155774b941f0SAlexander V. Chernikov /* Check for existence */ 155874b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1559ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) == 0) { 156074b941f0SAlexander V. Chernikov exists = 1; 156174b941f0SAlexander V. Chernikov break; 156274b941f0SAlexander V. Chernikov } 156374b941f0SAlexander V. Chernikov } 156474b941f0SAlexander V. Chernikov } 156574b941f0SAlexander V. Chernikov 156674b941f0SAlexander V. Chernikov if (exists == 1) { 156774b941f0SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 156874b941f0SAlexander V. Chernikov return (EEXIST); 156974b941f0SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 1570648e8380SAlexander V. Chernikov value = tmp->value; 157174b941f0SAlexander V. Chernikov tmp->value = tei->value; 1572648e8380SAlexander V. Chernikov tei->value = value; 157374b941f0SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 157474b941f0SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 157574b941f0SAlexander V. Chernikov *pnum = 0; 157674b941f0SAlexander V. Chernikov } else { 15774c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 15784c0c07a5SAlexander V. Chernikov return (EFBIG); 157974b941f0SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next); 158074b941f0SAlexander V. Chernikov tb->ent_ptr = NULL; 158174b941f0SAlexander V. Chernikov *pnum = 1; 1582ce2817b5SAlexander V. Chernikov 1583b6ee846eSAlexander V. Chernikov /* Update counters */ 1584b6ee846eSAlexander V. Chernikov if (tei->subtype == AF_INET) 15850bce0c23SAlexander V. Chernikov cfg->items4++; 1586b6ee846eSAlexander V. Chernikov else 15870bce0c23SAlexander V. Chernikov cfg->items6++; 158874b941f0SAlexander V. Chernikov } 158974b941f0SAlexander V. Chernikov 159074b941f0SAlexander V. Chernikov return (0); 159174b941f0SAlexander V. Chernikov } 159274b941f0SAlexander V. Chernikov 159374b941f0SAlexander V. Chernikov static int 159474b941f0SAlexander V. Chernikov ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 159574b941f0SAlexander V. Chernikov void *ta_buf) 159674b941f0SAlexander V. Chernikov { 159774b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 159874b941f0SAlexander V. Chernikov 159974b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 160074b941f0SAlexander V. Chernikov 1601ce2817b5SAlexander V. Chernikov return (tei_to_chash_ent(tei, &tb->ent)); 160274b941f0SAlexander V. Chernikov } 160374b941f0SAlexander V. Chernikov 160474b941f0SAlexander V. Chernikov static int 160574b941f0SAlexander V. Chernikov ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1606b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 160774b941f0SAlexander V. Chernikov { 16080bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 160974b941f0SAlexander V. Chernikov struct chashbhead *head; 16100bce0c23SAlexander V. Chernikov struct chashentry *tmp, *tmp_next, *ent; 161174b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 161274b941f0SAlexander V. Chernikov uint32_t hash; 161374b941f0SAlexander V. Chernikov 16140bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 161574b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 16160bce0c23SAlexander V. Chernikov ent = &tb->ent; 161774b941f0SAlexander V. Chernikov 161874b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) { 16190bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask4) 162074b941f0SAlexander V. Chernikov return (EINVAL); 16210bce0c23SAlexander V. Chernikov head = cfg->head4; 16220bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4); 162374b941f0SAlexander V. Chernikov 16240bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) { 16250bce0c23SAlexander V. Chernikov if (tmp->a.a4 != ent->a.a4) 1626648e8380SAlexander V. Chernikov continue; 1627648e8380SAlexander V. Chernikov 16280bce0c23SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, chashentry, next); 16290bce0c23SAlexander V. Chernikov cfg->items4--; 16300bce0c23SAlexander V. Chernikov tb->ent_ptr = tmp; 16310bce0c23SAlexander V. Chernikov tei->value = tmp->value; 1632648e8380SAlexander V. Chernikov *pnum = 1; 163374b941f0SAlexander V. Chernikov return (0); 163474b941f0SAlexander V. Chernikov } 163574b941f0SAlexander V. Chernikov } else { 16360bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask6) 163774b941f0SAlexander V. Chernikov return (EINVAL); 16380bce0c23SAlexander V. Chernikov head = cfg->head6; 16390bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6); 16400bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) { 16410bce0c23SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) != 0) 1642648e8380SAlexander V. Chernikov continue; 1643648e8380SAlexander V. Chernikov 16440bce0c23SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, chashentry, next); 16450bce0c23SAlexander V. Chernikov cfg->items6--; 16460bce0c23SAlexander V. Chernikov tb->ent_ptr = tmp; 16470bce0c23SAlexander V. Chernikov tei->value = tmp->value; 164874b941f0SAlexander V. Chernikov *pnum = 1; 164974b941f0SAlexander V. Chernikov return (0); 165074b941f0SAlexander V. Chernikov } 165174b941f0SAlexander V. Chernikov } 165274b941f0SAlexander V. Chernikov 165374b941f0SAlexander V. Chernikov return (ENOENT); 165474b941f0SAlexander V. Chernikov } 165574b941f0SAlexander V. Chernikov 165674b941f0SAlexander V. Chernikov static void 165774b941f0SAlexander V. Chernikov ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 165874b941f0SAlexander V. Chernikov void *ta_buf) 165974b941f0SAlexander V. Chernikov { 166074b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 166174b941f0SAlexander V. Chernikov 166274b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 166374b941f0SAlexander V. Chernikov 166474b941f0SAlexander V. Chernikov if (tb->ent_ptr != NULL) 166574b941f0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 166674b941f0SAlexander V. Chernikov } 166774b941f0SAlexander V. Chernikov 1668ce2817b5SAlexander V. Chernikov /* 1669ce2817b5SAlexander V. Chernikov * Hash growing callbacks. 1670ce2817b5SAlexander V. Chernikov */ 1671ce2817b5SAlexander V. Chernikov 1672b6ee846eSAlexander V. Chernikov static int 1673301290bcSAlexander V. Chernikov ta_need_modify_chash(void *ta_state, struct table_info *ti, uint32_t count, 1674b6ee846eSAlexander V. Chernikov uint64_t *pflags) 1675b6ee846eSAlexander V. Chernikov { 1676b6ee846eSAlexander V. Chernikov struct chash_cfg *cfg; 1677b6ee846eSAlexander V. Chernikov uint64_t data; 1678b6ee846eSAlexander V. Chernikov 1679b6ee846eSAlexander V. Chernikov /* 1680b6ee846eSAlexander V. Chernikov * Since we don't know exact number of IPv4/IPv6 records in @count, 1681b6ee846eSAlexander V. Chernikov * ignore non-zero @count value at all. Check current hash sizes 1682b6ee846eSAlexander V. Chernikov * and return appropriate data. 1683b6ee846eSAlexander V. Chernikov */ 1684b6ee846eSAlexander V. Chernikov 1685b6ee846eSAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1686b6ee846eSAlexander V. Chernikov 1687b6ee846eSAlexander V. Chernikov data = 0; 1688b6ee846eSAlexander V. Chernikov if (cfg->items4 > cfg->size4 && cfg->size4 < 65536) 1689b6ee846eSAlexander V. Chernikov data |= (cfg->size4 * 2) << 16; 1690b6ee846eSAlexander V. Chernikov if (cfg->items6 > cfg->size6 && cfg->size6 < 65536) 1691b6ee846eSAlexander V. Chernikov data |= cfg->size6 * 2; 1692b6ee846eSAlexander V. Chernikov 1693b6ee846eSAlexander V. Chernikov if (data != 0) { 1694b6ee846eSAlexander V. Chernikov *pflags = data; 1695301290bcSAlexander V. Chernikov return (1); 1696b6ee846eSAlexander V. Chernikov } 1697b6ee846eSAlexander V. Chernikov 1698301290bcSAlexander V. Chernikov return (0); 1699b6ee846eSAlexander V. Chernikov } 1700b6ee846eSAlexander V. Chernikov 1701ce2817b5SAlexander V. Chernikov /* 1702ce2817b5SAlexander V. Chernikov * Allocate new, larger chash. 1703ce2817b5SAlexander V. Chernikov */ 1704ce2817b5SAlexander V. Chernikov static int 1705ce2817b5SAlexander V. Chernikov ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags) 1706ce2817b5SAlexander V. Chernikov { 1707ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1708ce2817b5SAlexander V. Chernikov struct chashbhead *head; 1709ce2817b5SAlexander V. Chernikov int i; 1710ce2817b5SAlexander V. Chernikov 1711ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1712ce2817b5SAlexander V. Chernikov 1713ce2817b5SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 1714b6ee846eSAlexander V. Chernikov mi->size = (*pflags >> 16) & 0xFFFF; 1715b6ee846eSAlexander V. Chernikov mi->size6 = *pflags & 0xFFFF; 1716b6ee846eSAlexander V. Chernikov if (mi->size > 0) { 1717b6ee846eSAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size, 1718b6ee846eSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1719ce2817b5SAlexander V. Chernikov for (i = 0; i < mi->size; i++) 1720ce2817b5SAlexander V. Chernikov SLIST_INIT(&head[i]); 1721ce2817b5SAlexander V. Chernikov mi->main_ptr = head; 1722b6ee846eSAlexander V. Chernikov } 1723b6ee846eSAlexander V. Chernikov 1724b6ee846eSAlexander V. Chernikov if (mi->size6 > 0) { 1725b6ee846eSAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size6, 1726b6ee846eSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1727b6ee846eSAlexander V. Chernikov for (i = 0; i < mi->size6; i++) 1728b6ee846eSAlexander V. Chernikov SLIST_INIT(&head[i]); 1729b6ee846eSAlexander V. Chernikov mi->main_ptr6 = head; 1730b6ee846eSAlexander V. Chernikov } 1731ce2817b5SAlexander V. Chernikov 1732ce2817b5SAlexander V. Chernikov return (0); 1733ce2817b5SAlexander V. Chernikov } 1734ce2817b5SAlexander V. Chernikov 1735ce2817b5SAlexander V. Chernikov /* 1736ce2817b5SAlexander V. Chernikov * Copy data from old runtime array to new one. 1737ce2817b5SAlexander V. Chernikov */ 1738ce2817b5SAlexander V. Chernikov static int 1739ce2817b5SAlexander V. Chernikov ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1740ce2817b5SAlexander V. Chernikov uint64_t *pflags) 1741ce2817b5SAlexander V. Chernikov { 1742ce2817b5SAlexander V. Chernikov 1743ce2817b5SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */ 1744ce2817b5SAlexander V. Chernikov return (0); 1745ce2817b5SAlexander V. Chernikov } 1746ce2817b5SAlexander V. Chernikov 1747ce2817b5SAlexander V. Chernikov /* 1748ce2817b5SAlexander V. Chernikov * Switch old & new arrays. 1749ce2817b5SAlexander V. Chernikov */ 1750301290bcSAlexander V. Chernikov static void 1751ce2817b5SAlexander V. Chernikov ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1752ce2817b5SAlexander V. Chernikov uint64_t pflags) 1753ce2817b5SAlexander V. Chernikov { 1754ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1755b6ee846eSAlexander V. Chernikov struct chash_cfg *cfg; 1756ce2817b5SAlexander V. Chernikov struct chashbhead *old_head, *new_head; 1757ce2817b5SAlexander V. Chernikov struct chashentry *ent, *ent_next; 1758ce2817b5SAlexander V. Chernikov int af, i, mlen; 1759ce2817b5SAlexander V. Chernikov uint32_t nhash; 1760b6ee846eSAlexander V. Chernikov size_t old_size, new_size; 1761ce2817b5SAlexander V. Chernikov 1762ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1763b6ee846eSAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1764ce2817b5SAlexander V. Chernikov 1765ce2817b5SAlexander V. Chernikov /* Check which hash we need to grow and do we still need that */ 1766b6ee846eSAlexander V. Chernikov if (mi->size > 0 && cfg->size4 < mi->size) { 1767ce2817b5SAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr; 1768b6ee846eSAlexander V. Chernikov new_size = mi->size; 1769b6ee846eSAlexander V. Chernikov old_size = cfg->size4; 1770b6ee846eSAlexander V. Chernikov old_head = ti->state; 1771b6ee846eSAlexander V. Chernikov mlen = cfg->mask4; 1772b6ee846eSAlexander V. Chernikov af = AF_INET; 1773b6ee846eSAlexander V. Chernikov 1774ce2817b5SAlexander V. Chernikov for (i = 0; i < old_size; i++) { 1775ce2817b5SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 1776b6ee846eSAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, new_size); 1777ce2817b5SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 1778ce2817b5SAlexander V. Chernikov } 1779ce2817b5SAlexander V. Chernikov } 1780ce2817b5SAlexander V. Chernikov 1781ce2817b5SAlexander V. Chernikov ti->state = new_head; 1782b6ee846eSAlexander V. Chernikov cfg->head4 = new_head; 1783b6ee846eSAlexander V. Chernikov cfg->size4 = mi->size; 1784b6ee846eSAlexander V. Chernikov mi->main_ptr = old_head; 1785ce2817b5SAlexander V. Chernikov } 1786ce2817b5SAlexander V. Chernikov 1787b6ee846eSAlexander V. Chernikov if (mi->size6 > 0 && cfg->size6 < mi->size6) { 1788b6ee846eSAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr6; 1789b6ee846eSAlexander V. Chernikov new_size = mi->size6; 1790b6ee846eSAlexander V. Chernikov old_size = cfg->size6; 1791b6ee846eSAlexander V. Chernikov old_head = ti->xstate; 1792b6ee846eSAlexander V. Chernikov mlen = cfg->mask6; 1793b6ee846eSAlexander V. Chernikov af = AF_INET6; 1794914bffb6SAlexander V. Chernikov 1795b6ee846eSAlexander V. Chernikov for (i = 0; i < old_size; i++) { 1796b6ee846eSAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 1797b6ee846eSAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, new_size); 1798b6ee846eSAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 1799b6ee846eSAlexander V. Chernikov } 1800b6ee846eSAlexander V. Chernikov } 1801b6ee846eSAlexander V. Chernikov 1802b6ee846eSAlexander V. Chernikov ti->xstate = new_head; 1803b6ee846eSAlexander V. Chernikov cfg->head6 = new_head; 1804b6ee846eSAlexander V. Chernikov cfg->size6 = mi->size6; 1805b6ee846eSAlexander V. Chernikov mi->main_ptr6 = old_head; 1806b6ee846eSAlexander V. Chernikov } 1807b6ee846eSAlexander V. Chernikov 1808b6ee846eSAlexander V. Chernikov /* Update lower 32 bits with new values */ 1809b6ee846eSAlexander V. Chernikov ti->data &= 0xFFFFFFFF00000000; 1810b6ee846eSAlexander V. Chernikov ti->data |= log2(cfg->size4) << 8 | log2(cfg->size6); 1811ce2817b5SAlexander V. Chernikov } 1812ce2817b5SAlexander V. Chernikov 1813ce2817b5SAlexander V. Chernikov /* 1814ce2817b5SAlexander V. Chernikov * Free unneded array. 1815ce2817b5SAlexander V. Chernikov */ 1816ce2817b5SAlexander V. Chernikov static void 1817ce2817b5SAlexander V. Chernikov ta_flush_mod_chash(void *ta_buf) 1818ce2817b5SAlexander V. Chernikov { 1819ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1820ce2817b5SAlexander V. Chernikov 1821ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1822ce2817b5SAlexander V. Chernikov if (mi->main_ptr != NULL) 1823ce2817b5SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 1824b6ee846eSAlexander V. Chernikov if (mi->main_ptr6 != NULL) 1825b6ee846eSAlexander V. Chernikov free(mi->main_ptr6, M_IPFW); 1826ce2817b5SAlexander V. Chernikov } 1827ce2817b5SAlexander V. Chernikov 1828c21034b7SAlexander V. Chernikov struct table_algo addr_hash = { 1829c21034b7SAlexander V. Chernikov .name = "addr:hash", 1830c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR, 183157a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_chash), 183274b941f0SAlexander V. Chernikov .init = ta_init_chash, 183374b941f0SAlexander V. Chernikov .destroy = ta_destroy_chash, 183474b941f0SAlexander V. Chernikov .prepare_add = ta_prepare_add_chash, 183574b941f0SAlexander V. Chernikov .prepare_del = ta_prepare_del_chash, 183674b941f0SAlexander V. Chernikov .add = ta_add_chash, 183774b941f0SAlexander V. Chernikov .del = ta_del_chash, 183874b941f0SAlexander V. Chernikov .flush_entry = ta_flush_chash_entry, 183974b941f0SAlexander V. Chernikov .foreach = ta_foreach_chash, 184074b941f0SAlexander V. Chernikov .dump_tentry = ta_dump_chash_tentry, 184174b941f0SAlexander V. Chernikov .find_tentry = ta_find_chash_tentry, 184274b941f0SAlexander V. Chernikov .print_config = ta_print_chash_config, 18435f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_chash_tinfo, 1844301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_chash, 1845ce2817b5SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_chash, 1846ce2817b5SAlexander V. Chernikov .fill_mod = ta_fill_mod_chash, 1847ce2817b5SAlexander V. Chernikov .modify = ta_modify_chash, 1848ce2817b5SAlexander V. Chernikov .flush_mod = ta_flush_mod_chash, 184974b941f0SAlexander V. Chernikov }; 185074b941f0SAlexander V. Chernikov 185174b941f0SAlexander V. Chernikov 185274b941f0SAlexander V. Chernikov /* 185368394ec8SAlexander V. Chernikov * Iface table cmds. 185468394ec8SAlexander V. Chernikov * 185568394ec8SAlexander V. Chernikov * Implementation: 185668394ec8SAlexander V. Chernikov * 185768394ec8SAlexander V. Chernikov * Runtime part: 185868394ec8SAlexander V. Chernikov * - sorted array of "struct ifidx" pointed by ti->state. 1859b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to IFIDX_CHUNK. Only existing 186068394ec8SAlexander V. Chernikov * interfaces are stored in array, however its allocated size is 186168394ec8SAlexander V. Chernikov * sufficient to hold all table records if needed. 186268394ec8SAlexander V. Chernikov * - current array size is stored in ti->data 186368394ec8SAlexander V. Chernikov * 186468394ec8SAlexander V. Chernikov * Table data: 186568394ec8SAlexander V. Chernikov * - "struct iftable_cfg" is allocated to store table state (ta_state). 186668394ec8SAlexander V. Chernikov * - All table records are stored inside namedobj instance. 18679f7d47b0SAlexander V. Chernikov * 18689f7d47b0SAlexander V. Chernikov */ 18699f7d47b0SAlexander V. Chernikov 187068394ec8SAlexander V. Chernikov struct ifidx { 187168394ec8SAlexander V. Chernikov uint16_t kidx; 187268394ec8SAlexander V. Chernikov uint16_t spare; 187368394ec8SAlexander V. Chernikov uint32_t value; 187468394ec8SAlexander V. Chernikov }; 18750cba2b28SAlexander V. Chernikov #define DEFAULT_IFIDX_SIZE 64 187668394ec8SAlexander V. Chernikov 187768394ec8SAlexander V. Chernikov struct iftable_cfg; 187868394ec8SAlexander V. Chernikov 187968394ec8SAlexander V. Chernikov struct ifentry { 188068394ec8SAlexander V. Chernikov struct named_object no; 188168394ec8SAlexander V. Chernikov struct ipfw_ifc ic; 188268394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 188368394ec8SAlexander V. Chernikov uint32_t value; 188468394ec8SAlexander V. Chernikov int linked; 188568394ec8SAlexander V. Chernikov }; 188668394ec8SAlexander V. Chernikov 188768394ec8SAlexander V. Chernikov struct iftable_cfg { 188868394ec8SAlexander V. Chernikov struct namedobj_instance *ii; 188968394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 189068394ec8SAlexander V. Chernikov struct table_info *ti; 189168394ec8SAlexander V. Chernikov void *main_ptr; 189268394ec8SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 189368394ec8SAlexander V. Chernikov size_t count; /* Number of all items */ 189468394ec8SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 189568394ec8SAlexander V. Chernikov }; 189668394ec8SAlexander V. Chernikov 18970bce0c23SAlexander V. Chernikov struct ta_buf_ifidx 18980bce0c23SAlexander V. Chernikov { 18990bce0c23SAlexander V. Chernikov struct ifentry *ife; 19000bce0c23SAlexander V. Chernikov uint32_t value; 19010bce0c23SAlexander V. Chernikov }; 190268394ec8SAlexander V. Chernikov 190368394ec8SAlexander V. Chernikov int compare_ifidx(const void *k, const void *v); 190468394ec8SAlexander V. Chernikov static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex); 1905*9fe15d06SAlexander V. Chernikov static struct ifidx * ifidx_find(struct table_info *ti, void *key); 1906*9fe15d06SAlexander V. Chernikov static int ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen, 1907*9fe15d06SAlexander V. Chernikov uint32_t *val); 1908*9fe15d06SAlexander V. Chernikov static int ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, 1909*9fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 1910*9fe15d06SAlexander V. Chernikov static void ta_change_ti_ifidx(void *ta_state, struct table_info *ti); 1911*9fe15d06SAlexander V. Chernikov static void destroy_ifidx_locked(struct namedobj_instance *ii, 1912*9fe15d06SAlexander V. Chernikov struct named_object *no, void *arg); 1913*9fe15d06SAlexander V. Chernikov static void ta_destroy_ifidx(void *ta_state, struct table_info *ti); 1914*9fe15d06SAlexander V. Chernikov static void ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, 1915*9fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 1916*9fe15d06SAlexander V. Chernikov static int ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 1917*9fe15d06SAlexander V. Chernikov void *ta_buf); 1918*9fe15d06SAlexander V. Chernikov static int ta_add_ifidx(void *ta_state, struct table_info *ti, 1919*9fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 1920*9fe15d06SAlexander V. Chernikov static int ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 1921*9fe15d06SAlexander V. Chernikov void *ta_buf); 1922*9fe15d06SAlexander V. Chernikov static int ta_del_ifidx(void *ta_state, struct table_info *ti, 1923*9fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 1924*9fe15d06SAlexander V. Chernikov static void ta_flush_ifidx_entry(struct ip_fw_chain *ch, 1925*9fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf); 1926*9fe15d06SAlexander V. Chernikov static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex); 1927*9fe15d06SAlexander V. Chernikov static int ta_need_modify_ifidx(void *ta_state, struct table_info *ti, 1928*9fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 1929*9fe15d06SAlexander V. Chernikov static int ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags); 1930*9fe15d06SAlexander V. Chernikov static int ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, 1931*9fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t *pflags); 1932*9fe15d06SAlexander V. Chernikov static void ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 1933*9fe15d06SAlexander V. Chernikov uint64_t pflags); 1934*9fe15d06SAlexander V. Chernikov static void ta_flush_mod_ifidx(void *ta_buf); 1935*9fe15d06SAlexander V. Chernikov static int ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e, 1936*9fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 1937*9fe15d06SAlexander V. Chernikov static int ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, 1938*9fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 1939*9fe15d06SAlexander V. Chernikov static void foreach_ifidx(struct namedobj_instance *ii, struct named_object *no, 1940*9fe15d06SAlexander V. Chernikov void *arg); 1941*9fe15d06SAlexander V. Chernikov static void ta_foreach_ifidx(void *ta_state, struct table_info *ti, 1942*9fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 194368394ec8SAlexander V. Chernikov 194468394ec8SAlexander V. Chernikov int 194568394ec8SAlexander V. Chernikov compare_ifidx(const void *k, const void *v) 194668394ec8SAlexander V. Chernikov { 1947d4e1b515SAlexander V. Chernikov const struct ifidx *ifidx; 194868394ec8SAlexander V. Chernikov uint16_t key; 194968394ec8SAlexander V. Chernikov 1950d4e1b515SAlexander V. Chernikov key = *((const uint16_t *)k); 1951d4e1b515SAlexander V. Chernikov ifidx = (const struct ifidx *)v; 195268394ec8SAlexander V. Chernikov 195368394ec8SAlexander V. Chernikov if (key < ifidx->kidx) 195468394ec8SAlexander V. Chernikov return (-1); 195568394ec8SAlexander V. Chernikov else if (key > ifidx->kidx) 195668394ec8SAlexander V. Chernikov return (1); 195768394ec8SAlexander V. Chernikov 195868394ec8SAlexander V. Chernikov return (0); 195968394ec8SAlexander V. Chernikov } 196068394ec8SAlexander V. Chernikov 196168394ec8SAlexander V. Chernikov /* 196268394ec8SAlexander V. Chernikov * Adds item @item with key @key into ascending-sorted array @base. 196368394ec8SAlexander V. Chernikov * Assumes @base has enough additional storage. 196468394ec8SAlexander V. Chernikov * 196568394ec8SAlexander V. Chernikov * Returns 1 on success, 0 on duplicate key. 196668394ec8SAlexander V. Chernikov */ 19679f7d47b0SAlexander V. Chernikov static int 196868394ec8SAlexander V. Chernikov badd(const void *key, void *item, void *base, size_t nmemb, 196968394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *)) 197068394ec8SAlexander V. Chernikov { 197168394ec8SAlexander V. Chernikov int min, max, mid, shift, res; 197268394ec8SAlexander V. Chernikov caddr_t paddr; 197368394ec8SAlexander V. Chernikov 197468394ec8SAlexander V. Chernikov if (nmemb == 0) { 197568394ec8SAlexander V. Chernikov memcpy(base, item, size); 197668394ec8SAlexander V. Chernikov return (1); 197768394ec8SAlexander V. Chernikov } 197868394ec8SAlexander V. Chernikov 197968394ec8SAlexander V. Chernikov /* Binary search */ 198068394ec8SAlexander V. Chernikov min = 0; 198168394ec8SAlexander V. Chernikov max = nmemb - 1; 198268394ec8SAlexander V. Chernikov mid = 0; 198368394ec8SAlexander V. Chernikov while (min <= max) { 198468394ec8SAlexander V. Chernikov mid = (min + max) / 2; 198568394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 198668394ec8SAlexander V. Chernikov if (res == 0) 198768394ec8SAlexander V. Chernikov return (0); 198868394ec8SAlexander V. Chernikov 198968394ec8SAlexander V. Chernikov if (res > 0) 199068394ec8SAlexander V. Chernikov min = mid + 1; 199168394ec8SAlexander V. Chernikov else 199268394ec8SAlexander V. Chernikov max = mid - 1; 199368394ec8SAlexander V. Chernikov } 199468394ec8SAlexander V. Chernikov 199568394ec8SAlexander V. Chernikov /* Item not found. */ 199668394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 199768394ec8SAlexander V. Chernikov if (res > 0) 199868394ec8SAlexander V. Chernikov shift = mid + 1; 199968394ec8SAlexander V. Chernikov else 200068394ec8SAlexander V. Chernikov shift = mid; 200168394ec8SAlexander V. Chernikov 200268394ec8SAlexander V. Chernikov paddr = (caddr_t)base + shift * size; 200368394ec8SAlexander V. Chernikov if (nmemb > shift) 200468394ec8SAlexander V. Chernikov memmove(paddr + size, paddr, (nmemb - shift) * size); 200568394ec8SAlexander V. Chernikov 200668394ec8SAlexander V. Chernikov memcpy(paddr, item, size); 200768394ec8SAlexander V. Chernikov 200868394ec8SAlexander V. Chernikov return (1); 200968394ec8SAlexander V. Chernikov } 201068394ec8SAlexander V. Chernikov 201168394ec8SAlexander V. Chernikov /* 201268394ec8SAlexander V. Chernikov * Deletes item with key @key from ascending-sorted array @base. 201368394ec8SAlexander V. Chernikov * 201468394ec8SAlexander V. Chernikov * Returns 1 on success, 0 for non-existent key. 201568394ec8SAlexander V. Chernikov */ 201668394ec8SAlexander V. Chernikov static int 201768394ec8SAlexander V. Chernikov bdel(const void *key, void *base, size_t nmemb, size_t size, 201868394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *)) 201968394ec8SAlexander V. Chernikov { 202068394ec8SAlexander V. Chernikov caddr_t item; 202168394ec8SAlexander V. Chernikov size_t sz; 202268394ec8SAlexander V. Chernikov 202368394ec8SAlexander V. Chernikov item = (caddr_t)bsearch(key, base, nmemb, size, compar); 202468394ec8SAlexander V. Chernikov 202568394ec8SAlexander V. Chernikov if (item == NULL) 202668394ec8SAlexander V. Chernikov return (0); 202768394ec8SAlexander V. Chernikov 202868394ec8SAlexander V. Chernikov sz = (caddr_t)base + nmemb * size - item; 202968394ec8SAlexander V. Chernikov 203068394ec8SAlexander V. Chernikov if (sz > 0) 203168394ec8SAlexander V. Chernikov memmove(item, item + size, sz); 203268394ec8SAlexander V. Chernikov 203368394ec8SAlexander V. Chernikov return (1); 203468394ec8SAlexander V. Chernikov } 203568394ec8SAlexander V. Chernikov 203668394ec8SAlexander V. Chernikov static struct ifidx * 203768394ec8SAlexander V. Chernikov ifidx_find(struct table_info *ti, void *key) 203868394ec8SAlexander V. Chernikov { 203968394ec8SAlexander V. Chernikov struct ifidx *ifi; 204068394ec8SAlexander V. Chernikov 204168394ec8SAlexander V. Chernikov ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx), 204268394ec8SAlexander V. Chernikov compare_ifidx); 204368394ec8SAlexander V. Chernikov 204468394ec8SAlexander V. Chernikov return (ifi); 204568394ec8SAlexander V. Chernikov } 204668394ec8SAlexander V. Chernikov 204768394ec8SAlexander V. Chernikov static int 204868394ec8SAlexander V. Chernikov ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen, 20499f7d47b0SAlexander V. Chernikov uint32_t *val) 20509f7d47b0SAlexander V. Chernikov { 205168394ec8SAlexander V. Chernikov struct ifidx *ifi; 20529f7d47b0SAlexander V. Chernikov 205368394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, key); 20549f7d47b0SAlexander V. Chernikov 205568394ec8SAlexander V. Chernikov if (ifi != NULL) { 205668394ec8SAlexander V. Chernikov *val = ifi->value; 20579f7d47b0SAlexander V. Chernikov return (1); 20589f7d47b0SAlexander V. Chernikov } 20599f7d47b0SAlexander V. Chernikov 20609f7d47b0SAlexander V. Chernikov return (0); 20619f7d47b0SAlexander V. Chernikov } 20629f7d47b0SAlexander V. Chernikov 20639f7d47b0SAlexander V. Chernikov static int 206468394ec8SAlexander V. Chernikov ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 2065914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 20669f7d47b0SAlexander V. Chernikov { 206768394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 20689f7d47b0SAlexander V. Chernikov 206968394ec8SAlexander V. Chernikov icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO); 20709f7d47b0SAlexander V. Chernikov 20710cba2b28SAlexander V. Chernikov icfg->ii = ipfw_objhash_create(DEFAULT_IFIDX_SIZE); 20720cba2b28SAlexander V. Chernikov icfg->size = DEFAULT_IFIDX_SIZE; 20730bce0c23SAlexander V. Chernikov icfg->main_ptr = malloc(sizeof(struct ifidx) * icfg->size, M_IPFW, 207468394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 207568394ec8SAlexander V. Chernikov icfg->ch = ch; 20769f7d47b0SAlexander V. Chernikov 207768394ec8SAlexander V. Chernikov *ta_state = icfg; 207868394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 207968394ec8SAlexander V. Chernikov ti->lookup = ta_lookup_ifidx; 20809f7d47b0SAlexander V. Chernikov 20819f7d47b0SAlexander V. Chernikov return (0); 20829f7d47b0SAlexander V. Chernikov } 20839f7d47b0SAlexander V. Chernikov 208468394ec8SAlexander V. Chernikov /* 208568394ec8SAlexander V. Chernikov * Handle tableinfo @ti pointer change (on table array resize). 208668394ec8SAlexander V. Chernikov */ 208768394ec8SAlexander V. Chernikov static void 208868394ec8SAlexander V. Chernikov ta_change_ti_ifidx(void *ta_state, struct table_info *ti) 208968394ec8SAlexander V. Chernikov { 209068394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 209168394ec8SAlexander V. Chernikov 209268394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 209368394ec8SAlexander V. Chernikov icfg->ti = ti; 209468394ec8SAlexander V. Chernikov } 20959f7d47b0SAlexander V. Chernikov 20969f7d47b0SAlexander V. Chernikov static void 209768394ec8SAlexander V. Chernikov destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no, 209868394ec8SAlexander V. Chernikov void *arg) 20999f7d47b0SAlexander V. Chernikov { 210068394ec8SAlexander V. Chernikov struct ifentry *ife; 210168394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 21029f7d47b0SAlexander V. Chernikov 210368394ec8SAlexander V. Chernikov ch = (struct ip_fw_chain *)arg; 210468394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 210568394ec8SAlexander V. Chernikov 210668394ec8SAlexander V. Chernikov ipfw_iface_del_notify(ch, &ife->ic); 210768394ec8SAlexander V. Chernikov free(ife, M_IPFW_TBL); 21089f7d47b0SAlexander V. Chernikov } 21099f7d47b0SAlexander V. Chernikov 211068394ec8SAlexander V. Chernikov 211168394ec8SAlexander V. Chernikov /* 211268394ec8SAlexander V. Chernikov * Destroys table @ti 211368394ec8SAlexander V. Chernikov */ 211468394ec8SAlexander V. Chernikov static void 211568394ec8SAlexander V. Chernikov ta_destroy_ifidx(void *ta_state, struct table_info *ti) 21169f7d47b0SAlexander V. Chernikov { 211768394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 211868394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 211968394ec8SAlexander V. Chernikov 212068394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 212168394ec8SAlexander V. Chernikov ch = icfg->ch; 212268394ec8SAlexander V. Chernikov 212368394ec8SAlexander V. Chernikov if (icfg->main_ptr != NULL) 212468394ec8SAlexander V. Chernikov free(icfg->main_ptr, M_IPFW); 212568394ec8SAlexander V. Chernikov 212668394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch); 212768394ec8SAlexander V. Chernikov 212868394ec8SAlexander V. Chernikov ipfw_objhash_destroy(icfg->ii); 212968394ec8SAlexander V. Chernikov 213068394ec8SAlexander V. Chernikov free(icfg, M_IPFW); 213168394ec8SAlexander V. Chernikov } 213268394ec8SAlexander V. Chernikov 213368394ec8SAlexander V. Chernikov /* 21345f379342SAlexander V. Chernikov * Provide algo-specific table info 21355f379342SAlexander V. Chernikov */ 21365f379342SAlexander V. Chernikov static void 21375f379342SAlexander V. Chernikov ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 21385f379342SAlexander V. Chernikov { 21395f379342SAlexander V. Chernikov struct iftable_cfg *cfg; 21405f379342SAlexander V. Chernikov 21415f379342SAlexander V. Chernikov cfg = (struct iftable_cfg *)ta_state; 21425f379342SAlexander V. Chernikov 21435f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_ARRAY; 21445f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 21455f379342SAlexander V. Chernikov tinfo->count4 = cfg->used; 21465f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct ifidx); 21475f379342SAlexander V. Chernikov } 21485f379342SAlexander V. Chernikov 21495f379342SAlexander V. Chernikov /* 215068394ec8SAlexander V. Chernikov * Prepare state to add to the table: 215168394ec8SAlexander V. Chernikov * allocate ifentry and reference needed interface. 215268394ec8SAlexander V. Chernikov */ 21539f7d47b0SAlexander V. Chernikov static int 215468394ec8SAlexander V. Chernikov ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 215568394ec8SAlexander V. Chernikov void *ta_buf) 215668394ec8SAlexander V. Chernikov { 215768394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 215868394ec8SAlexander V. Chernikov char *ifname; 215968394ec8SAlexander V. Chernikov struct ifentry *ife; 216068394ec8SAlexander V. Chernikov 216168394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 216268394ec8SAlexander V. Chernikov 216368394ec8SAlexander V. Chernikov /* Check if string is terminated */ 216468394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 216568394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 216668394ec8SAlexander V. Chernikov return (EINVAL); 216768394ec8SAlexander V. Chernikov 216868394ec8SAlexander V. Chernikov ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO); 216968394ec8SAlexander V. Chernikov ife->ic.cb = if_notifier; 217068394ec8SAlexander V. Chernikov ife->ic.cbdata = ife; 217168394ec8SAlexander V. Chernikov 21728ebca97fSAlexander V. Chernikov if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0) { 21738ebca97fSAlexander V. Chernikov free(ife, M_IPFW_TBL); 217468394ec8SAlexander V. Chernikov return (EINVAL); 21758ebca97fSAlexander V. Chernikov } 217668394ec8SAlexander V. Chernikov 217768394ec8SAlexander V. Chernikov /* Use ipfw_iface 'ifname' field as stable storage */ 217868394ec8SAlexander V. Chernikov ife->no.name = ife->ic.iface->ifname; 217968394ec8SAlexander V. Chernikov 218068394ec8SAlexander V. Chernikov tb->ife = ife; 218168394ec8SAlexander V. Chernikov 218268394ec8SAlexander V. Chernikov return (0); 218368394ec8SAlexander V. Chernikov } 218468394ec8SAlexander V. Chernikov 218568394ec8SAlexander V. Chernikov static int 2186adea6201SAlexander V. Chernikov ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2187b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 218868394ec8SAlexander V. Chernikov { 218968394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 219068394ec8SAlexander V. Chernikov struct ifentry *ife, *tmp; 219168394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 219268394ec8SAlexander V. Chernikov struct ipfw_iface *iif; 219368394ec8SAlexander V. Chernikov struct ifidx *ifi; 219468394ec8SAlexander V. Chernikov char *ifname; 2195648e8380SAlexander V. Chernikov uint32_t value; 219668394ec8SAlexander V. Chernikov 219768394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 219868394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 219968394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 220068394ec8SAlexander V. Chernikov ife = tb->ife; 220168394ec8SAlexander V. Chernikov 220268394ec8SAlexander V. Chernikov ife->icfg = icfg; 220313263632SAlexander V. Chernikov ife->value = tei->value; 220468394ec8SAlexander V. Chernikov 220568394ec8SAlexander V. Chernikov tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 220668394ec8SAlexander V. Chernikov 220768394ec8SAlexander V. Chernikov if (tmp != NULL) { 220868394ec8SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 220968394ec8SAlexander V. Chernikov return (EEXIST); 221068394ec8SAlexander V. Chernikov 2211648e8380SAlexander V. Chernikov /* Exchange values in @tmp and @tei */ 2212648e8380SAlexander V. Chernikov value = tmp->value; 2213648e8380SAlexander V. Chernikov tmp->value = tei->value; 2214648e8380SAlexander V. Chernikov tei->value = value; 221568394ec8SAlexander V. Chernikov 2216648e8380SAlexander V. Chernikov iif = tmp->ic.iface; 221768394ec8SAlexander V. Chernikov if (iif->resolved != 0) { 2218648e8380SAlexander V. Chernikov /* We have to update runtime value, too */ 221968394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, &iif->ifindex); 222068394ec8SAlexander V. Chernikov ifi->value = ife->value; 222168394ec8SAlexander V. Chernikov } 222268394ec8SAlexander V. Chernikov 222368394ec8SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 222468394ec8SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 2225adea6201SAlexander V. Chernikov *pnum = 0; 222668394ec8SAlexander V. Chernikov return (0); 222768394ec8SAlexander V. Chernikov } 222868394ec8SAlexander V. Chernikov 22294c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 22304c0c07a5SAlexander V. Chernikov return (EFBIG); 22314c0c07a5SAlexander V. Chernikov 223268394ec8SAlexander V. Chernikov /* Link to internal list */ 223368394ec8SAlexander V. Chernikov ipfw_objhash_add(icfg->ii, &ife->no); 223468394ec8SAlexander V. Chernikov 223568394ec8SAlexander V. Chernikov /* Link notifier (possible running its callback) */ 223668394ec8SAlexander V. Chernikov ipfw_iface_add_notify(icfg->ch, &ife->ic); 223768394ec8SAlexander V. Chernikov icfg->count++; 223868394ec8SAlexander V. Chernikov 223968394ec8SAlexander V. Chernikov tb->ife = NULL; 2240adea6201SAlexander V. Chernikov *pnum = 1; 224168394ec8SAlexander V. Chernikov 224268394ec8SAlexander V. Chernikov return (0); 224368394ec8SAlexander V. Chernikov } 224468394ec8SAlexander V. Chernikov 224568394ec8SAlexander V. Chernikov /* 224668394ec8SAlexander V. Chernikov * Prepare to delete key from table. 224768394ec8SAlexander V. Chernikov * Do basic interface name checks. 224868394ec8SAlexander V. Chernikov */ 224968394ec8SAlexander V. Chernikov static int 225068394ec8SAlexander V. Chernikov ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 225168394ec8SAlexander V. Chernikov void *ta_buf) 22529f7d47b0SAlexander V. Chernikov { 225374b941f0SAlexander V. Chernikov struct ta_buf_ifidx *tb; 2254e0a8b9eeSAlexander V. Chernikov char *ifname; 22559f7d47b0SAlexander V. Chernikov 225674b941f0SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 22579f7d47b0SAlexander V. Chernikov 22589f7d47b0SAlexander V. Chernikov /* Check if string is terminated */ 2259e0a8b9eeSAlexander V. Chernikov ifname = (char *)tei->paddr; 2260e0a8b9eeSAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 22619f7d47b0SAlexander V. Chernikov return (EINVAL); 22629f7d47b0SAlexander V. Chernikov 22639f7d47b0SAlexander V. Chernikov return (0); 22649f7d47b0SAlexander V. Chernikov } 22659f7d47b0SAlexander V. Chernikov 226668394ec8SAlexander V. Chernikov /* 226768394ec8SAlexander V. Chernikov * Remove key from both configuration list and 226868394ec8SAlexander V. Chernikov * runtime array. Removed interface notification. 226968394ec8SAlexander V. Chernikov */ 22709f7d47b0SAlexander V. Chernikov static int 2271adea6201SAlexander V. Chernikov ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2272b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 22739f7d47b0SAlexander V. Chernikov { 227468394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 227568394ec8SAlexander V. Chernikov struct ifentry *ife; 227668394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 227768394ec8SAlexander V. Chernikov char *ifname; 227868394ec8SAlexander V. Chernikov uint16_t ifindex; 227968394ec8SAlexander V. Chernikov int res; 22809f7d47b0SAlexander V. Chernikov 228168394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 228268394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 228368394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 228468394ec8SAlexander V. Chernikov ife = tb->ife; 22859f7d47b0SAlexander V. Chernikov 228668394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 22879f7d47b0SAlexander V. Chernikov 228868394ec8SAlexander V. Chernikov if (ife == NULL) 228981d3153dSAlexander V. Chernikov return (ENOENT); 22909f7d47b0SAlexander V. Chernikov 229168394ec8SAlexander V. Chernikov if (ife->linked != 0) { 229268394ec8SAlexander V. Chernikov /* We have to remove item from runtime */ 229368394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 229468394ec8SAlexander V. Chernikov 229568394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 229668394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 229768394ec8SAlexander V. Chernikov 229868394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 229968394ec8SAlexander V. Chernikov icfg->used--; 230068394ec8SAlexander V. Chernikov ti->data = icfg->used; 230168394ec8SAlexander V. Chernikov ife->linked = 0; 230268394ec8SAlexander V. Chernikov } 230368394ec8SAlexander V. Chernikov 230468394ec8SAlexander V. Chernikov /* Unlink from local list */ 230568394ec8SAlexander V. Chernikov ipfw_objhash_del(icfg->ii, &ife->no); 230668394ec8SAlexander V. Chernikov /* Unlink notifier */ 230768394ec8SAlexander V. Chernikov ipfw_iface_del_notify(icfg->ch, &ife->ic); 230868394ec8SAlexander V. Chernikov 230968394ec8SAlexander V. Chernikov icfg->count--; 2310648e8380SAlexander V. Chernikov tei->value = ife->value; 231168394ec8SAlexander V. Chernikov 231268394ec8SAlexander V. Chernikov tb->ife = ife; 2313adea6201SAlexander V. Chernikov *pnum = 1; 231468394ec8SAlexander V. Chernikov 23159f7d47b0SAlexander V. Chernikov return (0); 23169f7d47b0SAlexander V. Chernikov } 23179f7d47b0SAlexander V. Chernikov 231868394ec8SAlexander V. Chernikov /* 231968394ec8SAlexander V. Chernikov * Flush deleted entry. 232068394ec8SAlexander V. Chernikov * Drops interface reference and frees entry. 232168394ec8SAlexander V. Chernikov */ 23229f7d47b0SAlexander V. Chernikov static void 232368394ec8SAlexander V. Chernikov ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 232468394ec8SAlexander V. Chernikov void *ta_buf) 23259f7d47b0SAlexander V. Chernikov { 232668394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 23279f7d47b0SAlexander V. Chernikov 232868394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 23299f7d47b0SAlexander V. Chernikov 233068394ec8SAlexander V. Chernikov if (tb->ife != NULL) { 233168394ec8SAlexander V. Chernikov /* Unlink first */ 233268394ec8SAlexander V. Chernikov ipfw_iface_unref(ch, &tb->ife->ic); 233368394ec8SAlexander V. Chernikov free(tb->ife, M_IPFW_TBL); 233468394ec8SAlexander V. Chernikov } 233568394ec8SAlexander V. Chernikov } 233668394ec8SAlexander V. Chernikov 233768394ec8SAlexander V. Chernikov 233868394ec8SAlexander V. Chernikov /* 233968394ec8SAlexander V. Chernikov * Handle interface announce/withdrawal for particular table. 234068394ec8SAlexander V. Chernikov * Every real runtime array modification happens here. 234168394ec8SAlexander V. Chernikov */ 234268394ec8SAlexander V. Chernikov static void 234368394ec8SAlexander V. Chernikov if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex) 234468394ec8SAlexander V. Chernikov { 234568394ec8SAlexander V. Chernikov struct ifentry *ife; 234668394ec8SAlexander V. Chernikov struct ifidx ifi; 234768394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 234868394ec8SAlexander V. Chernikov struct table_info *ti; 234968394ec8SAlexander V. Chernikov int res; 235068394ec8SAlexander V. Chernikov 235168394ec8SAlexander V. Chernikov ife = (struct ifentry *)cbdata; 235268394ec8SAlexander V. Chernikov icfg = ife->icfg; 235368394ec8SAlexander V. Chernikov ti = icfg->ti; 235468394ec8SAlexander V. Chernikov 235568394ec8SAlexander V. Chernikov KASSERT(ti != NULL, ("ti=NULL, check change_ti handler")); 235668394ec8SAlexander V. Chernikov 235768394ec8SAlexander V. Chernikov if (ife->linked == 0 && ifindex != 0) { 235868394ec8SAlexander V. Chernikov /* Interface announce */ 235968394ec8SAlexander V. Chernikov ifi.kidx = ifindex; 236068394ec8SAlexander V. Chernikov ifi.spare = 0; 236168394ec8SAlexander V. Chernikov ifi.value = ife->value; 236268394ec8SAlexander V. Chernikov res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used, 236368394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 236468394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d already exists", ifindex)); 236568394ec8SAlexander V. Chernikov icfg->used++; 236668394ec8SAlexander V. Chernikov ti->data = icfg->used; 236768394ec8SAlexander V. Chernikov ife->linked = 1; 236868394ec8SAlexander V. Chernikov } else if (ife->linked != 0 && ifindex == 0) { 236968394ec8SAlexander V. Chernikov /* Interface withdrawal */ 237068394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 237168394ec8SAlexander V. Chernikov 237268394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 237368394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 237468394ec8SAlexander V. Chernikov 237568394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 237668394ec8SAlexander V. Chernikov icfg->used--; 237768394ec8SAlexander V. Chernikov ti->data = icfg->used; 237868394ec8SAlexander V. Chernikov ife->linked = 0; 237968394ec8SAlexander V. Chernikov } 238068394ec8SAlexander V. Chernikov } 238168394ec8SAlexander V. Chernikov 238268394ec8SAlexander V. Chernikov 238368394ec8SAlexander V. Chernikov /* 238468394ec8SAlexander V. Chernikov * Table growing callbacks. 238568394ec8SAlexander V. Chernikov */ 238668394ec8SAlexander V. Chernikov 2387b6ee846eSAlexander V. Chernikov static int 2388301290bcSAlexander V. Chernikov ta_need_modify_ifidx(void *ta_state, struct table_info *ti, uint32_t count, 2389b6ee846eSAlexander V. Chernikov uint64_t *pflags) 2390b6ee846eSAlexander V. Chernikov { 2391b6ee846eSAlexander V. Chernikov struct iftable_cfg *cfg; 23920bce0c23SAlexander V. Chernikov uint32_t size; 2393b6ee846eSAlexander V. Chernikov 2394b6ee846eSAlexander V. Chernikov cfg = (struct iftable_cfg *)ta_state; 2395b6ee846eSAlexander V. Chernikov 23960bce0c23SAlexander V. Chernikov size = cfg->size; 23970bce0c23SAlexander V. Chernikov while (size < cfg->count + count) 23980bce0c23SAlexander V. Chernikov size *= 2; 23990bce0c23SAlexander V. Chernikov 24000bce0c23SAlexander V. Chernikov if (size != cfg->size) { 24010bce0c23SAlexander V. Chernikov *pflags = size; 2402301290bcSAlexander V. Chernikov return (1); 2403b6ee846eSAlexander V. Chernikov } 2404b6ee846eSAlexander V. Chernikov 2405301290bcSAlexander V. Chernikov return (0); 2406b6ee846eSAlexander V. Chernikov } 2407b6ee846eSAlexander V. Chernikov 240868394ec8SAlexander V. Chernikov /* 240968394ec8SAlexander V. Chernikov * Allocate ned, larger runtime ifidx array. 241068394ec8SAlexander V. Chernikov */ 241168394ec8SAlexander V. Chernikov static int 241268394ec8SAlexander V. Chernikov ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags) 241368394ec8SAlexander V. Chernikov { 24140bce0c23SAlexander V. Chernikov struct mod_item *mi; 241568394ec8SAlexander V. Chernikov 24160bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 241768394ec8SAlexander V. Chernikov 24180bce0c23SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 241968394ec8SAlexander V. Chernikov mi->size = *pflags; 242068394ec8SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW, 242168394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 242268394ec8SAlexander V. Chernikov 242368394ec8SAlexander V. Chernikov return (0); 242468394ec8SAlexander V. Chernikov } 242568394ec8SAlexander V. Chernikov 242668394ec8SAlexander V. Chernikov /* 242768394ec8SAlexander V. Chernikov * Copy data from old runtime array to new one. 242868394ec8SAlexander V. Chernikov */ 242968394ec8SAlexander V. Chernikov static int 243068394ec8SAlexander V. Chernikov ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 243168394ec8SAlexander V. Chernikov uint64_t *pflags) 243268394ec8SAlexander V. Chernikov { 24330bce0c23SAlexander V. Chernikov struct mod_item *mi; 243468394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 243568394ec8SAlexander V. Chernikov 24360bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 243768394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 243868394ec8SAlexander V. Chernikov 243968394ec8SAlexander V. Chernikov /* Check if we still need to grow array */ 244068394ec8SAlexander V. Chernikov if (icfg->size >= mi->size) { 244168394ec8SAlexander V. Chernikov *pflags = 0; 244268394ec8SAlexander V. Chernikov return (0); 244368394ec8SAlexander V. Chernikov } 244468394ec8SAlexander V. Chernikov 244568394ec8SAlexander V. Chernikov memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx)); 244668394ec8SAlexander V. Chernikov 244768394ec8SAlexander V. Chernikov return (0); 244868394ec8SAlexander V. Chernikov } 244968394ec8SAlexander V. Chernikov 245068394ec8SAlexander V. Chernikov /* 245168394ec8SAlexander V. Chernikov * Switch old & new arrays. 245268394ec8SAlexander V. Chernikov */ 2453301290bcSAlexander V. Chernikov static void 245468394ec8SAlexander V. Chernikov ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 245568394ec8SAlexander V. Chernikov uint64_t pflags) 245668394ec8SAlexander V. Chernikov { 24570bce0c23SAlexander V. Chernikov struct mod_item *mi; 245868394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 245968394ec8SAlexander V. Chernikov void *old_ptr; 246068394ec8SAlexander V. Chernikov 24610bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 246268394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 246368394ec8SAlexander V. Chernikov 246468394ec8SAlexander V. Chernikov old_ptr = icfg->main_ptr; 246568394ec8SAlexander V. Chernikov icfg->main_ptr = mi->main_ptr; 246668394ec8SAlexander V. Chernikov icfg->size = mi->size; 246768394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 246868394ec8SAlexander V. Chernikov 246968394ec8SAlexander V. Chernikov mi->main_ptr = old_ptr; 247068394ec8SAlexander V. Chernikov } 247168394ec8SAlexander V. Chernikov 247268394ec8SAlexander V. Chernikov /* 247368394ec8SAlexander V. Chernikov * Free unneded array. 247468394ec8SAlexander V. Chernikov */ 247568394ec8SAlexander V. Chernikov static void 247668394ec8SAlexander V. Chernikov ta_flush_mod_ifidx(void *ta_buf) 247768394ec8SAlexander V. Chernikov { 24780bce0c23SAlexander V. Chernikov struct mod_item *mi; 247968394ec8SAlexander V. Chernikov 24800bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 248168394ec8SAlexander V. Chernikov if (mi->main_ptr != NULL) 248268394ec8SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 24839f7d47b0SAlexander V. Chernikov } 24849f7d47b0SAlexander V. Chernikov 24859f7d47b0SAlexander V. Chernikov static int 248668394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e, 248781d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 24889f7d47b0SAlexander V. Chernikov { 248968394ec8SAlexander V. Chernikov struct ifentry *ife; 24909f7d47b0SAlexander V. Chernikov 249168394ec8SAlexander V. Chernikov ife = (struct ifentry *)e; 249268394ec8SAlexander V. Chernikov 249381d3153dSAlexander V. Chernikov tent->masklen = 8 * IF_NAMESIZE; 249468394ec8SAlexander V. Chernikov memcpy(&tent->k, ife->no.name, IF_NAMESIZE); 24950cba2b28SAlexander V. Chernikov tent->v.kidx = ife->value; 24969f7d47b0SAlexander V. Chernikov 24979f7d47b0SAlexander V. Chernikov return (0); 24989f7d47b0SAlexander V. Chernikov } 24999f7d47b0SAlexander V. Chernikov 250081d3153dSAlexander V. Chernikov static int 2501914bffb6SAlexander V. Chernikov ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, 2502914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 250381d3153dSAlexander V. Chernikov { 250468394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 250568394ec8SAlexander V. Chernikov struct ifentry *ife; 250668394ec8SAlexander V. Chernikov char *ifname; 250781d3153dSAlexander V. Chernikov 250868394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 2509914bffb6SAlexander V. Chernikov ifname = tent->k.iface; 251081d3153dSAlexander V. Chernikov 251168394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 251268394ec8SAlexander V. Chernikov return (EINVAL); 251381d3153dSAlexander V. Chernikov 251468394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 251568394ec8SAlexander V. Chernikov 251668394ec8SAlexander V. Chernikov if (ife != NULL) { 251768394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(ta_state, ti, ife, tent); 251881d3153dSAlexander V. Chernikov return (0); 251981d3153dSAlexander V. Chernikov } 252081d3153dSAlexander V. Chernikov 252181d3153dSAlexander V. Chernikov return (ENOENT); 252281d3153dSAlexander V. Chernikov } 252381d3153dSAlexander V. Chernikov 252468394ec8SAlexander V. Chernikov struct wa_ifidx { 252568394ec8SAlexander V. Chernikov ta_foreach_f *f; 252668394ec8SAlexander V. Chernikov void *arg; 252768394ec8SAlexander V. Chernikov }; 252868394ec8SAlexander V. Chernikov 25299f7d47b0SAlexander V. Chernikov static void 253068394ec8SAlexander V. Chernikov foreach_ifidx(struct namedobj_instance *ii, struct named_object *no, 25319f7d47b0SAlexander V. Chernikov void *arg) 25329f7d47b0SAlexander V. Chernikov { 253368394ec8SAlexander V. Chernikov struct ifentry *ife; 253468394ec8SAlexander V. Chernikov struct wa_ifidx *wa; 25359f7d47b0SAlexander V. Chernikov 253668394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 253768394ec8SAlexander V. Chernikov wa = (struct wa_ifidx *)arg; 253868394ec8SAlexander V. Chernikov 253968394ec8SAlexander V. Chernikov wa->f(ife, wa->arg); 25409f7d47b0SAlexander V. Chernikov } 25419f7d47b0SAlexander V. Chernikov 254268394ec8SAlexander V. Chernikov static void 254368394ec8SAlexander V. Chernikov ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f, 254468394ec8SAlexander V. Chernikov void *arg) 254568394ec8SAlexander V. Chernikov { 254668394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 254768394ec8SAlexander V. Chernikov struct wa_ifidx wa; 254868394ec8SAlexander V. Chernikov 254968394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 255068394ec8SAlexander V. Chernikov 255168394ec8SAlexander V. Chernikov wa.f = f; 255268394ec8SAlexander V. Chernikov wa.arg = arg; 255368394ec8SAlexander V. Chernikov 255468394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa); 255568394ec8SAlexander V. Chernikov } 255668394ec8SAlexander V. Chernikov 255774b941f0SAlexander V. Chernikov struct table_algo iface_idx = { 2558adea6201SAlexander V. Chernikov .name = "iface:array", 25599d099b4fSAlexander V. Chernikov .type = IPFW_TABLE_INTERFACE, 256057a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 256157a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_ifidx), 256268394ec8SAlexander V. Chernikov .init = ta_init_ifidx, 256368394ec8SAlexander V. Chernikov .destroy = ta_destroy_ifidx, 256468394ec8SAlexander V. Chernikov .prepare_add = ta_prepare_add_ifidx, 256568394ec8SAlexander V. Chernikov .prepare_del = ta_prepare_del_ifidx, 256668394ec8SAlexander V. Chernikov .add = ta_add_ifidx, 256768394ec8SAlexander V. Chernikov .del = ta_del_ifidx, 256868394ec8SAlexander V. Chernikov .flush_entry = ta_flush_ifidx_entry, 256968394ec8SAlexander V. Chernikov .foreach = ta_foreach_ifidx, 257068394ec8SAlexander V. Chernikov .dump_tentry = ta_dump_ifidx_tentry, 257168394ec8SAlexander V. Chernikov .find_tentry = ta_find_ifidx_tentry, 25725f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_ifidx_tinfo, 2573301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_ifidx, 257468394ec8SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_ifidx, 257568394ec8SAlexander V. Chernikov .fill_mod = ta_fill_mod_ifidx, 257668394ec8SAlexander V. Chernikov .modify = ta_modify_ifidx, 257768394ec8SAlexander V. Chernikov .flush_mod = ta_flush_mod_ifidx, 257868394ec8SAlexander V. Chernikov .change_ti = ta_change_ti_ifidx, 25799f7d47b0SAlexander V. Chernikov }; 25809f7d47b0SAlexander V. Chernikov 2581b23d5de9SAlexander V. Chernikov /* 2582b23d5de9SAlexander V. Chernikov * Number array cmds. 2583b23d5de9SAlexander V. Chernikov * 2584b23d5de9SAlexander V. Chernikov * Implementation: 2585b23d5de9SAlexander V. Chernikov * 2586b23d5de9SAlexander V. Chernikov * Runtime part: 2587b23d5de9SAlexander V. Chernikov * - sorted array of "struct numarray" pointed by ti->state. 2588b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to NUMARRAY_CHUNK. 2589b23d5de9SAlexander V. Chernikov * - current array size is stored in ti->data 2590b23d5de9SAlexander V. Chernikov * 2591b23d5de9SAlexander V. Chernikov */ 2592b23d5de9SAlexander V. Chernikov 2593b23d5de9SAlexander V. Chernikov struct numarray { 2594b23d5de9SAlexander V. Chernikov uint32_t number; 2595b23d5de9SAlexander V. Chernikov uint32_t value; 2596b23d5de9SAlexander V. Chernikov }; 2597b23d5de9SAlexander V. Chernikov 2598b23d5de9SAlexander V. Chernikov struct numarray_cfg { 2599b23d5de9SAlexander V. Chernikov void *main_ptr; 2600b23d5de9SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 2601b23d5de9SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 2602b23d5de9SAlexander V. Chernikov }; 2603b23d5de9SAlexander V. Chernikov 26040bce0c23SAlexander V. Chernikov struct ta_buf_numarray 26050bce0c23SAlexander V. Chernikov { 26060bce0c23SAlexander V. Chernikov struct numarray na; 26070bce0c23SAlexander V. Chernikov }; 2608b23d5de9SAlexander V. Chernikov 2609b23d5de9SAlexander V. Chernikov int compare_numarray(const void *k, const void *v); 2610*9fe15d06SAlexander V. Chernikov static struct numarray *numarray_find(struct table_info *ti, void *key); 2611*9fe15d06SAlexander V. Chernikov static int ta_lookup_numarray(struct table_info *ti, void *key, 2612*9fe15d06SAlexander V. Chernikov uint32_t keylen, uint32_t *val); 2613*9fe15d06SAlexander V. Chernikov static int ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, 2614*9fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 2615*9fe15d06SAlexander V. Chernikov static void ta_destroy_numarray(void *ta_state, struct table_info *ti); 2616*9fe15d06SAlexander V. Chernikov static void ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, 2617*9fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 2618*9fe15d06SAlexander V. Chernikov static int ta_prepare_add_numarray(struct ip_fw_chain *ch, 2619*9fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf); 2620*9fe15d06SAlexander V. Chernikov static int ta_add_numarray(void *ta_state, struct table_info *ti, 2621*9fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 2622*9fe15d06SAlexander V. Chernikov static int ta_del_numarray(void *ta_state, struct table_info *ti, 2623*9fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 2624*9fe15d06SAlexander V. Chernikov static void ta_flush_numarray_entry(struct ip_fw_chain *ch, 2625*9fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf); 2626*9fe15d06SAlexander V. Chernikov static int ta_need_modify_numarray(void *ta_state, struct table_info *ti, 2627*9fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 2628*9fe15d06SAlexander V. Chernikov static int ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags); 2629*9fe15d06SAlexander V. Chernikov static int ta_fill_mod_numarray(void *ta_state, struct table_info *ti, 2630*9fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t *pflags); 2631*9fe15d06SAlexander V. Chernikov static void ta_modify_numarray(void *ta_state, struct table_info *ti, 2632*9fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t pflags); 2633*9fe15d06SAlexander V. Chernikov static void ta_flush_mod_numarray(void *ta_buf); 2634*9fe15d06SAlexander V. Chernikov static int ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, 2635*9fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent); 2636*9fe15d06SAlexander V. Chernikov static int ta_find_numarray_tentry(void *ta_state, struct table_info *ti, 2637*9fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 2638*9fe15d06SAlexander V. Chernikov static void ta_foreach_numarray(void *ta_state, struct table_info *ti, 2639*9fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 2640b23d5de9SAlexander V. Chernikov 2641b23d5de9SAlexander V. Chernikov int 2642b23d5de9SAlexander V. Chernikov compare_numarray(const void *k, const void *v) 2643b23d5de9SAlexander V. Chernikov { 2644d4e1b515SAlexander V. Chernikov const struct numarray *na; 2645b23d5de9SAlexander V. Chernikov uint32_t key; 2646b23d5de9SAlexander V. Chernikov 2647d4e1b515SAlexander V. Chernikov key = *((const uint32_t *)k); 2648d4e1b515SAlexander V. Chernikov na = (const struct numarray *)v; 2649b23d5de9SAlexander V. Chernikov 2650b23d5de9SAlexander V. Chernikov if (key < na->number) 2651b23d5de9SAlexander V. Chernikov return (-1); 2652b23d5de9SAlexander V. Chernikov else if (key > na->number) 2653b23d5de9SAlexander V. Chernikov return (1); 2654b23d5de9SAlexander V. Chernikov 2655b23d5de9SAlexander V. Chernikov return (0); 2656b23d5de9SAlexander V. Chernikov } 2657b23d5de9SAlexander V. Chernikov 2658b23d5de9SAlexander V. Chernikov static struct numarray * 2659b23d5de9SAlexander V. Chernikov numarray_find(struct table_info *ti, void *key) 2660b23d5de9SAlexander V. Chernikov { 2661b23d5de9SAlexander V. Chernikov struct numarray *ri; 2662b23d5de9SAlexander V. Chernikov 2663b23d5de9SAlexander V. Chernikov ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray), 2664b23d5de9SAlexander V. Chernikov compare_ifidx); 2665b23d5de9SAlexander V. Chernikov 2666b23d5de9SAlexander V. Chernikov return (ri); 2667b23d5de9SAlexander V. Chernikov } 2668b23d5de9SAlexander V. Chernikov 2669b23d5de9SAlexander V. Chernikov static int 2670b23d5de9SAlexander V. Chernikov ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen, 2671b23d5de9SAlexander V. Chernikov uint32_t *val) 2672b23d5de9SAlexander V. Chernikov { 2673b23d5de9SAlexander V. Chernikov struct numarray *ri; 2674b23d5de9SAlexander V. Chernikov 2675b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, key); 2676b23d5de9SAlexander V. Chernikov 2677b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2678b23d5de9SAlexander V. Chernikov *val = ri->value; 2679b23d5de9SAlexander V. Chernikov return (1); 2680b23d5de9SAlexander V. Chernikov } 2681b23d5de9SAlexander V. Chernikov 2682b23d5de9SAlexander V. Chernikov return (0); 2683b23d5de9SAlexander V. Chernikov } 2684b23d5de9SAlexander V. Chernikov 2685b23d5de9SAlexander V. Chernikov static int 2686b23d5de9SAlexander V. Chernikov ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 2687914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 2688b23d5de9SAlexander V. Chernikov { 2689b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2690b23d5de9SAlexander V. Chernikov 2691b23d5de9SAlexander V. Chernikov cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO); 2692b23d5de9SAlexander V. Chernikov 26930bce0c23SAlexander V. Chernikov cfg->size = 16; 2694b23d5de9SAlexander V. Chernikov cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW, 2695b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO); 2696b23d5de9SAlexander V. Chernikov 2697b23d5de9SAlexander V. Chernikov *ta_state = cfg; 2698b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr; 2699b23d5de9SAlexander V. Chernikov ti->lookup = ta_lookup_numarray; 2700b23d5de9SAlexander V. Chernikov 2701b23d5de9SAlexander V. Chernikov return (0); 2702b23d5de9SAlexander V. Chernikov } 2703b23d5de9SAlexander V. Chernikov 2704b23d5de9SAlexander V. Chernikov /* 2705b23d5de9SAlexander V. Chernikov * Destroys table @ti 2706b23d5de9SAlexander V. Chernikov */ 2707b23d5de9SAlexander V. Chernikov static void 2708b23d5de9SAlexander V. Chernikov ta_destroy_numarray(void *ta_state, struct table_info *ti) 2709b23d5de9SAlexander V. Chernikov { 2710b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2711b23d5de9SAlexander V. Chernikov 2712b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2713b23d5de9SAlexander V. Chernikov 2714b23d5de9SAlexander V. Chernikov if (cfg->main_ptr != NULL) 2715b23d5de9SAlexander V. Chernikov free(cfg->main_ptr, M_IPFW); 2716b23d5de9SAlexander V. Chernikov 2717b23d5de9SAlexander V. Chernikov free(cfg, M_IPFW); 2718b23d5de9SAlexander V. Chernikov } 2719b23d5de9SAlexander V. Chernikov 2720b23d5de9SAlexander V. Chernikov /* 27215f379342SAlexander V. Chernikov * Provide algo-specific table info 27225f379342SAlexander V. Chernikov */ 27235f379342SAlexander V. Chernikov static void 27245f379342SAlexander V. Chernikov ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 27255f379342SAlexander V. Chernikov { 27265f379342SAlexander V. Chernikov struct numarray_cfg *cfg; 27275f379342SAlexander V. Chernikov 27285f379342SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 27295f379342SAlexander V. Chernikov 27305f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_ARRAY; 27315f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 27325f379342SAlexander V. Chernikov tinfo->count4 = cfg->used; 27335f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct numarray); 27345f379342SAlexander V. Chernikov } 27355f379342SAlexander V. Chernikov 27365f379342SAlexander V. Chernikov /* 2737b23d5de9SAlexander V. Chernikov * Prepare for addition/deletion to an array. 2738b23d5de9SAlexander V. Chernikov */ 2739b23d5de9SAlexander V. Chernikov static int 2740b23d5de9SAlexander V. Chernikov ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei, 2741b23d5de9SAlexander V. Chernikov void *ta_buf) 2742b23d5de9SAlexander V. Chernikov { 2743b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2744b23d5de9SAlexander V. Chernikov 2745b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2746b23d5de9SAlexander V. Chernikov 2747b23d5de9SAlexander V. Chernikov tb->na.number = *((uint32_t *)tei->paddr); 2748b23d5de9SAlexander V. Chernikov 2749b23d5de9SAlexander V. Chernikov return (0); 2750b23d5de9SAlexander V. Chernikov } 2751b23d5de9SAlexander V. Chernikov 2752b23d5de9SAlexander V. Chernikov static int 2753b23d5de9SAlexander V. Chernikov ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2754b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 2755b23d5de9SAlexander V. Chernikov { 2756b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2757b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2758b23d5de9SAlexander V. Chernikov struct numarray *ri; 2759b23d5de9SAlexander V. Chernikov int res; 2760648e8380SAlexander V. Chernikov uint32_t value; 2761b23d5de9SAlexander V. Chernikov 2762b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2763b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2764b23d5de9SAlexander V. Chernikov 276513263632SAlexander V. Chernikov /* Read current value from @tei */ 276613263632SAlexander V. Chernikov tb->na.value = tei->value; 276713263632SAlexander V. Chernikov 2768b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number); 2769b23d5de9SAlexander V. Chernikov 2770b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2771b23d5de9SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 2772b23d5de9SAlexander V. Chernikov return (EEXIST); 2773b23d5de9SAlexander V. Chernikov 2774648e8380SAlexander V. Chernikov /* Exchange values between ri and @tei */ 2775648e8380SAlexander V. Chernikov value = ri->value; 2776648e8380SAlexander V. Chernikov ri->value = tei->value; 2777648e8380SAlexander V. Chernikov tei->value = value; 2778b23d5de9SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 2779b23d5de9SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 2780b23d5de9SAlexander V. Chernikov *pnum = 0; 2781b23d5de9SAlexander V. Chernikov return (0); 2782b23d5de9SAlexander V. Chernikov } 2783b23d5de9SAlexander V. Chernikov 27844c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 27854c0c07a5SAlexander V. Chernikov return (EFBIG); 27864c0c07a5SAlexander V. Chernikov 2787b23d5de9SAlexander V. Chernikov res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used, 2788b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray); 2789b23d5de9SAlexander V. Chernikov 2790b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %d already exists", tb->na.number)); 2791b23d5de9SAlexander V. Chernikov cfg->used++; 2792b23d5de9SAlexander V. Chernikov ti->data = cfg->used; 2793b23d5de9SAlexander V. Chernikov *pnum = 1; 2794b23d5de9SAlexander V. Chernikov 2795b23d5de9SAlexander V. Chernikov return (0); 2796b23d5de9SAlexander V. Chernikov } 2797b23d5de9SAlexander V. Chernikov 2798b23d5de9SAlexander V. Chernikov /* 2799b23d5de9SAlexander V. Chernikov * Remove key from both configuration list and 2800b23d5de9SAlexander V. Chernikov * runtime array. Removed interface notification. 2801b23d5de9SAlexander V. Chernikov */ 2802b23d5de9SAlexander V. Chernikov static int 2803b23d5de9SAlexander V. Chernikov ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2804b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 2805b23d5de9SAlexander V. Chernikov { 2806b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2807b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2808b23d5de9SAlexander V. Chernikov struct numarray *ri; 2809b23d5de9SAlexander V. Chernikov int res; 2810b23d5de9SAlexander V. Chernikov 2811b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2812b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2813b23d5de9SAlexander V. Chernikov 2814b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number); 2815b23d5de9SAlexander V. Chernikov if (ri == NULL) 2816b23d5de9SAlexander V. Chernikov return (ENOENT); 2817b23d5de9SAlexander V. Chernikov 2818648e8380SAlexander V. Chernikov tei->value = ri->value; 2819648e8380SAlexander V. Chernikov 2820b23d5de9SAlexander V. Chernikov res = bdel(&tb->na.number, cfg->main_ptr, cfg->used, 2821b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray); 2822b23d5de9SAlexander V. Chernikov 2823b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %u does not exist", tb->na.number)); 2824b23d5de9SAlexander V. Chernikov cfg->used--; 2825b23d5de9SAlexander V. Chernikov ti->data = cfg->used; 2826b23d5de9SAlexander V. Chernikov *pnum = 1; 2827b23d5de9SAlexander V. Chernikov 2828b23d5de9SAlexander V. Chernikov return (0); 2829b23d5de9SAlexander V. Chernikov } 2830b23d5de9SAlexander V. Chernikov 2831b23d5de9SAlexander V. Chernikov static void 2832b23d5de9SAlexander V. Chernikov ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 2833b23d5de9SAlexander V. Chernikov void *ta_buf) 2834b23d5de9SAlexander V. Chernikov { 2835b23d5de9SAlexander V. Chernikov 28360bce0c23SAlexander V. Chernikov /* We don't have any state, do nothing */ 2837b23d5de9SAlexander V. Chernikov } 2838b23d5de9SAlexander V. Chernikov 2839b23d5de9SAlexander V. Chernikov 2840b23d5de9SAlexander V. Chernikov /* 2841b23d5de9SAlexander V. Chernikov * Table growing callbacks. 2842b23d5de9SAlexander V. Chernikov */ 2843b23d5de9SAlexander V. Chernikov 2844b6ee846eSAlexander V. Chernikov static int 2845301290bcSAlexander V. Chernikov ta_need_modify_numarray(void *ta_state, struct table_info *ti, uint32_t count, 2846b6ee846eSAlexander V. Chernikov uint64_t *pflags) 2847b6ee846eSAlexander V. Chernikov { 2848b6ee846eSAlexander V. Chernikov struct numarray_cfg *cfg; 28490bce0c23SAlexander V. Chernikov size_t size; 2850b6ee846eSAlexander V. Chernikov 2851b6ee846eSAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2852b6ee846eSAlexander V. Chernikov 28530bce0c23SAlexander V. Chernikov size = cfg->size; 28540bce0c23SAlexander V. Chernikov while (size < cfg->used + count) 28550bce0c23SAlexander V. Chernikov size *= 2; 28560bce0c23SAlexander V. Chernikov 28570bce0c23SAlexander V. Chernikov if (size != cfg->size) { 28580bce0c23SAlexander V. Chernikov *pflags = size; 2859301290bcSAlexander V. Chernikov return (1); 2860b6ee846eSAlexander V. Chernikov } 2861b6ee846eSAlexander V. Chernikov 2862301290bcSAlexander V. Chernikov return (0); 2863b6ee846eSAlexander V. Chernikov } 2864b6ee846eSAlexander V. Chernikov 2865b23d5de9SAlexander V. Chernikov /* 2866b6ee846eSAlexander V. Chernikov * Allocate new, larger runtime array. 2867b23d5de9SAlexander V. Chernikov */ 2868b23d5de9SAlexander V. Chernikov static int 2869b23d5de9SAlexander V. Chernikov ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags) 2870b23d5de9SAlexander V. Chernikov { 2871b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2872b23d5de9SAlexander V. Chernikov 2873b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2874b23d5de9SAlexander V. Chernikov 2875b23d5de9SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 2876b23d5de9SAlexander V. Chernikov mi->size = *pflags; 2877b23d5de9SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW, 2878b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO); 2879b23d5de9SAlexander V. Chernikov 2880b23d5de9SAlexander V. Chernikov return (0); 2881b23d5de9SAlexander V. Chernikov } 2882b23d5de9SAlexander V. Chernikov 2883b23d5de9SAlexander V. Chernikov /* 2884b23d5de9SAlexander V. Chernikov * Copy data from old runtime array to new one. 2885b23d5de9SAlexander V. Chernikov */ 2886b23d5de9SAlexander V. Chernikov static int 2887b23d5de9SAlexander V. Chernikov ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf, 2888b23d5de9SAlexander V. Chernikov uint64_t *pflags) 2889b23d5de9SAlexander V. Chernikov { 2890b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2891b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2892b23d5de9SAlexander V. Chernikov 2893b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2894b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2895b23d5de9SAlexander V. Chernikov 2896b23d5de9SAlexander V. Chernikov /* Check if we still need to grow array */ 2897b23d5de9SAlexander V. Chernikov if (cfg->size >= mi->size) { 2898b23d5de9SAlexander V. Chernikov *pflags = 0; 2899b23d5de9SAlexander V. Chernikov return (0); 2900b23d5de9SAlexander V. Chernikov } 2901b23d5de9SAlexander V. Chernikov 2902b23d5de9SAlexander V. Chernikov memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray)); 2903b23d5de9SAlexander V. Chernikov 2904b23d5de9SAlexander V. Chernikov return (0); 2905b23d5de9SAlexander V. Chernikov } 2906b23d5de9SAlexander V. Chernikov 2907b23d5de9SAlexander V. Chernikov /* 2908b23d5de9SAlexander V. Chernikov * Switch old & new arrays. 2909b23d5de9SAlexander V. Chernikov */ 2910301290bcSAlexander V. Chernikov static void 2911b23d5de9SAlexander V. Chernikov ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf, 2912b23d5de9SAlexander V. Chernikov uint64_t pflags) 2913b23d5de9SAlexander V. Chernikov { 2914b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2915b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2916b23d5de9SAlexander V. Chernikov void *old_ptr; 2917b23d5de9SAlexander V. Chernikov 2918b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2919b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2920b23d5de9SAlexander V. Chernikov 2921b23d5de9SAlexander V. Chernikov old_ptr = cfg->main_ptr; 2922b23d5de9SAlexander V. Chernikov cfg->main_ptr = mi->main_ptr; 2923b23d5de9SAlexander V. Chernikov cfg->size = mi->size; 2924b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr; 2925b23d5de9SAlexander V. Chernikov 2926b23d5de9SAlexander V. Chernikov mi->main_ptr = old_ptr; 2927b23d5de9SAlexander V. Chernikov } 2928b23d5de9SAlexander V. Chernikov 2929b23d5de9SAlexander V. Chernikov /* 2930b23d5de9SAlexander V. Chernikov * Free unneded array. 2931b23d5de9SAlexander V. Chernikov */ 2932b23d5de9SAlexander V. Chernikov static void 2933b23d5de9SAlexander V. Chernikov ta_flush_mod_numarray(void *ta_buf) 2934b23d5de9SAlexander V. Chernikov { 2935b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2936b23d5de9SAlexander V. Chernikov 2937b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2938b23d5de9SAlexander V. Chernikov if (mi->main_ptr != NULL) 2939b23d5de9SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 2940b23d5de9SAlexander V. Chernikov } 2941b23d5de9SAlexander V. Chernikov 2942b23d5de9SAlexander V. Chernikov static int 2943b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e, 2944b23d5de9SAlexander V. Chernikov ipfw_obj_tentry *tent) 2945b23d5de9SAlexander V. Chernikov { 2946b23d5de9SAlexander V. Chernikov struct numarray *na; 2947b23d5de9SAlexander V. Chernikov 2948b23d5de9SAlexander V. Chernikov na = (struct numarray *)e; 2949b23d5de9SAlexander V. Chernikov 2950b23d5de9SAlexander V. Chernikov tent->k.key = na->number; 29510cba2b28SAlexander V. Chernikov tent->v.kidx = na->value; 2952b23d5de9SAlexander V. Chernikov 2953b23d5de9SAlexander V. Chernikov return (0); 2954b23d5de9SAlexander V. Chernikov } 2955b23d5de9SAlexander V. Chernikov 2956b23d5de9SAlexander V. Chernikov static int 2957914bffb6SAlexander V. Chernikov ta_find_numarray_tentry(void *ta_state, struct table_info *ti, 2958914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 2959b23d5de9SAlexander V. Chernikov { 2960b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2961b23d5de9SAlexander V. Chernikov struct numarray *ri; 2962b23d5de9SAlexander V. Chernikov 2963b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2964b23d5de9SAlexander V. Chernikov 2965914bffb6SAlexander V. Chernikov ri = numarray_find(ti, &tent->k.key); 2966b23d5de9SAlexander V. Chernikov 2967b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2968b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(ta_state, ti, ri, tent); 2969b23d5de9SAlexander V. Chernikov return (0); 2970b23d5de9SAlexander V. Chernikov } 2971b23d5de9SAlexander V. Chernikov 2972b23d5de9SAlexander V. Chernikov return (ENOENT); 2973b23d5de9SAlexander V. Chernikov } 2974b23d5de9SAlexander V. Chernikov 2975b23d5de9SAlexander V. Chernikov static void 2976b23d5de9SAlexander V. Chernikov ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f, 2977b23d5de9SAlexander V. Chernikov void *arg) 2978b23d5de9SAlexander V. Chernikov { 2979b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2980b23d5de9SAlexander V. Chernikov struct numarray *array; 2981b23d5de9SAlexander V. Chernikov int i; 2982b23d5de9SAlexander V. Chernikov 2983b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2984b23d5de9SAlexander V. Chernikov array = cfg->main_ptr; 2985b23d5de9SAlexander V. Chernikov 2986b23d5de9SAlexander V. Chernikov for (i = 0; i < cfg->used; i++) 2987b23d5de9SAlexander V. Chernikov f(&array[i], arg); 2988b23d5de9SAlexander V. Chernikov } 2989b23d5de9SAlexander V. Chernikov 2990b23d5de9SAlexander V. Chernikov struct table_algo number_array = { 2991b23d5de9SAlexander V. Chernikov .name = "number:array", 2992b23d5de9SAlexander V. Chernikov .type = IPFW_TABLE_NUMBER, 299357a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_numarray), 2994b23d5de9SAlexander V. Chernikov .init = ta_init_numarray, 2995b23d5de9SAlexander V. Chernikov .destroy = ta_destroy_numarray, 2996b23d5de9SAlexander V. Chernikov .prepare_add = ta_prepare_add_numarray, 2997b23d5de9SAlexander V. Chernikov .prepare_del = ta_prepare_add_numarray, 2998b23d5de9SAlexander V. Chernikov .add = ta_add_numarray, 2999b23d5de9SAlexander V. Chernikov .del = ta_del_numarray, 3000b23d5de9SAlexander V. Chernikov .flush_entry = ta_flush_numarray_entry, 3001b23d5de9SAlexander V. Chernikov .foreach = ta_foreach_numarray, 3002b23d5de9SAlexander V. Chernikov .dump_tentry = ta_dump_numarray_tentry, 3003b23d5de9SAlexander V. Chernikov .find_tentry = ta_find_numarray_tentry, 30045f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_numarray_tinfo, 3005301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_numarray, 3006b23d5de9SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_numarray, 3007b23d5de9SAlexander V. Chernikov .fill_mod = ta_fill_mod_numarray, 3008b23d5de9SAlexander V. Chernikov .modify = ta_modify_numarray, 3009b23d5de9SAlexander V. Chernikov .flush_mod = ta_flush_mod_numarray, 3010b23d5de9SAlexander V. Chernikov }; 3011b23d5de9SAlexander V. Chernikov 3012914bffb6SAlexander V. Chernikov /* 3013914bffb6SAlexander V. Chernikov * flow:hash cmds 3014914bffb6SAlexander V. Chernikov * 3015914bffb6SAlexander V. Chernikov * 3016914bffb6SAlexander V. Chernikov * ti->data: 3017914bffb6SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6] 3018914bffb6SAlexander V. Chernikov * [ 8][ 8[ 8][ 8] 3019914bffb6SAlexander V. Chernikov * 3020914bffb6SAlexander V. Chernikov * inv.mask4: 32 - mask 3021914bffb6SAlexander V. Chernikov * inv.mask6: 3022914bffb6SAlexander V. Chernikov * 1) _slow lookup: mask 3023914bffb6SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8 3024914bffb6SAlexander V. Chernikov * 3) _64: 8 3025914bffb6SAlexander V. Chernikov * 3026914bffb6SAlexander V. Chernikov * 3027914bffb6SAlexander V. Chernikov * pflags: 3028b6ee846eSAlexander V. Chernikov * [hsize4][hsize6] 3029b6ee846eSAlexander V. Chernikov * [ 16][ 16] 3030914bffb6SAlexander V. Chernikov */ 3031914bffb6SAlexander V. Chernikov 3032914bffb6SAlexander V. Chernikov struct fhashentry; 3033914bffb6SAlexander V. Chernikov 3034914bffb6SAlexander V. Chernikov SLIST_HEAD(fhashbhead, fhashentry); 3035914bffb6SAlexander V. Chernikov 3036914bffb6SAlexander V. Chernikov struct fhashentry { 3037914bffb6SAlexander V. Chernikov SLIST_ENTRY(fhashentry) next; 3038914bffb6SAlexander V. Chernikov uint8_t af; 3039914bffb6SAlexander V. Chernikov uint8_t proto; 3040914bffb6SAlexander V. Chernikov uint16_t spare0; 3041914bffb6SAlexander V. Chernikov uint16_t dport; 3042914bffb6SAlexander V. Chernikov uint16_t sport; 3043914bffb6SAlexander V. Chernikov uint32_t value; 3044914bffb6SAlexander V. Chernikov uint32_t spare1; 3045914bffb6SAlexander V. Chernikov }; 3046914bffb6SAlexander V. Chernikov 3047914bffb6SAlexander V. Chernikov struct fhashentry4 { 3048914bffb6SAlexander V. Chernikov struct fhashentry e; 3049914bffb6SAlexander V. Chernikov struct in_addr dip; 3050914bffb6SAlexander V. Chernikov struct in_addr sip; 3051914bffb6SAlexander V. Chernikov }; 3052914bffb6SAlexander V. Chernikov 3053914bffb6SAlexander V. Chernikov struct fhashentry6 { 3054914bffb6SAlexander V. Chernikov struct fhashentry e; 3055914bffb6SAlexander V. Chernikov struct in6_addr dip6; 3056914bffb6SAlexander V. Chernikov struct in6_addr sip6; 3057914bffb6SAlexander V. Chernikov }; 3058914bffb6SAlexander V. Chernikov 3059914bffb6SAlexander V. Chernikov struct fhash_cfg { 3060914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3061914bffb6SAlexander V. Chernikov size_t size; 3062914bffb6SAlexander V. Chernikov size_t items; 3063914bffb6SAlexander V. Chernikov struct fhashentry4 fe4; 3064914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 3065914bffb6SAlexander V. Chernikov }; 3066914bffb6SAlexander V. Chernikov 30673fe2ef91SAlexander V. Chernikov struct ta_buf_fhash { 30680bce0c23SAlexander V. Chernikov void *ent_ptr; 30690bce0c23SAlexander V. Chernikov struct fhashentry6 fe6; 30700bce0c23SAlexander V. Chernikov }; 30710bce0c23SAlexander V. Chernikov 3072*9fe15d06SAlexander V. Chernikov static __inline int cmp_flow_ent(struct fhashentry *a, 3073*9fe15d06SAlexander V. Chernikov struct fhashentry *b, size_t sz); 3074*9fe15d06SAlexander V. Chernikov static __inline uint32_t hash_flow4(struct fhashentry4 *f, int hsize); 3075*9fe15d06SAlexander V. Chernikov static __inline uint32_t hash_flow6(struct fhashentry6 *f, int hsize); 3076*9fe15d06SAlexander V. Chernikov static uint32_t hash_flow_ent(struct fhashentry *ent, uint32_t size); 3077*9fe15d06SAlexander V. Chernikov static int ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen, 3078*9fe15d06SAlexander V. Chernikov uint32_t *val); 3079*9fe15d06SAlexander V. Chernikov static int ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, 3080*9fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 3081*9fe15d06SAlexander V. Chernikov static void ta_destroy_fhash(void *ta_state, struct table_info *ti); 3082*9fe15d06SAlexander V. Chernikov static void ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, 3083*9fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 3084*9fe15d06SAlexander V. Chernikov static int ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, 3085*9fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent); 3086*9fe15d06SAlexander V. Chernikov static int tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent); 3087*9fe15d06SAlexander V. Chernikov static int ta_find_fhash_tentry(void *ta_state, struct table_info *ti, 3088*9fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 3089*9fe15d06SAlexander V. Chernikov static void ta_foreach_fhash(void *ta_state, struct table_info *ti, 3090*9fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 3091*9fe15d06SAlexander V. Chernikov static int ta_prepare_add_fhash(struct ip_fw_chain *ch, 3092*9fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf); 3093*9fe15d06SAlexander V. Chernikov static int ta_add_fhash(void *ta_state, struct table_info *ti, 3094*9fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 3095*9fe15d06SAlexander V. Chernikov static int ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 3096*9fe15d06SAlexander V. Chernikov void *ta_buf); 3097*9fe15d06SAlexander V. Chernikov static int ta_del_fhash(void *ta_state, struct table_info *ti, 3098*9fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 3099*9fe15d06SAlexander V. Chernikov static void ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 3100*9fe15d06SAlexander V. Chernikov void *ta_buf); 3101*9fe15d06SAlexander V. Chernikov static int ta_need_modify_fhash(void *ta_state, struct table_info *ti, 3102*9fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 3103*9fe15d06SAlexander V. Chernikov static int ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags); 3104*9fe15d06SAlexander V. Chernikov static int ta_fill_mod_fhash(void *ta_state, struct table_info *ti, 3105*9fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t *pflags); 3106*9fe15d06SAlexander V. Chernikov static void ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3107*9fe15d06SAlexander V. Chernikov uint64_t pflags); 3108*9fe15d06SAlexander V. Chernikov static void ta_flush_mod_fhash(void *ta_buf); 3109*9fe15d06SAlexander V. Chernikov 3110914bffb6SAlexander V. Chernikov static __inline int 3111914bffb6SAlexander V. Chernikov cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz) 3112914bffb6SAlexander V. Chernikov { 3113914bffb6SAlexander V. Chernikov uint64_t *ka, *kb; 3114914bffb6SAlexander V. Chernikov 3115914bffb6SAlexander V. Chernikov ka = (uint64_t *)(&a->next + 1); 3116914bffb6SAlexander V. Chernikov kb = (uint64_t *)(&b->next + 1); 3117914bffb6SAlexander V. Chernikov 3118914bffb6SAlexander V. Chernikov if (*ka == *kb && (memcmp(a + 1, b + 1, sz) == 0)) 3119914bffb6SAlexander V. Chernikov return (1); 3120914bffb6SAlexander V. Chernikov 3121914bffb6SAlexander V. Chernikov return (0); 3122914bffb6SAlexander V. Chernikov } 3123914bffb6SAlexander V. Chernikov 3124914bffb6SAlexander V. Chernikov static __inline uint32_t 3125914bffb6SAlexander V. Chernikov hash_flow4(struct fhashentry4 *f, int hsize) 3126914bffb6SAlexander V. Chernikov { 3127914bffb6SAlexander V. Chernikov uint32_t i; 3128914bffb6SAlexander V. Chernikov 3129914bffb6SAlexander V. Chernikov i = (f->dip.s_addr) ^ (f->sip.s_addr) ^ (f->e.dport) ^ (f->e.sport); 3130914bffb6SAlexander V. Chernikov 3131914bffb6SAlexander V. Chernikov return (i % (hsize - 1)); 3132914bffb6SAlexander V. Chernikov } 3133914bffb6SAlexander V. Chernikov 3134914bffb6SAlexander V. Chernikov static __inline uint32_t 3135914bffb6SAlexander V. Chernikov hash_flow6(struct fhashentry6 *f, int hsize) 3136914bffb6SAlexander V. Chernikov { 3137914bffb6SAlexander V. Chernikov uint32_t i; 3138914bffb6SAlexander V. Chernikov 3139914bffb6SAlexander V. Chernikov i = (f->dip6.__u6_addr.__u6_addr32[2]) ^ 3140914bffb6SAlexander V. Chernikov (f->dip6.__u6_addr.__u6_addr32[3]) ^ 3141914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[2]) ^ 3142914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[3]) ^ 3143914bffb6SAlexander V. Chernikov (f->e.dport) ^ (f->e.sport); 3144914bffb6SAlexander V. Chernikov 3145914bffb6SAlexander V. Chernikov return (i % (hsize - 1)); 3146914bffb6SAlexander V. Chernikov } 3147914bffb6SAlexander V. Chernikov 3148914bffb6SAlexander V. Chernikov static uint32_t 3149914bffb6SAlexander V. Chernikov hash_flow_ent(struct fhashentry *ent, uint32_t size) 3150914bffb6SAlexander V. Chernikov { 3151914bffb6SAlexander V. Chernikov uint32_t hash; 3152914bffb6SAlexander V. Chernikov 3153914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) { 3154914bffb6SAlexander V. Chernikov hash = hash_flow4((struct fhashentry4 *)ent, size); 3155914bffb6SAlexander V. Chernikov } else { 3156914bffb6SAlexander V. Chernikov hash = hash_flow6((struct fhashentry6 *)ent, size); 3157914bffb6SAlexander V. Chernikov } 3158914bffb6SAlexander V. Chernikov 3159914bffb6SAlexander V. Chernikov return (hash); 3160914bffb6SAlexander V. Chernikov } 3161914bffb6SAlexander V. Chernikov 3162914bffb6SAlexander V. Chernikov static int 3163914bffb6SAlexander V. Chernikov ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen, 3164914bffb6SAlexander V. Chernikov uint32_t *val) 3165914bffb6SAlexander V. Chernikov { 3166914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3167914bffb6SAlexander V. Chernikov struct fhashentry *ent; 3168914bffb6SAlexander V. Chernikov struct fhashentry4 *m4; 3169914bffb6SAlexander V. Chernikov struct ipfw_flow_id *id; 3170914bffb6SAlexander V. Chernikov uint16_t hash, hsize; 3171914bffb6SAlexander V. Chernikov 3172914bffb6SAlexander V. Chernikov id = (struct ipfw_flow_id *)key; 3173914bffb6SAlexander V. Chernikov head = (struct fhashbhead *)ti->state; 3174914bffb6SAlexander V. Chernikov hsize = ti->data; 3175914bffb6SAlexander V. Chernikov m4 = (struct fhashentry4 *)ti->xstate; 3176914bffb6SAlexander V. Chernikov 3177914bffb6SAlexander V. Chernikov if (id->addr_type == 4) { 3178914bffb6SAlexander V. Chernikov struct fhashentry4 f; 3179914bffb6SAlexander V. Chernikov 3180914bffb6SAlexander V. Chernikov /* Copy hash mask */ 3181914bffb6SAlexander V. Chernikov f = *m4; 3182914bffb6SAlexander V. Chernikov 3183914bffb6SAlexander V. Chernikov f.dip.s_addr &= id->dst_ip; 3184914bffb6SAlexander V. Chernikov f.sip.s_addr &= id->src_ip; 3185914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port; 3186914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port; 3187914bffb6SAlexander V. Chernikov f.e.proto &= id->proto; 3188914bffb6SAlexander V. Chernikov hash = hash_flow4(&f, hsize); 3189914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 3190914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) { 3191914bffb6SAlexander V. Chernikov *val = ent->value; 3192914bffb6SAlexander V. Chernikov return (1); 3193914bffb6SAlexander V. Chernikov } 3194914bffb6SAlexander V. Chernikov } 3195914bffb6SAlexander V. Chernikov } else if (id->addr_type == 6) { 3196914bffb6SAlexander V. Chernikov struct fhashentry6 f; 3197914bffb6SAlexander V. Chernikov uint64_t *fp, *idp; 3198914bffb6SAlexander V. Chernikov 3199914bffb6SAlexander V. Chernikov /* Copy hash mask */ 3200914bffb6SAlexander V. Chernikov f = *((struct fhashentry6 *)(m4 + 1)); 3201914bffb6SAlexander V. Chernikov 3202914bffb6SAlexander V. Chernikov /* Handle lack of __u6_addr.__u6_addr64 */ 3203914bffb6SAlexander V. Chernikov fp = (uint64_t *)&f.dip6; 3204914bffb6SAlexander V. Chernikov idp = (uint64_t *)&id->dst_ip6; 3205914bffb6SAlexander V. Chernikov /* src IPv6 is stored after dst IPv6 */ 3206914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 3207914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 3208914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 3209914bffb6SAlexander V. Chernikov *fp &= *idp; 3210914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port; 3211914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port; 3212914bffb6SAlexander V. Chernikov f.e.proto &= id->proto; 3213914bffb6SAlexander V. Chernikov hash = hash_flow6(&f, hsize); 3214914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 3215914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) { 3216914bffb6SAlexander V. Chernikov *val = ent->value; 3217914bffb6SAlexander V. Chernikov return (1); 3218914bffb6SAlexander V. Chernikov } 3219914bffb6SAlexander V. Chernikov } 3220914bffb6SAlexander V. Chernikov } 3221914bffb6SAlexander V. Chernikov 3222914bffb6SAlexander V. Chernikov return (0); 3223914bffb6SAlexander V. Chernikov } 3224914bffb6SAlexander V. Chernikov 3225914bffb6SAlexander V. Chernikov /* 3226914bffb6SAlexander V. Chernikov * New table. 3227914bffb6SAlexander V. Chernikov */ 3228914bffb6SAlexander V. Chernikov static int 3229914bffb6SAlexander V. Chernikov ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 3230914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 3231914bffb6SAlexander V. Chernikov { 3232914bffb6SAlexander V. Chernikov int i; 3233914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3234914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 3235914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 3236914bffb6SAlexander V. Chernikov 3237914bffb6SAlexander V. Chernikov cfg = malloc(sizeof(struct fhash_cfg), M_IPFW, M_WAITOK | M_ZERO); 3238914bffb6SAlexander V. Chernikov 3239914bffb6SAlexander V. Chernikov cfg->size = 512; 3240914bffb6SAlexander V. Chernikov 3241914bffb6SAlexander V. Chernikov cfg->head = malloc(sizeof(struct fhashbhead) * cfg->size, M_IPFW, 3242914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO); 3243914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 3244914bffb6SAlexander V. Chernikov SLIST_INIT(&cfg->head[i]); 3245914bffb6SAlexander V. Chernikov 3246914bffb6SAlexander V. Chernikov /* Fill in fe masks based on @tflags */ 3247914bffb6SAlexander V. Chernikov fe4 = &cfg->fe4; 3248914bffb6SAlexander V. Chernikov fe6 = &cfg->fe6; 3249914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCIP) { 3250914bffb6SAlexander V. Chernikov memset(&fe4->sip, 0xFF, sizeof(fe4->sip)); 3251914bffb6SAlexander V. Chernikov memset(&fe6->sip6, 0xFF, sizeof(fe6->sip6)); 3252914bffb6SAlexander V. Chernikov } 3253914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTIP) { 3254914bffb6SAlexander V. Chernikov memset(&fe4->dip, 0xFF, sizeof(fe4->dip)); 3255914bffb6SAlexander V. Chernikov memset(&fe6->dip6, 0xFF, sizeof(fe6->dip6)); 3256914bffb6SAlexander V. Chernikov } 3257914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCPORT) { 3258914bffb6SAlexander V. Chernikov memset(&fe4->e.sport, 0xFF, sizeof(fe4->e.sport)); 3259914bffb6SAlexander V. Chernikov memset(&fe6->e.sport, 0xFF, sizeof(fe6->e.sport)); 3260914bffb6SAlexander V. Chernikov } 3261914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTPORT) { 3262914bffb6SAlexander V. Chernikov memset(&fe4->e.dport, 0xFF, sizeof(fe4->e.dport)); 3263914bffb6SAlexander V. Chernikov memset(&fe6->e.dport, 0xFF, sizeof(fe6->e.dport)); 3264914bffb6SAlexander V. Chernikov } 3265914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_PROTO) { 3266914bffb6SAlexander V. Chernikov memset(&fe4->e.proto, 0xFF, sizeof(fe4->e.proto)); 3267914bffb6SAlexander V. Chernikov memset(&fe6->e.proto, 0xFF, sizeof(fe6->e.proto)); 3268914bffb6SAlexander V. Chernikov } 3269914bffb6SAlexander V. Chernikov 3270914bffb6SAlexander V. Chernikov fe4->e.af = AF_INET; 3271914bffb6SAlexander V. Chernikov fe6->e.af = AF_INET6; 3272914bffb6SAlexander V. Chernikov 3273914bffb6SAlexander V. Chernikov *ta_state = cfg; 3274914bffb6SAlexander V. Chernikov ti->state = cfg->head; 3275914bffb6SAlexander V. Chernikov ti->xstate = &cfg->fe4; 3276914bffb6SAlexander V. Chernikov ti->data = cfg->size; 3277914bffb6SAlexander V. Chernikov ti->lookup = ta_lookup_fhash; 3278914bffb6SAlexander V. Chernikov 3279914bffb6SAlexander V. Chernikov return (0); 3280914bffb6SAlexander V. Chernikov } 3281914bffb6SAlexander V. Chernikov 3282914bffb6SAlexander V. Chernikov static void 3283914bffb6SAlexander V. Chernikov ta_destroy_fhash(void *ta_state, struct table_info *ti) 3284914bffb6SAlexander V. Chernikov { 3285914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3286914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3287914bffb6SAlexander V. Chernikov int i; 3288914bffb6SAlexander V. Chernikov 3289914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3290914bffb6SAlexander V. Chernikov 3291914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 3292914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) 3293914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL); 3294914bffb6SAlexander V. Chernikov 3295914bffb6SAlexander V. Chernikov free(cfg->head, M_IPFW); 3296914bffb6SAlexander V. Chernikov free(cfg, M_IPFW); 3297914bffb6SAlexander V. Chernikov } 3298914bffb6SAlexander V. Chernikov 32995f379342SAlexander V. Chernikov /* 33005f379342SAlexander V. Chernikov * Provide algo-specific table info 33015f379342SAlexander V. Chernikov */ 33025f379342SAlexander V. Chernikov static void 33035f379342SAlexander V. Chernikov ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 33045f379342SAlexander V. Chernikov { 33055f379342SAlexander V. Chernikov struct fhash_cfg *cfg; 33065f379342SAlexander V. Chernikov 33075f379342SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 33085f379342SAlexander V. Chernikov 33095f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFITEM; 33105f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_HASH; 33115f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 33125f379342SAlexander V. Chernikov tinfo->count4 = cfg->items; 33135f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct fhashentry4); 33145f379342SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct fhashentry6); 33155f379342SAlexander V. Chernikov } 33165f379342SAlexander V. Chernikov 3317914bffb6SAlexander V. Chernikov static int 3318914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e, 3319914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 3320914bffb6SAlexander V. Chernikov { 3321914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3322914bffb6SAlexander V. Chernikov struct fhashentry *ent; 3323914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 3324*9fe15d06SAlexander V. Chernikov #ifdef INET6 3325914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 3326*9fe15d06SAlexander V. Chernikov #endif 3327914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 3328914bffb6SAlexander V. Chernikov 3329914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3330914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)e; 3331914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 3332914bffb6SAlexander V. Chernikov 3333914bffb6SAlexander V. Chernikov tfe->af = ent->af; 3334914bffb6SAlexander V. Chernikov tfe->proto = ent->proto; 3335914bffb6SAlexander V. Chernikov tfe->dport = htons(ent->dport); 3336914bffb6SAlexander V. Chernikov tfe->sport = htons(ent->sport); 33370cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value; 3338914bffb6SAlexander V. Chernikov tent->subtype = ent->af; 3339914bffb6SAlexander V. Chernikov 3340914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) { 3341914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent; 3342914bffb6SAlexander V. Chernikov tfe->a.a4.sip.s_addr = htonl(fe4->sip.s_addr); 3343914bffb6SAlexander V. Chernikov tfe->a.a4.dip.s_addr = htonl(fe4->dip.s_addr); 3344914bffb6SAlexander V. Chernikov tent->masklen = 32; 3345914bffb6SAlexander V. Chernikov #ifdef INET6 3346914bffb6SAlexander V. Chernikov } else { 3347914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent; 3348914bffb6SAlexander V. Chernikov tfe->a.a6.sip6 = fe6->sip6; 3349914bffb6SAlexander V. Chernikov tfe->a.a6.dip6 = fe6->dip6; 3350914bffb6SAlexander V. Chernikov tent->masklen = 128; 3351914bffb6SAlexander V. Chernikov #endif 3352914bffb6SAlexander V. Chernikov } 3353914bffb6SAlexander V. Chernikov 3354914bffb6SAlexander V. Chernikov return (0); 3355914bffb6SAlexander V. Chernikov } 3356914bffb6SAlexander V. Chernikov 3357914bffb6SAlexander V. Chernikov static int 3358914bffb6SAlexander V. Chernikov tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent) 3359914bffb6SAlexander V. Chernikov { 3360914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 3361914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 3362914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 3363914bffb6SAlexander V. Chernikov 3364914bffb6SAlexander V. Chernikov tfe = (struct tflow_entry *)tei->paddr; 3365914bffb6SAlexander V. Chernikov 3366914bffb6SAlexander V. Chernikov ent->af = tei->subtype; 3367914bffb6SAlexander V. Chernikov ent->proto = tfe->proto; 3368914bffb6SAlexander V. Chernikov ent->dport = ntohs(tfe->dport); 3369914bffb6SAlexander V. Chernikov ent->sport = ntohs(tfe->sport); 3370914bffb6SAlexander V. Chernikov 3371914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) { 3372914bffb6SAlexander V. Chernikov #ifdef INET 3373914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent; 3374914bffb6SAlexander V. Chernikov fe4->sip.s_addr = ntohl(tfe->a.a4.sip.s_addr); 3375914bffb6SAlexander V. Chernikov fe4->dip.s_addr = ntohl(tfe->a.a4.dip.s_addr); 3376914bffb6SAlexander V. Chernikov #endif 3377914bffb6SAlexander V. Chernikov #ifdef INET6 3378914bffb6SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 3379914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent; 3380914bffb6SAlexander V. Chernikov fe6->sip6 = tfe->a.a6.sip6; 3381914bffb6SAlexander V. Chernikov fe6->dip6 = tfe->a.a6.dip6; 3382914bffb6SAlexander V. Chernikov #endif 3383914bffb6SAlexander V. Chernikov } else { 3384914bffb6SAlexander V. Chernikov /* Unknown CIDR type */ 3385914bffb6SAlexander V. Chernikov return (EINVAL); 3386914bffb6SAlexander V. Chernikov } 3387914bffb6SAlexander V. Chernikov 3388914bffb6SAlexander V. Chernikov return (0); 3389914bffb6SAlexander V. Chernikov } 3390914bffb6SAlexander V. Chernikov 3391914bffb6SAlexander V. Chernikov 3392914bffb6SAlexander V. Chernikov static int 3393914bffb6SAlexander V. Chernikov ta_find_fhash_tentry(void *ta_state, struct table_info *ti, 3394914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 3395914bffb6SAlexander V. Chernikov { 3396914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3397914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3398914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3399914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 3400914bffb6SAlexander V. Chernikov struct tentry_info tei; 3401914bffb6SAlexander V. Chernikov int error; 3402914bffb6SAlexander V. Chernikov uint32_t hash; 3403914bffb6SAlexander V. Chernikov size_t sz; 3404914bffb6SAlexander V. Chernikov 3405914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3406914bffb6SAlexander V. Chernikov 3407914bffb6SAlexander V. Chernikov ent = &fe6.e; 3408914bffb6SAlexander V. Chernikov 3409914bffb6SAlexander V. Chernikov memset(&fe6, 0, sizeof(fe6)); 3410914bffb6SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 3411914bffb6SAlexander V. Chernikov 3412914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.flow; 3413914bffb6SAlexander V. Chernikov tei.subtype = tent->subtype; 3414914bffb6SAlexander V. Chernikov 3415914bffb6SAlexander V. Chernikov if ((error = tei_to_fhash_ent(&tei, ent)) != 0) 3416914bffb6SAlexander V. Chernikov return (error); 3417914bffb6SAlexander V. Chernikov 3418914bffb6SAlexander V. Chernikov head = cfg->head; 3419914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3420914bffb6SAlexander V. Chernikov 3421914bffb6SAlexander V. Chernikov if (tei.subtype == AF_INET) 3422914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3423914bffb6SAlexander V. Chernikov else 3424914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3425914bffb6SAlexander V. Chernikov 3426914bffb6SAlexander V. Chernikov /* Check for existence */ 3427914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3428914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 3429914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(ta_state, ti, tmp, tent); 3430914bffb6SAlexander V. Chernikov return (0); 3431914bffb6SAlexander V. Chernikov } 3432914bffb6SAlexander V. Chernikov } 3433914bffb6SAlexander V. Chernikov 3434914bffb6SAlexander V. Chernikov return (ENOENT); 3435914bffb6SAlexander V. Chernikov } 3436914bffb6SAlexander V. Chernikov 3437914bffb6SAlexander V. Chernikov static void 3438914bffb6SAlexander V. Chernikov ta_foreach_fhash(void *ta_state, struct table_info *ti, ta_foreach_f *f, 3439914bffb6SAlexander V. Chernikov void *arg) 3440914bffb6SAlexander V. Chernikov { 3441914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3442914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3443914bffb6SAlexander V. Chernikov int i; 3444914bffb6SAlexander V. Chernikov 3445914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3446914bffb6SAlexander V. Chernikov 3447914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 3448914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) 3449914bffb6SAlexander V. Chernikov f(ent, arg); 3450914bffb6SAlexander V. Chernikov } 3451914bffb6SAlexander V. Chernikov 3452914bffb6SAlexander V. Chernikov static int 3453914bffb6SAlexander V. Chernikov ta_prepare_add_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 3454914bffb6SAlexander V. Chernikov void *ta_buf) 3455914bffb6SAlexander V. Chernikov { 3456914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3457914bffb6SAlexander V. Chernikov struct fhashentry *ent; 3458914bffb6SAlexander V. Chernikov size_t sz; 3459914bffb6SAlexander V. Chernikov int error; 3460914bffb6SAlexander V. Chernikov 3461914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3462914bffb6SAlexander V. Chernikov 3463914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3464914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry4); 3465914bffb6SAlexander V. Chernikov else if (tei->subtype == AF_INET6) 3466914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry6); 3467914bffb6SAlexander V. Chernikov else 3468914bffb6SAlexander V. Chernikov return (EINVAL); 3469914bffb6SAlexander V. Chernikov 3470914bffb6SAlexander V. Chernikov ent = malloc(sz, M_IPFW_TBL, M_WAITOK | M_ZERO); 3471914bffb6SAlexander V. Chernikov 3472914bffb6SAlexander V. Chernikov error = tei_to_fhash_ent(tei, ent); 3473914bffb6SAlexander V. Chernikov if (error != 0) { 3474914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL); 3475914bffb6SAlexander V. Chernikov return (error); 3476914bffb6SAlexander V. Chernikov } 3477914bffb6SAlexander V. Chernikov tb->ent_ptr = ent; 3478914bffb6SAlexander V. Chernikov 3479914bffb6SAlexander V. Chernikov return (0); 3480914bffb6SAlexander V. Chernikov } 3481914bffb6SAlexander V. Chernikov 3482914bffb6SAlexander V. Chernikov static int 3483914bffb6SAlexander V. Chernikov ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 3484b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 3485914bffb6SAlexander V. Chernikov { 3486914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3487914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3488914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3489914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3490914bffb6SAlexander V. Chernikov int exists; 3491648e8380SAlexander V. Chernikov uint32_t hash, value; 3492914bffb6SAlexander V. Chernikov size_t sz; 3493914bffb6SAlexander V. Chernikov 3494914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3495914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3496914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)tb->ent_ptr; 3497914bffb6SAlexander V. Chernikov exists = 0; 3498914bffb6SAlexander V. Chernikov 349913263632SAlexander V. Chernikov /* Read current value from @tei */ 350013263632SAlexander V. Chernikov ent->value = tei->value; 350113263632SAlexander V. Chernikov 3502914bffb6SAlexander V. Chernikov head = cfg->head; 3503914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3504914bffb6SAlexander V. Chernikov 3505914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3506914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3507914bffb6SAlexander V. Chernikov else 3508914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3509914bffb6SAlexander V. Chernikov 3510914bffb6SAlexander V. Chernikov /* Check for existence */ 3511914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3512914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 3513914bffb6SAlexander V. Chernikov exists = 1; 3514914bffb6SAlexander V. Chernikov break; 3515914bffb6SAlexander V. Chernikov } 3516914bffb6SAlexander V. Chernikov } 3517914bffb6SAlexander V. Chernikov 3518914bffb6SAlexander V. Chernikov if (exists == 1) { 3519914bffb6SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 3520914bffb6SAlexander V. Chernikov return (EEXIST); 3521914bffb6SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 3522648e8380SAlexander V. Chernikov /* Exchange values between tmp and @tei */ 3523648e8380SAlexander V. Chernikov value = tmp->value; 3524914bffb6SAlexander V. Chernikov tmp->value = tei->value; 3525648e8380SAlexander V. Chernikov tei->value = value; 3526914bffb6SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 3527914bffb6SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 3528914bffb6SAlexander V. Chernikov *pnum = 0; 3529914bffb6SAlexander V. Chernikov } else { 35304c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 35314c0c07a5SAlexander V. Chernikov return (EFBIG); 35324c0c07a5SAlexander V. Chernikov 3533914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next); 3534914bffb6SAlexander V. Chernikov tb->ent_ptr = NULL; 3535914bffb6SAlexander V. Chernikov *pnum = 1; 3536914bffb6SAlexander V. Chernikov 3537914bffb6SAlexander V. Chernikov /* Update counters and check if we need to grow hash */ 3538914bffb6SAlexander V. Chernikov cfg->items++; 3539914bffb6SAlexander V. Chernikov } 3540914bffb6SAlexander V. Chernikov 3541914bffb6SAlexander V. Chernikov return (0); 3542914bffb6SAlexander V. Chernikov } 3543914bffb6SAlexander V. Chernikov 3544914bffb6SAlexander V. Chernikov static int 3545914bffb6SAlexander V. Chernikov ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 3546914bffb6SAlexander V. Chernikov void *ta_buf) 3547914bffb6SAlexander V. Chernikov { 3548914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3549914bffb6SAlexander V. Chernikov 3550914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3551914bffb6SAlexander V. Chernikov 3552914bffb6SAlexander V. Chernikov return (tei_to_fhash_ent(tei, &tb->fe6.e)); 3553914bffb6SAlexander V. Chernikov } 3554914bffb6SAlexander V. Chernikov 3555914bffb6SAlexander V. Chernikov static int 3556914bffb6SAlexander V. Chernikov ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 3557b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 3558914bffb6SAlexander V. Chernikov { 3559914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3560914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3561914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3562914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3563914bffb6SAlexander V. Chernikov uint32_t hash; 3564914bffb6SAlexander V. Chernikov size_t sz; 3565914bffb6SAlexander V. Chernikov 3566914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3567914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3568914bffb6SAlexander V. Chernikov ent = &tb->fe6.e; 3569914bffb6SAlexander V. Chernikov 3570914bffb6SAlexander V. Chernikov head = cfg->head; 3571914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3572914bffb6SAlexander V. Chernikov 3573914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3574914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3575914bffb6SAlexander V. Chernikov else 3576914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3577914bffb6SAlexander V. Chernikov 3578914bffb6SAlexander V. Chernikov /* Check for existence */ 3579914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3580648e8380SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) == 0) 3581648e8380SAlexander V. Chernikov continue; 3582648e8380SAlexander V. Chernikov 3583914bffb6SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, fhashentry, next); 3584648e8380SAlexander V. Chernikov tei->value = tmp->value; 3585914bffb6SAlexander V. Chernikov *pnum = 1; 3586914bffb6SAlexander V. Chernikov cfg->items--; 3587648e8380SAlexander V. Chernikov tb->ent_ptr = tmp; 3588914bffb6SAlexander V. Chernikov return (0); 3589914bffb6SAlexander V. Chernikov } 3590914bffb6SAlexander V. Chernikov 3591914bffb6SAlexander V. Chernikov return (ENOENT); 3592914bffb6SAlexander V. Chernikov } 3593914bffb6SAlexander V. Chernikov 3594914bffb6SAlexander V. Chernikov static void 3595914bffb6SAlexander V. Chernikov ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 3596914bffb6SAlexander V. Chernikov void *ta_buf) 3597914bffb6SAlexander V. Chernikov { 3598914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3599914bffb6SAlexander V. Chernikov 3600914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3601914bffb6SAlexander V. Chernikov 3602914bffb6SAlexander V. Chernikov if (tb->ent_ptr != NULL) 3603914bffb6SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 3604914bffb6SAlexander V. Chernikov } 3605914bffb6SAlexander V. Chernikov 3606914bffb6SAlexander V. Chernikov /* 3607914bffb6SAlexander V. Chernikov * Hash growing callbacks. 3608914bffb6SAlexander V. Chernikov */ 3609914bffb6SAlexander V. Chernikov 3610b6ee846eSAlexander V. Chernikov static int 3611301290bcSAlexander V. Chernikov ta_need_modify_fhash(void *ta_state, struct table_info *ti, uint32_t count, 3612b6ee846eSAlexander V. Chernikov uint64_t *pflags) 3613b6ee846eSAlexander V. Chernikov { 3614b6ee846eSAlexander V. Chernikov struct fhash_cfg *cfg; 3615b6ee846eSAlexander V. Chernikov 3616b6ee846eSAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3617b6ee846eSAlexander V. Chernikov 3618b6ee846eSAlexander V. Chernikov if (cfg->items > cfg->size && cfg->size < 65536) { 3619b6ee846eSAlexander V. Chernikov *pflags = cfg->size * 2; 3620301290bcSAlexander V. Chernikov return (1); 3621b6ee846eSAlexander V. Chernikov } 3622b6ee846eSAlexander V. Chernikov 3623301290bcSAlexander V. Chernikov return (0); 3624b6ee846eSAlexander V. Chernikov } 3625b6ee846eSAlexander V. Chernikov 3626914bffb6SAlexander V. Chernikov /* 3627914bffb6SAlexander V. Chernikov * Allocate new, larger fhash. 3628914bffb6SAlexander V. Chernikov */ 3629914bffb6SAlexander V. Chernikov static int 3630914bffb6SAlexander V. Chernikov ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags) 3631914bffb6SAlexander V. Chernikov { 3632914bffb6SAlexander V. Chernikov struct mod_item *mi; 3633914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3634914bffb6SAlexander V. Chernikov int i; 3635914bffb6SAlexander V. Chernikov 3636914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3637914bffb6SAlexander V. Chernikov 3638914bffb6SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 3639914bffb6SAlexander V. Chernikov mi->size = *pflags; 3640914bffb6SAlexander V. Chernikov head = malloc(sizeof(struct fhashbhead) * mi->size, M_IPFW, 3641914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO); 3642914bffb6SAlexander V. Chernikov for (i = 0; i < mi->size; i++) 3643914bffb6SAlexander V. Chernikov SLIST_INIT(&head[i]); 3644914bffb6SAlexander V. Chernikov 3645914bffb6SAlexander V. Chernikov mi->main_ptr = head; 3646914bffb6SAlexander V. Chernikov 3647914bffb6SAlexander V. Chernikov return (0); 3648914bffb6SAlexander V. Chernikov } 3649914bffb6SAlexander V. Chernikov 3650914bffb6SAlexander V. Chernikov /* 3651914bffb6SAlexander V. Chernikov * Copy data from old runtime array to new one. 3652914bffb6SAlexander V. Chernikov */ 3653914bffb6SAlexander V. Chernikov static int 3654914bffb6SAlexander V. Chernikov ta_fill_mod_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3655914bffb6SAlexander V. Chernikov uint64_t *pflags) 3656914bffb6SAlexander V. Chernikov { 3657914bffb6SAlexander V. Chernikov 3658914bffb6SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */ 3659914bffb6SAlexander V. Chernikov return (0); 3660914bffb6SAlexander V. Chernikov } 3661914bffb6SAlexander V. Chernikov 3662914bffb6SAlexander V. Chernikov /* 3663914bffb6SAlexander V. Chernikov * Switch old & new arrays. 3664914bffb6SAlexander V. Chernikov */ 3665301290bcSAlexander V. Chernikov static void 3666914bffb6SAlexander V. Chernikov ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3667914bffb6SAlexander V. Chernikov uint64_t pflags) 3668914bffb6SAlexander V. Chernikov { 3669914bffb6SAlexander V. Chernikov struct mod_item *mi; 3670914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3671914bffb6SAlexander V. Chernikov struct fhashbhead *old_head, *new_head; 3672914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3673914bffb6SAlexander V. Chernikov int i; 3674914bffb6SAlexander V. Chernikov uint32_t nhash; 3675914bffb6SAlexander V. Chernikov size_t old_size; 3676914bffb6SAlexander V. Chernikov 3677914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3678914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3679914bffb6SAlexander V. Chernikov 3680914bffb6SAlexander V. Chernikov old_size = cfg->size; 3681914bffb6SAlexander V. Chernikov old_head = ti->state; 3682914bffb6SAlexander V. Chernikov 3683914bffb6SAlexander V. Chernikov new_head = (struct fhashbhead *)mi->main_ptr; 3684914bffb6SAlexander V. Chernikov for (i = 0; i < old_size; i++) { 3685914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 3686914bffb6SAlexander V. Chernikov nhash = hash_flow_ent(ent, mi->size); 3687914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 3688914bffb6SAlexander V. Chernikov } 3689914bffb6SAlexander V. Chernikov } 3690914bffb6SAlexander V. Chernikov 3691914bffb6SAlexander V. Chernikov ti->state = new_head; 3692914bffb6SAlexander V. Chernikov ti->data = mi->size; 3693914bffb6SAlexander V. Chernikov cfg->head = new_head; 3694914bffb6SAlexander V. Chernikov cfg->size = mi->size; 3695914bffb6SAlexander V. Chernikov 3696914bffb6SAlexander V. Chernikov mi->main_ptr = old_head; 3697914bffb6SAlexander V. Chernikov } 3698914bffb6SAlexander V. Chernikov 3699914bffb6SAlexander V. Chernikov /* 3700914bffb6SAlexander V. Chernikov * Free unneded array. 3701914bffb6SAlexander V. Chernikov */ 3702914bffb6SAlexander V. Chernikov static void 3703914bffb6SAlexander V. Chernikov ta_flush_mod_fhash(void *ta_buf) 3704914bffb6SAlexander V. Chernikov { 3705914bffb6SAlexander V. Chernikov struct mod_item *mi; 3706914bffb6SAlexander V. Chernikov 3707914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3708914bffb6SAlexander V. Chernikov if (mi->main_ptr != NULL) 3709914bffb6SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 3710914bffb6SAlexander V. Chernikov } 3711914bffb6SAlexander V. Chernikov 3712914bffb6SAlexander V. Chernikov struct table_algo flow_hash = { 3713914bffb6SAlexander V. Chernikov .name = "flow:hash", 3714914bffb6SAlexander V. Chernikov .type = IPFW_TABLE_FLOW, 371557a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 371657a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_fhash), 3717914bffb6SAlexander V. Chernikov .init = ta_init_fhash, 3718914bffb6SAlexander V. Chernikov .destroy = ta_destroy_fhash, 3719914bffb6SAlexander V. Chernikov .prepare_add = ta_prepare_add_fhash, 3720914bffb6SAlexander V. Chernikov .prepare_del = ta_prepare_del_fhash, 3721914bffb6SAlexander V. Chernikov .add = ta_add_fhash, 3722914bffb6SAlexander V. Chernikov .del = ta_del_fhash, 3723914bffb6SAlexander V. Chernikov .flush_entry = ta_flush_fhash_entry, 3724914bffb6SAlexander V. Chernikov .foreach = ta_foreach_fhash, 3725914bffb6SAlexander V. Chernikov .dump_tentry = ta_dump_fhash_tentry, 3726914bffb6SAlexander V. Chernikov .find_tentry = ta_find_fhash_tentry, 37275f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_fhash_tinfo, 3728301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_fhash, 3729914bffb6SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_fhash, 3730914bffb6SAlexander V. Chernikov .fill_mod = ta_fill_mod_fhash, 3731914bffb6SAlexander V. Chernikov .modify = ta_modify_fhash, 3732914bffb6SAlexander V. Chernikov .flush_mod = ta_flush_mod_fhash, 3733914bffb6SAlexander V. Chernikov }; 37343fe2ef91SAlexander V. Chernikov 3735d3b00c08SAlexander V. Chernikov /* 3736d3b00c08SAlexander V. Chernikov * Kernel fibs bindings. 3737d3b00c08SAlexander V. Chernikov * 3738d3b00c08SAlexander V. Chernikov * Implementation: 3739d3b00c08SAlexander V. Chernikov * 3740d3b00c08SAlexander V. Chernikov * Runtime part: 3741d3b00c08SAlexander V. Chernikov * - fully relies on route API 3742d3b00c08SAlexander V. Chernikov * - fib number is stored in ti->data 3743d3b00c08SAlexander V. Chernikov * 3744d3b00c08SAlexander V. Chernikov */ 3745d3b00c08SAlexander V. Chernikov 3746*9fe15d06SAlexander V. Chernikov static struct rtentry *lookup_kfib(void *key, int keylen, int fib); 3747*9fe15d06SAlexander V. Chernikov static int ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen, 3748*9fe15d06SAlexander V. Chernikov uint32_t *val); 3749*9fe15d06SAlexander V. Chernikov static int kfib_parse_opts(int *pfib, char *data); 3750*9fe15d06SAlexander V. Chernikov static void ta_print_kfib_config(void *ta_state, struct table_info *ti, 3751*9fe15d06SAlexander V. Chernikov char *buf, size_t bufsize); 3752*9fe15d06SAlexander V. Chernikov static int ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, 3753*9fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 3754*9fe15d06SAlexander V. Chernikov static void ta_destroy_kfib(void *ta_state, struct table_info *ti); 3755*9fe15d06SAlexander V. Chernikov static void ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, 3756*9fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 3757*9fe15d06SAlexander V. Chernikov static int contigmask(uint8_t *p, int len); 3758*9fe15d06SAlexander V. Chernikov static int ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e, 3759*9fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 3760*9fe15d06SAlexander V. Chernikov static int ta_find_kfib_tentry(void *ta_state, struct table_info *ti, 3761*9fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 3762*9fe15d06SAlexander V. Chernikov static void ta_foreach_kfib(void *ta_state, struct table_info *ti, 3763*9fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 3764*9fe15d06SAlexander V. Chernikov 3765d3b00c08SAlexander V. Chernikov static struct rtentry * 3766d3b00c08SAlexander V. Chernikov lookup_kfib(void *key, int keylen, int fib) 3767d3b00c08SAlexander V. Chernikov { 3768d3b00c08SAlexander V. Chernikov struct sockaddr *s; 3769d3b00c08SAlexander V. Chernikov 3770d3b00c08SAlexander V. Chernikov if (keylen == 4) { 3771d3b00c08SAlexander V. Chernikov struct sockaddr_in sin; 3772d3b00c08SAlexander V. Chernikov bzero(&sin, sizeof(sin)); 3773d3b00c08SAlexander V. Chernikov sin.sin_len = sizeof(struct sockaddr_in); 3774d3b00c08SAlexander V. Chernikov sin.sin_family = AF_INET; 3775d3b00c08SAlexander V. Chernikov sin.sin_addr.s_addr = *(in_addr_t *)key; 3776d3b00c08SAlexander V. Chernikov s = (struct sockaddr *)&sin; 3777d3b00c08SAlexander V. Chernikov } else { 3778d3b00c08SAlexander V. Chernikov struct sockaddr_in6 sin6; 3779d3b00c08SAlexander V. Chernikov bzero(&sin6, sizeof(sin6)); 3780d3b00c08SAlexander V. Chernikov sin6.sin6_len = sizeof(struct sockaddr_in6); 3781d3b00c08SAlexander V. Chernikov sin6.sin6_family = AF_INET6; 3782d3b00c08SAlexander V. Chernikov sin6.sin6_addr = *(struct in6_addr *)key; 3783d3b00c08SAlexander V. Chernikov s = (struct sockaddr *)&sin6; 3784d3b00c08SAlexander V. Chernikov } 3785d3b00c08SAlexander V. Chernikov 3786d3b00c08SAlexander V. Chernikov return (rtalloc1_fib(s, 0, 0, fib)); 3787d3b00c08SAlexander V. Chernikov } 3788d3b00c08SAlexander V. Chernikov 3789d3b00c08SAlexander V. Chernikov static int 3790d3b00c08SAlexander V. Chernikov ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen, 3791d3b00c08SAlexander V. Chernikov uint32_t *val) 3792d3b00c08SAlexander V. Chernikov { 3793d3b00c08SAlexander V. Chernikov struct rtentry *rte; 3794d3b00c08SAlexander V. Chernikov 3795d3b00c08SAlexander V. Chernikov if ((rte = lookup_kfib(key, keylen, ti->data)) == NULL) 3796d3b00c08SAlexander V. Chernikov return (0); 3797d3b00c08SAlexander V. Chernikov 3798d3b00c08SAlexander V. Chernikov *val = 0; 3799d3b00c08SAlexander V. Chernikov RTFREE_LOCKED(rte); 3800d3b00c08SAlexander V. Chernikov 3801d3b00c08SAlexander V. Chernikov return (1); 3802d3b00c08SAlexander V. Chernikov } 3803d3b00c08SAlexander V. Chernikov 3804d3b00c08SAlexander V. Chernikov /* Parse 'fib=%d' */ 3805d3b00c08SAlexander V. Chernikov static int 3806d3b00c08SAlexander V. Chernikov kfib_parse_opts(int *pfib, char *data) 3807d3b00c08SAlexander V. Chernikov { 3808d3b00c08SAlexander V. Chernikov char *pdel, *pend, *s; 3809d3b00c08SAlexander V. Chernikov int fibnum; 3810d3b00c08SAlexander V. Chernikov 3811d3b00c08SAlexander V. Chernikov if (data == NULL) 3812d3b00c08SAlexander V. Chernikov return (0); 3813d3b00c08SAlexander V. Chernikov if ((pdel = strchr(data, ' ')) == NULL) 3814d3b00c08SAlexander V. Chernikov return (0); 3815d3b00c08SAlexander V. Chernikov while (*pdel == ' ') 3816d3b00c08SAlexander V. Chernikov pdel++; 3817d3b00c08SAlexander V. Chernikov if (strncmp(pdel, "fib=", 4) != 0) 3818d3b00c08SAlexander V. Chernikov return (EINVAL); 3819d3b00c08SAlexander V. Chernikov if ((s = strchr(pdel, ' ')) != NULL) 3820d3b00c08SAlexander V. Chernikov *s++ = '\0'; 3821d3b00c08SAlexander V. Chernikov 3822d3b00c08SAlexander V. Chernikov pdel += 4; 3823d3b00c08SAlexander V. Chernikov /* Need \d+ */ 3824d3b00c08SAlexander V. Chernikov fibnum = strtol(pdel, &pend, 10); 3825d3b00c08SAlexander V. Chernikov if (*pend != '\0') 3826d3b00c08SAlexander V. Chernikov return (EINVAL); 3827d3b00c08SAlexander V. Chernikov 3828d3b00c08SAlexander V. Chernikov *pfib = fibnum; 3829d3b00c08SAlexander V. Chernikov 3830d3b00c08SAlexander V. Chernikov return (0); 3831d3b00c08SAlexander V. Chernikov } 3832d3b00c08SAlexander V. Chernikov 3833d3b00c08SAlexander V. Chernikov static void 3834d3b00c08SAlexander V. Chernikov ta_print_kfib_config(void *ta_state, struct table_info *ti, char *buf, 3835d3b00c08SAlexander V. Chernikov size_t bufsize) 3836d3b00c08SAlexander V. Chernikov { 3837d3b00c08SAlexander V. Chernikov 3838d3b00c08SAlexander V. Chernikov if (ti->data != 0) 3839c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s fib=%lu", "addr:kfib", ti->data); 3840d3b00c08SAlexander V. Chernikov else 3841c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s", "addr:kfib"); 3842d3b00c08SAlexander V. Chernikov } 3843d3b00c08SAlexander V. Chernikov 3844d3b00c08SAlexander V. Chernikov static int 3845d3b00c08SAlexander V. Chernikov ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 3846d3b00c08SAlexander V. Chernikov char *data, uint8_t tflags) 3847d3b00c08SAlexander V. Chernikov { 3848d3b00c08SAlexander V. Chernikov int error, fibnum; 3849d3b00c08SAlexander V. Chernikov 3850d3b00c08SAlexander V. Chernikov fibnum = 0; 3851d3b00c08SAlexander V. Chernikov if ((error = kfib_parse_opts(&fibnum, data)) != 0) 3852d3b00c08SAlexander V. Chernikov return (error); 3853d3b00c08SAlexander V. Chernikov 3854d3b00c08SAlexander V. Chernikov if (fibnum >= rt_numfibs) 3855d3b00c08SAlexander V. Chernikov return (E2BIG); 3856d3b00c08SAlexander V. Chernikov 3857d3b00c08SAlexander V. Chernikov ti->data = fibnum; 3858d3b00c08SAlexander V. Chernikov ti->lookup = ta_lookup_kfib; 3859d3b00c08SAlexander V. Chernikov 3860d3b00c08SAlexander V. Chernikov return (0); 3861d3b00c08SAlexander V. Chernikov } 3862d3b00c08SAlexander V. Chernikov 3863d3b00c08SAlexander V. Chernikov /* 3864d3b00c08SAlexander V. Chernikov * Destroys table @ti 3865d3b00c08SAlexander V. Chernikov */ 3866d3b00c08SAlexander V. Chernikov static void 3867d3b00c08SAlexander V. Chernikov ta_destroy_kfib(void *ta_state, struct table_info *ti) 3868d3b00c08SAlexander V. Chernikov { 3869d3b00c08SAlexander V. Chernikov 3870d3b00c08SAlexander V. Chernikov } 3871d3b00c08SAlexander V. Chernikov 3872d3b00c08SAlexander V. Chernikov /* 3873d3b00c08SAlexander V. Chernikov * Provide algo-specific table info 3874d3b00c08SAlexander V. Chernikov */ 3875d3b00c08SAlexander V. Chernikov static void 3876d3b00c08SAlexander V. Chernikov ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 3877d3b00c08SAlexander V. Chernikov { 3878d3b00c08SAlexander V. Chernikov 3879d3b00c08SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA; 3880d3b00c08SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_RADIX; 3881d3b00c08SAlexander V. Chernikov tinfo->count4 = 0; 3882d3b00c08SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct rtentry); 3883d3b00c08SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_RADIX; 3884d3b00c08SAlexander V. Chernikov tinfo->count6 = 0; 3885d3b00c08SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct rtentry); 3886d3b00c08SAlexander V. Chernikov } 3887d3b00c08SAlexander V. Chernikov 3888d3b00c08SAlexander V. Chernikov static int 3889d3b00c08SAlexander V. Chernikov contigmask(uint8_t *p, int len) 3890d3b00c08SAlexander V. Chernikov { 3891d3b00c08SAlexander V. Chernikov int i, n; 3892d3b00c08SAlexander V. Chernikov 3893d3b00c08SAlexander V. Chernikov for (i = 0; i < len ; i++) 3894d3b00c08SAlexander V. Chernikov if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 3895d3b00c08SAlexander V. Chernikov break; 3896d3b00c08SAlexander V. Chernikov for (n= i + 1; n < len; n++) 3897d3b00c08SAlexander V. Chernikov if ( (p[n/8] & (1 << (7 - (n % 8)))) != 0) 3898d3b00c08SAlexander V. Chernikov return (-1); /* mask not contiguous */ 3899d3b00c08SAlexander V. Chernikov return (i); 3900d3b00c08SAlexander V. Chernikov } 3901d3b00c08SAlexander V. Chernikov 3902d3b00c08SAlexander V. Chernikov 3903d3b00c08SAlexander V. Chernikov static int 3904d3b00c08SAlexander V. Chernikov ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e, 3905d3b00c08SAlexander V. Chernikov ipfw_obj_tentry *tent) 3906d3b00c08SAlexander V. Chernikov { 3907d3b00c08SAlexander V. Chernikov struct rtentry *rte; 3908d3b00c08SAlexander V. Chernikov struct sockaddr_in *addr, *mask; 3909d3b00c08SAlexander V. Chernikov struct sockaddr_in6 *addr6, *mask6; 3910d3b00c08SAlexander V. Chernikov int len; 3911d3b00c08SAlexander V. Chernikov 3912d3b00c08SAlexander V. Chernikov rte = (struct rtentry *)e; 3913d3b00c08SAlexander V. Chernikov addr = (struct sockaddr_in *)rt_key(rte); 3914d3b00c08SAlexander V. Chernikov mask = (struct sockaddr_in *)rt_mask(rte); 3915d3b00c08SAlexander V. Chernikov len = 0; 3916d3b00c08SAlexander V. Chernikov 3917d3b00c08SAlexander V. Chernikov /* Guess IPv4/IPv6 radix by sockaddr family */ 3918d3b00c08SAlexander V. Chernikov if (addr->sin_family == AF_INET) { 3919d3b00c08SAlexander V. Chernikov tent->k.addr.s_addr = addr->sin_addr.s_addr; 3920d3b00c08SAlexander V. Chernikov len = 32; 3921d3b00c08SAlexander V. Chernikov if (mask != NULL) 3922d3b00c08SAlexander V. Chernikov len = contigmask((uint8_t *)&mask->sin_addr, 32); 3923d3b00c08SAlexander V. Chernikov if (len == -1) 3924d3b00c08SAlexander V. Chernikov len = 0; 3925d3b00c08SAlexander V. Chernikov tent->masklen = len; 3926d3b00c08SAlexander V. Chernikov tent->subtype = AF_INET; 39270cba2b28SAlexander V. Chernikov tent->v.kidx = 0; /* Do we need to put GW here? */ 3928d3b00c08SAlexander V. Chernikov #ifdef INET6 3929d3b00c08SAlexander V. Chernikov } else if (addr->sin_family == AF_INET6) { 3930d3b00c08SAlexander V. Chernikov addr6 = (struct sockaddr_in6 *)addr; 3931d3b00c08SAlexander V. Chernikov mask6 = (struct sockaddr_in6 *)mask; 3932d3b00c08SAlexander V. Chernikov memcpy(&tent->k, &addr6->sin6_addr, sizeof(struct in6_addr)); 3933d3b00c08SAlexander V. Chernikov len = 128; 3934d3b00c08SAlexander V. Chernikov if (mask6 != NULL) 3935d3b00c08SAlexander V. Chernikov len = contigmask((uint8_t *)&mask6->sin6_addr, 128); 3936d3b00c08SAlexander V. Chernikov if (len == -1) 3937d3b00c08SAlexander V. Chernikov len = 0; 3938d3b00c08SAlexander V. Chernikov tent->masklen = len; 3939d3b00c08SAlexander V. Chernikov tent->subtype = AF_INET6; 39400cba2b28SAlexander V. Chernikov tent->v.kidx = 0; 3941d3b00c08SAlexander V. Chernikov #endif 3942d3b00c08SAlexander V. Chernikov } 3943d3b00c08SAlexander V. Chernikov 3944d3b00c08SAlexander V. Chernikov return (0); 3945d3b00c08SAlexander V. Chernikov } 3946d3b00c08SAlexander V. Chernikov 3947d3b00c08SAlexander V. Chernikov static int 3948d3b00c08SAlexander V. Chernikov ta_find_kfib_tentry(void *ta_state, struct table_info *ti, 3949d3b00c08SAlexander V. Chernikov ipfw_obj_tentry *tent) 3950d3b00c08SAlexander V. Chernikov { 3951d3b00c08SAlexander V. Chernikov struct rtentry *rte; 3952d3b00c08SAlexander V. Chernikov void *key; 3953d3b00c08SAlexander V. Chernikov int keylen; 3954d3b00c08SAlexander V. Chernikov 3955d3b00c08SAlexander V. Chernikov if (tent->subtype == AF_INET) { 3956d3b00c08SAlexander V. Chernikov key = &tent->k.addr; 3957d3b00c08SAlexander V. Chernikov keylen = sizeof(struct in_addr); 3958d3b00c08SAlexander V. Chernikov } else { 3959d3b00c08SAlexander V. Chernikov key = &tent->k.addr6; 3960d3b00c08SAlexander V. Chernikov keylen = sizeof(struct in6_addr); 3961d3b00c08SAlexander V. Chernikov } 3962d3b00c08SAlexander V. Chernikov 3963d3b00c08SAlexander V. Chernikov if ((rte = lookup_kfib(key, keylen, ti->data)) == NULL) 3964d3b00c08SAlexander V. Chernikov return (0); 3965d3b00c08SAlexander V. Chernikov 3966d3b00c08SAlexander V. Chernikov if (rte != NULL) { 3967d3b00c08SAlexander V. Chernikov ta_dump_kfib_tentry(ta_state, ti, rte, tent); 3968d3b00c08SAlexander V. Chernikov RTFREE_LOCKED(rte); 3969d3b00c08SAlexander V. Chernikov return (0); 3970d3b00c08SAlexander V. Chernikov } 3971d3b00c08SAlexander V. Chernikov 3972d3b00c08SAlexander V. Chernikov return (ENOENT); 3973d3b00c08SAlexander V. Chernikov } 3974d3b00c08SAlexander V. Chernikov 3975d3b00c08SAlexander V. Chernikov static void 3976d3b00c08SAlexander V. Chernikov ta_foreach_kfib(void *ta_state, struct table_info *ti, ta_foreach_f *f, 3977d3b00c08SAlexander V. Chernikov void *arg) 3978d3b00c08SAlexander V. Chernikov { 3979d3b00c08SAlexander V. Chernikov struct radix_node_head *rnh; 3980d3b00c08SAlexander V. Chernikov int error; 3981d3b00c08SAlexander V. Chernikov 3982d3b00c08SAlexander V. Chernikov rnh = rt_tables_get_rnh(ti->data, AF_INET); 3983d3b00c08SAlexander V. Chernikov if (rnh != NULL) { 3984d3b00c08SAlexander V. Chernikov RADIX_NODE_HEAD_RLOCK(rnh); 3985d3b00c08SAlexander V. Chernikov error = rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 3986d3b00c08SAlexander V. Chernikov RADIX_NODE_HEAD_RUNLOCK(rnh); 3987d3b00c08SAlexander V. Chernikov } 3988d3b00c08SAlexander V. Chernikov 3989d3b00c08SAlexander V. Chernikov rnh = rt_tables_get_rnh(ti->data, AF_INET6); 3990d3b00c08SAlexander V. Chernikov if (rnh != NULL) { 3991d3b00c08SAlexander V. Chernikov RADIX_NODE_HEAD_RLOCK(rnh); 3992d3b00c08SAlexander V. Chernikov error = rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 3993d3b00c08SAlexander V. Chernikov RADIX_NODE_HEAD_RUNLOCK(rnh); 3994d3b00c08SAlexander V. Chernikov } 3995d3b00c08SAlexander V. Chernikov } 3996d3b00c08SAlexander V. Chernikov 3997c21034b7SAlexander V. Chernikov struct table_algo addr_kfib = { 3998c21034b7SAlexander V. Chernikov .name = "addr:kfib", 3999c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR, 4000d3b00c08SAlexander V. Chernikov .flags = TA_FLAG_READONLY, 4001d3b00c08SAlexander V. Chernikov .ta_buf_size = 0, 4002d3b00c08SAlexander V. Chernikov .init = ta_init_kfib, 4003d3b00c08SAlexander V. Chernikov .destroy = ta_destroy_kfib, 4004d3b00c08SAlexander V. Chernikov .foreach = ta_foreach_kfib, 4005d3b00c08SAlexander V. Chernikov .dump_tentry = ta_dump_kfib_tentry, 4006d3b00c08SAlexander V. Chernikov .find_tentry = ta_find_kfib_tentry, 4007d3b00c08SAlexander V. Chernikov .dump_tinfo = ta_dump_kfib_tinfo, 4008d3b00c08SAlexander V. Chernikov .print_config = ta_print_kfib_config, 4009d3b00c08SAlexander V. Chernikov }; 4010d3b00c08SAlexander V. Chernikov 40119f7d47b0SAlexander V. Chernikov void 40120b565ac0SAlexander V. Chernikov ipfw_table_algo_init(struct ip_fw_chain *ch) 40139f7d47b0SAlexander V. Chernikov { 40140b565ac0SAlexander V. Chernikov size_t sz; 40150b565ac0SAlexander V. Chernikov 40169f7d47b0SAlexander V. Chernikov /* 40179f7d47b0SAlexander V. Chernikov * Register all algorithms presented here. 40189f7d47b0SAlexander V. Chernikov */ 40190b565ac0SAlexander V. Chernikov sz = sizeof(struct table_algo); 4020c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_radix, sz, &addr_radix.idx); 4021c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_hash, sz, &addr_hash.idx); 40220b565ac0SAlexander V. Chernikov ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx); 4023b23d5de9SAlexander V. Chernikov ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx); 4024914bffb6SAlexander V. Chernikov ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx); 4025c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_kfib, sz, &addr_kfib.idx); 40269f7d47b0SAlexander V. Chernikov } 40279f7d47b0SAlexander V. Chernikov 40289f7d47b0SAlexander V. Chernikov void 40290b565ac0SAlexander V. Chernikov ipfw_table_algo_destroy(struct ip_fw_chain *ch) 40309f7d47b0SAlexander V. Chernikov { 40310b565ac0SAlexander V. Chernikov 4032c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_radix.idx); 4033c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_hash.idx); 40340b565ac0SAlexander V. Chernikov ipfw_del_table_algo(ch, iface_idx.idx); 4035b23d5de9SAlexander V. Chernikov ipfw_del_table_algo(ch, number_array.idx); 4036914bffb6SAlexander V. Chernikov ipfw_del_table_algo(ch, flow_hash.idx); 4037c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_kfib.idx); 40389f7d47b0SAlexander V. Chernikov } 40399f7d47b0SAlexander V. Chernikov 40409f7d47b0SAlexander V. Chernikov 4041