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> 289f7d47b0SAlexander V. Chernikov __FBSDID("$FreeBSD: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c 267384 2014-06-12 09:59:11Z melifaro $"); 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 3699f7d47b0SAlexander V. Chernikov static int 3709f7d47b0SAlexander V. Chernikov ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen, 3719f7d47b0SAlexander V. Chernikov uint32_t *val) 3729f7d47b0SAlexander V. Chernikov { 3739f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 3749f7d47b0SAlexander V. Chernikov 3759f7d47b0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 376c21034b7SAlexander V. Chernikov struct radix_addr_entry *ent; 3779f7d47b0SAlexander V. Chernikov struct sockaddr_in sa; 3789f7d47b0SAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 3799f7d47b0SAlexander V. Chernikov sa.sin_addr.s_addr = *((in_addr_t *)key); 3809f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 381c21034b7SAlexander V. Chernikov ent = (struct radix_addr_entry *)(rnh->rnh_matchaddr(&sa, rnh)); 3829f7d47b0SAlexander V. Chernikov if (ent != NULL) { 3839f7d47b0SAlexander V. Chernikov *val = ent->value; 3849f7d47b0SAlexander V. Chernikov return (1); 3859f7d47b0SAlexander V. Chernikov } 3869f7d47b0SAlexander V. Chernikov } else { 387c21034b7SAlexander V. Chernikov struct radix_addr_xentry *xent; 388e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 3899f7d47b0SAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 3909f7d47b0SAlexander V. Chernikov memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr)); 3919f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 392c21034b7SAlexander V. Chernikov xent = (struct radix_addr_xentry *)(rnh->rnh_matchaddr(&sa6, rnh)); 3939f7d47b0SAlexander V. Chernikov if (xent != NULL) { 3949f7d47b0SAlexander V. Chernikov *val = xent->value; 3959f7d47b0SAlexander V. Chernikov return (1); 3969f7d47b0SAlexander V. Chernikov } 3979f7d47b0SAlexander V. Chernikov } 3989f7d47b0SAlexander V. Chernikov 3999f7d47b0SAlexander V. Chernikov return (0); 4009f7d47b0SAlexander V. Chernikov } 4019f7d47b0SAlexander V. Chernikov 4029f7d47b0SAlexander V. Chernikov /* 4039f7d47b0SAlexander V. Chernikov * New table 4049f7d47b0SAlexander V. Chernikov */ 4059f7d47b0SAlexander V. Chernikov static int 40668394ec8SAlexander V. Chernikov ta_init_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 407914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 4089f7d47b0SAlexander V. Chernikov { 4095f379342SAlexander V. Chernikov struct radix_cfg *cfg; 4109f7d47b0SAlexander V. Chernikov 4119f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->state, OFF_LEN_INET)) 4129f7d47b0SAlexander V. Chernikov return (ENOMEM); 4139f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) { 4149f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 4159f7d47b0SAlexander V. Chernikov return (ENOMEM); 4169f7d47b0SAlexander V. Chernikov } 4179f7d47b0SAlexander V. Chernikov 4185f379342SAlexander V. Chernikov cfg = malloc(sizeof(struct radix_cfg), M_IPFW, M_WAITOK | M_ZERO); 4195f379342SAlexander V. Chernikov 4205f379342SAlexander V. Chernikov *ta_state = cfg; 4219f7d47b0SAlexander V. Chernikov ti->lookup = ta_lookup_radix; 4229f7d47b0SAlexander V. Chernikov 4239f7d47b0SAlexander V. Chernikov return (0); 4249f7d47b0SAlexander V. Chernikov } 4259f7d47b0SAlexander V. Chernikov 4269f7d47b0SAlexander V. Chernikov static int 427a399f8beSAlexander V. Chernikov flush_radix_entry(struct radix_node *rn, void *arg) 4289f7d47b0SAlexander V. Chernikov { 4299f7d47b0SAlexander V. Chernikov struct radix_node_head * const rnh = arg; 430c21034b7SAlexander V. Chernikov struct radix_addr_entry *ent; 4319f7d47b0SAlexander V. Chernikov 432c21034b7SAlexander V. Chernikov ent = (struct radix_addr_entry *) 4339f7d47b0SAlexander V. Chernikov rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 4349f7d47b0SAlexander V. Chernikov if (ent != NULL) 4359f7d47b0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 4369f7d47b0SAlexander V. Chernikov return (0); 4379f7d47b0SAlexander V. Chernikov } 4389f7d47b0SAlexander V. Chernikov 4399f7d47b0SAlexander V. Chernikov static void 4409f7d47b0SAlexander V. Chernikov ta_destroy_radix(void *ta_state, struct table_info *ti) 4419f7d47b0SAlexander V. Chernikov { 4425f379342SAlexander V. Chernikov struct radix_cfg *cfg; 4439f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 4449f7d47b0SAlexander V. Chernikov 4455f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 4465f379342SAlexander V. Chernikov 4479f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 448a399f8beSAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_radix_entry, rnh); 4499f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 4509f7d47b0SAlexander V. Chernikov 4519f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 452a399f8beSAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_radix_entry, rnh); 4539f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->xstate); 4545f379342SAlexander V. Chernikov 4555f379342SAlexander V. Chernikov free(cfg, M_IPFW); 4565f379342SAlexander V. Chernikov } 4575f379342SAlexander V. Chernikov 4585f379342SAlexander V. Chernikov /* 4595f379342SAlexander V. Chernikov * Provide algo-specific table info 4605f379342SAlexander V. Chernikov */ 4615f379342SAlexander V. Chernikov static void 4625f379342SAlexander V. Chernikov ta_dump_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 4635f379342SAlexander V. Chernikov { 4645f379342SAlexander V. Chernikov struct radix_cfg *cfg; 4655f379342SAlexander V. Chernikov 4665f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 4675f379342SAlexander V. Chernikov 4685f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM; 4695f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_RADIX; 4705f379342SAlexander V. Chernikov tinfo->count4 = cfg->count4; 471c21034b7SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct radix_addr_entry); 4725f379342SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_RADIX; 4735f379342SAlexander V. Chernikov tinfo->count6 = cfg->count6; 474c21034b7SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct radix_addr_xentry); 4759f7d47b0SAlexander V. Chernikov } 4769f7d47b0SAlexander V. Chernikov 4779f7d47b0SAlexander V. Chernikov static int 47881d3153dSAlexander V. Chernikov ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e, 47981d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 4809f7d47b0SAlexander V. Chernikov { 481c21034b7SAlexander V. Chernikov struct radix_addr_entry *n; 482c21034b7SAlexander V. Chernikov struct radix_addr_xentry *xn; 4839f7d47b0SAlexander V. Chernikov 484c21034b7SAlexander V. Chernikov n = (struct radix_addr_entry *)e; 4859f7d47b0SAlexander V. Chernikov 4869f7d47b0SAlexander V. Chernikov /* Guess IPv4/IPv6 radix by sockaddr family */ 4879f7d47b0SAlexander V. Chernikov if (n->addr.sin_family == AF_INET) { 48881d3153dSAlexander V. Chernikov tent->k.addr.s_addr = n->addr.sin_addr.s_addr; 489e0a8b9eeSAlexander V. Chernikov tent->masklen = n->masklen; 49081d3153dSAlexander V. Chernikov tent->subtype = AF_INET; 4910cba2b28SAlexander V. Chernikov tent->v.kidx = n->value; 4929f7d47b0SAlexander V. Chernikov #ifdef INET6 4939f7d47b0SAlexander V. Chernikov } else { 494c21034b7SAlexander V. Chernikov xn = (struct radix_addr_xentry *)e; 495e0a8b9eeSAlexander V. Chernikov memcpy(&tent->k, &xn->addr6.sin6_addr, sizeof(struct in6_addr)); 496e0a8b9eeSAlexander V. Chernikov tent->masklen = xn->masklen; 49781d3153dSAlexander V. Chernikov tent->subtype = AF_INET6; 4980cba2b28SAlexander V. Chernikov tent->v.kidx = xn->value; 4999f7d47b0SAlexander V. Chernikov #endif 5009f7d47b0SAlexander V. Chernikov } 5019f7d47b0SAlexander V. Chernikov 5029f7d47b0SAlexander V. Chernikov return (0); 5039f7d47b0SAlexander V. Chernikov } 5049f7d47b0SAlexander V. Chernikov 50581d3153dSAlexander V. Chernikov static int 506914bffb6SAlexander V. Chernikov ta_find_radix_tentry(void *ta_state, struct table_info *ti, 507914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 50881d3153dSAlexander V. Chernikov { 50981d3153dSAlexander V. Chernikov struct radix_node_head *rnh; 51081d3153dSAlexander V. Chernikov void *e; 51181d3153dSAlexander V. Chernikov 51281d3153dSAlexander V. Chernikov e = NULL; 513914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) { 51481d3153dSAlexander V. Chernikov struct sockaddr_in sa; 51581d3153dSAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 516914bffb6SAlexander V. Chernikov sa.sin_addr.s_addr = tent->k.addr.s_addr; 51781d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 51881d3153dSAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa, rnh); 51981d3153dSAlexander V. Chernikov } else { 520e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 52181d3153dSAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 522914bffb6SAlexander V. Chernikov memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr)); 52381d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 52481d3153dSAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa6, rnh); 52581d3153dSAlexander V. Chernikov } 52681d3153dSAlexander V. Chernikov 52781d3153dSAlexander V. Chernikov if (e != NULL) { 52881d3153dSAlexander V. Chernikov ta_dump_radix_tentry(ta_state, ti, e, tent); 52981d3153dSAlexander V. Chernikov return (0); 53081d3153dSAlexander V. Chernikov } 53181d3153dSAlexander V. Chernikov 53281d3153dSAlexander V. Chernikov return (ENOENT); 53381d3153dSAlexander V. Chernikov } 53481d3153dSAlexander V. Chernikov 5359f7d47b0SAlexander V. Chernikov static void 5369f7d47b0SAlexander V. Chernikov ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f, 5379f7d47b0SAlexander V. Chernikov void *arg) 5389f7d47b0SAlexander V. Chernikov { 5399f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 5409f7d47b0SAlexander V. Chernikov 5419f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 5429f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 5439f7d47b0SAlexander V. Chernikov 5449f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 5459f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 5469f7d47b0SAlexander V. Chernikov } 5479f7d47b0SAlexander V. Chernikov 5489f7d47b0SAlexander V. Chernikov 5499f7d47b0SAlexander V. Chernikov #ifdef INET6 5509f7d47b0SAlexander V. Chernikov static inline void 5519f7d47b0SAlexander V. Chernikov ipv6_writemask(struct in6_addr *addr6, uint8_t mask) 5529f7d47b0SAlexander V. Chernikov { 5539f7d47b0SAlexander V. Chernikov uint32_t *cp; 5549f7d47b0SAlexander V. Chernikov 5559f7d47b0SAlexander V. Chernikov for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32) 5569f7d47b0SAlexander V. Chernikov *cp++ = 0xFFFFFFFF; 5579f7d47b0SAlexander V. Chernikov *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0); 5589f7d47b0SAlexander V. Chernikov } 5599f7d47b0SAlexander V. Chernikov #endif 5609f7d47b0SAlexander V. Chernikov 5612e324d29SAlexander V. Chernikov static void 5622e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa, 5632e324d29SAlexander V. Chernikov struct sockaddr *ma, int *set_mask) 5642e324d29SAlexander V. Chernikov { 5652e324d29SAlexander V. Chernikov int mlen; 5662e324d29SAlexander V. Chernikov struct sockaddr_in *addr, *mask; 567720ee730SAlexander V. Chernikov struct sa_in6 *addr6, *mask6; 5682e324d29SAlexander V. Chernikov in_addr_t a4; 5692e324d29SAlexander V. Chernikov 5702e324d29SAlexander V. Chernikov mlen = tei->masklen; 5712e324d29SAlexander V. Chernikov 5722e324d29SAlexander V. Chernikov if (tei->subtype == AF_INET) { 5732e324d29SAlexander V. Chernikov #ifdef INET 5742e324d29SAlexander V. Chernikov addr = (struct sockaddr_in *)sa; 5752e324d29SAlexander V. Chernikov mask = (struct sockaddr_in *)ma; 5762e324d29SAlexander V. Chernikov /* Set 'total' structure length */ 5772e324d29SAlexander V. Chernikov KEY_LEN(*addr) = KEY_LEN_INET; 5782e324d29SAlexander V. Chernikov KEY_LEN(*mask) = KEY_LEN_INET; 5792e324d29SAlexander V. Chernikov addr->sin_family = AF_INET; 5802e324d29SAlexander V. Chernikov mask->sin_addr.s_addr = 5812e324d29SAlexander V. Chernikov htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 5822e324d29SAlexander V. Chernikov a4 = *((in_addr_t *)tei->paddr); 5832e324d29SAlexander V. Chernikov addr->sin_addr.s_addr = a4 & mask->sin_addr.s_addr; 5842e324d29SAlexander V. Chernikov if (mlen != 32) 5852e324d29SAlexander V. Chernikov *set_mask = 1; 5862e324d29SAlexander V. Chernikov else 5872e324d29SAlexander V. Chernikov *set_mask = 0; 5882e324d29SAlexander V. Chernikov #endif 5892e324d29SAlexander V. Chernikov #ifdef INET6 5902e324d29SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 5912e324d29SAlexander V. Chernikov /* IPv6 case */ 592720ee730SAlexander V. Chernikov addr6 = (struct sa_in6 *)sa; 593720ee730SAlexander V. Chernikov mask6 = (struct sa_in6 *)ma; 5942e324d29SAlexander V. Chernikov /* Set 'total' structure length */ 5952e324d29SAlexander V. Chernikov KEY_LEN(*addr6) = KEY_LEN_INET6; 5962e324d29SAlexander V. Chernikov KEY_LEN(*mask6) = KEY_LEN_INET6; 5972e324d29SAlexander V. Chernikov addr6->sin6_family = AF_INET6; 5982e324d29SAlexander V. Chernikov ipv6_writemask(&mask6->sin6_addr, mlen); 5992e324d29SAlexander V. Chernikov memcpy(&addr6->sin6_addr, tei->paddr, sizeof(struct in6_addr)); 6002e324d29SAlexander V. Chernikov APPLY_MASK(&addr6->sin6_addr, &mask6->sin6_addr); 6012e324d29SAlexander V. Chernikov if (mlen != 128) 6022e324d29SAlexander V. Chernikov *set_mask = 1; 6032e324d29SAlexander V. Chernikov else 6042e324d29SAlexander V. Chernikov *set_mask = 0; 6052e324d29SAlexander V. Chernikov } 6062e324d29SAlexander V. Chernikov #endif 6072e324d29SAlexander V. Chernikov } 6089f7d47b0SAlexander V. Chernikov 6099f7d47b0SAlexander V. Chernikov static int 610a399f8beSAlexander V. Chernikov ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 61168394ec8SAlexander V. Chernikov void *ta_buf) 6129f7d47b0SAlexander V. Chernikov { 613c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 614c21034b7SAlexander V. Chernikov struct radix_addr_entry *ent; 615c21034b7SAlexander V. Chernikov struct radix_addr_xentry *xent; 6162e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask; 6172e324d29SAlexander V. Chernikov int mlen, set_mask; 6189f7d47b0SAlexander V. Chernikov 619c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 6209f7d47b0SAlexander V. Chernikov 6219f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 6222e324d29SAlexander V. Chernikov set_mask = 0; 6239f7d47b0SAlexander V. Chernikov 624ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 6259f7d47b0SAlexander V. Chernikov #ifdef INET 6269f7d47b0SAlexander V. Chernikov if (mlen > 32) 6279f7d47b0SAlexander V. Chernikov return (EINVAL); 6289f7d47b0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 629e0a8b9eeSAlexander V. Chernikov ent->masklen = mlen; 6302e324d29SAlexander V. Chernikov 6312e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&ent->addr; 6322e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma; 6339f7d47b0SAlexander V. Chernikov tb->ent_ptr = ent; 6349f7d47b0SAlexander V. Chernikov #endif 6359f7d47b0SAlexander V. Chernikov #ifdef INET6 636ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 6379f7d47b0SAlexander V. Chernikov /* IPv6 case */ 6389f7d47b0SAlexander V. Chernikov if (mlen > 128) 6399f7d47b0SAlexander V. Chernikov return (EINVAL); 6409f7d47b0SAlexander V. Chernikov xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO); 641e0a8b9eeSAlexander V. Chernikov xent->masklen = mlen; 6422e324d29SAlexander V. Chernikov 6432e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&xent->addr6; 6442e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma; 6459f7d47b0SAlexander V. Chernikov tb->ent_ptr = xent; 6469f7d47b0SAlexander V. Chernikov #endif 6479f7d47b0SAlexander V. Chernikov } else { 6489f7d47b0SAlexander V. Chernikov /* Unknown CIDR type */ 6499f7d47b0SAlexander V. Chernikov return (EINVAL); 6509f7d47b0SAlexander V. Chernikov } 6519f7d47b0SAlexander V. Chernikov 6522e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(tei, addr, mask, &set_mask); 6532e324d29SAlexander V. Chernikov /* Set pointers */ 6542e324d29SAlexander V. Chernikov tb->addr_ptr = addr; 6552e324d29SAlexander V. Chernikov if (set_mask != 0) 6562e324d29SAlexander V. Chernikov tb->mask_ptr = mask; 6572e324d29SAlexander V. Chernikov 6589f7d47b0SAlexander V. Chernikov return (0); 6599f7d47b0SAlexander V. Chernikov } 6609f7d47b0SAlexander V. Chernikov 6619f7d47b0SAlexander V. Chernikov static int 662a399f8beSAlexander V. Chernikov ta_add_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, 663b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 6649f7d47b0SAlexander V. Chernikov { 6655f379342SAlexander V. Chernikov struct radix_cfg *cfg; 6669f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 6679f7d47b0SAlexander V. Chernikov struct radix_node *rn; 668c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 669648e8380SAlexander V. Chernikov uint32_t *old_value, value; 6709f7d47b0SAlexander V. Chernikov 6715f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 672c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 6739f7d47b0SAlexander V. Chernikov 67413263632SAlexander V. Chernikov /* Save current entry value from @tei */ 67513263632SAlexander V. Chernikov if (tei->subtype == AF_INET) { 6769f7d47b0SAlexander V. Chernikov rnh = ti->state; 67713263632SAlexander V. Chernikov ((struct radix_addr_entry *)tb->ent_ptr)->value = tei->value; 67813263632SAlexander V. Chernikov } else { 6799f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 68013263632SAlexander V. Chernikov ((struct radix_addr_xentry *)tb->ent_ptr)->value = tei->value; 68113263632SAlexander V. Chernikov } 6829f7d47b0SAlexander V. Chernikov 6834c0c07a5SAlexander V. Chernikov /* Search for an entry first */ 6844c0c07a5SAlexander V. Chernikov rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, rnh); 6854c0c07a5SAlexander V. Chernikov if (rn != NULL) { 686ac35ff17SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 6879f7d47b0SAlexander V. Chernikov return (EEXIST); 688ac35ff17SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 689648e8380SAlexander V. Chernikov if (tei->subtype == AF_INET) 690c21034b7SAlexander V. Chernikov old_value = &((struct radix_addr_entry *)rn)->value; 691648e8380SAlexander V. Chernikov else 692c21034b7SAlexander V. Chernikov old_value = &((struct radix_addr_xentry *)rn)->value; 693648e8380SAlexander V. Chernikov 694648e8380SAlexander V. Chernikov value = *old_value; 695648e8380SAlexander V. Chernikov *old_value = tei->value; 696648e8380SAlexander V. Chernikov tei->value = value; 697ac35ff17SAlexander V. Chernikov 698ac35ff17SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 699ac35ff17SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 700adea6201SAlexander V. Chernikov *pnum = 0; 701e0a8b9eeSAlexander V. Chernikov 702e0a8b9eeSAlexander V. Chernikov return (0); 703ac35ff17SAlexander V. Chernikov } 704ac35ff17SAlexander V. Chernikov 7054c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 7064c0c07a5SAlexander V. Chernikov return (EFBIG); 7074c0c07a5SAlexander V. Chernikov 7084c0c07a5SAlexander V. Chernikov rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr); 7094c0c07a5SAlexander V. Chernikov if (rn == NULL) { 7104c0c07a5SAlexander V. Chernikov /* Unknown error */ 7114c0c07a5SAlexander V. Chernikov return (EINVAL); 7124c0c07a5SAlexander V. Chernikov } 7134c0c07a5SAlexander V. Chernikov 7145f379342SAlexander V. Chernikov if (tei->subtype == AF_INET) 7155f379342SAlexander V. Chernikov cfg->count4++; 7165f379342SAlexander V. Chernikov else 7175f379342SAlexander V. Chernikov cfg->count6++; 718ac35ff17SAlexander V. Chernikov tb->ent_ptr = NULL; 719adea6201SAlexander V. Chernikov *pnum = 1; 7209f7d47b0SAlexander V. Chernikov 7219f7d47b0SAlexander V. Chernikov return (0); 7229f7d47b0SAlexander V. Chernikov } 7239f7d47b0SAlexander V. Chernikov 7249f7d47b0SAlexander V. Chernikov static int 725a399f8beSAlexander V. Chernikov ta_prepare_del_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 72668394ec8SAlexander V. Chernikov void *ta_buf) 7279f7d47b0SAlexander V. Chernikov { 728c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 7292e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask; 7302e324d29SAlexander V. Chernikov int mlen, set_mask; 7319f7d47b0SAlexander V. Chernikov 732c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 7339f7d47b0SAlexander V. Chernikov 7349f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 7352e324d29SAlexander V. Chernikov set_mask = 0; 7369f7d47b0SAlexander V. Chernikov 737ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 738e0a8b9eeSAlexander V. Chernikov if (mlen > 32) 739e0a8b9eeSAlexander V. Chernikov return (EINVAL); 7402e324d29SAlexander V. Chernikov 7412e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a4.sa; 7422e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma; 7439f7d47b0SAlexander V. Chernikov #ifdef INET6 744ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 7459f7d47b0SAlexander V. Chernikov if (mlen > 128) 7469f7d47b0SAlexander V. Chernikov return (EINVAL); 7472e324d29SAlexander V. Chernikov 7482e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a6.sa; 7492e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma; 7509f7d47b0SAlexander V. Chernikov #endif 7519f7d47b0SAlexander V. Chernikov } else 7529f7d47b0SAlexander V. Chernikov return (EINVAL); 7539f7d47b0SAlexander V. Chernikov 7542e324d29SAlexander V. Chernikov tei_to_sockaddr_ent(tei, addr, mask, &set_mask); 7552e324d29SAlexander V. Chernikov tb->addr_ptr = addr; 7562e324d29SAlexander V. Chernikov if (set_mask != 0) 7572e324d29SAlexander V. Chernikov tb->mask_ptr = mask; 7582e324d29SAlexander V. Chernikov 7599f7d47b0SAlexander V. Chernikov return (0); 7609f7d47b0SAlexander V. Chernikov } 7619f7d47b0SAlexander V. Chernikov 7629f7d47b0SAlexander V. Chernikov static int 763a399f8beSAlexander V. Chernikov ta_del_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, 764b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 7659f7d47b0SAlexander V. Chernikov { 7665f379342SAlexander V. Chernikov struct radix_cfg *cfg; 7679f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 7689f7d47b0SAlexander V. Chernikov struct radix_node *rn; 769c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 7709f7d47b0SAlexander V. Chernikov 7715f379342SAlexander V. Chernikov cfg = (struct radix_cfg *)ta_state; 772c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 7739f7d47b0SAlexander V. Chernikov 774ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) 7759f7d47b0SAlexander V. Chernikov rnh = ti->state; 7769f7d47b0SAlexander V. Chernikov else 7779f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 7789f7d47b0SAlexander V. Chernikov 7799f7d47b0SAlexander V. Chernikov rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh); 7809f7d47b0SAlexander V. Chernikov 7813a845e10SAlexander V. Chernikov if (rn == NULL) 7823a845e10SAlexander V. Chernikov return (ENOENT); 7833a845e10SAlexander V. Chernikov 784648e8380SAlexander V. Chernikov /* Save entry value to @tei */ 785648e8380SAlexander V. Chernikov if (tei->subtype == AF_INET) 786c21034b7SAlexander V. Chernikov tei->value = ((struct radix_addr_entry *)rn)->value; 787648e8380SAlexander V. Chernikov else 788c21034b7SAlexander V. Chernikov tei->value = ((struct radix_addr_xentry *)rn)->value; 789648e8380SAlexander V. Chernikov 7909f7d47b0SAlexander V. Chernikov tb->ent_ptr = rn; 7919f7d47b0SAlexander V. Chernikov 7925f379342SAlexander V. Chernikov if (tei->subtype == AF_INET) 7935f379342SAlexander V. Chernikov cfg->count4--; 7945f379342SAlexander V. Chernikov else 7955f379342SAlexander V. Chernikov cfg->count6--; 796adea6201SAlexander V. Chernikov *pnum = 1; 797adea6201SAlexander V. Chernikov 7989f7d47b0SAlexander V. Chernikov return (0); 7999f7d47b0SAlexander V. Chernikov } 8009f7d47b0SAlexander V. Chernikov 8019f7d47b0SAlexander V. Chernikov static void 802a399f8beSAlexander V. Chernikov ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 80368394ec8SAlexander V. Chernikov void *ta_buf) 8049f7d47b0SAlexander V. Chernikov { 805c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 8069f7d47b0SAlexander V. Chernikov 807c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 8089f7d47b0SAlexander V. Chernikov 809ac35ff17SAlexander V. Chernikov if (tb->ent_ptr != NULL) 8109f7d47b0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 8119f7d47b0SAlexander V. Chernikov } 8129f7d47b0SAlexander V. Chernikov 813b6ee846eSAlexander V. Chernikov static int 814301290bcSAlexander V. Chernikov ta_need_modify_radix(void *ta_state, struct table_info *ti, uint32_t count, 815b6ee846eSAlexander V. Chernikov uint64_t *pflags) 816b6ee846eSAlexander V. Chernikov { 817b6ee846eSAlexander V. Chernikov 818b6ee846eSAlexander V. Chernikov /* 8190bce0c23SAlexander V. Chernikov * radix does not require additional memory allocations 820b6ee846eSAlexander V. Chernikov * other than nodes itself. Adding new masks to the tree do 821b6ee846eSAlexander V. Chernikov * but we don't have any API to call (and we don't known which 822b6ee846eSAlexander V. Chernikov * sizes do we need). 823b6ee846eSAlexander V. Chernikov */ 824301290bcSAlexander V. Chernikov return (0); 825b6ee846eSAlexander V. Chernikov } 826b6ee846eSAlexander V. Chernikov 827c21034b7SAlexander V. Chernikov struct table_algo addr_radix = { 828c21034b7SAlexander V. Chernikov .name = "addr:radix", 829c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR, 83057a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 831c21034b7SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_radix), 8329f7d47b0SAlexander V. Chernikov .init = ta_init_radix, 8339f7d47b0SAlexander V. Chernikov .destroy = ta_destroy_radix, 834a399f8beSAlexander V. Chernikov .prepare_add = ta_prepare_add_radix, 835a399f8beSAlexander V. Chernikov .prepare_del = ta_prepare_del_radix, 836a399f8beSAlexander V. Chernikov .add = ta_add_radix, 837a399f8beSAlexander V. Chernikov .del = ta_del_radix, 838a399f8beSAlexander V. Chernikov .flush_entry = ta_flush_radix_entry, 8399f7d47b0SAlexander V. Chernikov .foreach = ta_foreach_radix, 84081d3153dSAlexander V. Chernikov .dump_tentry = ta_dump_radix_tentry, 84181d3153dSAlexander V. Chernikov .find_tentry = ta_find_radix_tentry, 8425f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_radix_tinfo, 843301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_radix, 8449f7d47b0SAlexander V. Chernikov }; 8459f7d47b0SAlexander V. Chernikov 8469f7d47b0SAlexander V. Chernikov 8479f7d47b0SAlexander V. Chernikov /* 848c21034b7SAlexander V. Chernikov * addr:hash cmds 84974b941f0SAlexander V. Chernikov * 85074b941f0SAlexander V. Chernikov * 85174b941f0SAlexander V. Chernikov * ti->data: 85274b941f0SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6] 85374b941f0SAlexander V. Chernikov * [ 8][ 8[ 8][ 8] 85474b941f0SAlexander V. Chernikov * 85574b941f0SAlexander V. Chernikov * inv.mask4: 32 - mask 85674b941f0SAlexander V. Chernikov * inv.mask6: 85774b941f0SAlexander V. Chernikov * 1) _slow lookup: mask 85874b941f0SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8 85974b941f0SAlexander V. Chernikov * 3) _64: 8 860ce2817b5SAlexander V. Chernikov * 861ce2817b5SAlexander V. Chernikov * 862ce2817b5SAlexander V. Chernikov * pflags: 863ce2817b5SAlexander V. Chernikov * [v4=1/v6=0][hsize] 864ce2817b5SAlexander V. Chernikov * [ 32][ 32] 86574b941f0SAlexander V. Chernikov */ 86674b941f0SAlexander V. Chernikov 86774b941f0SAlexander V. Chernikov struct chashentry; 86874b941f0SAlexander V. Chernikov 86974b941f0SAlexander V. Chernikov SLIST_HEAD(chashbhead, chashentry); 87074b941f0SAlexander V. Chernikov 87174b941f0SAlexander V. Chernikov struct chash_cfg { 87274b941f0SAlexander V. Chernikov struct chashbhead *head4; 87374b941f0SAlexander V. Chernikov struct chashbhead *head6; 87474b941f0SAlexander V. Chernikov size_t size4; 87574b941f0SAlexander V. Chernikov size_t size6; 876ce2817b5SAlexander V. Chernikov size_t items4; 877ce2817b5SAlexander V. Chernikov size_t items6; 87874b941f0SAlexander V. Chernikov uint8_t mask4; 87974b941f0SAlexander V. Chernikov uint8_t mask6; 88074b941f0SAlexander V. Chernikov }; 88174b941f0SAlexander V. Chernikov 88274b941f0SAlexander V. Chernikov struct chashentry { 88374b941f0SAlexander V. Chernikov SLIST_ENTRY(chashentry) next; 88474b941f0SAlexander V. Chernikov uint32_t value; 88574b941f0SAlexander V. Chernikov uint32_t type; 88674b941f0SAlexander V. Chernikov union { 88774b941f0SAlexander V. Chernikov uint32_t a4; /* Host format */ 88874b941f0SAlexander V. Chernikov struct in6_addr a6; /* Network format */ 88974b941f0SAlexander V. Chernikov } a; 89074b941f0SAlexander V. Chernikov }; 89174b941f0SAlexander V. Chernikov 8920bce0c23SAlexander V. Chernikov struct ta_buf_chash 8930bce0c23SAlexander V. Chernikov { 8940bce0c23SAlexander V. Chernikov void *ent_ptr; 8950bce0c23SAlexander V. Chernikov struct chashentry ent; 8960bce0c23SAlexander V. Chernikov }; 8970bce0c23SAlexander V. Chernikov 8980bce0c23SAlexander V. Chernikov 89974b941f0SAlexander V. Chernikov static __inline uint32_t 90074b941f0SAlexander V. Chernikov hash_ip(uint32_t addr, int hsize) 90174b941f0SAlexander V. Chernikov { 90274b941f0SAlexander V. Chernikov 90374b941f0SAlexander V. Chernikov return (addr % (hsize - 1)); 90474b941f0SAlexander V. Chernikov } 90574b941f0SAlexander V. Chernikov 90674b941f0SAlexander V. Chernikov static __inline uint32_t 90774b941f0SAlexander V. Chernikov hash_ip6(struct in6_addr *addr6, int hsize) 90874b941f0SAlexander V. Chernikov { 90974b941f0SAlexander V. Chernikov uint32_t i; 91074b941f0SAlexander V. Chernikov 91174b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^ 91274b941f0SAlexander V. Chernikov addr6->s6_addr32[2] ^ addr6->s6_addr32[3]; 91374b941f0SAlexander V. Chernikov 91474b941f0SAlexander V. Chernikov return (i % (hsize - 1)); 91574b941f0SAlexander V. Chernikov } 91674b941f0SAlexander V. Chernikov 91774b941f0SAlexander V. Chernikov 91874b941f0SAlexander V. Chernikov static __inline uint16_t 91974b941f0SAlexander V. Chernikov hash_ip64(struct in6_addr *addr6, int hsize) 92074b941f0SAlexander V. Chernikov { 92174b941f0SAlexander V. Chernikov uint32_t i; 92274b941f0SAlexander V. Chernikov 92374b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1]; 92474b941f0SAlexander V. Chernikov 92574b941f0SAlexander V. Chernikov return (i % (hsize - 1)); 92674b941f0SAlexander V. Chernikov } 92774b941f0SAlexander V. Chernikov 92874b941f0SAlexander V. Chernikov 92974b941f0SAlexander V. Chernikov static __inline uint32_t 93074b941f0SAlexander V. Chernikov hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize) 93174b941f0SAlexander V. Chernikov { 93274b941f0SAlexander V. Chernikov struct in6_addr mask6; 93374b941f0SAlexander V. Chernikov 93474b941f0SAlexander V. Chernikov ipv6_writemask(&mask6, mask); 93574b941f0SAlexander V. Chernikov memcpy(addr6, key, sizeof(struct in6_addr)); 93674b941f0SAlexander V. Chernikov APPLY_MASK(addr6, &mask6); 93774b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize)); 93874b941f0SAlexander V. Chernikov } 93974b941f0SAlexander V. Chernikov 94074b941f0SAlexander V. Chernikov static __inline uint32_t 94174b941f0SAlexander V. Chernikov hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize) 94274b941f0SAlexander V. Chernikov { 94374b941f0SAlexander V. Chernikov uint64_t *paddr; 94474b941f0SAlexander V. Chernikov 94574b941f0SAlexander V. Chernikov paddr = (uint64_t *)addr6; 94674b941f0SAlexander V. Chernikov *paddr = 0; 94774b941f0SAlexander V. Chernikov *(paddr + 1) = 0; 94874b941f0SAlexander V. Chernikov memcpy(addr6, key, mask); 94974b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize)); 95074b941f0SAlexander V. Chernikov } 95174b941f0SAlexander V. Chernikov 95274b941f0SAlexander V. Chernikov static int 95374b941f0SAlexander V. Chernikov ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen, 95474b941f0SAlexander V. Chernikov uint32_t *val) 95574b941f0SAlexander V. Chernikov { 95674b941f0SAlexander V. Chernikov struct chashbhead *head; 95774b941f0SAlexander V. Chernikov struct chashentry *ent; 95874b941f0SAlexander V. Chernikov uint16_t hash, hsize; 95974b941f0SAlexander V. Chernikov uint8_t imask; 96074b941f0SAlexander V. Chernikov 96174b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 96274b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 96374b941f0SAlexander V. Chernikov imask = ti->data >> 24; 96474b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 96574b941f0SAlexander V. Chernikov uint32_t a; 96674b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 96774b941f0SAlexander V. Chernikov a = a >> imask; 96874b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 96974b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 97074b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 97174b941f0SAlexander V. Chernikov *val = ent->value; 97274b941f0SAlexander V. Chernikov return (1); 97374b941f0SAlexander V. Chernikov } 97474b941f0SAlexander V. Chernikov } 97574b941f0SAlexander V. Chernikov } else { 97674b941f0SAlexander V. Chernikov /* IPv6: worst scenario: non-round mask */ 97774b941f0SAlexander V. Chernikov struct in6_addr addr6; 97874b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 97974b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16; 98074b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 98174b941f0SAlexander V. Chernikov hash = hash_ip6_slow(&addr6, key, imask, hsize); 98274b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 98374b941f0SAlexander V. Chernikov if (memcmp(&ent->a.a6, &addr6, 16) == 0) { 98474b941f0SAlexander V. Chernikov *val = ent->value; 98574b941f0SAlexander V. Chernikov return (1); 98674b941f0SAlexander V. Chernikov } 98774b941f0SAlexander V. Chernikov } 98874b941f0SAlexander V. Chernikov } 98974b941f0SAlexander V. Chernikov 99074b941f0SAlexander V. Chernikov return (0); 99174b941f0SAlexander V. Chernikov } 99274b941f0SAlexander V. Chernikov 99374b941f0SAlexander V. Chernikov static int 99474b941f0SAlexander V. Chernikov ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen, 99574b941f0SAlexander V. Chernikov uint32_t *val) 99674b941f0SAlexander V. Chernikov { 99774b941f0SAlexander V. Chernikov struct chashbhead *head; 99874b941f0SAlexander V. Chernikov struct chashentry *ent; 99974b941f0SAlexander V. Chernikov uint16_t hash, hsize; 100074b941f0SAlexander V. Chernikov uint8_t imask; 100174b941f0SAlexander V. Chernikov 100274b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 100374b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 100474b941f0SAlexander V. Chernikov imask = ti->data >> 24; 100574b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 100674b941f0SAlexander V. Chernikov uint32_t a; 100774b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 100874b941f0SAlexander V. Chernikov a = a >> imask; 100974b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 101074b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 101174b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 101274b941f0SAlexander V. Chernikov *val = ent->value; 101374b941f0SAlexander V. Chernikov return (1); 101474b941f0SAlexander V. Chernikov } 101574b941f0SAlexander V. Chernikov } 101674b941f0SAlexander V. Chernikov } else { 101774b941f0SAlexander V. Chernikov /* IPv6: aligned to 8bit mask */ 101874b941f0SAlexander V. Chernikov struct in6_addr addr6; 101974b941f0SAlexander V. Chernikov uint64_t *paddr, *ptmp; 102074b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 102174b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16; 102274b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 102374b941f0SAlexander V. Chernikov 102474b941f0SAlexander V. Chernikov hash = hash_ip6_al(&addr6, key, imask, hsize); 102574b941f0SAlexander V. Chernikov paddr = (uint64_t *)&addr6; 102674b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 102774b941f0SAlexander V. Chernikov ptmp = (uint64_t *)&ent->a.a6; 102874b941f0SAlexander V. Chernikov if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) { 102974b941f0SAlexander V. Chernikov *val = ent->value; 103074b941f0SAlexander V. Chernikov return (1); 103174b941f0SAlexander V. Chernikov } 103274b941f0SAlexander V. Chernikov } 103374b941f0SAlexander V. Chernikov } 103474b941f0SAlexander V. Chernikov 103574b941f0SAlexander V. Chernikov return (0); 103674b941f0SAlexander V. Chernikov } 103774b941f0SAlexander V. Chernikov 103874b941f0SAlexander V. Chernikov static int 103974b941f0SAlexander V. Chernikov ta_lookup_chash_64(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: /64 */ 106374b941f0SAlexander V. Chernikov uint64_t a6, *paddr; 106474b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 106574b941f0SAlexander V. Chernikov paddr = (uint64_t *)key; 106674b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 106774b941f0SAlexander V. Chernikov a6 = *paddr; 106874b941f0SAlexander V. Chernikov hash = hash_ip64((struct in6_addr *)key, hsize); 106974b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 107074b941f0SAlexander V. Chernikov paddr = (uint64_t *)&ent->a.a6; 107174b941f0SAlexander V. Chernikov if (a6 == *paddr) { 107274b941f0SAlexander V. Chernikov *val = ent->value; 107374b941f0SAlexander V. Chernikov return (1); 107474b941f0SAlexander V. Chernikov } 107574b941f0SAlexander V. Chernikov } 107674b941f0SAlexander V. Chernikov } 107774b941f0SAlexander V. Chernikov 107874b941f0SAlexander V. Chernikov return (0); 107974b941f0SAlexander V. Chernikov } 108074b941f0SAlexander V. Chernikov 108174b941f0SAlexander V. Chernikov static int 10820bce0c23SAlexander V. Chernikov chash_parse_opts(struct chash_cfg *cfg, char *data) 108374b941f0SAlexander V. Chernikov { 108474b941f0SAlexander V. Chernikov char *pdel, *pend, *s; 108574b941f0SAlexander V. Chernikov int mask4, mask6; 108674b941f0SAlexander V. Chernikov 10870bce0c23SAlexander V. Chernikov mask4 = cfg->mask4; 10880bce0c23SAlexander V. Chernikov mask6 = cfg->mask6; 108974b941f0SAlexander V. Chernikov 109074b941f0SAlexander V. Chernikov if (data == NULL) 109174b941f0SAlexander V. Chernikov return (0); 109274b941f0SAlexander V. Chernikov if ((pdel = strchr(data, ' ')) == NULL) 109374b941f0SAlexander V. Chernikov return (0); 109474b941f0SAlexander V. Chernikov while (*pdel == ' ') 109574b941f0SAlexander V. Chernikov pdel++; 109674b941f0SAlexander V. Chernikov if (strncmp(pdel, "masks=", 6) != 0) 109774b941f0SAlexander V. Chernikov return (EINVAL); 109874b941f0SAlexander V. Chernikov if ((s = strchr(pdel, ' ')) != NULL) 109974b941f0SAlexander V. Chernikov *s++ = '\0'; 110074b941f0SAlexander V. Chernikov 110174b941f0SAlexander V. Chernikov pdel += 6; 110274b941f0SAlexander V. Chernikov /* Need /XX[,/YY] */ 110374b941f0SAlexander V. Chernikov if (*pdel++ != '/') 110474b941f0SAlexander V. Chernikov return (EINVAL); 110574b941f0SAlexander V. Chernikov mask4 = strtol(pdel, &pend, 10); 110674b941f0SAlexander V. Chernikov if (*pend == ',') { 110774b941f0SAlexander V. Chernikov /* ,/YY */ 110874b941f0SAlexander V. Chernikov pdel = pend + 1; 110974b941f0SAlexander V. Chernikov if (*pdel++ != '/') 111074b941f0SAlexander V. Chernikov return (EINVAL); 111174b941f0SAlexander V. Chernikov mask6 = strtol(pdel, &pend, 10); 111274b941f0SAlexander V. Chernikov if (*pend != '\0') 111374b941f0SAlexander V. Chernikov return (EINVAL); 111474b941f0SAlexander V. Chernikov } else if (*pend != '\0') 111574b941f0SAlexander V. Chernikov return (EINVAL); 111674b941f0SAlexander V. Chernikov 111774b941f0SAlexander V. Chernikov if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128) 111874b941f0SAlexander V. Chernikov return (EINVAL); 111974b941f0SAlexander V. Chernikov 11200bce0c23SAlexander V. Chernikov cfg->mask4 = mask4; 11210bce0c23SAlexander V. Chernikov cfg->mask6 = mask6; 112274b941f0SAlexander V. Chernikov 112374b941f0SAlexander V. Chernikov return (0); 112474b941f0SAlexander V. Chernikov } 112574b941f0SAlexander V. Chernikov 112674b941f0SAlexander V. Chernikov static void 112774b941f0SAlexander V. Chernikov ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf, 112874b941f0SAlexander V. Chernikov size_t bufsize) 112974b941f0SAlexander V. Chernikov { 11300bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 113174b941f0SAlexander V. Chernikov 11320bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 113374b941f0SAlexander V. Chernikov 11340bce0c23SAlexander V. Chernikov if (cfg->mask4 != 32 || cfg->mask6 != 128) 1135c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s masks=/%d,/%d", "addr:hash", 11360bce0c23SAlexander V. Chernikov cfg->mask4, cfg->mask6); 113774b941f0SAlexander V. Chernikov else 1138c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s", "addr:hash"); 113974b941f0SAlexander V. Chernikov } 114074b941f0SAlexander V. Chernikov 1141914bffb6SAlexander V. Chernikov static int 1142914bffb6SAlexander V. Chernikov log2(uint32_t v) 1143914bffb6SAlexander V. Chernikov { 1144914bffb6SAlexander V. Chernikov uint32_t r; 1145914bffb6SAlexander V. Chernikov 1146914bffb6SAlexander V. Chernikov r = 0; 1147914bffb6SAlexander V. Chernikov while (v >>= 1) 1148914bffb6SAlexander V. Chernikov r++; 1149914bffb6SAlexander V. Chernikov 1150914bffb6SAlexander V. Chernikov return (r); 1151914bffb6SAlexander V. Chernikov } 115274b941f0SAlexander V. Chernikov 115374b941f0SAlexander V. Chernikov /* 115474b941f0SAlexander V. Chernikov * New table. 115574b941f0SAlexander V. Chernikov * We assume 'data' to be either NULL or the following format: 1156c21034b7SAlexander V. Chernikov * 'addr:hash [masks=/32[,/128]]' 115774b941f0SAlexander V. Chernikov */ 115874b941f0SAlexander V. Chernikov static int 115974b941f0SAlexander V. Chernikov ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 1160914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 116174b941f0SAlexander V. Chernikov { 116274b941f0SAlexander V. Chernikov int error, i; 1163914bffb6SAlexander V. Chernikov uint32_t hsize; 11640bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 116574b941f0SAlexander V. Chernikov 11660bce0c23SAlexander V. Chernikov cfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO); 116774b941f0SAlexander V. Chernikov 11680bce0c23SAlexander V. Chernikov cfg->mask4 = 32; 11690bce0c23SAlexander V. Chernikov cfg->mask6 = 128; 117074b941f0SAlexander V. Chernikov 11710bce0c23SAlexander V. Chernikov if ((error = chash_parse_opts(cfg, data)) != 0) { 11720bce0c23SAlexander V. Chernikov free(cfg, M_IPFW); 117374b941f0SAlexander V. Chernikov return (error); 117474b941f0SAlexander V. Chernikov } 117574b941f0SAlexander V. Chernikov 11760bce0c23SAlexander V. Chernikov cfg->size4 = 128; 11770bce0c23SAlexander V. Chernikov cfg->size6 = 128; 117874b941f0SAlexander V. Chernikov 11790bce0c23SAlexander V. Chernikov cfg->head4 = malloc(sizeof(struct chashbhead) * cfg->size4, M_IPFW, 118074b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO); 11810bce0c23SAlexander V. Chernikov cfg->head6 = malloc(sizeof(struct chashbhead) * cfg->size6, M_IPFW, 118274b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO); 11830bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 11840bce0c23SAlexander V. Chernikov SLIST_INIT(&cfg->head4[i]); 11850bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 11860bce0c23SAlexander V. Chernikov SLIST_INIT(&cfg->head6[i]); 118774b941f0SAlexander V. Chernikov 118874b941f0SAlexander V. Chernikov 11890bce0c23SAlexander V. Chernikov *ta_state = cfg; 11900bce0c23SAlexander V. Chernikov ti->state = cfg->head4; 11910bce0c23SAlexander V. Chernikov ti->xstate = cfg->head6; 119274b941f0SAlexander V. Chernikov 119374b941f0SAlexander V. Chernikov /* Store data depending on v6 mask length */ 11940bce0c23SAlexander V. Chernikov hsize = log2(cfg->size4) << 8 | log2(cfg->size6); 11950bce0c23SAlexander V. Chernikov if (cfg->mask6 == 64) { 11960bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | (128 - cfg->mask6) << 16| 1197914bffb6SAlexander V. Chernikov hsize; 119874b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_64; 11990bce0c23SAlexander V. Chernikov } else if ((cfg->mask6 % 8) == 0) { 12000bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | 12010bce0c23SAlexander V. Chernikov cfg->mask6 << 13 | hsize; 120274b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_aligned; 120374b941f0SAlexander V. Chernikov } else { 120474b941f0SAlexander V. Chernikov /* don't do that! */ 12050bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | 12060bce0c23SAlexander V. Chernikov cfg->mask6 << 16 | hsize; 120774b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_slow; 120874b941f0SAlexander V. Chernikov } 120974b941f0SAlexander V. Chernikov 121074b941f0SAlexander V. Chernikov return (0); 121174b941f0SAlexander V. Chernikov } 121274b941f0SAlexander V. Chernikov 121374b941f0SAlexander V. Chernikov static void 121474b941f0SAlexander V. Chernikov ta_destroy_chash(void *ta_state, struct table_info *ti) 121574b941f0SAlexander V. Chernikov { 12160bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 121774b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next; 121874b941f0SAlexander V. Chernikov int i; 121974b941f0SAlexander V. Chernikov 12200bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 122174b941f0SAlexander V. Chernikov 12220bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 12230bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next) 122474b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 122574b941f0SAlexander V. Chernikov 12260bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 12270bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next) 122874b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 122974b941f0SAlexander V. Chernikov 12300bce0c23SAlexander V. Chernikov free(cfg->head4, M_IPFW); 12310bce0c23SAlexander V. Chernikov free(cfg->head6, M_IPFW); 1232ce2817b5SAlexander V. Chernikov 12330bce0c23SAlexander V. Chernikov free(cfg, M_IPFW); 123474b941f0SAlexander V. Chernikov } 123574b941f0SAlexander V. Chernikov 12365f379342SAlexander V. Chernikov static void 12375f379342SAlexander V. Chernikov ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 12385f379342SAlexander V. Chernikov { 12395f379342SAlexander V. Chernikov struct chash_cfg *cfg; 12405f379342SAlexander V. Chernikov 12415f379342SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 12425f379342SAlexander V. Chernikov 12435f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM; 12445f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_HASH; 12455f379342SAlexander V. Chernikov tinfo->size4 = cfg->size4; 12465f379342SAlexander V. Chernikov tinfo->count4 = cfg->items4; 12475f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct chashentry); 12485f379342SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_HASH; 12495f379342SAlexander V. Chernikov tinfo->size6 = cfg->size6; 12505f379342SAlexander V. Chernikov tinfo->count6 = cfg->items6; 12515f379342SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct chashentry); 12525f379342SAlexander V. Chernikov } 12535f379342SAlexander V. Chernikov 125474b941f0SAlexander V. Chernikov static int 125574b941f0SAlexander V. Chernikov ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e, 125674b941f0SAlexander V. Chernikov ipfw_obj_tentry *tent) 125774b941f0SAlexander V. Chernikov { 12580bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 125974b941f0SAlexander V. Chernikov struct chashentry *ent; 126074b941f0SAlexander V. Chernikov 12610bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 126274b941f0SAlexander V. Chernikov ent = (struct chashentry *)e; 126374b941f0SAlexander V. Chernikov 126474b941f0SAlexander V. Chernikov if (ent->type == AF_INET) { 12650bce0c23SAlexander V. Chernikov tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - cfg->mask4)); 12660bce0c23SAlexander V. Chernikov tent->masklen = cfg->mask4; 126774b941f0SAlexander V. Chernikov tent->subtype = AF_INET; 12680cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value; 126974b941f0SAlexander V. Chernikov #ifdef INET6 127074b941f0SAlexander V. Chernikov } else { 127174b941f0SAlexander V. Chernikov memcpy(&tent->k, &ent->a.a6, sizeof(struct in6_addr)); 12720bce0c23SAlexander V. Chernikov tent->masklen = cfg->mask6; 127374b941f0SAlexander V. Chernikov tent->subtype = AF_INET6; 12740cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value; 127574b941f0SAlexander V. Chernikov #endif 127674b941f0SAlexander V. Chernikov } 127774b941f0SAlexander V. Chernikov 127874b941f0SAlexander V. Chernikov return (0); 127974b941f0SAlexander V. Chernikov } 128074b941f0SAlexander V. Chernikov 1281ce2817b5SAlexander V. Chernikov static uint32_t 1282ce2817b5SAlexander V. Chernikov hash_ent(struct chashentry *ent, int af, int mlen, uint32_t size) 1283ce2817b5SAlexander V. Chernikov { 1284ce2817b5SAlexander V. Chernikov uint32_t hash; 1285ce2817b5SAlexander V. Chernikov 1286ce2817b5SAlexander V. Chernikov if (af == AF_INET) { 1287ce2817b5SAlexander V. Chernikov hash = hash_ip(ent->a.a4, size); 1288ce2817b5SAlexander V. Chernikov } else { 1289ce2817b5SAlexander V. Chernikov if (mlen == 64) 1290ce2817b5SAlexander V. Chernikov hash = hash_ip64(&ent->a.a6, size); 1291ce2817b5SAlexander V. Chernikov else 1292ce2817b5SAlexander V. Chernikov hash = hash_ip6(&ent->a.a6, size); 1293ce2817b5SAlexander V. Chernikov } 1294ce2817b5SAlexander V. Chernikov 1295ce2817b5SAlexander V. Chernikov return (hash); 1296ce2817b5SAlexander V. Chernikov } 1297ce2817b5SAlexander V. Chernikov 1298ce2817b5SAlexander V. Chernikov static int 1299ce2817b5SAlexander V. Chernikov tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent) 1300ce2817b5SAlexander V. Chernikov { 1301ce2817b5SAlexander V. Chernikov struct in6_addr mask6; 1302ce2817b5SAlexander V. Chernikov int mlen; 1303ce2817b5SAlexander V. Chernikov 1304ce2817b5SAlexander V. Chernikov 1305ce2817b5SAlexander V. Chernikov mlen = tei->masklen; 1306ce2817b5SAlexander V. Chernikov 1307ce2817b5SAlexander V. Chernikov if (tei->subtype == AF_INET) { 1308ce2817b5SAlexander V. Chernikov #ifdef INET 1309ce2817b5SAlexander V. Chernikov if (mlen > 32) 1310ce2817b5SAlexander V. Chernikov return (EINVAL); 1311ce2817b5SAlexander V. Chernikov ent->type = AF_INET; 1312ce2817b5SAlexander V. Chernikov 1313ce2817b5SAlexander V. Chernikov /* Calculate masked address */ 1314ce2817b5SAlexander V. Chernikov ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen); 1315ce2817b5SAlexander V. Chernikov #endif 1316ce2817b5SAlexander V. Chernikov #ifdef INET6 1317ce2817b5SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 1318ce2817b5SAlexander V. Chernikov /* IPv6 case */ 1319ce2817b5SAlexander V. Chernikov if (mlen > 128) 1320ce2817b5SAlexander V. Chernikov return (EINVAL); 1321ce2817b5SAlexander V. Chernikov ent->type = AF_INET6; 1322ce2817b5SAlexander V. Chernikov 1323ce2817b5SAlexander V. Chernikov ipv6_writemask(&mask6, mlen); 1324ce2817b5SAlexander V. Chernikov memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr)); 1325ce2817b5SAlexander V. Chernikov APPLY_MASK(&ent->a.a6, &mask6); 1326ce2817b5SAlexander V. Chernikov #endif 1327ce2817b5SAlexander V. Chernikov } else { 1328ce2817b5SAlexander V. Chernikov /* Unknown CIDR type */ 1329ce2817b5SAlexander V. Chernikov return (EINVAL); 1330ce2817b5SAlexander V. Chernikov } 1331ce2817b5SAlexander V. Chernikov 1332ce2817b5SAlexander V. Chernikov return (0); 1333ce2817b5SAlexander V. Chernikov } 1334ce2817b5SAlexander V. Chernikov 133574b941f0SAlexander V. Chernikov static int 1336914bffb6SAlexander V. Chernikov ta_find_chash_tentry(void *ta_state, struct table_info *ti, 1337914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 133874b941f0SAlexander V. Chernikov { 13390bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 1340ce2817b5SAlexander V. Chernikov struct chashbhead *head; 1341ce2817b5SAlexander V. Chernikov struct chashentry ent, *tmp; 1342ce2817b5SAlexander V. Chernikov struct tentry_info tei; 1343ce2817b5SAlexander V. Chernikov int error; 1344ce2817b5SAlexander V. Chernikov uint32_t hash; 134574b941f0SAlexander V. Chernikov 13460bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1347ce2817b5SAlexander V. Chernikov 1348ce2817b5SAlexander V. Chernikov memset(&ent, 0, sizeof(ent)); 1349ce2817b5SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 1350ce2817b5SAlexander V. Chernikov 1351914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) { 1352914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr; 13530bce0c23SAlexander V. Chernikov tei.masklen = cfg->mask4; 1354ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET; 135574b941f0SAlexander V. Chernikov 1356ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0) 1357ce2817b5SAlexander V. Chernikov return (error); 1358ce2817b5SAlexander V. Chernikov 13590bce0c23SAlexander V. Chernikov head = cfg->head4; 13600bce0c23SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET, cfg->mask4, cfg->size4); 1361ce2817b5SAlexander V. Chernikov /* Check for existence */ 1362ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1363ce2817b5SAlexander V. Chernikov if (tmp->a.a4 != ent.a.a4) 1364ce2817b5SAlexander V. Chernikov continue; 1365ce2817b5SAlexander V. Chernikov 1366ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent); 136774b941f0SAlexander V. Chernikov return (0); 136874b941f0SAlexander V. Chernikov } 1369ce2817b5SAlexander V. Chernikov } else { 1370914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr6; 13710bce0c23SAlexander V. Chernikov tei.masklen = cfg->mask6; 1372ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET6; 1373ce2817b5SAlexander V. Chernikov 1374ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0) 1375ce2817b5SAlexander V. Chernikov return (error); 1376ce2817b5SAlexander V. Chernikov 13770bce0c23SAlexander V. Chernikov head = cfg->head6; 13780bce0c23SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET6, cfg->mask6, cfg->size6); 1379ce2817b5SAlexander V. Chernikov /* Check for existence */ 1380ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1381ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0) 1382ce2817b5SAlexander V. Chernikov continue; 1383ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent); 1384ce2817b5SAlexander V. Chernikov return (0); 1385ce2817b5SAlexander V. Chernikov } 1386ce2817b5SAlexander V. Chernikov } 1387ce2817b5SAlexander V. Chernikov 138874b941f0SAlexander V. Chernikov return (ENOENT); 138974b941f0SAlexander V. Chernikov } 139074b941f0SAlexander V. Chernikov 139174b941f0SAlexander V. Chernikov static void 139274b941f0SAlexander V. Chernikov ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f, 139374b941f0SAlexander V. Chernikov void *arg) 139474b941f0SAlexander V. Chernikov { 13950bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 139674b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next; 139774b941f0SAlexander V. Chernikov int i; 139874b941f0SAlexander V. Chernikov 13990bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 140074b941f0SAlexander V. Chernikov 14010bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 14020bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next) 140374b941f0SAlexander V. Chernikov f(ent, arg); 140474b941f0SAlexander V. Chernikov 14050bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 14060bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next) 140774b941f0SAlexander V. Chernikov f(ent, arg); 140874b941f0SAlexander V. Chernikov } 140974b941f0SAlexander V. Chernikov 141074b941f0SAlexander V. Chernikov static int 141174b941f0SAlexander V. Chernikov ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 141274b941f0SAlexander V. Chernikov void *ta_buf) 141374b941f0SAlexander V. Chernikov { 141474b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 141574b941f0SAlexander V. Chernikov struct chashentry *ent; 1416ce2817b5SAlexander V. Chernikov int error; 141774b941f0SAlexander V. Chernikov 141874b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 141974b941f0SAlexander V. Chernikov 142074b941f0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 142174b941f0SAlexander V. Chernikov 1422ce2817b5SAlexander V. Chernikov error = tei_to_chash_ent(tei, ent); 1423ce2817b5SAlexander V. Chernikov if (error != 0) { 1424ce2817b5SAlexander V. Chernikov free(ent, M_IPFW_TBL); 1425ce2817b5SAlexander V. Chernikov return (error); 142674b941f0SAlexander V. Chernikov } 1427ce2817b5SAlexander V. Chernikov tb->ent_ptr = ent; 142874b941f0SAlexander V. Chernikov 142974b941f0SAlexander V. Chernikov return (0); 143074b941f0SAlexander V. Chernikov } 143174b941f0SAlexander V. Chernikov 143274b941f0SAlexander V. Chernikov static int 143374b941f0SAlexander V. Chernikov ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1434b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 143574b941f0SAlexander V. Chernikov { 14360bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 143774b941f0SAlexander V. Chernikov struct chashbhead *head; 143874b941f0SAlexander V. Chernikov struct chashentry *ent, *tmp; 143974b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 144074b941f0SAlexander V. Chernikov int exists; 1441648e8380SAlexander V. Chernikov uint32_t hash, value; 144274b941f0SAlexander V. Chernikov 14430bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 144474b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 144574b941f0SAlexander V. Chernikov ent = (struct chashentry *)tb->ent_ptr; 144674b941f0SAlexander V. Chernikov hash = 0; 144774b941f0SAlexander V. Chernikov exists = 0; 144874b941f0SAlexander V. Chernikov 144913263632SAlexander V. Chernikov /* Read current value from @tei */ 145013263632SAlexander V. Chernikov ent->value = tei->value; 145113263632SAlexander V. Chernikov 145213263632SAlexander V. Chernikov /* Read cuurrent value */ 145374b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) { 14540bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask4) 145574b941f0SAlexander V. Chernikov return (EINVAL); 14560bce0c23SAlexander V. Chernikov head = cfg->head4; 14570bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4); 1458ce2817b5SAlexander V. Chernikov 145974b941f0SAlexander V. Chernikov /* Check for existence */ 146074b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 146174b941f0SAlexander V. Chernikov if (tmp->a.a4 == ent->a.a4) { 146274b941f0SAlexander V. Chernikov exists = 1; 146374b941f0SAlexander V. Chernikov break; 146474b941f0SAlexander V. Chernikov } 146574b941f0SAlexander V. Chernikov } 146674b941f0SAlexander V. Chernikov } else { 14670bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask6) 146874b941f0SAlexander V. Chernikov return (EINVAL); 14690bce0c23SAlexander V. Chernikov head = cfg->head6; 14700bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6); 147174b941f0SAlexander V. Chernikov /* Check for existence */ 147274b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1473ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) == 0) { 147474b941f0SAlexander V. Chernikov exists = 1; 147574b941f0SAlexander V. Chernikov break; 147674b941f0SAlexander V. Chernikov } 147774b941f0SAlexander V. Chernikov } 147874b941f0SAlexander V. Chernikov } 147974b941f0SAlexander V. Chernikov 148074b941f0SAlexander V. Chernikov if (exists == 1) { 148174b941f0SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 148274b941f0SAlexander V. Chernikov return (EEXIST); 148374b941f0SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 1484648e8380SAlexander V. Chernikov value = tmp->value; 148574b941f0SAlexander V. Chernikov tmp->value = tei->value; 1486648e8380SAlexander V. Chernikov tei->value = value; 148774b941f0SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 148874b941f0SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 148974b941f0SAlexander V. Chernikov *pnum = 0; 149074b941f0SAlexander V. Chernikov } else { 14914c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 14924c0c07a5SAlexander V. Chernikov return (EFBIG); 149374b941f0SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next); 149474b941f0SAlexander V. Chernikov tb->ent_ptr = NULL; 149574b941f0SAlexander V. Chernikov *pnum = 1; 1496ce2817b5SAlexander V. Chernikov 1497b6ee846eSAlexander V. Chernikov /* Update counters */ 1498b6ee846eSAlexander V. Chernikov if (tei->subtype == AF_INET) 14990bce0c23SAlexander V. Chernikov cfg->items4++; 1500b6ee846eSAlexander V. Chernikov else 15010bce0c23SAlexander V. Chernikov cfg->items6++; 150274b941f0SAlexander V. Chernikov } 150374b941f0SAlexander V. Chernikov 150474b941f0SAlexander V. Chernikov return (0); 150574b941f0SAlexander V. Chernikov } 150674b941f0SAlexander V. Chernikov 150774b941f0SAlexander V. Chernikov static int 150874b941f0SAlexander V. Chernikov ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 150974b941f0SAlexander V. Chernikov void *ta_buf) 151074b941f0SAlexander V. Chernikov { 151174b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 151274b941f0SAlexander V. Chernikov 151374b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 151474b941f0SAlexander V. Chernikov 1515ce2817b5SAlexander V. Chernikov return (tei_to_chash_ent(tei, &tb->ent)); 151674b941f0SAlexander V. Chernikov } 151774b941f0SAlexander V. Chernikov 151874b941f0SAlexander V. Chernikov static int 151974b941f0SAlexander V. Chernikov ta_del_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; 15240bce0c23SAlexander V. Chernikov struct chashentry *tmp, *tmp_next, *ent; 152574b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 152674b941f0SAlexander V. Chernikov uint32_t hash; 152774b941f0SAlexander V. Chernikov 15280bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 152974b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 15300bce0c23SAlexander V. Chernikov ent = &tb->ent; 153174b941f0SAlexander V. Chernikov 153274b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) { 15330bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask4) 153474b941f0SAlexander V. Chernikov return (EINVAL); 15350bce0c23SAlexander V. Chernikov head = cfg->head4; 15360bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4); 153774b941f0SAlexander V. Chernikov 15380bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) { 15390bce0c23SAlexander V. Chernikov if (tmp->a.a4 != ent->a.a4) 1540648e8380SAlexander V. Chernikov continue; 1541648e8380SAlexander V. Chernikov 15420bce0c23SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, chashentry, next); 15430bce0c23SAlexander V. Chernikov cfg->items4--; 15440bce0c23SAlexander V. Chernikov tb->ent_ptr = tmp; 15450bce0c23SAlexander V. Chernikov tei->value = tmp->value; 1546648e8380SAlexander V. Chernikov *pnum = 1; 154774b941f0SAlexander V. Chernikov return (0); 154874b941f0SAlexander V. Chernikov } 154974b941f0SAlexander V. Chernikov } else { 15500bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask6) 155174b941f0SAlexander V. Chernikov return (EINVAL); 15520bce0c23SAlexander V. Chernikov head = cfg->head6; 15530bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6); 15540bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) { 15550bce0c23SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) != 0) 1556648e8380SAlexander V. Chernikov continue; 1557648e8380SAlexander V. Chernikov 15580bce0c23SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, chashentry, next); 15590bce0c23SAlexander V. Chernikov cfg->items6--; 15600bce0c23SAlexander V. Chernikov tb->ent_ptr = tmp; 15610bce0c23SAlexander V. Chernikov tei->value = tmp->value; 156274b941f0SAlexander V. Chernikov *pnum = 1; 156374b941f0SAlexander V. Chernikov return (0); 156474b941f0SAlexander V. Chernikov } 156574b941f0SAlexander V. Chernikov } 156674b941f0SAlexander V. Chernikov 156774b941f0SAlexander V. Chernikov return (ENOENT); 156874b941f0SAlexander V. Chernikov } 156974b941f0SAlexander V. Chernikov 157074b941f0SAlexander V. Chernikov static void 157174b941f0SAlexander V. Chernikov ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 157274b941f0SAlexander V. Chernikov void *ta_buf) 157374b941f0SAlexander V. Chernikov { 157474b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 157574b941f0SAlexander V. Chernikov 157674b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 157774b941f0SAlexander V. Chernikov 157874b941f0SAlexander V. Chernikov if (tb->ent_ptr != NULL) 157974b941f0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 158074b941f0SAlexander V. Chernikov } 158174b941f0SAlexander V. Chernikov 1582ce2817b5SAlexander V. Chernikov /* 1583ce2817b5SAlexander V. Chernikov * Hash growing callbacks. 1584ce2817b5SAlexander V. Chernikov */ 1585ce2817b5SAlexander V. Chernikov 1586b6ee846eSAlexander V. Chernikov static int 1587301290bcSAlexander V. Chernikov ta_need_modify_chash(void *ta_state, struct table_info *ti, uint32_t count, 1588b6ee846eSAlexander V. Chernikov uint64_t *pflags) 1589b6ee846eSAlexander V. Chernikov { 1590b6ee846eSAlexander V. Chernikov struct chash_cfg *cfg; 1591b6ee846eSAlexander V. Chernikov uint64_t data; 1592b6ee846eSAlexander V. Chernikov 1593b6ee846eSAlexander V. Chernikov /* 1594b6ee846eSAlexander V. Chernikov * Since we don't know exact number of IPv4/IPv6 records in @count, 1595b6ee846eSAlexander V. Chernikov * ignore non-zero @count value at all. Check current hash sizes 1596b6ee846eSAlexander V. Chernikov * and return appropriate data. 1597b6ee846eSAlexander V. Chernikov */ 1598b6ee846eSAlexander V. Chernikov 1599b6ee846eSAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1600b6ee846eSAlexander V. Chernikov 1601b6ee846eSAlexander V. Chernikov data = 0; 1602b6ee846eSAlexander V. Chernikov if (cfg->items4 > cfg->size4 && cfg->size4 < 65536) 1603b6ee846eSAlexander V. Chernikov data |= (cfg->size4 * 2) << 16; 1604b6ee846eSAlexander V. Chernikov if (cfg->items6 > cfg->size6 && cfg->size6 < 65536) 1605b6ee846eSAlexander V. Chernikov data |= cfg->size6 * 2; 1606b6ee846eSAlexander V. Chernikov 1607b6ee846eSAlexander V. Chernikov if (data != 0) { 1608b6ee846eSAlexander V. Chernikov *pflags = data; 1609301290bcSAlexander V. Chernikov return (1); 1610b6ee846eSAlexander V. Chernikov } 1611b6ee846eSAlexander V. Chernikov 1612301290bcSAlexander V. Chernikov return (0); 1613b6ee846eSAlexander V. Chernikov } 1614b6ee846eSAlexander V. Chernikov 1615ce2817b5SAlexander V. Chernikov /* 1616ce2817b5SAlexander V. Chernikov * Allocate new, larger chash. 1617ce2817b5SAlexander V. Chernikov */ 1618ce2817b5SAlexander V. Chernikov static int 1619ce2817b5SAlexander V. Chernikov ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags) 1620ce2817b5SAlexander V. Chernikov { 1621ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1622ce2817b5SAlexander V. Chernikov struct chashbhead *head; 1623ce2817b5SAlexander V. Chernikov int i; 1624ce2817b5SAlexander V. Chernikov 1625ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1626ce2817b5SAlexander V. Chernikov 1627ce2817b5SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 1628b6ee846eSAlexander V. Chernikov mi->size = (*pflags >> 16) & 0xFFFF; 1629b6ee846eSAlexander V. Chernikov mi->size6 = *pflags & 0xFFFF; 1630b6ee846eSAlexander V. Chernikov if (mi->size > 0) { 1631b6ee846eSAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size, 1632b6ee846eSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1633ce2817b5SAlexander V. Chernikov for (i = 0; i < mi->size; i++) 1634ce2817b5SAlexander V. Chernikov SLIST_INIT(&head[i]); 1635ce2817b5SAlexander V. Chernikov mi->main_ptr = head; 1636b6ee846eSAlexander V. Chernikov } 1637b6ee846eSAlexander V. Chernikov 1638b6ee846eSAlexander V. Chernikov if (mi->size6 > 0) { 1639b6ee846eSAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size6, 1640b6ee846eSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1641b6ee846eSAlexander V. Chernikov for (i = 0; i < mi->size6; i++) 1642b6ee846eSAlexander V. Chernikov SLIST_INIT(&head[i]); 1643b6ee846eSAlexander V. Chernikov mi->main_ptr6 = head; 1644b6ee846eSAlexander V. Chernikov } 1645ce2817b5SAlexander V. Chernikov 1646ce2817b5SAlexander V. Chernikov return (0); 1647ce2817b5SAlexander V. Chernikov } 1648ce2817b5SAlexander V. Chernikov 1649ce2817b5SAlexander V. Chernikov /* 1650ce2817b5SAlexander V. Chernikov * Copy data from old runtime array to new one. 1651ce2817b5SAlexander V. Chernikov */ 1652ce2817b5SAlexander V. Chernikov static int 1653ce2817b5SAlexander V. Chernikov ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1654ce2817b5SAlexander V. Chernikov uint64_t *pflags) 1655ce2817b5SAlexander V. Chernikov { 1656ce2817b5SAlexander V. Chernikov 1657ce2817b5SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */ 1658ce2817b5SAlexander V. Chernikov return (0); 1659ce2817b5SAlexander V. Chernikov } 1660ce2817b5SAlexander V. Chernikov 1661ce2817b5SAlexander V. Chernikov /* 1662ce2817b5SAlexander V. Chernikov * Switch old & new arrays. 1663ce2817b5SAlexander V. Chernikov */ 1664301290bcSAlexander V. Chernikov static void 1665ce2817b5SAlexander V. Chernikov ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1666ce2817b5SAlexander V. Chernikov uint64_t pflags) 1667ce2817b5SAlexander V. Chernikov { 1668ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1669b6ee846eSAlexander V. Chernikov struct chash_cfg *cfg; 1670ce2817b5SAlexander V. Chernikov struct chashbhead *old_head, *new_head; 1671ce2817b5SAlexander V. Chernikov struct chashentry *ent, *ent_next; 1672ce2817b5SAlexander V. Chernikov int af, i, mlen; 1673ce2817b5SAlexander V. Chernikov uint32_t nhash; 1674b6ee846eSAlexander V. Chernikov size_t old_size, new_size; 1675ce2817b5SAlexander V. Chernikov 1676ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1677b6ee846eSAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1678ce2817b5SAlexander V. Chernikov 1679ce2817b5SAlexander V. Chernikov /* Check which hash we need to grow and do we still need that */ 1680b6ee846eSAlexander V. Chernikov if (mi->size > 0 && cfg->size4 < mi->size) { 1681ce2817b5SAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr; 1682b6ee846eSAlexander V. Chernikov new_size = mi->size; 1683b6ee846eSAlexander V. Chernikov old_size = cfg->size4; 1684b6ee846eSAlexander V. Chernikov old_head = ti->state; 1685b6ee846eSAlexander V. Chernikov mlen = cfg->mask4; 1686b6ee846eSAlexander V. Chernikov af = AF_INET; 1687b6ee846eSAlexander V. Chernikov 1688ce2817b5SAlexander V. Chernikov for (i = 0; i < old_size; i++) { 1689ce2817b5SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 1690b6ee846eSAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, new_size); 1691ce2817b5SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 1692ce2817b5SAlexander V. Chernikov } 1693ce2817b5SAlexander V. Chernikov } 1694ce2817b5SAlexander V. Chernikov 1695ce2817b5SAlexander V. Chernikov ti->state = new_head; 1696b6ee846eSAlexander V. Chernikov cfg->head4 = new_head; 1697b6ee846eSAlexander V. Chernikov cfg->size4 = mi->size; 1698b6ee846eSAlexander V. Chernikov mi->main_ptr = old_head; 1699ce2817b5SAlexander V. Chernikov } 1700ce2817b5SAlexander V. Chernikov 1701b6ee846eSAlexander V. Chernikov if (mi->size6 > 0 && cfg->size6 < mi->size6) { 1702b6ee846eSAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr6; 1703b6ee846eSAlexander V. Chernikov new_size = mi->size6; 1704b6ee846eSAlexander V. Chernikov old_size = cfg->size6; 1705b6ee846eSAlexander V. Chernikov old_head = ti->xstate; 1706b6ee846eSAlexander V. Chernikov mlen = cfg->mask6; 1707b6ee846eSAlexander V. Chernikov af = AF_INET6; 1708914bffb6SAlexander V. Chernikov 1709b6ee846eSAlexander V. Chernikov for (i = 0; i < old_size; i++) { 1710b6ee846eSAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 1711b6ee846eSAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, new_size); 1712b6ee846eSAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 1713b6ee846eSAlexander V. Chernikov } 1714b6ee846eSAlexander V. Chernikov } 1715b6ee846eSAlexander V. Chernikov 1716b6ee846eSAlexander V. Chernikov ti->xstate = new_head; 1717b6ee846eSAlexander V. Chernikov cfg->head6 = new_head; 1718b6ee846eSAlexander V. Chernikov cfg->size6 = mi->size6; 1719b6ee846eSAlexander V. Chernikov mi->main_ptr6 = old_head; 1720b6ee846eSAlexander V. Chernikov } 1721b6ee846eSAlexander V. Chernikov 1722b6ee846eSAlexander V. Chernikov /* Update lower 32 bits with new values */ 1723b6ee846eSAlexander V. Chernikov ti->data &= 0xFFFFFFFF00000000; 1724b6ee846eSAlexander V. Chernikov ti->data |= log2(cfg->size4) << 8 | log2(cfg->size6); 1725ce2817b5SAlexander V. Chernikov } 1726ce2817b5SAlexander V. Chernikov 1727ce2817b5SAlexander V. Chernikov /* 1728ce2817b5SAlexander V. Chernikov * Free unneded array. 1729ce2817b5SAlexander V. Chernikov */ 1730ce2817b5SAlexander V. Chernikov static void 1731ce2817b5SAlexander V. Chernikov ta_flush_mod_chash(void *ta_buf) 1732ce2817b5SAlexander V. Chernikov { 1733ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1734ce2817b5SAlexander V. Chernikov 1735ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1736ce2817b5SAlexander V. Chernikov if (mi->main_ptr != NULL) 1737ce2817b5SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 1738b6ee846eSAlexander V. Chernikov if (mi->main_ptr6 != NULL) 1739b6ee846eSAlexander V. Chernikov free(mi->main_ptr6, M_IPFW); 1740ce2817b5SAlexander V. Chernikov } 1741ce2817b5SAlexander V. Chernikov 1742c21034b7SAlexander V. Chernikov struct table_algo addr_hash = { 1743c21034b7SAlexander V. Chernikov .name = "addr:hash", 1744c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR, 174557a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_chash), 174674b941f0SAlexander V. Chernikov .init = ta_init_chash, 174774b941f0SAlexander V. Chernikov .destroy = ta_destroy_chash, 174874b941f0SAlexander V. Chernikov .prepare_add = ta_prepare_add_chash, 174974b941f0SAlexander V. Chernikov .prepare_del = ta_prepare_del_chash, 175074b941f0SAlexander V. Chernikov .add = ta_add_chash, 175174b941f0SAlexander V. Chernikov .del = ta_del_chash, 175274b941f0SAlexander V. Chernikov .flush_entry = ta_flush_chash_entry, 175374b941f0SAlexander V. Chernikov .foreach = ta_foreach_chash, 175474b941f0SAlexander V. Chernikov .dump_tentry = ta_dump_chash_tentry, 175574b941f0SAlexander V. Chernikov .find_tentry = ta_find_chash_tentry, 175674b941f0SAlexander V. Chernikov .print_config = ta_print_chash_config, 17575f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_chash_tinfo, 1758301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_chash, 1759ce2817b5SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_chash, 1760ce2817b5SAlexander V. Chernikov .fill_mod = ta_fill_mod_chash, 1761ce2817b5SAlexander V. Chernikov .modify = ta_modify_chash, 1762ce2817b5SAlexander V. Chernikov .flush_mod = ta_flush_mod_chash, 176374b941f0SAlexander V. Chernikov }; 176474b941f0SAlexander V. Chernikov 176574b941f0SAlexander V. Chernikov 176674b941f0SAlexander V. Chernikov /* 176768394ec8SAlexander V. Chernikov * Iface table cmds. 176868394ec8SAlexander V. Chernikov * 176968394ec8SAlexander V. Chernikov * Implementation: 177068394ec8SAlexander V. Chernikov * 177168394ec8SAlexander V. Chernikov * Runtime part: 177268394ec8SAlexander V. Chernikov * - sorted array of "struct ifidx" pointed by ti->state. 1773b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to IFIDX_CHUNK. Only existing 177468394ec8SAlexander V. Chernikov * interfaces are stored in array, however its allocated size is 177568394ec8SAlexander V. Chernikov * sufficient to hold all table records if needed. 177668394ec8SAlexander V. Chernikov * - current array size is stored in ti->data 177768394ec8SAlexander V. Chernikov * 177868394ec8SAlexander V. Chernikov * Table data: 177968394ec8SAlexander V. Chernikov * - "struct iftable_cfg" is allocated to store table state (ta_state). 178068394ec8SAlexander V. Chernikov * - All table records are stored inside namedobj instance. 17819f7d47b0SAlexander V. Chernikov * 17829f7d47b0SAlexander V. Chernikov */ 17839f7d47b0SAlexander V. Chernikov 178468394ec8SAlexander V. Chernikov struct ifidx { 178568394ec8SAlexander V. Chernikov uint16_t kidx; 178668394ec8SAlexander V. Chernikov uint16_t spare; 178768394ec8SAlexander V. Chernikov uint32_t value; 178868394ec8SAlexander V. Chernikov }; 17890cba2b28SAlexander V. Chernikov #define DEFAULT_IFIDX_SIZE 64 179068394ec8SAlexander V. Chernikov 179168394ec8SAlexander V. Chernikov struct iftable_cfg; 179268394ec8SAlexander V. Chernikov 179368394ec8SAlexander V. Chernikov struct ifentry { 179468394ec8SAlexander V. Chernikov struct named_object no; 179568394ec8SAlexander V. Chernikov struct ipfw_ifc ic; 179668394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 179768394ec8SAlexander V. Chernikov uint32_t value; 179868394ec8SAlexander V. Chernikov int linked; 179968394ec8SAlexander V. Chernikov }; 180068394ec8SAlexander V. Chernikov 180168394ec8SAlexander V. Chernikov struct iftable_cfg { 180268394ec8SAlexander V. Chernikov struct namedobj_instance *ii; 180368394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 180468394ec8SAlexander V. Chernikov struct table_info *ti; 180568394ec8SAlexander V. Chernikov void *main_ptr; 180668394ec8SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 180768394ec8SAlexander V. Chernikov size_t count; /* Number of all items */ 180868394ec8SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 180968394ec8SAlexander V. Chernikov }; 181068394ec8SAlexander V. Chernikov 18110bce0c23SAlexander V. Chernikov struct ta_buf_ifidx 18120bce0c23SAlexander V. Chernikov { 18130bce0c23SAlexander V. Chernikov struct ifentry *ife; 18140bce0c23SAlexander V. Chernikov uint32_t value; 18150bce0c23SAlexander V. Chernikov }; 181668394ec8SAlexander V. Chernikov 181768394ec8SAlexander V. Chernikov int compare_ifidx(const void *k, const void *v); 181868394ec8SAlexander V. Chernikov static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex); 181968394ec8SAlexander V. Chernikov 182068394ec8SAlexander V. Chernikov int 182168394ec8SAlexander V. Chernikov compare_ifidx(const void *k, const void *v) 182268394ec8SAlexander V. Chernikov { 1823d4e1b515SAlexander V. Chernikov const struct ifidx *ifidx; 182468394ec8SAlexander V. Chernikov uint16_t key; 182568394ec8SAlexander V. Chernikov 1826d4e1b515SAlexander V. Chernikov key = *((const uint16_t *)k); 1827d4e1b515SAlexander V. Chernikov ifidx = (const struct ifidx *)v; 182868394ec8SAlexander V. Chernikov 182968394ec8SAlexander V. Chernikov if (key < ifidx->kidx) 183068394ec8SAlexander V. Chernikov return (-1); 183168394ec8SAlexander V. Chernikov else if (key > ifidx->kidx) 183268394ec8SAlexander V. Chernikov return (1); 183368394ec8SAlexander V. Chernikov 183468394ec8SAlexander V. Chernikov return (0); 183568394ec8SAlexander V. Chernikov } 183668394ec8SAlexander V. Chernikov 183768394ec8SAlexander V. Chernikov /* 183868394ec8SAlexander V. Chernikov * Adds item @item with key @key into ascending-sorted array @base. 183968394ec8SAlexander V. Chernikov * Assumes @base has enough additional storage. 184068394ec8SAlexander V. Chernikov * 184168394ec8SAlexander V. Chernikov * Returns 1 on success, 0 on duplicate key. 184268394ec8SAlexander V. Chernikov */ 18439f7d47b0SAlexander V. Chernikov static int 184468394ec8SAlexander V. Chernikov badd(const void *key, void *item, void *base, size_t nmemb, 184568394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *)) 184668394ec8SAlexander V. Chernikov { 184768394ec8SAlexander V. Chernikov int min, max, mid, shift, res; 184868394ec8SAlexander V. Chernikov caddr_t paddr; 184968394ec8SAlexander V. Chernikov 185068394ec8SAlexander V. Chernikov if (nmemb == 0) { 185168394ec8SAlexander V. Chernikov memcpy(base, item, size); 185268394ec8SAlexander V. Chernikov return (1); 185368394ec8SAlexander V. Chernikov } 185468394ec8SAlexander V. Chernikov 185568394ec8SAlexander V. Chernikov /* Binary search */ 185668394ec8SAlexander V. Chernikov min = 0; 185768394ec8SAlexander V. Chernikov max = nmemb - 1; 185868394ec8SAlexander V. Chernikov mid = 0; 185968394ec8SAlexander V. Chernikov while (min <= max) { 186068394ec8SAlexander V. Chernikov mid = (min + max) / 2; 186168394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 186268394ec8SAlexander V. Chernikov if (res == 0) 186368394ec8SAlexander V. Chernikov return (0); 186468394ec8SAlexander V. Chernikov 186568394ec8SAlexander V. Chernikov if (res > 0) 186668394ec8SAlexander V. Chernikov min = mid + 1; 186768394ec8SAlexander V. Chernikov else 186868394ec8SAlexander V. Chernikov max = mid - 1; 186968394ec8SAlexander V. Chernikov } 187068394ec8SAlexander V. Chernikov 187168394ec8SAlexander V. Chernikov /* Item not found. */ 187268394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 187368394ec8SAlexander V. Chernikov if (res > 0) 187468394ec8SAlexander V. Chernikov shift = mid + 1; 187568394ec8SAlexander V. Chernikov else 187668394ec8SAlexander V. Chernikov shift = mid; 187768394ec8SAlexander V. Chernikov 187868394ec8SAlexander V. Chernikov paddr = (caddr_t)base + shift * size; 187968394ec8SAlexander V. Chernikov if (nmemb > shift) 188068394ec8SAlexander V. Chernikov memmove(paddr + size, paddr, (nmemb - shift) * size); 188168394ec8SAlexander V. Chernikov 188268394ec8SAlexander V. Chernikov memcpy(paddr, item, size); 188368394ec8SAlexander V. Chernikov 188468394ec8SAlexander V. Chernikov return (1); 188568394ec8SAlexander V. Chernikov } 188668394ec8SAlexander V. Chernikov 188768394ec8SAlexander V. Chernikov /* 188868394ec8SAlexander V. Chernikov * Deletes item with key @key from ascending-sorted array @base. 188968394ec8SAlexander V. Chernikov * 189068394ec8SAlexander V. Chernikov * Returns 1 on success, 0 for non-existent key. 189168394ec8SAlexander V. Chernikov */ 189268394ec8SAlexander V. Chernikov static int 189368394ec8SAlexander V. Chernikov bdel(const void *key, void *base, size_t nmemb, size_t size, 189468394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *)) 189568394ec8SAlexander V. Chernikov { 189668394ec8SAlexander V. Chernikov caddr_t item; 189768394ec8SAlexander V. Chernikov size_t sz; 189868394ec8SAlexander V. Chernikov 189968394ec8SAlexander V. Chernikov item = (caddr_t)bsearch(key, base, nmemb, size, compar); 190068394ec8SAlexander V. Chernikov 190168394ec8SAlexander V. Chernikov if (item == NULL) 190268394ec8SAlexander V. Chernikov return (0); 190368394ec8SAlexander V. Chernikov 190468394ec8SAlexander V. Chernikov sz = (caddr_t)base + nmemb * size - item; 190568394ec8SAlexander V. Chernikov 190668394ec8SAlexander V. Chernikov if (sz > 0) 190768394ec8SAlexander V. Chernikov memmove(item, item + size, sz); 190868394ec8SAlexander V. Chernikov 190968394ec8SAlexander V. Chernikov return (1); 191068394ec8SAlexander V. Chernikov } 191168394ec8SAlexander V. Chernikov 191268394ec8SAlexander V. Chernikov static struct ifidx * 191368394ec8SAlexander V. Chernikov ifidx_find(struct table_info *ti, void *key) 191468394ec8SAlexander V. Chernikov { 191568394ec8SAlexander V. Chernikov struct ifidx *ifi; 191668394ec8SAlexander V. Chernikov 191768394ec8SAlexander V. Chernikov ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx), 191868394ec8SAlexander V. Chernikov compare_ifidx); 191968394ec8SAlexander V. Chernikov 192068394ec8SAlexander V. Chernikov return (ifi); 192168394ec8SAlexander V. Chernikov } 192268394ec8SAlexander V. Chernikov 192368394ec8SAlexander V. Chernikov static int 192468394ec8SAlexander V. Chernikov ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen, 19259f7d47b0SAlexander V. Chernikov uint32_t *val) 19269f7d47b0SAlexander V. Chernikov { 192768394ec8SAlexander V. Chernikov struct ifidx *ifi; 19289f7d47b0SAlexander V. Chernikov 192968394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, key); 19309f7d47b0SAlexander V. Chernikov 193168394ec8SAlexander V. Chernikov if (ifi != NULL) { 193268394ec8SAlexander V. Chernikov *val = ifi->value; 19339f7d47b0SAlexander V. Chernikov return (1); 19349f7d47b0SAlexander V. Chernikov } 19359f7d47b0SAlexander V. Chernikov 19369f7d47b0SAlexander V. Chernikov return (0); 19379f7d47b0SAlexander V. Chernikov } 19389f7d47b0SAlexander V. Chernikov 19399f7d47b0SAlexander V. Chernikov static int 194068394ec8SAlexander V. Chernikov ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 1941914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 19429f7d47b0SAlexander V. Chernikov { 194368394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 19449f7d47b0SAlexander V. Chernikov 194568394ec8SAlexander V. Chernikov icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO); 19469f7d47b0SAlexander V. Chernikov 19470cba2b28SAlexander V. Chernikov icfg->ii = ipfw_objhash_create(DEFAULT_IFIDX_SIZE); 19480cba2b28SAlexander V. Chernikov icfg->size = DEFAULT_IFIDX_SIZE; 19490bce0c23SAlexander V. Chernikov icfg->main_ptr = malloc(sizeof(struct ifidx) * icfg->size, M_IPFW, 195068394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 195168394ec8SAlexander V. Chernikov icfg->ch = ch; 19529f7d47b0SAlexander V. Chernikov 195368394ec8SAlexander V. Chernikov *ta_state = icfg; 195468394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 195568394ec8SAlexander V. Chernikov ti->lookup = ta_lookup_ifidx; 19569f7d47b0SAlexander V. Chernikov 19579f7d47b0SAlexander V. Chernikov return (0); 19589f7d47b0SAlexander V. Chernikov } 19599f7d47b0SAlexander V. Chernikov 196068394ec8SAlexander V. Chernikov /* 196168394ec8SAlexander V. Chernikov * Handle tableinfo @ti pointer change (on table array resize). 196268394ec8SAlexander V. Chernikov */ 196368394ec8SAlexander V. Chernikov static void 196468394ec8SAlexander V. Chernikov ta_change_ti_ifidx(void *ta_state, struct table_info *ti) 196568394ec8SAlexander V. Chernikov { 196668394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 196768394ec8SAlexander V. Chernikov 196868394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 196968394ec8SAlexander V. Chernikov icfg->ti = ti; 197068394ec8SAlexander V. Chernikov } 19719f7d47b0SAlexander V. Chernikov 19729f7d47b0SAlexander V. Chernikov static void 197368394ec8SAlexander V. Chernikov destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no, 197468394ec8SAlexander V. Chernikov void *arg) 19759f7d47b0SAlexander V. Chernikov { 197668394ec8SAlexander V. Chernikov struct ifentry *ife; 197768394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 19789f7d47b0SAlexander V. Chernikov 197968394ec8SAlexander V. Chernikov ch = (struct ip_fw_chain *)arg; 198068394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 198168394ec8SAlexander V. Chernikov 198268394ec8SAlexander V. Chernikov ipfw_iface_del_notify(ch, &ife->ic); 198368394ec8SAlexander V. Chernikov free(ife, M_IPFW_TBL); 19849f7d47b0SAlexander V. Chernikov } 19859f7d47b0SAlexander V. Chernikov 198668394ec8SAlexander V. Chernikov 198768394ec8SAlexander V. Chernikov /* 198868394ec8SAlexander V. Chernikov * Destroys table @ti 198968394ec8SAlexander V. Chernikov */ 199068394ec8SAlexander V. Chernikov static void 199168394ec8SAlexander V. Chernikov ta_destroy_ifidx(void *ta_state, struct table_info *ti) 19929f7d47b0SAlexander V. Chernikov { 199368394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 199468394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 199568394ec8SAlexander V. Chernikov 199668394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 199768394ec8SAlexander V. Chernikov ch = icfg->ch; 199868394ec8SAlexander V. Chernikov 199968394ec8SAlexander V. Chernikov if (icfg->main_ptr != NULL) 200068394ec8SAlexander V. Chernikov free(icfg->main_ptr, M_IPFW); 200168394ec8SAlexander V. Chernikov 200268394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch); 200368394ec8SAlexander V. Chernikov 200468394ec8SAlexander V. Chernikov ipfw_objhash_destroy(icfg->ii); 200568394ec8SAlexander V. Chernikov 200668394ec8SAlexander V. Chernikov free(icfg, M_IPFW); 200768394ec8SAlexander V. Chernikov } 200868394ec8SAlexander V. Chernikov 200968394ec8SAlexander V. Chernikov /* 20105f379342SAlexander V. Chernikov * Provide algo-specific table info 20115f379342SAlexander V. Chernikov */ 20125f379342SAlexander V. Chernikov static void 20135f379342SAlexander V. Chernikov ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 20145f379342SAlexander V. Chernikov { 20155f379342SAlexander V. Chernikov struct iftable_cfg *cfg; 20165f379342SAlexander V. Chernikov 20175f379342SAlexander V. Chernikov cfg = (struct iftable_cfg *)ta_state; 20185f379342SAlexander V. Chernikov 20195f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_ARRAY; 20205f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 20215f379342SAlexander V. Chernikov tinfo->count4 = cfg->used; 20225f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct ifidx); 20235f379342SAlexander V. Chernikov } 20245f379342SAlexander V. Chernikov 20255f379342SAlexander V. Chernikov /* 202668394ec8SAlexander V. Chernikov * Prepare state to add to the table: 202768394ec8SAlexander V. Chernikov * allocate ifentry and reference needed interface. 202868394ec8SAlexander V. Chernikov */ 20299f7d47b0SAlexander V. Chernikov static int 203068394ec8SAlexander V. Chernikov ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 203168394ec8SAlexander V. Chernikov void *ta_buf) 203268394ec8SAlexander V. Chernikov { 203368394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 203468394ec8SAlexander V. Chernikov char *ifname; 203568394ec8SAlexander V. Chernikov struct ifentry *ife; 203668394ec8SAlexander V. Chernikov 203768394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 203868394ec8SAlexander V. Chernikov 203968394ec8SAlexander V. Chernikov /* Check if string is terminated */ 204068394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 204168394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 204268394ec8SAlexander V. Chernikov return (EINVAL); 204368394ec8SAlexander V. Chernikov 204468394ec8SAlexander V. Chernikov ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO); 204568394ec8SAlexander V. Chernikov ife->ic.cb = if_notifier; 204668394ec8SAlexander V. Chernikov ife->ic.cbdata = ife; 204768394ec8SAlexander V. Chernikov 2048*8ebca97fSAlexander V. Chernikov if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0) { 2049*8ebca97fSAlexander V. Chernikov free(ife, M_IPFW_TBL); 205068394ec8SAlexander V. Chernikov return (EINVAL); 2051*8ebca97fSAlexander V. Chernikov } 205268394ec8SAlexander V. Chernikov 205368394ec8SAlexander V. Chernikov /* Use ipfw_iface 'ifname' field as stable storage */ 205468394ec8SAlexander V. Chernikov ife->no.name = ife->ic.iface->ifname; 205568394ec8SAlexander V. Chernikov 205668394ec8SAlexander V. Chernikov tb->ife = ife; 205768394ec8SAlexander V. Chernikov 205868394ec8SAlexander V. Chernikov return (0); 205968394ec8SAlexander V. Chernikov } 206068394ec8SAlexander V. Chernikov 206168394ec8SAlexander V. Chernikov static int 2062adea6201SAlexander V. Chernikov ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2063b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 206468394ec8SAlexander V. Chernikov { 206568394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 206668394ec8SAlexander V. Chernikov struct ifentry *ife, *tmp; 206768394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 206868394ec8SAlexander V. Chernikov struct ipfw_iface *iif; 206968394ec8SAlexander V. Chernikov struct ifidx *ifi; 207068394ec8SAlexander V. Chernikov char *ifname; 2071648e8380SAlexander V. Chernikov uint32_t value; 207268394ec8SAlexander V. Chernikov 207368394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 207468394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 207568394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 207668394ec8SAlexander V. Chernikov ife = tb->ife; 207768394ec8SAlexander V. Chernikov 207868394ec8SAlexander V. Chernikov ife->icfg = icfg; 207913263632SAlexander V. Chernikov ife->value = tei->value; 208068394ec8SAlexander V. Chernikov 208168394ec8SAlexander V. Chernikov tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 208268394ec8SAlexander V. Chernikov 208368394ec8SAlexander V. Chernikov if (tmp != NULL) { 208468394ec8SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 208568394ec8SAlexander V. Chernikov return (EEXIST); 208668394ec8SAlexander V. Chernikov 2087648e8380SAlexander V. Chernikov /* Exchange values in @tmp and @tei */ 2088648e8380SAlexander V. Chernikov value = tmp->value; 2089648e8380SAlexander V. Chernikov tmp->value = tei->value; 2090648e8380SAlexander V. Chernikov tei->value = value; 209168394ec8SAlexander V. Chernikov 2092648e8380SAlexander V. Chernikov iif = tmp->ic.iface; 209368394ec8SAlexander V. Chernikov if (iif->resolved != 0) { 2094648e8380SAlexander V. Chernikov /* We have to update runtime value, too */ 209568394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, &iif->ifindex); 209668394ec8SAlexander V. Chernikov ifi->value = ife->value; 209768394ec8SAlexander V. Chernikov } 209868394ec8SAlexander V. Chernikov 209968394ec8SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 210068394ec8SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 2101adea6201SAlexander V. Chernikov *pnum = 0; 210268394ec8SAlexander V. Chernikov return (0); 210368394ec8SAlexander V. Chernikov } 210468394ec8SAlexander V. Chernikov 21054c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 21064c0c07a5SAlexander V. Chernikov return (EFBIG); 21074c0c07a5SAlexander V. Chernikov 210868394ec8SAlexander V. Chernikov /* Link to internal list */ 210968394ec8SAlexander V. Chernikov ipfw_objhash_add(icfg->ii, &ife->no); 211068394ec8SAlexander V. Chernikov 211168394ec8SAlexander V. Chernikov /* Link notifier (possible running its callback) */ 211268394ec8SAlexander V. Chernikov ipfw_iface_add_notify(icfg->ch, &ife->ic); 211368394ec8SAlexander V. Chernikov icfg->count++; 211468394ec8SAlexander V. Chernikov 211568394ec8SAlexander V. Chernikov tb->ife = NULL; 2116adea6201SAlexander V. Chernikov *pnum = 1; 211768394ec8SAlexander V. Chernikov 211868394ec8SAlexander V. Chernikov return (0); 211968394ec8SAlexander V. Chernikov } 212068394ec8SAlexander V. Chernikov 212168394ec8SAlexander V. Chernikov /* 212268394ec8SAlexander V. Chernikov * Prepare to delete key from table. 212368394ec8SAlexander V. Chernikov * Do basic interface name checks. 212468394ec8SAlexander V. Chernikov */ 212568394ec8SAlexander V. Chernikov static int 212668394ec8SAlexander V. Chernikov ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 212768394ec8SAlexander V. Chernikov void *ta_buf) 21289f7d47b0SAlexander V. Chernikov { 212974b941f0SAlexander V. Chernikov struct ta_buf_ifidx *tb; 2130e0a8b9eeSAlexander V. Chernikov char *ifname; 21319f7d47b0SAlexander V. Chernikov 213274b941f0SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 21339f7d47b0SAlexander V. Chernikov 21349f7d47b0SAlexander V. Chernikov /* Check if string is terminated */ 2135e0a8b9eeSAlexander V. Chernikov ifname = (char *)tei->paddr; 2136e0a8b9eeSAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 21379f7d47b0SAlexander V. Chernikov return (EINVAL); 21389f7d47b0SAlexander V. Chernikov 21399f7d47b0SAlexander V. Chernikov return (0); 21409f7d47b0SAlexander V. Chernikov } 21419f7d47b0SAlexander V. Chernikov 214268394ec8SAlexander V. Chernikov /* 214368394ec8SAlexander V. Chernikov * Remove key from both configuration list and 214468394ec8SAlexander V. Chernikov * runtime array. Removed interface notification. 214568394ec8SAlexander V. Chernikov */ 21469f7d47b0SAlexander V. Chernikov static int 2147adea6201SAlexander V. Chernikov ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2148b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 21499f7d47b0SAlexander V. Chernikov { 215068394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 215168394ec8SAlexander V. Chernikov struct ifentry *ife; 215268394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 215368394ec8SAlexander V. Chernikov char *ifname; 215468394ec8SAlexander V. Chernikov uint16_t ifindex; 215568394ec8SAlexander V. Chernikov int res; 21569f7d47b0SAlexander V. Chernikov 215768394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 215868394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 215968394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 216068394ec8SAlexander V. Chernikov ife = tb->ife; 21619f7d47b0SAlexander V. Chernikov 216268394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 21639f7d47b0SAlexander V. Chernikov 216468394ec8SAlexander V. Chernikov if (ife == NULL) 216581d3153dSAlexander V. Chernikov return (ENOENT); 21669f7d47b0SAlexander V. Chernikov 216768394ec8SAlexander V. Chernikov if (ife->linked != 0) { 216868394ec8SAlexander V. Chernikov /* We have to remove item from runtime */ 216968394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 217068394ec8SAlexander V. Chernikov 217168394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 217268394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 217368394ec8SAlexander V. Chernikov 217468394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 217568394ec8SAlexander V. Chernikov icfg->used--; 217668394ec8SAlexander V. Chernikov ti->data = icfg->used; 217768394ec8SAlexander V. Chernikov ife->linked = 0; 217868394ec8SAlexander V. Chernikov } 217968394ec8SAlexander V. Chernikov 218068394ec8SAlexander V. Chernikov /* Unlink from local list */ 218168394ec8SAlexander V. Chernikov ipfw_objhash_del(icfg->ii, &ife->no); 218268394ec8SAlexander V. Chernikov /* Unlink notifier */ 218368394ec8SAlexander V. Chernikov ipfw_iface_del_notify(icfg->ch, &ife->ic); 218468394ec8SAlexander V. Chernikov 218568394ec8SAlexander V. Chernikov icfg->count--; 2186648e8380SAlexander V. Chernikov tei->value = ife->value; 218768394ec8SAlexander V. Chernikov 218868394ec8SAlexander V. Chernikov tb->ife = ife; 2189adea6201SAlexander V. Chernikov *pnum = 1; 219068394ec8SAlexander V. Chernikov 21919f7d47b0SAlexander V. Chernikov return (0); 21929f7d47b0SAlexander V. Chernikov } 21939f7d47b0SAlexander V. Chernikov 219468394ec8SAlexander V. Chernikov /* 219568394ec8SAlexander V. Chernikov * Flush deleted entry. 219668394ec8SAlexander V. Chernikov * Drops interface reference and frees entry. 219768394ec8SAlexander V. Chernikov */ 21989f7d47b0SAlexander V. Chernikov static void 219968394ec8SAlexander V. Chernikov ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 220068394ec8SAlexander V. Chernikov void *ta_buf) 22019f7d47b0SAlexander V. Chernikov { 220268394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 22039f7d47b0SAlexander V. Chernikov 220468394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 22059f7d47b0SAlexander V. Chernikov 220668394ec8SAlexander V. Chernikov if (tb->ife != NULL) { 220768394ec8SAlexander V. Chernikov /* Unlink first */ 220868394ec8SAlexander V. Chernikov ipfw_iface_unref(ch, &tb->ife->ic); 220968394ec8SAlexander V. Chernikov free(tb->ife, M_IPFW_TBL); 221068394ec8SAlexander V. Chernikov } 221168394ec8SAlexander V. Chernikov } 221268394ec8SAlexander V. Chernikov 221368394ec8SAlexander V. Chernikov 221468394ec8SAlexander V. Chernikov /* 221568394ec8SAlexander V. Chernikov * Handle interface announce/withdrawal for particular table. 221668394ec8SAlexander V. Chernikov * Every real runtime array modification happens here. 221768394ec8SAlexander V. Chernikov */ 221868394ec8SAlexander V. Chernikov static void 221968394ec8SAlexander V. Chernikov if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex) 222068394ec8SAlexander V. Chernikov { 222168394ec8SAlexander V. Chernikov struct ifentry *ife; 222268394ec8SAlexander V. Chernikov struct ifidx ifi; 222368394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 222468394ec8SAlexander V. Chernikov struct table_info *ti; 222568394ec8SAlexander V. Chernikov int res; 222668394ec8SAlexander V. Chernikov 222768394ec8SAlexander V. Chernikov ife = (struct ifentry *)cbdata; 222868394ec8SAlexander V. Chernikov icfg = ife->icfg; 222968394ec8SAlexander V. Chernikov ti = icfg->ti; 223068394ec8SAlexander V. Chernikov 223168394ec8SAlexander V. Chernikov KASSERT(ti != NULL, ("ti=NULL, check change_ti handler")); 223268394ec8SAlexander V. Chernikov 223368394ec8SAlexander V. Chernikov if (ife->linked == 0 && ifindex != 0) { 223468394ec8SAlexander V. Chernikov /* Interface announce */ 223568394ec8SAlexander V. Chernikov ifi.kidx = ifindex; 223668394ec8SAlexander V. Chernikov ifi.spare = 0; 223768394ec8SAlexander V. Chernikov ifi.value = ife->value; 223868394ec8SAlexander V. Chernikov res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used, 223968394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 224068394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d already exists", ifindex)); 224168394ec8SAlexander V. Chernikov icfg->used++; 224268394ec8SAlexander V. Chernikov ti->data = icfg->used; 224368394ec8SAlexander V. Chernikov ife->linked = 1; 224468394ec8SAlexander V. Chernikov } else if (ife->linked != 0 && ifindex == 0) { 224568394ec8SAlexander V. Chernikov /* Interface withdrawal */ 224668394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 224768394ec8SAlexander V. Chernikov 224868394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 224968394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 225068394ec8SAlexander V. Chernikov 225168394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 225268394ec8SAlexander V. Chernikov icfg->used--; 225368394ec8SAlexander V. Chernikov ti->data = icfg->used; 225468394ec8SAlexander V. Chernikov ife->linked = 0; 225568394ec8SAlexander V. Chernikov } 225668394ec8SAlexander V. Chernikov } 225768394ec8SAlexander V. Chernikov 225868394ec8SAlexander V. Chernikov 225968394ec8SAlexander V. Chernikov /* 226068394ec8SAlexander V. Chernikov * Table growing callbacks. 226168394ec8SAlexander V. Chernikov */ 226268394ec8SAlexander V. Chernikov 2263b6ee846eSAlexander V. Chernikov static int 2264301290bcSAlexander V. Chernikov ta_need_modify_ifidx(void *ta_state, struct table_info *ti, uint32_t count, 2265b6ee846eSAlexander V. Chernikov uint64_t *pflags) 2266b6ee846eSAlexander V. Chernikov { 2267b6ee846eSAlexander V. Chernikov struct iftable_cfg *cfg; 22680bce0c23SAlexander V. Chernikov uint32_t size; 2269b6ee846eSAlexander V. Chernikov 2270b6ee846eSAlexander V. Chernikov cfg = (struct iftable_cfg *)ta_state; 2271b6ee846eSAlexander V. Chernikov 22720bce0c23SAlexander V. Chernikov size = cfg->size; 22730bce0c23SAlexander V. Chernikov while (size < cfg->count + count) 22740bce0c23SAlexander V. Chernikov size *= 2; 22750bce0c23SAlexander V. Chernikov 22760bce0c23SAlexander V. Chernikov if (size != cfg->size) { 22770bce0c23SAlexander V. Chernikov *pflags = size; 2278301290bcSAlexander V. Chernikov return (1); 2279b6ee846eSAlexander V. Chernikov } 2280b6ee846eSAlexander V. Chernikov 2281301290bcSAlexander V. Chernikov return (0); 2282b6ee846eSAlexander V. Chernikov } 2283b6ee846eSAlexander V. Chernikov 228468394ec8SAlexander V. Chernikov /* 228568394ec8SAlexander V. Chernikov * Allocate ned, larger runtime ifidx array. 228668394ec8SAlexander V. Chernikov */ 228768394ec8SAlexander V. Chernikov static int 228868394ec8SAlexander V. Chernikov ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags) 228968394ec8SAlexander V. Chernikov { 22900bce0c23SAlexander V. Chernikov struct mod_item *mi; 229168394ec8SAlexander V. Chernikov 22920bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 229368394ec8SAlexander V. Chernikov 22940bce0c23SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 229568394ec8SAlexander V. Chernikov mi->size = *pflags; 229668394ec8SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW, 229768394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 229868394ec8SAlexander V. Chernikov 229968394ec8SAlexander V. Chernikov return (0); 230068394ec8SAlexander V. Chernikov } 230168394ec8SAlexander V. Chernikov 230268394ec8SAlexander V. Chernikov /* 230368394ec8SAlexander V. Chernikov * Copy data from old runtime array to new one. 230468394ec8SAlexander V. Chernikov */ 230568394ec8SAlexander V. Chernikov static int 230668394ec8SAlexander V. Chernikov ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 230768394ec8SAlexander V. Chernikov uint64_t *pflags) 230868394ec8SAlexander V. Chernikov { 23090bce0c23SAlexander V. Chernikov struct mod_item *mi; 231068394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 231168394ec8SAlexander V. Chernikov 23120bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 231368394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 231468394ec8SAlexander V. Chernikov 231568394ec8SAlexander V. Chernikov /* Check if we still need to grow array */ 231668394ec8SAlexander V. Chernikov if (icfg->size >= mi->size) { 231768394ec8SAlexander V. Chernikov *pflags = 0; 231868394ec8SAlexander V. Chernikov return (0); 231968394ec8SAlexander V. Chernikov } 232068394ec8SAlexander V. Chernikov 232168394ec8SAlexander V. Chernikov memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx)); 232268394ec8SAlexander V. Chernikov 232368394ec8SAlexander V. Chernikov return (0); 232468394ec8SAlexander V. Chernikov } 232568394ec8SAlexander V. Chernikov 232668394ec8SAlexander V. Chernikov /* 232768394ec8SAlexander V. Chernikov * Switch old & new arrays. 232868394ec8SAlexander V. Chernikov */ 2329301290bcSAlexander V. Chernikov static void 233068394ec8SAlexander V. Chernikov ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 233168394ec8SAlexander V. Chernikov uint64_t pflags) 233268394ec8SAlexander V. Chernikov { 23330bce0c23SAlexander V. Chernikov struct mod_item *mi; 233468394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 233568394ec8SAlexander V. Chernikov void *old_ptr; 233668394ec8SAlexander V. Chernikov 23370bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 233868394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 233968394ec8SAlexander V. Chernikov 234068394ec8SAlexander V. Chernikov old_ptr = icfg->main_ptr; 234168394ec8SAlexander V. Chernikov icfg->main_ptr = mi->main_ptr; 234268394ec8SAlexander V. Chernikov icfg->size = mi->size; 234368394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 234468394ec8SAlexander V. Chernikov 234568394ec8SAlexander V. Chernikov mi->main_ptr = old_ptr; 234668394ec8SAlexander V. Chernikov } 234768394ec8SAlexander V. Chernikov 234868394ec8SAlexander V. Chernikov /* 234968394ec8SAlexander V. Chernikov * Free unneded array. 235068394ec8SAlexander V. Chernikov */ 235168394ec8SAlexander V. Chernikov static void 235268394ec8SAlexander V. Chernikov ta_flush_mod_ifidx(void *ta_buf) 235368394ec8SAlexander V. Chernikov { 23540bce0c23SAlexander V. Chernikov struct mod_item *mi; 235568394ec8SAlexander V. Chernikov 23560bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 235768394ec8SAlexander V. Chernikov if (mi->main_ptr != NULL) 235868394ec8SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 23599f7d47b0SAlexander V. Chernikov } 23609f7d47b0SAlexander V. Chernikov 23619f7d47b0SAlexander V. Chernikov static int 236268394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e, 236381d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 23649f7d47b0SAlexander V. Chernikov { 236568394ec8SAlexander V. Chernikov struct ifentry *ife; 23669f7d47b0SAlexander V. Chernikov 236768394ec8SAlexander V. Chernikov ife = (struct ifentry *)e; 236868394ec8SAlexander V. Chernikov 236981d3153dSAlexander V. Chernikov tent->masklen = 8 * IF_NAMESIZE; 237068394ec8SAlexander V. Chernikov memcpy(&tent->k, ife->no.name, IF_NAMESIZE); 23710cba2b28SAlexander V. Chernikov tent->v.kidx = ife->value; 23729f7d47b0SAlexander V. Chernikov 23739f7d47b0SAlexander V. Chernikov return (0); 23749f7d47b0SAlexander V. Chernikov } 23759f7d47b0SAlexander V. Chernikov 237681d3153dSAlexander V. Chernikov static int 2377914bffb6SAlexander V. Chernikov ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, 2378914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 237981d3153dSAlexander V. Chernikov { 238068394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 238168394ec8SAlexander V. Chernikov struct ifentry *ife; 238268394ec8SAlexander V. Chernikov char *ifname; 238381d3153dSAlexander V. Chernikov 238468394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 2385914bffb6SAlexander V. Chernikov ifname = tent->k.iface; 238681d3153dSAlexander V. Chernikov 238768394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 238868394ec8SAlexander V. Chernikov return (EINVAL); 238981d3153dSAlexander V. Chernikov 239068394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 239168394ec8SAlexander V. Chernikov 239268394ec8SAlexander V. Chernikov if (ife != NULL) { 239368394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(ta_state, ti, ife, tent); 239481d3153dSAlexander V. Chernikov return (0); 239581d3153dSAlexander V. Chernikov } 239681d3153dSAlexander V. Chernikov 239781d3153dSAlexander V. Chernikov return (ENOENT); 239881d3153dSAlexander V. Chernikov } 239981d3153dSAlexander V. Chernikov 240068394ec8SAlexander V. Chernikov struct wa_ifidx { 240168394ec8SAlexander V. Chernikov ta_foreach_f *f; 240268394ec8SAlexander V. Chernikov void *arg; 240368394ec8SAlexander V. Chernikov }; 240468394ec8SAlexander V. Chernikov 24059f7d47b0SAlexander V. Chernikov static void 240668394ec8SAlexander V. Chernikov foreach_ifidx(struct namedobj_instance *ii, struct named_object *no, 24079f7d47b0SAlexander V. Chernikov void *arg) 24089f7d47b0SAlexander V. Chernikov { 240968394ec8SAlexander V. Chernikov struct ifentry *ife; 241068394ec8SAlexander V. Chernikov struct wa_ifidx *wa; 24119f7d47b0SAlexander V. Chernikov 241268394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 241368394ec8SAlexander V. Chernikov wa = (struct wa_ifidx *)arg; 241468394ec8SAlexander V. Chernikov 241568394ec8SAlexander V. Chernikov wa->f(ife, wa->arg); 24169f7d47b0SAlexander V. Chernikov } 24179f7d47b0SAlexander V. Chernikov 241868394ec8SAlexander V. Chernikov static void 241968394ec8SAlexander V. Chernikov ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f, 242068394ec8SAlexander V. Chernikov void *arg) 242168394ec8SAlexander V. Chernikov { 242268394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 242368394ec8SAlexander V. Chernikov struct wa_ifidx wa; 242468394ec8SAlexander V. Chernikov 242568394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 242668394ec8SAlexander V. Chernikov 242768394ec8SAlexander V. Chernikov wa.f = f; 242868394ec8SAlexander V. Chernikov wa.arg = arg; 242968394ec8SAlexander V. Chernikov 243068394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa); 243168394ec8SAlexander V. Chernikov } 243268394ec8SAlexander V. Chernikov 243374b941f0SAlexander V. Chernikov struct table_algo iface_idx = { 2434adea6201SAlexander V. Chernikov .name = "iface:array", 24359d099b4fSAlexander V. Chernikov .type = IPFW_TABLE_INTERFACE, 243657a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 243757a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_ifidx), 243868394ec8SAlexander V. Chernikov .init = ta_init_ifidx, 243968394ec8SAlexander V. Chernikov .destroy = ta_destroy_ifidx, 244068394ec8SAlexander V. Chernikov .prepare_add = ta_prepare_add_ifidx, 244168394ec8SAlexander V. Chernikov .prepare_del = ta_prepare_del_ifidx, 244268394ec8SAlexander V. Chernikov .add = ta_add_ifidx, 244368394ec8SAlexander V. Chernikov .del = ta_del_ifidx, 244468394ec8SAlexander V. Chernikov .flush_entry = ta_flush_ifidx_entry, 244568394ec8SAlexander V. Chernikov .foreach = ta_foreach_ifidx, 244668394ec8SAlexander V. Chernikov .dump_tentry = ta_dump_ifidx_tentry, 244768394ec8SAlexander V. Chernikov .find_tentry = ta_find_ifidx_tentry, 24485f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_ifidx_tinfo, 2449301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_ifidx, 245068394ec8SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_ifidx, 245168394ec8SAlexander V. Chernikov .fill_mod = ta_fill_mod_ifidx, 245268394ec8SAlexander V. Chernikov .modify = ta_modify_ifidx, 245368394ec8SAlexander V. Chernikov .flush_mod = ta_flush_mod_ifidx, 245468394ec8SAlexander V. Chernikov .change_ti = ta_change_ti_ifidx, 24559f7d47b0SAlexander V. Chernikov }; 24569f7d47b0SAlexander V. Chernikov 2457b23d5de9SAlexander V. Chernikov /* 2458b23d5de9SAlexander V. Chernikov * Number array cmds. 2459b23d5de9SAlexander V. Chernikov * 2460b23d5de9SAlexander V. Chernikov * Implementation: 2461b23d5de9SAlexander V. Chernikov * 2462b23d5de9SAlexander V. Chernikov * Runtime part: 2463b23d5de9SAlexander V. Chernikov * - sorted array of "struct numarray" pointed by ti->state. 2464b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to NUMARRAY_CHUNK. 2465b23d5de9SAlexander V. Chernikov * - current array size is stored in ti->data 2466b23d5de9SAlexander V. Chernikov * 2467b23d5de9SAlexander V. Chernikov */ 2468b23d5de9SAlexander V. Chernikov 2469b23d5de9SAlexander V. Chernikov struct numarray { 2470b23d5de9SAlexander V. Chernikov uint32_t number; 2471b23d5de9SAlexander V. Chernikov uint32_t value; 2472b23d5de9SAlexander V. Chernikov }; 2473b23d5de9SAlexander V. Chernikov 2474b23d5de9SAlexander V. Chernikov struct numarray_cfg { 2475b23d5de9SAlexander V. Chernikov void *main_ptr; 2476b23d5de9SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 2477b23d5de9SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 2478b23d5de9SAlexander V. Chernikov }; 2479b23d5de9SAlexander V. Chernikov 24800bce0c23SAlexander V. Chernikov struct ta_buf_numarray 24810bce0c23SAlexander V. Chernikov { 24820bce0c23SAlexander V. Chernikov struct numarray na; 24830bce0c23SAlexander V. Chernikov }; 2484b23d5de9SAlexander V. Chernikov 2485b23d5de9SAlexander V. Chernikov int compare_numarray(const void *k, const void *v); 2486b23d5de9SAlexander V. Chernikov 2487b23d5de9SAlexander V. Chernikov int 2488b23d5de9SAlexander V. Chernikov compare_numarray(const void *k, const void *v) 2489b23d5de9SAlexander V. Chernikov { 2490d4e1b515SAlexander V. Chernikov const struct numarray *na; 2491b23d5de9SAlexander V. Chernikov uint32_t key; 2492b23d5de9SAlexander V. Chernikov 2493d4e1b515SAlexander V. Chernikov key = *((const uint32_t *)k); 2494d4e1b515SAlexander V. Chernikov na = (const struct numarray *)v; 2495b23d5de9SAlexander V. Chernikov 2496b23d5de9SAlexander V. Chernikov if (key < na->number) 2497b23d5de9SAlexander V. Chernikov return (-1); 2498b23d5de9SAlexander V. Chernikov else if (key > na->number) 2499b23d5de9SAlexander V. Chernikov return (1); 2500b23d5de9SAlexander V. Chernikov 2501b23d5de9SAlexander V. Chernikov return (0); 2502b23d5de9SAlexander V. Chernikov } 2503b23d5de9SAlexander V. Chernikov 2504b23d5de9SAlexander V. Chernikov static struct numarray * 2505b23d5de9SAlexander V. Chernikov numarray_find(struct table_info *ti, void *key) 2506b23d5de9SAlexander V. Chernikov { 2507b23d5de9SAlexander V. Chernikov struct numarray *ri; 2508b23d5de9SAlexander V. Chernikov 2509b23d5de9SAlexander V. Chernikov ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray), 2510b23d5de9SAlexander V. Chernikov compare_ifidx); 2511b23d5de9SAlexander V. Chernikov 2512b23d5de9SAlexander V. Chernikov return (ri); 2513b23d5de9SAlexander V. Chernikov } 2514b23d5de9SAlexander V. Chernikov 2515b23d5de9SAlexander V. Chernikov static int 2516b23d5de9SAlexander V. Chernikov ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen, 2517b23d5de9SAlexander V. Chernikov uint32_t *val) 2518b23d5de9SAlexander V. Chernikov { 2519b23d5de9SAlexander V. Chernikov struct numarray *ri; 2520b23d5de9SAlexander V. Chernikov 2521b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, key); 2522b23d5de9SAlexander V. Chernikov 2523b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2524b23d5de9SAlexander V. Chernikov *val = ri->value; 2525b23d5de9SAlexander V. Chernikov return (1); 2526b23d5de9SAlexander V. Chernikov } 2527b23d5de9SAlexander V. Chernikov 2528b23d5de9SAlexander V. Chernikov return (0); 2529b23d5de9SAlexander V. Chernikov } 2530b23d5de9SAlexander V. Chernikov 2531b23d5de9SAlexander V. Chernikov static int 2532b23d5de9SAlexander V. Chernikov ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 2533914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 2534b23d5de9SAlexander V. Chernikov { 2535b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2536b23d5de9SAlexander V. Chernikov 2537b23d5de9SAlexander V. Chernikov cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO); 2538b23d5de9SAlexander V. Chernikov 25390bce0c23SAlexander V. Chernikov cfg->size = 16; 2540b23d5de9SAlexander V. Chernikov cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW, 2541b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO); 2542b23d5de9SAlexander V. Chernikov 2543b23d5de9SAlexander V. Chernikov *ta_state = cfg; 2544b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr; 2545b23d5de9SAlexander V. Chernikov ti->lookup = ta_lookup_numarray; 2546b23d5de9SAlexander V. Chernikov 2547b23d5de9SAlexander V. Chernikov return (0); 2548b23d5de9SAlexander V. Chernikov } 2549b23d5de9SAlexander V. Chernikov 2550b23d5de9SAlexander V. Chernikov /* 2551b23d5de9SAlexander V. Chernikov * Destroys table @ti 2552b23d5de9SAlexander V. Chernikov */ 2553b23d5de9SAlexander V. Chernikov static void 2554b23d5de9SAlexander V. Chernikov ta_destroy_numarray(void *ta_state, struct table_info *ti) 2555b23d5de9SAlexander V. Chernikov { 2556b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2557b23d5de9SAlexander V. Chernikov 2558b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2559b23d5de9SAlexander V. Chernikov 2560b23d5de9SAlexander V. Chernikov if (cfg->main_ptr != NULL) 2561b23d5de9SAlexander V. Chernikov free(cfg->main_ptr, M_IPFW); 2562b23d5de9SAlexander V. Chernikov 2563b23d5de9SAlexander V. Chernikov free(cfg, M_IPFW); 2564b23d5de9SAlexander V. Chernikov } 2565b23d5de9SAlexander V. Chernikov 2566b23d5de9SAlexander V. Chernikov /* 25675f379342SAlexander V. Chernikov * Provide algo-specific table info 25685f379342SAlexander V. Chernikov */ 25695f379342SAlexander V. Chernikov static void 25705f379342SAlexander V. Chernikov ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 25715f379342SAlexander V. Chernikov { 25725f379342SAlexander V. Chernikov struct numarray_cfg *cfg; 25735f379342SAlexander V. Chernikov 25745f379342SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 25755f379342SAlexander V. Chernikov 25765f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_ARRAY; 25775f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 25785f379342SAlexander V. Chernikov tinfo->count4 = cfg->used; 25795f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct numarray); 25805f379342SAlexander V. Chernikov } 25815f379342SAlexander V. Chernikov 25825f379342SAlexander V. Chernikov /* 2583b23d5de9SAlexander V. Chernikov * Prepare for addition/deletion to an array. 2584b23d5de9SAlexander V. Chernikov */ 2585b23d5de9SAlexander V. Chernikov static int 2586b23d5de9SAlexander V. Chernikov ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei, 2587b23d5de9SAlexander V. Chernikov void *ta_buf) 2588b23d5de9SAlexander V. Chernikov { 2589b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2590b23d5de9SAlexander V. Chernikov 2591b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2592b23d5de9SAlexander V. Chernikov 2593b23d5de9SAlexander V. Chernikov tb->na.number = *((uint32_t *)tei->paddr); 2594b23d5de9SAlexander V. Chernikov 2595b23d5de9SAlexander V. Chernikov return (0); 2596b23d5de9SAlexander V. Chernikov } 2597b23d5de9SAlexander V. Chernikov 2598b23d5de9SAlexander V. Chernikov static int 2599b23d5de9SAlexander V. Chernikov ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2600b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 2601b23d5de9SAlexander V. Chernikov { 2602b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2603b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2604b23d5de9SAlexander V. Chernikov struct numarray *ri; 2605b23d5de9SAlexander V. Chernikov int res; 2606648e8380SAlexander V. Chernikov uint32_t value; 2607b23d5de9SAlexander V. Chernikov 2608b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2609b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2610b23d5de9SAlexander V. Chernikov 261113263632SAlexander V. Chernikov /* Read current value from @tei */ 261213263632SAlexander V. Chernikov tb->na.value = tei->value; 261313263632SAlexander V. Chernikov 2614b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number); 2615b23d5de9SAlexander V. Chernikov 2616b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2617b23d5de9SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 2618b23d5de9SAlexander V. Chernikov return (EEXIST); 2619b23d5de9SAlexander V. Chernikov 2620648e8380SAlexander V. Chernikov /* Exchange values between ri and @tei */ 2621648e8380SAlexander V. Chernikov value = ri->value; 2622648e8380SAlexander V. Chernikov ri->value = tei->value; 2623648e8380SAlexander V. Chernikov tei->value = value; 2624b23d5de9SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 2625b23d5de9SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 2626b23d5de9SAlexander V. Chernikov *pnum = 0; 2627b23d5de9SAlexander V. Chernikov return (0); 2628b23d5de9SAlexander V. Chernikov } 2629b23d5de9SAlexander V. Chernikov 26304c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 26314c0c07a5SAlexander V. Chernikov return (EFBIG); 26324c0c07a5SAlexander V. Chernikov 2633b23d5de9SAlexander V. Chernikov res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used, 2634b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray); 2635b23d5de9SAlexander V. Chernikov 2636b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %d already exists", tb->na.number)); 2637b23d5de9SAlexander V. Chernikov cfg->used++; 2638b23d5de9SAlexander V. Chernikov ti->data = cfg->used; 2639b23d5de9SAlexander V. Chernikov *pnum = 1; 2640b23d5de9SAlexander V. Chernikov 2641b23d5de9SAlexander V. Chernikov return (0); 2642b23d5de9SAlexander V. Chernikov } 2643b23d5de9SAlexander V. Chernikov 2644b23d5de9SAlexander V. Chernikov /* 2645b23d5de9SAlexander V. Chernikov * Remove key from both configuration list and 2646b23d5de9SAlexander V. Chernikov * runtime array. Removed interface notification. 2647b23d5de9SAlexander V. Chernikov */ 2648b23d5de9SAlexander V. Chernikov static int 2649b23d5de9SAlexander V. Chernikov ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2650b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 2651b23d5de9SAlexander V. Chernikov { 2652b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2653b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2654b23d5de9SAlexander V. Chernikov struct numarray *ri; 2655b23d5de9SAlexander V. Chernikov int res; 2656b23d5de9SAlexander V. Chernikov 2657b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2658b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2659b23d5de9SAlexander V. Chernikov 2660b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number); 2661b23d5de9SAlexander V. Chernikov if (ri == NULL) 2662b23d5de9SAlexander V. Chernikov return (ENOENT); 2663b23d5de9SAlexander V. Chernikov 2664648e8380SAlexander V. Chernikov tei->value = ri->value; 2665648e8380SAlexander V. Chernikov 2666b23d5de9SAlexander V. Chernikov res = bdel(&tb->na.number, cfg->main_ptr, cfg->used, 2667b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray); 2668b23d5de9SAlexander V. Chernikov 2669b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %u does not exist", tb->na.number)); 2670b23d5de9SAlexander V. Chernikov cfg->used--; 2671b23d5de9SAlexander V. Chernikov ti->data = cfg->used; 2672b23d5de9SAlexander V. Chernikov *pnum = 1; 2673b23d5de9SAlexander V. Chernikov 2674b23d5de9SAlexander V. Chernikov return (0); 2675b23d5de9SAlexander V. Chernikov } 2676b23d5de9SAlexander V. Chernikov 2677b23d5de9SAlexander V. Chernikov static void 2678b23d5de9SAlexander V. Chernikov ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 2679b23d5de9SAlexander V. Chernikov void *ta_buf) 2680b23d5de9SAlexander V. Chernikov { 2681b23d5de9SAlexander V. Chernikov 26820bce0c23SAlexander V. Chernikov /* We don't have any state, do nothing */ 2683b23d5de9SAlexander V. Chernikov } 2684b23d5de9SAlexander V. Chernikov 2685b23d5de9SAlexander V. Chernikov 2686b23d5de9SAlexander V. Chernikov /* 2687b23d5de9SAlexander V. Chernikov * Table growing callbacks. 2688b23d5de9SAlexander V. Chernikov */ 2689b23d5de9SAlexander V. Chernikov 2690b6ee846eSAlexander V. Chernikov static int 2691301290bcSAlexander V. Chernikov ta_need_modify_numarray(void *ta_state, struct table_info *ti, uint32_t count, 2692b6ee846eSAlexander V. Chernikov uint64_t *pflags) 2693b6ee846eSAlexander V. Chernikov { 2694b6ee846eSAlexander V. Chernikov struct numarray_cfg *cfg; 26950bce0c23SAlexander V. Chernikov size_t size; 2696b6ee846eSAlexander V. Chernikov 2697b6ee846eSAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2698b6ee846eSAlexander V. Chernikov 26990bce0c23SAlexander V. Chernikov size = cfg->size; 27000bce0c23SAlexander V. Chernikov while (size < cfg->used + count) 27010bce0c23SAlexander V. Chernikov size *= 2; 27020bce0c23SAlexander V. Chernikov 27030bce0c23SAlexander V. Chernikov if (size != cfg->size) { 27040bce0c23SAlexander V. Chernikov *pflags = size; 2705301290bcSAlexander V. Chernikov return (1); 2706b6ee846eSAlexander V. Chernikov } 2707b6ee846eSAlexander V. Chernikov 2708301290bcSAlexander V. Chernikov return (0); 2709b6ee846eSAlexander V. Chernikov } 2710b6ee846eSAlexander V. Chernikov 2711b23d5de9SAlexander V. Chernikov /* 2712b6ee846eSAlexander V. Chernikov * Allocate new, larger runtime array. 2713b23d5de9SAlexander V. Chernikov */ 2714b23d5de9SAlexander V. Chernikov static int 2715b23d5de9SAlexander V. Chernikov ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags) 2716b23d5de9SAlexander V. Chernikov { 2717b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2718b23d5de9SAlexander V. Chernikov 2719b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2720b23d5de9SAlexander V. Chernikov 2721b23d5de9SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 2722b23d5de9SAlexander V. Chernikov mi->size = *pflags; 2723b23d5de9SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW, 2724b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO); 2725b23d5de9SAlexander V. Chernikov 2726b23d5de9SAlexander V. Chernikov return (0); 2727b23d5de9SAlexander V. Chernikov } 2728b23d5de9SAlexander V. Chernikov 2729b23d5de9SAlexander V. Chernikov /* 2730b23d5de9SAlexander V. Chernikov * Copy data from old runtime array to new one. 2731b23d5de9SAlexander V. Chernikov */ 2732b23d5de9SAlexander V. Chernikov static int 2733b23d5de9SAlexander V. Chernikov ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf, 2734b23d5de9SAlexander V. Chernikov uint64_t *pflags) 2735b23d5de9SAlexander V. Chernikov { 2736b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2737b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2738b23d5de9SAlexander V. Chernikov 2739b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2740b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2741b23d5de9SAlexander V. Chernikov 2742b23d5de9SAlexander V. Chernikov /* Check if we still need to grow array */ 2743b23d5de9SAlexander V. Chernikov if (cfg->size >= mi->size) { 2744b23d5de9SAlexander V. Chernikov *pflags = 0; 2745b23d5de9SAlexander V. Chernikov return (0); 2746b23d5de9SAlexander V. Chernikov } 2747b23d5de9SAlexander V. Chernikov 2748b23d5de9SAlexander V. Chernikov memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray)); 2749b23d5de9SAlexander V. Chernikov 2750b23d5de9SAlexander V. Chernikov return (0); 2751b23d5de9SAlexander V. Chernikov } 2752b23d5de9SAlexander V. Chernikov 2753b23d5de9SAlexander V. Chernikov /* 2754b23d5de9SAlexander V. Chernikov * Switch old & new arrays. 2755b23d5de9SAlexander V. Chernikov */ 2756301290bcSAlexander V. Chernikov static void 2757b23d5de9SAlexander V. Chernikov ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf, 2758b23d5de9SAlexander V. Chernikov uint64_t pflags) 2759b23d5de9SAlexander V. Chernikov { 2760b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2761b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2762b23d5de9SAlexander V. Chernikov void *old_ptr; 2763b23d5de9SAlexander V. Chernikov 2764b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2765b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2766b23d5de9SAlexander V. Chernikov 2767b23d5de9SAlexander V. Chernikov old_ptr = cfg->main_ptr; 2768b23d5de9SAlexander V. Chernikov cfg->main_ptr = mi->main_ptr; 2769b23d5de9SAlexander V. Chernikov cfg->size = mi->size; 2770b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr; 2771b23d5de9SAlexander V. Chernikov 2772b23d5de9SAlexander V. Chernikov mi->main_ptr = old_ptr; 2773b23d5de9SAlexander V. Chernikov } 2774b23d5de9SAlexander V. Chernikov 2775b23d5de9SAlexander V. Chernikov /* 2776b23d5de9SAlexander V. Chernikov * Free unneded array. 2777b23d5de9SAlexander V. Chernikov */ 2778b23d5de9SAlexander V. Chernikov static void 2779b23d5de9SAlexander V. Chernikov ta_flush_mod_numarray(void *ta_buf) 2780b23d5de9SAlexander V. Chernikov { 2781b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2782b23d5de9SAlexander V. Chernikov 2783b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2784b23d5de9SAlexander V. Chernikov if (mi->main_ptr != NULL) 2785b23d5de9SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 2786b23d5de9SAlexander V. Chernikov } 2787b23d5de9SAlexander V. Chernikov 2788b23d5de9SAlexander V. Chernikov static int 2789b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e, 2790b23d5de9SAlexander V. Chernikov ipfw_obj_tentry *tent) 2791b23d5de9SAlexander V. Chernikov { 2792b23d5de9SAlexander V. Chernikov struct numarray *na; 2793b23d5de9SAlexander V. Chernikov 2794b23d5de9SAlexander V. Chernikov na = (struct numarray *)e; 2795b23d5de9SAlexander V. Chernikov 2796b23d5de9SAlexander V. Chernikov tent->k.key = na->number; 27970cba2b28SAlexander V. Chernikov tent->v.kidx = na->value; 2798b23d5de9SAlexander V. Chernikov 2799b23d5de9SAlexander V. Chernikov return (0); 2800b23d5de9SAlexander V. Chernikov } 2801b23d5de9SAlexander V. Chernikov 2802b23d5de9SAlexander V. Chernikov static int 2803914bffb6SAlexander V. Chernikov ta_find_numarray_tentry(void *ta_state, struct table_info *ti, 2804914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 2805b23d5de9SAlexander V. Chernikov { 2806b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2807b23d5de9SAlexander V. Chernikov struct numarray *ri; 2808b23d5de9SAlexander V. Chernikov 2809b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2810b23d5de9SAlexander V. Chernikov 2811914bffb6SAlexander V. Chernikov ri = numarray_find(ti, &tent->k.key); 2812b23d5de9SAlexander V. Chernikov 2813b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2814b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(ta_state, ti, ri, tent); 2815b23d5de9SAlexander V. Chernikov return (0); 2816b23d5de9SAlexander V. Chernikov } 2817b23d5de9SAlexander V. Chernikov 2818b23d5de9SAlexander V. Chernikov return (ENOENT); 2819b23d5de9SAlexander V. Chernikov } 2820b23d5de9SAlexander V. Chernikov 2821b23d5de9SAlexander V. Chernikov static void 2822b23d5de9SAlexander V. Chernikov ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f, 2823b23d5de9SAlexander V. Chernikov void *arg) 2824b23d5de9SAlexander V. Chernikov { 2825b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2826b23d5de9SAlexander V. Chernikov struct numarray *array; 2827b23d5de9SAlexander V. Chernikov int i; 2828b23d5de9SAlexander V. Chernikov 2829b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2830b23d5de9SAlexander V. Chernikov array = cfg->main_ptr; 2831b23d5de9SAlexander V. Chernikov 2832b23d5de9SAlexander V. Chernikov for (i = 0; i < cfg->used; i++) 2833b23d5de9SAlexander V. Chernikov f(&array[i], arg); 2834b23d5de9SAlexander V. Chernikov } 2835b23d5de9SAlexander V. Chernikov 2836b23d5de9SAlexander V. Chernikov struct table_algo number_array = { 2837b23d5de9SAlexander V. Chernikov .name = "number:array", 2838b23d5de9SAlexander V. Chernikov .type = IPFW_TABLE_NUMBER, 283957a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_numarray), 2840b23d5de9SAlexander V. Chernikov .init = ta_init_numarray, 2841b23d5de9SAlexander V. Chernikov .destroy = ta_destroy_numarray, 2842b23d5de9SAlexander V. Chernikov .prepare_add = ta_prepare_add_numarray, 2843b23d5de9SAlexander V. Chernikov .prepare_del = ta_prepare_add_numarray, 2844b23d5de9SAlexander V. Chernikov .add = ta_add_numarray, 2845b23d5de9SAlexander V. Chernikov .del = ta_del_numarray, 2846b23d5de9SAlexander V. Chernikov .flush_entry = ta_flush_numarray_entry, 2847b23d5de9SAlexander V. Chernikov .foreach = ta_foreach_numarray, 2848b23d5de9SAlexander V. Chernikov .dump_tentry = ta_dump_numarray_tentry, 2849b23d5de9SAlexander V. Chernikov .find_tentry = ta_find_numarray_tentry, 28505f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_numarray_tinfo, 2851301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_numarray, 2852b23d5de9SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_numarray, 2853b23d5de9SAlexander V. Chernikov .fill_mod = ta_fill_mod_numarray, 2854b23d5de9SAlexander V. Chernikov .modify = ta_modify_numarray, 2855b23d5de9SAlexander V. Chernikov .flush_mod = ta_flush_mod_numarray, 2856b23d5de9SAlexander V. Chernikov }; 2857b23d5de9SAlexander V. Chernikov 2858914bffb6SAlexander V. Chernikov /* 2859914bffb6SAlexander V. Chernikov * flow:hash cmds 2860914bffb6SAlexander V. Chernikov * 2861914bffb6SAlexander V. Chernikov * 2862914bffb6SAlexander V. Chernikov * ti->data: 2863914bffb6SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6] 2864914bffb6SAlexander V. Chernikov * [ 8][ 8[ 8][ 8] 2865914bffb6SAlexander V. Chernikov * 2866914bffb6SAlexander V. Chernikov * inv.mask4: 32 - mask 2867914bffb6SAlexander V. Chernikov * inv.mask6: 2868914bffb6SAlexander V. Chernikov * 1) _slow lookup: mask 2869914bffb6SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8 2870914bffb6SAlexander V. Chernikov * 3) _64: 8 2871914bffb6SAlexander V. Chernikov * 2872914bffb6SAlexander V. Chernikov * 2873914bffb6SAlexander V. Chernikov * pflags: 2874b6ee846eSAlexander V. Chernikov * [hsize4][hsize6] 2875b6ee846eSAlexander V. Chernikov * [ 16][ 16] 2876914bffb6SAlexander V. Chernikov */ 2877914bffb6SAlexander V. Chernikov 2878914bffb6SAlexander V. Chernikov struct fhashentry; 2879914bffb6SAlexander V. Chernikov 2880914bffb6SAlexander V. Chernikov SLIST_HEAD(fhashbhead, fhashentry); 2881914bffb6SAlexander V. Chernikov 2882914bffb6SAlexander V. Chernikov struct fhashentry { 2883914bffb6SAlexander V. Chernikov SLIST_ENTRY(fhashentry) next; 2884914bffb6SAlexander V. Chernikov uint8_t af; 2885914bffb6SAlexander V. Chernikov uint8_t proto; 2886914bffb6SAlexander V. Chernikov uint16_t spare0; 2887914bffb6SAlexander V. Chernikov uint16_t dport; 2888914bffb6SAlexander V. Chernikov uint16_t sport; 2889914bffb6SAlexander V. Chernikov uint32_t value; 2890914bffb6SAlexander V. Chernikov uint32_t spare1; 2891914bffb6SAlexander V. Chernikov }; 2892914bffb6SAlexander V. Chernikov 2893914bffb6SAlexander V. Chernikov struct fhashentry4 { 2894914bffb6SAlexander V. Chernikov struct fhashentry e; 2895914bffb6SAlexander V. Chernikov struct in_addr dip; 2896914bffb6SAlexander V. Chernikov struct in_addr sip; 2897914bffb6SAlexander V. Chernikov }; 2898914bffb6SAlexander V. Chernikov 2899914bffb6SAlexander V. Chernikov struct fhashentry6 { 2900914bffb6SAlexander V. Chernikov struct fhashentry e; 2901914bffb6SAlexander V. Chernikov struct in6_addr dip6; 2902914bffb6SAlexander V. Chernikov struct in6_addr sip6; 2903914bffb6SAlexander V. Chernikov }; 2904914bffb6SAlexander V. Chernikov 2905914bffb6SAlexander V. Chernikov struct fhash_cfg { 2906914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2907914bffb6SAlexander V. Chernikov size_t size; 2908914bffb6SAlexander V. Chernikov size_t items; 2909914bffb6SAlexander V. Chernikov struct fhashentry4 fe4; 2910914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 2911914bffb6SAlexander V. Chernikov }; 2912914bffb6SAlexander V. Chernikov 29133fe2ef91SAlexander V. Chernikov struct ta_buf_fhash { 29140bce0c23SAlexander V. Chernikov void *ent_ptr; 29150bce0c23SAlexander V. Chernikov struct fhashentry6 fe6; 29160bce0c23SAlexander V. Chernikov }; 29170bce0c23SAlexander V. Chernikov 2918914bffb6SAlexander V. Chernikov static __inline int 2919914bffb6SAlexander V. Chernikov cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz) 2920914bffb6SAlexander V. Chernikov { 2921914bffb6SAlexander V. Chernikov uint64_t *ka, *kb; 2922914bffb6SAlexander V. Chernikov 2923914bffb6SAlexander V. Chernikov ka = (uint64_t *)(&a->next + 1); 2924914bffb6SAlexander V. Chernikov kb = (uint64_t *)(&b->next + 1); 2925914bffb6SAlexander V. Chernikov 2926914bffb6SAlexander V. Chernikov if (*ka == *kb && (memcmp(a + 1, b + 1, sz) == 0)) 2927914bffb6SAlexander V. Chernikov return (1); 2928914bffb6SAlexander V. Chernikov 2929914bffb6SAlexander V. Chernikov return (0); 2930914bffb6SAlexander V. Chernikov } 2931914bffb6SAlexander V. Chernikov 2932914bffb6SAlexander V. Chernikov static __inline uint32_t 2933914bffb6SAlexander V. Chernikov hash_flow4(struct fhashentry4 *f, int hsize) 2934914bffb6SAlexander V. Chernikov { 2935914bffb6SAlexander V. Chernikov uint32_t i; 2936914bffb6SAlexander V. Chernikov 2937914bffb6SAlexander V. Chernikov i = (f->dip.s_addr) ^ (f->sip.s_addr) ^ (f->e.dport) ^ (f->e.sport); 2938914bffb6SAlexander V. Chernikov 2939914bffb6SAlexander V. Chernikov return (i % (hsize - 1)); 2940914bffb6SAlexander V. Chernikov } 2941914bffb6SAlexander V. Chernikov 2942914bffb6SAlexander V. Chernikov static __inline uint32_t 2943914bffb6SAlexander V. Chernikov hash_flow6(struct fhashentry6 *f, int hsize) 2944914bffb6SAlexander V. Chernikov { 2945914bffb6SAlexander V. Chernikov uint32_t i; 2946914bffb6SAlexander V. Chernikov 2947914bffb6SAlexander V. Chernikov i = (f->dip6.__u6_addr.__u6_addr32[2]) ^ 2948914bffb6SAlexander V. Chernikov (f->dip6.__u6_addr.__u6_addr32[3]) ^ 2949914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[2]) ^ 2950914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[3]) ^ 2951914bffb6SAlexander V. Chernikov (f->e.dport) ^ (f->e.sport); 2952914bffb6SAlexander V. Chernikov 2953914bffb6SAlexander V. Chernikov return (i % (hsize - 1)); 2954914bffb6SAlexander V. Chernikov } 2955914bffb6SAlexander V. Chernikov 2956914bffb6SAlexander V. Chernikov static uint32_t 2957914bffb6SAlexander V. Chernikov hash_flow_ent(struct fhashentry *ent, uint32_t size) 2958914bffb6SAlexander V. Chernikov { 2959914bffb6SAlexander V. Chernikov uint32_t hash; 2960914bffb6SAlexander V. Chernikov 2961914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) { 2962914bffb6SAlexander V. Chernikov hash = hash_flow4((struct fhashentry4 *)ent, size); 2963914bffb6SAlexander V. Chernikov } else { 2964914bffb6SAlexander V. Chernikov hash = hash_flow6((struct fhashentry6 *)ent, size); 2965914bffb6SAlexander V. Chernikov } 2966914bffb6SAlexander V. Chernikov 2967914bffb6SAlexander V. Chernikov return (hash); 2968914bffb6SAlexander V. Chernikov } 2969914bffb6SAlexander V. Chernikov 2970914bffb6SAlexander V. Chernikov static int 2971914bffb6SAlexander V. Chernikov ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen, 2972914bffb6SAlexander V. Chernikov uint32_t *val) 2973914bffb6SAlexander V. Chernikov { 2974914bffb6SAlexander V. Chernikov struct fhashbhead *head; 2975914bffb6SAlexander V. Chernikov struct fhashentry *ent; 2976914bffb6SAlexander V. Chernikov struct fhashentry4 *m4; 2977914bffb6SAlexander V. Chernikov struct ipfw_flow_id *id; 2978914bffb6SAlexander V. Chernikov uint16_t hash, hsize; 2979914bffb6SAlexander V. Chernikov 2980914bffb6SAlexander V. Chernikov id = (struct ipfw_flow_id *)key; 2981914bffb6SAlexander V. Chernikov head = (struct fhashbhead *)ti->state; 2982914bffb6SAlexander V. Chernikov hsize = ti->data; 2983914bffb6SAlexander V. Chernikov m4 = (struct fhashentry4 *)ti->xstate; 2984914bffb6SAlexander V. Chernikov 2985914bffb6SAlexander V. Chernikov if (id->addr_type == 4) { 2986914bffb6SAlexander V. Chernikov struct fhashentry4 f; 2987914bffb6SAlexander V. Chernikov 2988914bffb6SAlexander V. Chernikov /* Copy hash mask */ 2989914bffb6SAlexander V. Chernikov f = *m4; 2990914bffb6SAlexander V. Chernikov 2991914bffb6SAlexander V. Chernikov f.dip.s_addr &= id->dst_ip; 2992914bffb6SAlexander V. Chernikov f.sip.s_addr &= id->src_ip; 2993914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port; 2994914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port; 2995914bffb6SAlexander V. Chernikov f.e.proto &= id->proto; 2996914bffb6SAlexander V. Chernikov hash = hash_flow4(&f, hsize); 2997914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 2998914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) { 2999914bffb6SAlexander V. Chernikov *val = ent->value; 3000914bffb6SAlexander V. Chernikov return (1); 3001914bffb6SAlexander V. Chernikov } 3002914bffb6SAlexander V. Chernikov } 3003914bffb6SAlexander V. Chernikov } else if (id->addr_type == 6) { 3004914bffb6SAlexander V. Chernikov struct fhashentry6 f; 3005914bffb6SAlexander V. Chernikov uint64_t *fp, *idp; 3006914bffb6SAlexander V. Chernikov 3007914bffb6SAlexander V. Chernikov /* Copy hash mask */ 3008914bffb6SAlexander V. Chernikov f = *((struct fhashentry6 *)(m4 + 1)); 3009914bffb6SAlexander V. Chernikov 3010914bffb6SAlexander V. Chernikov /* Handle lack of __u6_addr.__u6_addr64 */ 3011914bffb6SAlexander V. Chernikov fp = (uint64_t *)&f.dip6; 3012914bffb6SAlexander V. Chernikov idp = (uint64_t *)&id->dst_ip6; 3013914bffb6SAlexander V. Chernikov /* src IPv6 is stored after dst IPv6 */ 3014914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 3015914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 3016914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 3017914bffb6SAlexander V. Chernikov *fp &= *idp; 3018914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port; 3019914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port; 3020914bffb6SAlexander V. Chernikov f.e.proto &= id->proto; 3021914bffb6SAlexander V. Chernikov hash = hash_flow6(&f, hsize); 3022914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 3023914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) { 3024914bffb6SAlexander V. Chernikov *val = ent->value; 3025914bffb6SAlexander V. Chernikov return (1); 3026914bffb6SAlexander V. Chernikov } 3027914bffb6SAlexander V. Chernikov } 3028914bffb6SAlexander V. Chernikov } 3029914bffb6SAlexander V. Chernikov 3030914bffb6SAlexander V. Chernikov return (0); 3031914bffb6SAlexander V. Chernikov } 3032914bffb6SAlexander V. Chernikov 3033914bffb6SAlexander V. Chernikov /* 3034914bffb6SAlexander V. Chernikov * New table. 3035914bffb6SAlexander V. Chernikov */ 3036914bffb6SAlexander V. Chernikov static int 3037914bffb6SAlexander V. Chernikov ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 3038914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 3039914bffb6SAlexander V. Chernikov { 3040914bffb6SAlexander V. Chernikov int i; 3041914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3042914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 3043914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 3044914bffb6SAlexander V. Chernikov 3045914bffb6SAlexander V. Chernikov cfg = malloc(sizeof(struct fhash_cfg), M_IPFW, M_WAITOK | M_ZERO); 3046914bffb6SAlexander V. Chernikov 3047914bffb6SAlexander V. Chernikov cfg->size = 512; 3048914bffb6SAlexander V. Chernikov 3049914bffb6SAlexander V. Chernikov cfg->head = malloc(sizeof(struct fhashbhead) * cfg->size, M_IPFW, 3050914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO); 3051914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 3052914bffb6SAlexander V. Chernikov SLIST_INIT(&cfg->head[i]); 3053914bffb6SAlexander V. Chernikov 3054914bffb6SAlexander V. Chernikov /* Fill in fe masks based on @tflags */ 3055914bffb6SAlexander V. Chernikov fe4 = &cfg->fe4; 3056914bffb6SAlexander V. Chernikov fe6 = &cfg->fe6; 3057914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCIP) { 3058914bffb6SAlexander V. Chernikov memset(&fe4->sip, 0xFF, sizeof(fe4->sip)); 3059914bffb6SAlexander V. Chernikov memset(&fe6->sip6, 0xFF, sizeof(fe6->sip6)); 3060914bffb6SAlexander V. Chernikov } 3061914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTIP) { 3062914bffb6SAlexander V. Chernikov memset(&fe4->dip, 0xFF, sizeof(fe4->dip)); 3063914bffb6SAlexander V. Chernikov memset(&fe6->dip6, 0xFF, sizeof(fe6->dip6)); 3064914bffb6SAlexander V. Chernikov } 3065914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCPORT) { 3066914bffb6SAlexander V. Chernikov memset(&fe4->e.sport, 0xFF, sizeof(fe4->e.sport)); 3067914bffb6SAlexander V. Chernikov memset(&fe6->e.sport, 0xFF, sizeof(fe6->e.sport)); 3068914bffb6SAlexander V. Chernikov } 3069914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTPORT) { 3070914bffb6SAlexander V. Chernikov memset(&fe4->e.dport, 0xFF, sizeof(fe4->e.dport)); 3071914bffb6SAlexander V. Chernikov memset(&fe6->e.dport, 0xFF, sizeof(fe6->e.dport)); 3072914bffb6SAlexander V. Chernikov } 3073914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_PROTO) { 3074914bffb6SAlexander V. Chernikov memset(&fe4->e.proto, 0xFF, sizeof(fe4->e.proto)); 3075914bffb6SAlexander V. Chernikov memset(&fe6->e.proto, 0xFF, sizeof(fe6->e.proto)); 3076914bffb6SAlexander V. Chernikov } 3077914bffb6SAlexander V. Chernikov 3078914bffb6SAlexander V. Chernikov fe4->e.af = AF_INET; 3079914bffb6SAlexander V. Chernikov fe6->e.af = AF_INET6; 3080914bffb6SAlexander V. Chernikov 3081914bffb6SAlexander V. Chernikov *ta_state = cfg; 3082914bffb6SAlexander V. Chernikov ti->state = cfg->head; 3083914bffb6SAlexander V. Chernikov ti->xstate = &cfg->fe4; 3084914bffb6SAlexander V. Chernikov ti->data = cfg->size; 3085914bffb6SAlexander V. Chernikov ti->lookup = ta_lookup_fhash; 3086914bffb6SAlexander V. Chernikov 3087914bffb6SAlexander V. Chernikov return (0); 3088914bffb6SAlexander V. Chernikov } 3089914bffb6SAlexander V. Chernikov 3090914bffb6SAlexander V. Chernikov static void 3091914bffb6SAlexander V. Chernikov ta_destroy_fhash(void *ta_state, struct table_info *ti) 3092914bffb6SAlexander V. Chernikov { 3093914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3094914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3095914bffb6SAlexander V. Chernikov int i; 3096914bffb6SAlexander V. Chernikov 3097914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3098914bffb6SAlexander V. Chernikov 3099914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 3100914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) 3101914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL); 3102914bffb6SAlexander V. Chernikov 3103914bffb6SAlexander V. Chernikov free(cfg->head, M_IPFW); 3104914bffb6SAlexander V. Chernikov free(cfg, M_IPFW); 3105914bffb6SAlexander V. Chernikov } 3106914bffb6SAlexander V. Chernikov 31075f379342SAlexander V. Chernikov /* 31085f379342SAlexander V. Chernikov * Provide algo-specific table info 31095f379342SAlexander V. Chernikov */ 31105f379342SAlexander V. Chernikov static void 31115f379342SAlexander V. Chernikov ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 31125f379342SAlexander V. Chernikov { 31135f379342SAlexander V. Chernikov struct fhash_cfg *cfg; 31145f379342SAlexander V. Chernikov 31155f379342SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 31165f379342SAlexander V. Chernikov 31175f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFITEM; 31185f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_HASH; 31195f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 31205f379342SAlexander V. Chernikov tinfo->count4 = cfg->items; 31215f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct fhashentry4); 31225f379342SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct fhashentry6); 31235f379342SAlexander V. Chernikov } 31245f379342SAlexander V. Chernikov 3125914bffb6SAlexander V. Chernikov static int 3126914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e, 3127914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 3128914bffb6SAlexander V. Chernikov { 3129914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3130914bffb6SAlexander V. Chernikov struct fhashentry *ent; 3131914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 3132914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 3133914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 3134914bffb6SAlexander V. Chernikov 3135914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3136914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)e; 3137914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 3138914bffb6SAlexander V. Chernikov 3139914bffb6SAlexander V. Chernikov tfe->af = ent->af; 3140914bffb6SAlexander V. Chernikov tfe->proto = ent->proto; 3141914bffb6SAlexander V. Chernikov tfe->dport = htons(ent->dport); 3142914bffb6SAlexander V. Chernikov tfe->sport = htons(ent->sport); 31430cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value; 3144914bffb6SAlexander V. Chernikov tent->subtype = ent->af; 3145914bffb6SAlexander V. Chernikov 3146914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) { 3147914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent; 3148914bffb6SAlexander V. Chernikov tfe->a.a4.sip.s_addr = htonl(fe4->sip.s_addr); 3149914bffb6SAlexander V. Chernikov tfe->a.a4.dip.s_addr = htonl(fe4->dip.s_addr); 3150914bffb6SAlexander V. Chernikov tent->masklen = 32; 3151914bffb6SAlexander V. Chernikov #ifdef INET6 3152914bffb6SAlexander V. Chernikov } else { 3153914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent; 3154914bffb6SAlexander V. Chernikov tfe->a.a6.sip6 = fe6->sip6; 3155914bffb6SAlexander V. Chernikov tfe->a.a6.dip6 = fe6->dip6; 3156914bffb6SAlexander V. Chernikov tent->masklen = 128; 3157914bffb6SAlexander V. Chernikov #endif 3158914bffb6SAlexander V. Chernikov } 3159914bffb6SAlexander V. Chernikov 3160914bffb6SAlexander V. Chernikov return (0); 3161914bffb6SAlexander V. Chernikov } 3162914bffb6SAlexander V. Chernikov 3163914bffb6SAlexander V. Chernikov static int 3164914bffb6SAlexander V. Chernikov tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent) 3165914bffb6SAlexander V. Chernikov { 3166914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 3167914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 3168914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 3169914bffb6SAlexander V. Chernikov 3170914bffb6SAlexander V. Chernikov tfe = (struct tflow_entry *)tei->paddr; 3171914bffb6SAlexander V. Chernikov 3172914bffb6SAlexander V. Chernikov ent->af = tei->subtype; 3173914bffb6SAlexander V. Chernikov ent->proto = tfe->proto; 3174914bffb6SAlexander V. Chernikov ent->dport = ntohs(tfe->dport); 3175914bffb6SAlexander V. Chernikov ent->sport = ntohs(tfe->sport); 3176914bffb6SAlexander V. Chernikov 3177914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) { 3178914bffb6SAlexander V. Chernikov #ifdef INET 3179914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent; 3180914bffb6SAlexander V. Chernikov fe4->sip.s_addr = ntohl(tfe->a.a4.sip.s_addr); 3181914bffb6SAlexander V. Chernikov fe4->dip.s_addr = ntohl(tfe->a.a4.dip.s_addr); 3182914bffb6SAlexander V. Chernikov #endif 3183914bffb6SAlexander V. Chernikov #ifdef INET6 3184914bffb6SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 3185914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent; 3186914bffb6SAlexander V. Chernikov fe6->sip6 = tfe->a.a6.sip6; 3187914bffb6SAlexander V. Chernikov fe6->dip6 = tfe->a.a6.dip6; 3188914bffb6SAlexander V. Chernikov #endif 3189914bffb6SAlexander V. Chernikov } else { 3190914bffb6SAlexander V. Chernikov /* Unknown CIDR type */ 3191914bffb6SAlexander V. Chernikov return (EINVAL); 3192914bffb6SAlexander V. Chernikov } 3193914bffb6SAlexander V. Chernikov 3194914bffb6SAlexander V. Chernikov return (0); 3195914bffb6SAlexander V. Chernikov } 3196914bffb6SAlexander V. Chernikov 3197914bffb6SAlexander V. Chernikov 3198914bffb6SAlexander V. Chernikov static int 3199914bffb6SAlexander V. Chernikov ta_find_fhash_tentry(void *ta_state, struct table_info *ti, 3200914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 3201914bffb6SAlexander V. Chernikov { 3202914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3203914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3204914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3205914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 3206914bffb6SAlexander V. Chernikov struct tentry_info tei; 3207914bffb6SAlexander V. Chernikov int error; 3208914bffb6SAlexander V. Chernikov uint32_t hash; 3209914bffb6SAlexander V. Chernikov size_t sz; 3210914bffb6SAlexander V. Chernikov 3211914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3212914bffb6SAlexander V. Chernikov 3213914bffb6SAlexander V. Chernikov ent = &fe6.e; 3214914bffb6SAlexander V. Chernikov 3215914bffb6SAlexander V. Chernikov memset(&fe6, 0, sizeof(fe6)); 3216914bffb6SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 3217914bffb6SAlexander V. Chernikov 3218914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.flow; 3219914bffb6SAlexander V. Chernikov tei.subtype = tent->subtype; 3220914bffb6SAlexander V. Chernikov 3221914bffb6SAlexander V. Chernikov if ((error = tei_to_fhash_ent(&tei, ent)) != 0) 3222914bffb6SAlexander V. Chernikov return (error); 3223914bffb6SAlexander V. Chernikov 3224914bffb6SAlexander V. Chernikov head = cfg->head; 3225914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3226914bffb6SAlexander V. Chernikov 3227914bffb6SAlexander V. Chernikov if (tei.subtype == AF_INET) 3228914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3229914bffb6SAlexander V. Chernikov else 3230914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3231914bffb6SAlexander V. Chernikov 3232914bffb6SAlexander V. Chernikov /* Check for existence */ 3233914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3234914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 3235914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(ta_state, ti, tmp, tent); 3236914bffb6SAlexander V. Chernikov return (0); 3237914bffb6SAlexander V. Chernikov } 3238914bffb6SAlexander V. Chernikov } 3239914bffb6SAlexander V. Chernikov 3240914bffb6SAlexander V. Chernikov return (ENOENT); 3241914bffb6SAlexander V. Chernikov } 3242914bffb6SAlexander V. Chernikov 3243914bffb6SAlexander V. Chernikov static void 3244914bffb6SAlexander V. Chernikov ta_foreach_fhash(void *ta_state, struct table_info *ti, ta_foreach_f *f, 3245914bffb6SAlexander V. Chernikov void *arg) 3246914bffb6SAlexander V. Chernikov { 3247914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3248914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3249914bffb6SAlexander V. Chernikov int i; 3250914bffb6SAlexander V. Chernikov 3251914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3252914bffb6SAlexander V. Chernikov 3253914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 3254914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) 3255914bffb6SAlexander V. Chernikov f(ent, arg); 3256914bffb6SAlexander V. Chernikov } 3257914bffb6SAlexander V. Chernikov 3258914bffb6SAlexander V. Chernikov static int 3259914bffb6SAlexander V. Chernikov ta_prepare_add_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 3260914bffb6SAlexander V. Chernikov void *ta_buf) 3261914bffb6SAlexander V. Chernikov { 3262914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3263914bffb6SAlexander V. Chernikov struct fhashentry *ent; 3264914bffb6SAlexander V. Chernikov size_t sz; 3265914bffb6SAlexander V. Chernikov int error; 3266914bffb6SAlexander V. Chernikov 3267914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3268914bffb6SAlexander V. Chernikov 3269914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3270914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry4); 3271914bffb6SAlexander V. Chernikov else if (tei->subtype == AF_INET6) 3272914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry6); 3273914bffb6SAlexander V. Chernikov else 3274914bffb6SAlexander V. Chernikov return (EINVAL); 3275914bffb6SAlexander V. Chernikov 3276914bffb6SAlexander V. Chernikov ent = malloc(sz, M_IPFW_TBL, M_WAITOK | M_ZERO); 3277914bffb6SAlexander V. Chernikov 3278914bffb6SAlexander V. Chernikov error = tei_to_fhash_ent(tei, ent); 3279914bffb6SAlexander V. Chernikov if (error != 0) { 3280914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL); 3281914bffb6SAlexander V. Chernikov return (error); 3282914bffb6SAlexander V. Chernikov } 3283914bffb6SAlexander V. Chernikov tb->ent_ptr = ent; 3284914bffb6SAlexander V. Chernikov 3285914bffb6SAlexander V. Chernikov return (0); 3286914bffb6SAlexander V. Chernikov } 3287914bffb6SAlexander V. Chernikov 3288914bffb6SAlexander V. Chernikov static int 3289914bffb6SAlexander V. Chernikov ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 3290b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 3291914bffb6SAlexander V. Chernikov { 3292914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3293914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3294914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3295914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3296914bffb6SAlexander V. Chernikov int exists; 3297648e8380SAlexander V. Chernikov uint32_t hash, value; 3298914bffb6SAlexander V. Chernikov size_t sz; 3299914bffb6SAlexander V. Chernikov 3300914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3301914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3302914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)tb->ent_ptr; 3303914bffb6SAlexander V. Chernikov exists = 0; 3304914bffb6SAlexander V. Chernikov 330513263632SAlexander V. Chernikov /* Read current value from @tei */ 330613263632SAlexander V. Chernikov ent->value = tei->value; 330713263632SAlexander V. Chernikov 3308914bffb6SAlexander V. Chernikov head = cfg->head; 3309914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3310914bffb6SAlexander V. Chernikov 3311914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3312914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3313914bffb6SAlexander V. Chernikov else 3314914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3315914bffb6SAlexander V. Chernikov 3316914bffb6SAlexander V. Chernikov /* Check for existence */ 3317914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3318914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 3319914bffb6SAlexander V. Chernikov exists = 1; 3320914bffb6SAlexander V. Chernikov break; 3321914bffb6SAlexander V. Chernikov } 3322914bffb6SAlexander V. Chernikov } 3323914bffb6SAlexander V. Chernikov 3324914bffb6SAlexander V. Chernikov if (exists == 1) { 3325914bffb6SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 3326914bffb6SAlexander V. Chernikov return (EEXIST); 3327914bffb6SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 3328648e8380SAlexander V. Chernikov /* Exchange values between tmp and @tei */ 3329648e8380SAlexander V. Chernikov value = tmp->value; 3330914bffb6SAlexander V. Chernikov tmp->value = tei->value; 3331648e8380SAlexander V. Chernikov tei->value = value; 3332914bffb6SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 3333914bffb6SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 3334914bffb6SAlexander V. Chernikov *pnum = 0; 3335914bffb6SAlexander V. Chernikov } else { 33364c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 33374c0c07a5SAlexander V. Chernikov return (EFBIG); 33384c0c07a5SAlexander V. Chernikov 3339914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next); 3340914bffb6SAlexander V. Chernikov tb->ent_ptr = NULL; 3341914bffb6SAlexander V. Chernikov *pnum = 1; 3342914bffb6SAlexander V. Chernikov 3343914bffb6SAlexander V. Chernikov /* Update counters and check if we need to grow hash */ 3344914bffb6SAlexander V. Chernikov cfg->items++; 3345914bffb6SAlexander V. Chernikov } 3346914bffb6SAlexander V. Chernikov 3347914bffb6SAlexander V. Chernikov return (0); 3348914bffb6SAlexander V. Chernikov } 3349914bffb6SAlexander V. Chernikov 3350914bffb6SAlexander V. Chernikov static int 3351914bffb6SAlexander V. Chernikov ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 3352914bffb6SAlexander V. Chernikov void *ta_buf) 3353914bffb6SAlexander V. Chernikov { 3354914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3355914bffb6SAlexander V. Chernikov 3356914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3357914bffb6SAlexander V. Chernikov 3358914bffb6SAlexander V. Chernikov return (tei_to_fhash_ent(tei, &tb->fe6.e)); 3359914bffb6SAlexander V. Chernikov } 3360914bffb6SAlexander V. Chernikov 3361914bffb6SAlexander V. Chernikov static int 3362914bffb6SAlexander V. Chernikov ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 3363b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 3364914bffb6SAlexander V. Chernikov { 3365914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3366914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3367914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3368914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3369914bffb6SAlexander V. Chernikov uint32_t hash; 3370914bffb6SAlexander V. Chernikov size_t sz; 3371914bffb6SAlexander V. Chernikov 3372914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3373914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3374914bffb6SAlexander V. Chernikov ent = &tb->fe6.e; 3375914bffb6SAlexander V. Chernikov 3376914bffb6SAlexander V. Chernikov head = cfg->head; 3377914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3378914bffb6SAlexander V. Chernikov 3379914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3380914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3381914bffb6SAlexander V. Chernikov else 3382914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3383914bffb6SAlexander V. Chernikov 3384914bffb6SAlexander V. Chernikov /* Check for existence */ 3385914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3386648e8380SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) == 0) 3387648e8380SAlexander V. Chernikov continue; 3388648e8380SAlexander V. Chernikov 3389914bffb6SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, fhashentry, next); 3390648e8380SAlexander V. Chernikov tei->value = tmp->value; 3391914bffb6SAlexander V. Chernikov *pnum = 1; 3392914bffb6SAlexander V. Chernikov cfg->items--; 3393648e8380SAlexander V. Chernikov tb->ent_ptr = tmp; 3394914bffb6SAlexander V. Chernikov return (0); 3395914bffb6SAlexander V. Chernikov } 3396914bffb6SAlexander V. Chernikov 3397914bffb6SAlexander V. Chernikov return (ENOENT); 3398914bffb6SAlexander V. Chernikov } 3399914bffb6SAlexander V. Chernikov 3400914bffb6SAlexander V. Chernikov static void 3401914bffb6SAlexander V. Chernikov ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 3402914bffb6SAlexander V. Chernikov void *ta_buf) 3403914bffb6SAlexander V. Chernikov { 3404914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3405914bffb6SAlexander V. Chernikov 3406914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3407914bffb6SAlexander V. Chernikov 3408914bffb6SAlexander V. Chernikov if (tb->ent_ptr != NULL) 3409914bffb6SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 3410914bffb6SAlexander V. Chernikov } 3411914bffb6SAlexander V. Chernikov 3412914bffb6SAlexander V. Chernikov /* 3413914bffb6SAlexander V. Chernikov * Hash growing callbacks. 3414914bffb6SAlexander V. Chernikov */ 3415914bffb6SAlexander V. Chernikov 3416b6ee846eSAlexander V. Chernikov static int 3417301290bcSAlexander V. Chernikov ta_need_modify_fhash(void *ta_state, struct table_info *ti, uint32_t count, 3418b6ee846eSAlexander V. Chernikov uint64_t *pflags) 3419b6ee846eSAlexander V. Chernikov { 3420b6ee846eSAlexander V. Chernikov struct fhash_cfg *cfg; 3421b6ee846eSAlexander V. Chernikov 3422b6ee846eSAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3423b6ee846eSAlexander V. Chernikov 3424b6ee846eSAlexander V. Chernikov if (cfg->items > cfg->size && cfg->size < 65536) { 3425b6ee846eSAlexander V. Chernikov *pflags = cfg->size * 2; 3426301290bcSAlexander V. Chernikov return (1); 3427b6ee846eSAlexander V. Chernikov } 3428b6ee846eSAlexander V. Chernikov 3429301290bcSAlexander V. Chernikov return (0); 3430b6ee846eSAlexander V. Chernikov } 3431b6ee846eSAlexander V. Chernikov 3432914bffb6SAlexander V. Chernikov /* 3433914bffb6SAlexander V. Chernikov * Allocate new, larger fhash. 3434914bffb6SAlexander V. Chernikov */ 3435914bffb6SAlexander V. Chernikov static int 3436914bffb6SAlexander V. Chernikov ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags) 3437914bffb6SAlexander V. Chernikov { 3438914bffb6SAlexander V. Chernikov struct mod_item *mi; 3439914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3440914bffb6SAlexander V. Chernikov int i; 3441914bffb6SAlexander V. Chernikov 3442914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3443914bffb6SAlexander V. Chernikov 3444914bffb6SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 3445914bffb6SAlexander V. Chernikov mi->size = *pflags; 3446914bffb6SAlexander V. Chernikov head = malloc(sizeof(struct fhashbhead) * mi->size, M_IPFW, 3447914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO); 3448914bffb6SAlexander V. Chernikov for (i = 0; i < mi->size; i++) 3449914bffb6SAlexander V. Chernikov SLIST_INIT(&head[i]); 3450914bffb6SAlexander V. Chernikov 3451914bffb6SAlexander V. Chernikov mi->main_ptr = head; 3452914bffb6SAlexander V. Chernikov 3453914bffb6SAlexander V. Chernikov return (0); 3454914bffb6SAlexander V. Chernikov } 3455914bffb6SAlexander V. Chernikov 3456914bffb6SAlexander V. Chernikov /* 3457914bffb6SAlexander V. Chernikov * Copy data from old runtime array to new one. 3458914bffb6SAlexander V. Chernikov */ 3459914bffb6SAlexander V. Chernikov static int 3460914bffb6SAlexander V. Chernikov ta_fill_mod_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3461914bffb6SAlexander V. Chernikov uint64_t *pflags) 3462914bffb6SAlexander V. Chernikov { 3463914bffb6SAlexander V. Chernikov 3464914bffb6SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */ 3465914bffb6SAlexander V. Chernikov return (0); 3466914bffb6SAlexander V. Chernikov } 3467914bffb6SAlexander V. Chernikov 3468914bffb6SAlexander V. Chernikov /* 3469914bffb6SAlexander V. Chernikov * Switch old & new arrays. 3470914bffb6SAlexander V. Chernikov */ 3471301290bcSAlexander V. Chernikov static void 3472914bffb6SAlexander V. Chernikov ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3473914bffb6SAlexander V. Chernikov uint64_t pflags) 3474914bffb6SAlexander V. Chernikov { 3475914bffb6SAlexander V. Chernikov struct mod_item *mi; 3476914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3477914bffb6SAlexander V. Chernikov struct fhashbhead *old_head, *new_head; 3478914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3479914bffb6SAlexander V. Chernikov int i; 3480914bffb6SAlexander V. Chernikov uint32_t nhash; 3481914bffb6SAlexander V. Chernikov size_t old_size; 3482914bffb6SAlexander V. Chernikov 3483914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3484914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3485914bffb6SAlexander V. Chernikov 3486914bffb6SAlexander V. Chernikov old_size = cfg->size; 3487914bffb6SAlexander V. Chernikov old_head = ti->state; 3488914bffb6SAlexander V. Chernikov 3489914bffb6SAlexander V. Chernikov new_head = (struct fhashbhead *)mi->main_ptr; 3490914bffb6SAlexander V. Chernikov for (i = 0; i < old_size; i++) { 3491914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 3492914bffb6SAlexander V. Chernikov nhash = hash_flow_ent(ent, mi->size); 3493914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 3494914bffb6SAlexander V. Chernikov } 3495914bffb6SAlexander V. Chernikov } 3496914bffb6SAlexander V. Chernikov 3497914bffb6SAlexander V. Chernikov ti->state = new_head; 3498914bffb6SAlexander V. Chernikov ti->data = mi->size; 3499914bffb6SAlexander V. Chernikov cfg->head = new_head; 3500914bffb6SAlexander V. Chernikov cfg->size = mi->size; 3501914bffb6SAlexander V. Chernikov 3502914bffb6SAlexander V. Chernikov mi->main_ptr = old_head; 3503914bffb6SAlexander V. Chernikov } 3504914bffb6SAlexander V. Chernikov 3505914bffb6SAlexander V. Chernikov /* 3506914bffb6SAlexander V. Chernikov * Free unneded array. 3507914bffb6SAlexander V. Chernikov */ 3508914bffb6SAlexander V. Chernikov static void 3509914bffb6SAlexander V. Chernikov ta_flush_mod_fhash(void *ta_buf) 3510914bffb6SAlexander V. Chernikov { 3511914bffb6SAlexander V. Chernikov struct mod_item *mi; 3512914bffb6SAlexander V. Chernikov 3513914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3514914bffb6SAlexander V. Chernikov if (mi->main_ptr != NULL) 3515914bffb6SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 3516914bffb6SAlexander V. Chernikov } 3517914bffb6SAlexander V. Chernikov 3518914bffb6SAlexander V. Chernikov struct table_algo flow_hash = { 3519914bffb6SAlexander V. Chernikov .name = "flow:hash", 3520914bffb6SAlexander V. Chernikov .type = IPFW_TABLE_FLOW, 352157a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 352257a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_fhash), 3523914bffb6SAlexander V. Chernikov .init = ta_init_fhash, 3524914bffb6SAlexander V. Chernikov .destroy = ta_destroy_fhash, 3525914bffb6SAlexander V. Chernikov .prepare_add = ta_prepare_add_fhash, 3526914bffb6SAlexander V. Chernikov .prepare_del = ta_prepare_del_fhash, 3527914bffb6SAlexander V. Chernikov .add = ta_add_fhash, 3528914bffb6SAlexander V. Chernikov .del = ta_del_fhash, 3529914bffb6SAlexander V. Chernikov .flush_entry = ta_flush_fhash_entry, 3530914bffb6SAlexander V. Chernikov .foreach = ta_foreach_fhash, 3531914bffb6SAlexander V. Chernikov .dump_tentry = ta_dump_fhash_tentry, 3532914bffb6SAlexander V. Chernikov .find_tentry = ta_find_fhash_tentry, 35335f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_fhash_tinfo, 3534301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_fhash, 3535914bffb6SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_fhash, 3536914bffb6SAlexander V. Chernikov .fill_mod = ta_fill_mod_fhash, 3537914bffb6SAlexander V. Chernikov .modify = ta_modify_fhash, 3538914bffb6SAlexander V. Chernikov .flush_mod = ta_flush_mod_fhash, 3539914bffb6SAlexander V. Chernikov }; 35403fe2ef91SAlexander V. Chernikov 3541d3b00c08SAlexander V. Chernikov /* 3542d3b00c08SAlexander V. Chernikov * Kernel fibs bindings. 3543d3b00c08SAlexander V. Chernikov * 3544d3b00c08SAlexander V. Chernikov * Implementation: 3545d3b00c08SAlexander V. Chernikov * 3546d3b00c08SAlexander V. Chernikov * Runtime part: 3547d3b00c08SAlexander V. Chernikov * - fully relies on route API 3548d3b00c08SAlexander V. Chernikov * - fib number is stored in ti->data 3549d3b00c08SAlexander V. Chernikov * 3550d3b00c08SAlexander V. Chernikov */ 3551d3b00c08SAlexander V. Chernikov 3552d3b00c08SAlexander V. Chernikov static struct rtentry * 3553d3b00c08SAlexander V. Chernikov lookup_kfib(void *key, int keylen, int fib) 3554d3b00c08SAlexander V. Chernikov { 3555d3b00c08SAlexander V. Chernikov struct sockaddr *s; 3556d3b00c08SAlexander V. Chernikov 3557d3b00c08SAlexander V. Chernikov if (keylen == 4) { 3558d3b00c08SAlexander V. Chernikov struct sockaddr_in sin; 3559d3b00c08SAlexander V. Chernikov bzero(&sin, sizeof(sin)); 3560d3b00c08SAlexander V. Chernikov sin.sin_len = sizeof(struct sockaddr_in); 3561d3b00c08SAlexander V. Chernikov sin.sin_family = AF_INET; 3562d3b00c08SAlexander V. Chernikov sin.sin_addr.s_addr = *(in_addr_t *)key; 3563d3b00c08SAlexander V. Chernikov s = (struct sockaddr *)&sin; 3564d3b00c08SAlexander V. Chernikov } else { 3565d3b00c08SAlexander V. Chernikov struct sockaddr_in6 sin6; 3566d3b00c08SAlexander V. Chernikov bzero(&sin6, sizeof(sin6)); 3567d3b00c08SAlexander V. Chernikov sin6.sin6_len = sizeof(struct sockaddr_in6); 3568d3b00c08SAlexander V. Chernikov sin6.sin6_family = AF_INET6; 3569d3b00c08SAlexander V. Chernikov sin6.sin6_addr = *(struct in6_addr *)key; 3570d3b00c08SAlexander V. Chernikov s = (struct sockaddr *)&sin6; 3571d3b00c08SAlexander V. Chernikov } 3572d3b00c08SAlexander V. Chernikov 3573d3b00c08SAlexander V. Chernikov return (rtalloc1_fib(s, 0, 0, fib)); 3574d3b00c08SAlexander V. Chernikov } 3575d3b00c08SAlexander V. Chernikov 3576d3b00c08SAlexander V. Chernikov static int 3577d3b00c08SAlexander V. Chernikov ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen, 3578d3b00c08SAlexander V. Chernikov uint32_t *val) 3579d3b00c08SAlexander V. Chernikov { 3580d3b00c08SAlexander V. Chernikov struct rtentry *rte; 3581d3b00c08SAlexander V. Chernikov 3582d3b00c08SAlexander V. Chernikov if ((rte = lookup_kfib(key, keylen, ti->data)) == NULL) 3583d3b00c08SAlexander V. Chernikov return (0); 3584d3b00c08SAlexander V. Chernikov 3585d3b00c08SAlexander V. Chernikov *val = 0; 3586d3b00c08SAlexander V. Chernikov RTFREE_LOCKED(rte); 3587d3b00c08SAlexander V. Chernikov 3588d3b00c08SAlexander V. Chernikov return (1); 3589d3b00c08SAlexander V. Chernikov } 3590d3b00c08SAlexander V. Chernikov 3591d3b00c08SAlexander V. Chernikov /* Parse 'fib=%d' */ 3592d3b00c08SAlexander V. Chernikov static int 3593d3b00c08SAlexander V. Chernikov kfib_parse_opts(int *pfib, char *data) 3594d3b00c08SAlexander V. Chernikov { 3595d3b00c08SAlexander V. Chernikov char *pdel, *pend, *s; 3596d3b00c08SAlexander V. Chernikov int fibnum; 3597d3b00c08SAlexander V. Chernikov 3598d3b00c08SAlexander V. Chernikov if (data == NULL) 3599d3b00c08SAlexander V. Chernikov return (0); 3600d3b00c08SAlexander V. Chernikov if ((pdel = strchr(data, ' ')) == NULL) 3601d3b00c08SAlexander V. Chernikov return (0); 3602d3b00c08SAlexander V. Chernikov while (*pdel == ' ') 3603d3b00c08SAlexander V. Chernikov pdel++; 3604d3b00c08SAlexander V. Chernikov if (strncmp(pdel, "fib=", 4) != 0) 3605d3b00c08SAlexander V. Chernikov return (EINVAL); 3606d3b00c08SAlexander V. Chernikov if ((s = strchr(pdel, ' ')) != NULL) 3607d3b00c08SAlexander V. Chernikov *s++ = '\0'; 3608d3b00c08SAlexander V. Chernikov 3609d3b00c08SAlexander V. Chernikov pdel += 4; 3610d3b00c08SAlexander V. Chernikov /* Need \d+ */ 3611d3b00c08SAlexander V. Chernikov fibnum = strtol(pdel, &pend, 10); 3612d3b00c08SAlexander V. Chernikov if (*pend != '\0') 3613d3b00c08SAlexander V. Chernikov return (EINVAL); 3614d3b00c08SAlexander V. Chernikov 3615d3b00c08SAlexander V. Chernikov *pfib = fibnum; 3616d3b00c08SAlexander V. Chernikov 3617d3b00c08SAlexander V. Chernikov return (0); 3618d3b00c08SAlexander V. Chernikov } 3619d3b00c08SAlexander V. Chernikov 3620d3b00c08SAlexander V. Chernikov static void 3621d3b00c08SAlexander V. Chernikov ta_print_kfib_config(void *ta_state, struct table_info *ti, char *buf, 3622d3b00c08SAlexander V. Chernikov size_t bufsize) 3623d3b00c08SAlexander V. Chernikov { 3624d3b00c08SAlexander V. Chernikov 3625d3b00c08SAlexander V. Chernikov if (ti->data != 0) 3626c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s fib=%lu", "addr:kfib", ti->data); 3627d3b00c08SAlexander V. Chernikov else 3628c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s", "addr:kfib"); 3629d3b00c08SAlexander V. Chernikov } 3630d3b00c08SAlexander V. Chernikov 3631d3b00c08SAlexander V. Chernikov static int 3632d3b00c08SAlexander V. Chernikov ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 3633d3b00c08SAlexander V. Chernikov char *data, uint8_t tflags) 3634d3b00c08SAlexander V. Chernikov { 3635d3b00c08SAlexander V. Chernikov int error, fibnum; 3636d3b00c08SAlexander V. Chernikov 3637d3b00c08SAlexander V. Chernikov fibnum = 0; 3638d3b00c08SAlexander V. Chernikov if ((error = kfib_parse_opts(&fibnum, data)) != 0) 3639d3b00c08SAlexander V. Chernikov return (error); 3640d3b00c08SAlexander V. Chernikov 3641d3b00c08SAlexander V. Chernikov if (fibnum >= rt_numfibs) 3642d3b00c08SAlexander V. Chernikov return (E2BIG); 3643d3b00c08SAlexander V. Chernikov 3644d3b00c08SAlexander V. Chernikov ti->data = fibnum; 3645d3b00c08SAlexander V. Chernikov ti->lookup = ta_lookup_kfib; 3646d3b00c08SAlexander V. Chernikov 3647d3b00c08SAlexander V. Chernikov return (0); 3648d3b00c08SAlexander V. Chernikov } 3649d3b00c08SAlexander V. Chernikov 3650d3b00c08SAlexander V. Chernikov /* 3651d3b00c08SAlexander V. Chernikov * Destroys table @ti 3652d3b00c08SAlexander V. Chernikov */ 3653d3b00c08SAlexander V. Chernikov static void 3654d3b00c08SAlexander V. Chernikov ta_destroy_kfib(void *ta_state, struct table_info *ti) 3655d3b00c08SAlexander V. Chernikov { 3656d3b00c08SAlexander V. Chernikov 3657d3b00c08SAlexander V. Chernikov } 3658d3b00c08SAlexander V. Chernikov 3659d3b00c08SAlexander V. Chernikov /* 3660d3b00c08SAlexander V. Chernikov * Provide algo-specific table info 3661d3b00c08SAlexander V. Chernikov */ 3662d3b00c08SAlexander V. Chernikov static void 3663d3b00c08SAlexander V. Chernikov ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 3664d3b00c08SAlexander V. Chernikov { 3665d3b00c08SAlexander V. Chernikov 3666d3b00c08SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA; 3667d3b00c08SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_RADIX; 3668d3b00c08SAlexander V. Chernikov tinfo->count4 = 0; 3669d3b00c08SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct rtentry); 3670d3b00c08SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_RADIX; 3671d3b00c08SAlexander V. Chernikov tinfo->count6 = 0; 3672d3b00c08SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct rtentry); 3673d3b00c08SAlexander V. Chernikov } 3674d3b00c08SAlexander V. Chernikov 3675d3b00c08SAlexander V. Chernikov static int 3676d3b00c08SAlexander V. Chernikov contigmask(uint8_t *p, int len) 3677d3b00c08SAlexander V. Chernikov { 3678d3b00c08SAlexander V. Chernikov int i, n; 3679d3b00c08SAlexander V. Chernikov 3680d3b00c08SAlexander V. Chernikov for (i = 0; i < len ; i++) 3681d3b00c08SAlexander V. Chernikov if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 3682d3b00c08SAlexander V. Chernikov break; 3683d3b00c08SAlexander V. Chernikov for (n= i + 1; n < len; n++) 3684d3b00c08SAlexander V. Chernikov if ( (p[n/8] & (1 << (7 - (n % 8)))) != 0) 3685d3b00c08SAlexander V. Chernikov return (-1); /* mask not contiguous */ 3686d3b00c08SAlexander V. Chernikov return (i); 3687d3b00c08SAlexander V. Chernikov } 3688d3b00c08SAlexander V. Chernikov 3689d3b00c08SAlexander V. Chernikov 3690d3b00c08SAlexander V. Chernikov static int 3691d3b00c08SAlexander V. Chernikov ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e, 3692d3b00c08SAlexander V. Chernikov ipfw_obj_tentry *tent) 3693d3b00c08SAlexander V. Chernikov { 3694d3b00c08SAlexander V. Chernikov struct rtentry *rte; 3695d3b00c08SAlexander V. Chernikov struct sockaddr_in *addr, *mask; 3696d3b00c08SAlexander V. Chernikov struct sockaddr_in6 *addr6, *mask6; 3697d3b00c08SAlexander V. Chernikov int len; 3698d3b00c08SAlexander V. Chernikov 3699d3b00c08SAlexander V. Chernikov rte = (struct rtentry *)e; 3700d3b00c08SAlexander V. Chernikov addr = (struct sockaddr_in *)rt_key(rte); 3701d3b00c08SAlexander V. Chernikov mask = (struct sockaddr_in *)rt_mask(rte); 3702d3b00c08SAlexander V. Chernikov len = 0; 3703d3b00c08SAlexander V. Chernikov 3704d3b00c08SAlexander V. Chernikov /* Guess IPv4/IPv6 radix by sockaddr family */ 3705d3b00c08SAlexander V. Chernikov if (addr->sin_family == AF_INET) { 3706d3b00c08SAlexander V. Chernikov tent->k.addr.s_addr = addr->sin_addr.s_addr; 3707d3b00c08SAlexander V. Chernikov len = 32; 3708d3b00c08SAlexander V. Chernikov if (mask != NULL) 3709d3b00c08SAlexander V. Chernikov len = contigmask((uint8_t *)&mask->sin_addr, 32); 3710d3b00c08SAlexander V. Chernikov if (len == -1) 3711d3b00c08SAlexander V. Chernikov len = 0; 3712d3b00c08SAlexander V. Chernikov tent->masklen = len; 3713d3b00c08SAlexander V. Chernikov tent->subtype = AF_INET; 37140cba2b28SAlexander V. Chernikov tent->v.kidx = 0; /* Do we need to put GW here? */ 3715d3b00c08SAlexander V. Chernikov #ifdef INET6 3716d3b00c08SAlexander V. Chernikov } else if (addr->sin_family == AF_INET6) { 3717d3b00c08SAlexander V. Chernikov addr6 = (struct sockaddr_in6 *)addr; 3718d3b00c08SAlexander V. Chernikov mask6 = (struct sockaddr_in6 *)mask; 3719d3b00c08SAlexander V. Chernikov memcpy(&tent->k, &addr6->sin6_addr, sizeof(struct in6_addr)); 3720d3b00c08SAlexander V. Chernikov len = 128; 3721d3b00c08SAlexander V. Chernikov if (mask6 != NULL) 3722d3b00c08SAlexander V. Chernikov len = contigmask((uint8_t *)&mask6->sin6_addr, 128); 3723d3b00c08SAlexander V. Chernikov if (len == -1) 3724d3b00c08SAlexander V. Chernikov len = 0; 3725d3b00c08SAlexander V. Chernikov tent->masklen = len; 3726d3b00c08SAlexander V. Chernikov tent->subtype = AF_INET6; 37270cba2b28SAlexander V. Chernikov tent->v.kidx = 0; 3728d3b00c08SAlexander V. Chernikov #endif 3729d3b00c08SAlexander V. Chernikov } 3730d3b00c08SAlexander V. Chernikov 3731d3b00c08SAlexander V. Chernikov return (0); 3732d3b00c08SAlexander V. Chernikov } 3733d3b00c08SAlexander V. Chernikov 3734d3b00c08SAlexander V. Chernikov static int 3735d3b00c08SAlexander V. Chernikov ta_find_kfib_tentry(void *ta_state, struct table_info *ti, 3736d3b00c08SAlexander V. Chernikov ipfw_obj_tentry *tent) 3737d3b00c08SAlexander V. Chernikov { 3738d3b00c08SAlexander V. Chernikov struct rtentry *rte; 3739d3b00c08SAlexander V. Chernikov void *key; 3740d3b00c08SAlexander V. Chernikov int keylen; 3741d3b00c08SAlexander V. Chernikov 3742d3b00c08SAlexander V. Chernikov if (tent->subtype == AF_INET) { 3743d3b00c08SAlexander V. Chernikov key = &tent->k.addr; 3744d3b00c08SAlexander V. Chernikov keylen = sizeof(struct in_addr); 3745d3b00c08SAlexander V. Chernikov } else { 3746d3b00c08SAlexander V. Chernikov key = &tent->k.addr6; 3747d3b00c08SAlexander V. Chernikov keylen = sizeof(struct in6_addr); 3748d3b00c08SAlexander V. Chernikov } 3749d3b00c08SAlexander V. Chernikov 3750d3b00c08SAlexander V. Chernikov if ((rte = lookup_kfib(key, keylen, ti->data)) == NULL) 3751d3b00c08SAlexander V. Chernikov return (0); 3752d3b00c08SAlexander V. Chernikov 3753d3b00c08SAlexander V. Chernikov if (rte != NULL) { 3754d3b00c08SAlexander V. Chernikov ta_dump_kfib_tentry(ta_state, ti, rte, tent); 3755d3b00c08SAlexander V. Chernikov RTFREE_LOCKED(rte); 3756d3b00c08SAlexander V. Chernikov return (0); 3757d3b00c08SAlexander V. Chernikov } 3758d3b00c08SAlexander V. Chernikov 3759d3b00c08SAlexander V. Chernikov return (ENOENT); 3760d3b00c08SAlexander V. Chernikov } 3761d3b00c08SAlexander V. Chernikov 3762d3b00c08SAlexander V. Chernikov static void 3763d3b00c08SAlexander V. Chernikov ta_foreach_kfib(void *ta_state, struct table_info *ti, ta_foreach_f *f, 3764d3b00c08SAlexander V. Chernikov void *arg) 3765d3b00c08SAlexander V. Chernikov { 3766d3b00c08SAlexander V. Chernikov struct radix_node_head *rnh; 3767d3b00c08SAlexander V. Chernikov int error; 3768d3b00c08SAlexander V. Chernikov 3769d3b00c08SAlexander V. Chernikov rnh = rt_tables_get_rnh(ti->data, AF_INET); 3770d3b00c08SAlexander V. Chernikov if (rnh != NULL) { 3771d3b00c08SAlexander V. Chernikov RADIX_NODE_HEAD_RLOCK(rnh); 3772d3b00c08SAlexander V. Chernikov error = rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 3773d3b00c08SAlexander V. Chernikov RADIX_NODE_HEAD_RUNLOCK(rnh); 3774d3b00c08SAlexander V. Chernikov } 3775d3b00c08SAlexander V. Chernikov 3776d3b00c08SAlexander V. Chernikov rnh = rt_tables_get_rnh(ti->data, AF_INET6); 3777d3b00c08SAlexander V. Chernikov if (rnh != NULL) { 3778d3b00c08SAlexander V. Chernikov RADIX_NODE_HEAD_RLOCK(rnh); 3779d3b00c08SAlexander V. Chernikov error = rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 3780d3b00c08SAlexander V. Chernikov RADIX_NODE_HEAD_RUNLOCK(rnh); 3781d3b00c08SAlexander V. Chernikov } 3782d3b00c08SAlexander V. Chernikov } 3783d3b00c08SAlexander V. Chernikov 3784c21034b7SAlexander V. Chernikov struct table_algo addr_kfib = { 3785c21034b7SAlexander V. Chernikov .name = "addr:kfib", 3786c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR, 3787d3b00c08SAlexander V. Chernikov .flags = TA_FLAG_READONLY, 3788d3b00c08SAlexander V. Chernikov .ta_buf_size = 0, 3789d3b00c08SAlexander V. Chernikov .init = ta_init_kfib, 3790d3b00c08SAlexander V. Chernikov .destroy = ta_destroy_kfib, 3791d3b00c08SAlexander V. Chernikov .foreach = ta_foreach_kfib, 3792d3b00c08SAlexander V. Chernikov .dump_tentry = ta_dump_kfib_tentry, 3793d3b00c08SAlexander V. Chernikov .find_tentry = ta_find_kfib_tentry, 3794d3b00c08SAlexander V. Chernikov .dump_tinfo = ta_dump_kfib_tinfo, 3795d3b00c08SAlexander V. Chernikov .print_config = ta_print_kfib_config, 3796d3b00c08SAlexander V. Chernikov }; 3797d3b00c08SAlexander V. Chernikov 37989f7d47b0SAlexander V. Chernikov void 37990b565ac0SAlexander V. Chernikov ipfw_table_algo_init(struct ip_fw_chain *ch) 38009f7d47b0SAlexander V. Chernikov { 38010b565ac0SAlexander V. Chernikov size_t sz; 38020b565ac0SAlexander V. Chernikov 38039f7d47b0SAlexander V. Chernikov /* 38049f7d47b0SAlexander V. Chernikov * Register all algorithms presented here. 38059f7d47b0SAlexander V. Chernikov */ 38060b565ac0SAlexander V. Chernikov sz = sizeof(struct table_algo); 3807c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_radix, sz, &addr_radix.idx); 3808c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_hash, sz, &addr_hash.idx); 38090b565ac0SAlexander V. Chernikov ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx); 3810b23d5de9SAlexander V. Chernikov ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx); 3811914bffb6SAlexander V. Chernikov ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx); 3812c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_kfib, sz, &addr_kfib.idx); 3813b1d105bcSAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_dxr, sz, &addr_dxr.idx); 38149f7d47b0SAlexander V. Chernikov } 38159f7d47b0SAlexander V. Chernikov 38169f7d47b0SAlexander V. Chernikov void 38170b565ac0SAlexander V. Chernikov ipfw_table_algo_destroy(struct ip_fw_chain *ch) 38189f7d47b0SAlexander V. Chernikov { 38190b565ac0SAlexander V. Chernikov 3820c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_radix.idx); 3821c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_hash.idx); 38220b565ac0SAlexander V. Chernikov ipfw_del_table_algo(ch, iface_idx.idx); 3823b23d5de9SAlexander V. Chernikov ipfw_del_table_algo(ch, number_array.idx); 3824914bffb6SAlexander V. Chernikov ipfw_del_table_algo(ch, flow_hash.idx); 3825c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_kfib.idx); 3826b1d105bcSAlexander V. Chernikov ipfw_del_table_algo(ch, addr_dxr.idx); 38279f7d47b0SAlexander V. Chernikov } 38289f7d47b0SAlexander V. Chernikov 38299f7d47b0SAlexander V. Chernikov 3830