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 /* 299f7d47b0SAlexander V. Chernikov * Lookup table algorithms. 309f7d47b0SAlexander V. Chernikov * 319f7d47b0SAlexander V. Chernikov */ 329f7d47b0SAlexander V. Chernikov 339f7d47b0SAlexander V. Chernikov #include "opt_ipfw.h" 349f7d47b0SAlexander V. Chernikov #include "opt_inet.h" 359f7d47b0SAlexander V. Chernikov #ifndef INET 369f7d47b0SAlexander V. Chernikov #error IPFIREWALL requires INET. 379f7d47b0SAlexander V. Chernikov #endif /* INET */ 389f7d47b0SAlexander V. Chernikov #include "opt_inet6.h" 399f7d47b0SAlexander V. Chernikov 409f7d47b0SAlexander V. Chernikov #include <sys/param.h> 419f7d47b0SAlexander V. Chernikov #include <sys/systm.h> 429f7d47b0SAlexander V. Chernikov #include <sys/malloc.h> 439f7d47b0SAlexander V. Chernikov #include <sys/kernel.h> 449f7d47b0SAlexander V. Chernikov #include <sys/lock.h> 459f7d47b0SAlexander V. Chernikov #include <sys/rwlock.h> 46d4e1b515SAlexander V. Chernikov #include <sys/rmlock.h> 479f7d47b0SAlexander V. Chernikov #include <sys/socket.h> 489f7d47b0SAlexander V. Chernikov #include <sys/queue.h> 4981cac390SArseny Smalyuk #include <net/ethernet.h> 509f7d47b0SAlexander V. Chernikov #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */ 519f7d47b0SAlexander V. Chernikov #include <net/radix.h> 52d3b00c08SAlexander V. Chernikov #include <net/route.h> 536ad7446cSAlexander V. Chernikov #include <net/route/nhop.h> 544451d893SAlexander V. Chernikov #include <net/route/route_ctl.h> 559f7d47b0SAlexander V. Chernikov 569f7d47b0SAlexander V. Chernikov #include <netinet/in.h> 57004d3e30SAlexander V. Chernikov #include <netinet/in_fib.h> 589f7d47b0SAlexander V. Chernikov #include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 599f7d47b0SAlexander V. Chernikov #include <netinet/ip_fw.h> 60004d3e30SAlexander V. Chernikov #include <netinet6/in6_fib.h> 619f7d47b0SAlexander V. Chernikov 629f7d47b0SAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_private.h> 63ea761a5dSAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_table.h> 649f7d47b0SAlexander V. Chernikov 65301290bcSAlexander V. Chernikov /* 66301290bcSAlexander V. Chernikov * IPFW table lookup algorithms. 67301290bcSAlexander V. Chernikov * 68301290bcSAlexander V. Chernikov * What is needed to add another table algo? 69301290bcSAlexander V. Chernikov * 70301290bcSAlexander V. Chernikov * Algo init: 71301290bcSAlexander V. Chernikov * * struct table_algo has to be filled with: 72c21034b7SAlexander V. Chernikov * name: "type:algoname" format, e.g. "addr:radix". Currently 73c21034b7SAlexander V. Chernikov * there are the following types: "addr", "iface", "number" and "flow". 74301290bcSAlexander V. Chernikov * type: one of IPFW_TABLE_* types 75301290bcSAlexander V. Chernikov * flags: one or more TA_FLAGS_* 76301290bcSAlexander V. Chernikov * ta_buf_size: size of structure used to store add/del item state. 77301290bcSAlexander V. Chernikov * Needs to be less than TA_BUF_SZ. 78301290bcSAlexander V. Chernikov * callbacks: see below for description. 79301290bcSAlexander V. Chernikov * * ipfw_add_table_algo / ipfw_del_table_algo has to be called 80301290bcSAlexander V. Chernikov * 81301290bcSAlexander V. Chernikov * Callbacks description: 82301290bcSAlexander V. Chernikov * 83301290bcSAlexander V. Chernikov * -init: request to initialize new table instance. 84301290bcSAlexander V. Chernikov * typedef int (ta_init)(struct ip_fw_chain *ch, void **ta_state, 85301290bcSAlexander V. Chernikov * struct table_info *ti, char *data, uint8_t tflags); 86301290bcSAlexander V. Chernikov * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success. 87301290bcSAlexander V. Chernikov * 88301290bcSAlexander V. Chernikov * Allocate all structures needed for normal operations. 89301290bcSAlexander V. Chernikov * * Caller may want to parse @data for some algo-specific 90301290bcSAlexander V. Chernikov * options provided by userland. 91301290bcSAlexander V. Chernikov * * Caller may want to save configuration state pointer to @ta_state 92301290bcSAlexander V. Chernikov * * Caller needs to save desired runtime structure pointer(s) 93301290bcSAlexander V. Chernikov * inside @ti fields. Note that it is not correct to save 94301290bcSAlexander V. Chernikov * @ti pointer at this moment. Use -change_ti hook for that. 95301290bcSAlexander V. Chernikov * * Caller has to fill in ti->lookup to appropriate function 96301290bcSAlexander V. Chernikov * pointer. 97301290bcSAlexander V. Chernikov * 98301290bcSAlexander V. Chernikov * 99301290bcSAlexander V. Chernikov * 100301290bcSAlexander V. Chernikov * -destroy: request to destroy table instance. 101301290bcSAlexander V. Chernikov * typedef void (ta_destroy)(void *ta_state, struct table_info *ti); 1020caab009SAlexander V. Chernikov * MANDATORY, unlocked. (M_WAITOK). 103301290bcSAlexander V. Chernikov * 104301290bcSAlexander V. Chernikov * Frees all table entries and all tables structures allocated by -init. 105301290bcSAlexander V. Chernikov * 106301290bcSAlexander V. Chernikov * 107301290bcSAlexander V. Chernikov * 108301290bcSAlexander V. Chernikov * -prepare_add: request to allocate state for adding new entry. 109301290bcSAlexander V. Chernikov * typedef int (ta_prepare_add)(struct ip_fw_chain *ch, struct tentry_info *tei, 110301290bcSAlexander V. Chernikov * void *ta_buf); 111301290bcSAlexander V. Chernikov * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success. 112301290bcSAlexander V. Chernikov * 11313263632SAlexander V. Chernikov * Allocates state and fills it in with all necessary data (EXCEPT value) 11413263632SAlexander V. Chernikov * from @tei to minimize operations needed to be done under WLOCK. 11513263632SAlexander V. Chernikov * "value" field has to be copied to new entry in @add callback. 116301290bcSAlexander V. Chernikov * Buffer ta_buf of size ta->ta_buf_sz may be used to store 117301290bcSAlexander V. Chernikov * allocated state. 118301290bcSAlexander V. Chernikov * 119301290bcSAlexander V. Chernikov * 120301290bcSAlexander V. Chernikov * 121301290bcSAlexander V. Chernikov * -prepare_del: request to set state for deleting existing entry. 122301290bcSAlexander V. Chernikov * typedef int (ta_prepare_del)(struct ip_fw_chain *ch, struct tentry_info *tei, 123301290bcSAlexander V. Chernikov * void *ta_buf); 124301290bcSAlexander V. Chernikov * MANDATORY, locked, UH. (M_NOWAIT). Returns 0 on success. 125301290bcSAlexander V. Chernikov * 126301290bcSAlexander V. Chernikov * Buffer ta_buf of size ta->ta_buf_sz may be used to store 127301290bcSAlexander V. Chernikov * allocated state. Caller should use on-stack ta_buf allocation 128301290bcSAlexander V. Chernikov * instead of doing malloc(). 129301290bcSAlexander V. Chernikov * 130301290bcSAlexander V. Chernikov * 131301290bcSAlexander V. Chernikov * 132301290bcSAlexander V. Chernikov * -add: request to insert new entry into runtime/config structures. 133301290bcSAlexander V. Chernikov * typedef int (ta_add)(void *ta_state, struct table_info *ti, 134301290bcSAlexander V. Chernikov * struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 135301290bcSAlexander V. Chernikov * MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success. 136301290bcSAlexander V. Chernikov * 137301290bcSAlexander V. Chernikov * Insert new entry using previously-allocated state in @ta_buf. 138301290bcSAlexander V. Chernikov * * @tei may have the following flags: 139301290bcSAlexander V. Chernikov * TEI_FLAGS_UPDATE: request to add or update entry. 140301290bcSAlexander V. Chernikov * TEI_FLAGS_DONTADD: request to update (but not add) entry. 141301290bcSAlexander V. Chernikov * * Caller is required to do the following: 14213263632SAlexander V. Chernikov * copy real entry value from @tei 143301290bcSAlexander V. Chernikov * entry added: return 0, set 1 to @pnum 144301290bcSAlexander V. Chernikov * entry updated: return 0, store 0 to @pnum, store old value in @tei, 145301290bcSAlexander V. Chernikov * add TEI_FLAGS_UPDATED flag to @tei. 146301290bcSAlexander V. Chernikov * entry exists: return EEXIST 147301290bcSAlexander V. Chernikov * entry not found: return ENOENT 148301290bcSAlexander V. Chernikov * other error: return non-zero error code. 149301290bcSAlexander V. Chernikov * 150301290bcSAlexander V. Chernikov * 151301290bcSAlexander V. Chernikov * 152301290bcSAlexander V. Chernikov * -del: request to delete existing entry from runtime/config structures. 153301290bcSAlexander V. Chernikov * typedef int (ta_del)(void *ta_state, struct table_info *ti, 154301290bcSAlexander V. Chernikov * struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 155301290bcSAlexander V. Chernikov * MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success. 156301290bcSAlexander V. Chernikov * 157301290bcSAlexander V. Chernikov * Delete entry using previously set up in @ta_buf. 158301290bcSAlexander V. Chernikov * * Caller is required to do the following: 15913263632SAlexander V. Chernikov * entry deleted: return 0, set 1 to @pnum, store old value in @tei. 160301290bcSAlexander V. Chernikov * entry not found: return ENOENT 161301290bcSAlexander V. Chernikov * other error: return non-zero error code. 162301290bcSAlexander V. Chernikov * 163301290bcSAlexander V. Chernikov * 164301290bcSAlexander V. Chernikov * 165301290bcSAlexander V. Chernikov * -flush_entry: flush entry state created by -prepare_add / -del / others 166301290bcSAlexander V. Chernikov * typedef void (ta_flush_entry)(struct ip_fw_chain *ch, 167301290bcSAlexander V. Chernikov * struct tentry_info *tei, void *ta_buf); 168301290bcSAlexander V. Chernikov * MANDATORY, may be locked. (M_NOWAIT). 169301290bcSAlexander V. Chernikov * 170301290bcSAlexander V. Chernikov * Delete state allocated by: 171301290bcSAlexander V. Chernikov * -prepare_add (-add returned EEXIST|UPDATED) 172301290bcSAlexander V. Chernikov * -prepare_del (if any) 173301290bcSAlexander V. Chernikov * -del 174301290bcSAlexander V. Chernikov * * Caller is required to handle empty @ta_buf correctly. 175301290bcSAlexander V. Chernikov * 176301290bcSAlexander V. Chernikov * 177301290bcSAlexander V. Chernikov * -find_tentry: finds entry specified by key @tei 178301290bcSAlexander V. Chernikov * typedef int ta_find_tentry(void *ta_state, struct table_info *ti, 179301290bcSAlexander V. Chernikov * ipfw_obj_tentry *tent); 180301290bcSAlexander V. Chernikov * OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 on success. 181301290bcSAlexander V. Chernikov * 182301290bcSAlexander V. Chernikov * Finds entry specified by given key. 183a4641f4eSPedro F. Giffuni * * Caller is required to do the following: 184301290bcSAlexander V. Chernikov * entry found: returns 0, export entry to @tent 185301290bcSAlexander V. Chernikov * entry not found: returns ENOENT 186301290bcSAlexander V. Chernikov * 187301290bcSAlexander V. Chernikov * 188301290bcSAlexander V. Chernikov * -need_modify: checks if @ti has enough space to hold another @count items. 189301290bcSAlexander V. Chernikov * typedef int (ta_need_modify)(void *ta_state, struct table_info *ti, 190301290bcSAlexander V. Chernikov * uint32_t count, uint64_t *pflags); 191fd0869d5SAlexander V. Chernikov * OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 if has. 192301290bcSAlexander V. Chernikov * 193301290bcSAlexander V. Chernikov * Checks if given table has enough space to add @count items without 194301290bcSAlexander V. Chernikov * resize. Caller may use @pflags to store desired modification data. 195301290bcSAlexander V. Chernikov * 196301290bcSAlexander V. Chernikov * 197301290bcSAlexander V. Chernikov * 198301290bcSAlexander V. Chernikov * -prepare_mod: allocate structures for table modification. 199301290bcSAlexander V. Chernikov * typedef int (ta_prepare_mod)(void *ta_buf, uint64_t *pflags); 200fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), unlocked. (M_WAITOK). Returns 0 on success. 201301290bcSAlexander V. Chernikov * 202301290bcSAlexander V. Chernikov * Allocate all needed state for table modification. Caller 203301290bcSAlexander V. Chernikov * should use `struct mod_item` to store new state in @ta_buf. 204301290bcSAlexander V. Chernikov * Up to TA_BUF_SZ (128 bytes) can be stored in @ta_buf. 205301290bcSAlexander V. Chernikov * 206301290bcSAlexander V. Chernikov * 207301290bcSAlexander V. Chernikov * 208301290bcSAlexander V. Chernikov * -fill_mod: copy some data to new state/ 209301290bcSAlexander V. Chernikov * typedef int (ta_fill_mod)(void *ta_state, struct table_info *ti, 210301290bcSAlexander V. Chernikov * void *ta_buf, uint64_t *pflags); 211fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), locked (UH). (M_NOWAIT). Returns 0 on success. 212301290bcSAlexander V. Chernikov * 213301290bcSAlexander V. Chernikov * Copy as much data as we can to minimize changes under WLOCK. 214301290bcSAlexander V. Chernikov * For example, array can be merged inside this callback. 215301290bcSAlexander V. Chernikov * 216301290bcSAlexander V. Chernikov * 217301290bcSAlexander V. Chernikov * 218301290bcSAlexander V. Chernikov * -modify: perform final modification. 219301290bcSAlexander V. Chernikov * typedef void (ta_modify)(void *ta_state, struct table_info *ti, 220301290bcSAlexander V. Chernikov * void *ta_buf, uint64_t pflags); 221fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), locked (UH+WLOCK). (M_NOWAIT). 222301290bcSAlexander V. Chernikov * 223301290bcSAlexander V. Chernikov * Performs all changes necessary to switch to new structures. 224301290bcSAlexander V. Chernikov * * Caller should save old pointers to @ta_buf storage. 225301290bcSAlexander V. Chernikov * 226301290bcSAlexander V. Chernikov * 227301290bcSAlexander V. Chernikov * 228301290bcSAlexander V. Chernikov * -flush_mod: flush table modification state. 229301290bcSAlexander V. Chernikov * typedef void (ta_flush_mod)(void *ta_buf); 230fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), unlocked. (M_WAITOK). 231301290bcSAlexander V. Chernikov * 232301290bcSAlexander V. Chernikov * Performs flush for the following: 233301290bcSAlexander V. Chernikov * - prepare_mod (modification was not necessary) 234301290bcSAlexander V. Chernikov * - modify (for the old state) 235301290bcSAlexander V. Chernikov * 236301290bcSAlexander V. Chernikov * 237301290bcSAlexander V. Chernikov * 238301290bcSAlexander V. Chernikov * -change_gi: monitor table info pointer changes 239301290bcSAlexander V. Chernikov * typedef void (ta_change_ti)(void *ta_state, struct table_info *ti); 240301290bcSAlexander V. Chernikov * OPTIONAL, locked (UH). (M_NOWAIT). 241301290bcSAlexander V. Chernikov * 242301290bcSAlexander V. Chernikov * Called on @ti pointer changed. Called immediately after -init 243301290bcSAlexander V. Chernikov * to set initial state. 244301290bcSAlexander V. Chernikov * 245301290bcSAlexander V. Chernikov * 246301290bcSAlexander V. Chernikov * 247301290bcSAlexander V. Chernikov * -foreach: calls @f for each table entry 248301290bcSAlexander V. Chernikov * typedef void ta_foreach(void *ta_state, struct table_info *ti, 249301290bcSAlexander V. Chernikov * ta_foreach_f *f, void *arg); 250301290bcSAlexander V. Chernikov * MANDATORY, locked(UH). (M_NOWAIT). 251301290bcSAlexander V. Chernikov * 252301290bcSAlexander V. Chernikov * Runs callback with specified argument for each table entry, 253301290bcSAlexander V. Chernikov * Typically used for dumping table entries. 254301290bcSAlexander V. Chernikov * 255301290bcSAlexander V. Chernikov * 256301290bcSAlexander V. Chernikov * 257301290bcSAlexander V. Chernikov * -dump_tentry: dump table entry in current @tentry format. 258301290bcSAlexander V. Chernikov * typedef int ta_dump_tentry(void *ta_state, struct table_info *ti, void *e, 259301290bcSAlexander V. Chernikov * ipfw_obj_tentry *tent); 260301290bcSAlexander V. Chernikov * MANDATORY, locked(UH). (M_NOWAIT). Returns 0 on success. 261301290bcSAlexander V. Chernikov * 262301290bcSAlexander V. Chernikov * Dumps entry @e to @tent. 263301290bcSAlexander V. Chernikov * 264301290bcSAlexander V. Chernikov * 265a4641f4eSPedro F. Giffuni * -print_config: prints custom algorithm options into buffer. 266301290bcSAlexander V. Chernikov * typedef void (ta_print_config)(void *ta_state, struct table_info *ti, 267301290bcSAlexander V. Chernikov * char *buf, size_t bufsize); 268301290bcSAlexander V. Chernikov * OPTIONAL. locked(UH). (M_NOWAIT). 269301290bcSAlexander V. Chernikov * 270301290bcSAlexander V. Chernikov * Prints custom algorithm options in the format suitable to pass 271301290bcSAlexander V. Chernikov * back to -init callback. 272301290bcSAlexander V. Chernikov * 273301290bcSAlexander V. Chernikov * 274301290bcSAlexander V. Chernikov * 275301290bcSAlexander V. Chernikov * -dump_tinfo: dumps algo-specific info. 276301290bcSAlexander V. Chernikov * typedef void ta_dump_tinfo(void *ta_state, struct table_info *ti, 277301290bcSAlexander V. Chernikov * ipfw_ta_tinfo *tinfo); 278301290bcSAlexander V. Chernikov * OPTIONAL. locked(UH). (M_NOWAIT). 279301290bcSAlexander V. Chernikov * 280301290bcSAlexander V. Chernikov * Dumps options like items size/hash size, etc. 281301290bcSAlexander V. Chernikov */ 282301290bcSAlexander V. Chernikov 283b1d105bcSAlexander V. Chernikov MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables"); 2849f7d47b0SAlexander V. Chernikov 2850bce0c23SAlexander V. Chernikov /* 2860bce0c23SAlexander V. Chernikov * Utility structures/functions common to more than one algo 2870bce0c23SAlexander V. Chernikov */ 2880bce0c23SAlexander V. Chernikov 2890bce0c23SAlexander V. Chernikov struct mod_item { 2900bce0c23SAlexander V. Chernikov void *main_ptr; 2910bce0c23SAlexander V. Chernikov size_t size; 2920bce0c23SAlexander V. Chernikov void *main_ptr6; 2930bce0c23SAlexander V. Chernikov size_t size6; 2940bce0c23SAlexander V. Chernikov }; 2950bce0c23SAlexander V. Chernikov 29668394ec8SAlexander V. Chernikov static int badd(const void *key, void *item, void *base, size_t nmemb, 29768394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *)); 29868394ec8SAlexander V. Chernikov static int bdel(const void *key, void *base, size_t nmemb, size_t size, 29968394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *)); 30068394ec8SAlexander V. Chernikov 30168394ec8SAlexander V. Chernikov /* 302c21034b7SAlexander V. Chernikov * ADDR implementation using radix 30368394ec8SAlexander V. Chernikov * 30468394ec8SAlexander V. Chernikov */ 30568394ec8SAlexander V. Chernikov 3069f7d47b0SAlexander V. Chernikov /* 3079f7d47b0SAlexander V. Chernikov * The radix code expects addr and mask to be array of bytes, 3089f7d47b0SAlexander V. Chernikov * with the first byte being the length of the array. rn_inithead 3099f7d47b0SAlexander V. Chernikov * is called with the offset in bits of the lookup key within the 3109f7d47b0SAlexander V. Chernikov * array. If we use a sockaddr_in as the underlying type, 3119f7d47b0SAlexander V. Chernikov * sin_len is conveniently located at offset 0, sin_addr is at 3129f7d47b0SAlexander V. Chernikov * offset 4 and normally aligned. 3139f7d47b0SAlexander V. Chernikov * But for portability, let's avoid assumption and make the code explicit 3149f7d47b0SAlexander V. Chernikov */ 3159f7d47b0SAlexander V. Chernikov #define KEY_LEN(v) *((uint8_t *)&(v)) 3169f7d47b0SAlexander V. Chernikov /* 31781cac390SArseny Smalyuk * Do not require radix to compare more than actual IPv4/IPv6/MAC address 3189f7d47b0SAlexander V. Chernikov */ 3199f7d47b0SAlexander V. Chernikov #define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t)) 320e0a8b9eeSAlexander V. Chernikov #define KEY_LEN_INET6 (offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr)) 32181cac390SArseny Smalyuk #define KEY_LEN_MAC (offsetof(struct sa_mac, mac_addr) + ETHER_ADDR_LEN) 3229f7d47b0SAlexander V. Chernikov 3239f7d47b0SAlexander V. Chernikov #define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr)) 324e0a8b9eeSAlexander V. Chernikov #define OFF_LEN_INET6 (8 * offsetof(struct sa_in6, sin6_addr)) 32581cac390SArseny Smalyuk #define OFF_LEN_MAC (8 * offsetof(struct sa_mac, mac_addr)) 3269f7d47b0SAlexander V. Chernikov 32781cac390SArseny Smalyuk struct addr_radix_entry { 3289f7d47b0SAlexander V. Chernikov struct radix_node rn[2]; 329e0a8b9eeSAlexander V. Chernikov struct sockaddr_in addr; 330e0a8b9eeSAlexander V. Chernikov uint32_t value; 331e0a8b9eeSAlexander V. Chernikov uint8_t masklen; 332e0a8b9eeSAlexander V. Chernikov }; 333e0a8b9eeSAlexander V. Chernikov 334e0a8b9eeSAlexander V. Chernikov struct sa_in6 { 335e0a8b9eeSAlexander V. Chernikov uint8_t sin6_len; 336e0a8b9eeSAlexander V. Chernikov uint8_t sin6_family; 337e0a8b9eeSAlexander V. Chernikov uint8_t pad[2]; 338e0a8b9eeSAlexander V. Chernikov struct in6_addr sin6_addr; 339e0a8b9eeSAlexander V. Chernikov }; 340e0a8b9eeSAlexander V. Chernikov 34181cac390SArseny Smalyuk struct addr_radix_xentry { 342e0a8b9eeSAlexander V. Chernikov struct radix_node rn[2]; 343e0a8b9eeSAlexander V. Chernikov struct sa_in6 addr6; 344e0a8b9eeSAlexander V. Chernikov uint32_t value; 345e0a8b9eeSAlexander V. Chernikov uint8_t masklen; 3469f7d47b0SAlexander V. Chernikov }; 3479f7d47b0SAlexander V. Chernikov 34881cac390SArseny Smalyuk struct addr_radix_cfg { 3495f379342SAlexander V. Chernikov struct radix_node_head *head4; 3505f379342SAlexander V. Chernikov struct radix_node_head *head6; 3515f379342SAlexander V. Chernikov size_t count4; 3525f379342SAlexander V. Chernikov size_t count6; 3535f379342SAlexander V. Chernikov }; 3545f379342SAlexander V. Chernikov 35581cac390SArseny Smalyuk struct sa_mac { 35681cac390SArseny Smalyuk uint8_t mac_len; 35781cac390SArseny Smalyuk struct ether_addr mac_addr; 35881cac390SArseny Smalyuk }; 35981cac390SArseny Smalyuk 360c21034b7SAlexander V. Chernikov struct ta_buf_radix 3610bce0c23SAlexander V. Chernikov { 3620bce0c23SAlexander V. Chernikov void *ent_ptr; 3630bce0c23SAlexander V. Chernikov struct sockaddr *addr_ptr; 3640bce0c23SAlexander V. Chernikov struct sockaddr *mask_ptr; 3650bce0c23SAlexander V. Chernikov union { 3660bce0c23SAlexander V. Chernikov struct { 3670bce0c23SAlexander V. Chernikov struct sockaddr_in sa; 3680bce0c23SAlexander V. Chernikov struct sockaddr_in ma; 3690bce0c23SAlexander V. Chernikov } a4; 3700bce0c23SAlexander V. Chernikov struct { 3710bce0c23SAlexander V. Chernikov struct sa_in6 sa; 3720bce0c23SAlexander V. Chernikov struct sa_in6 ma; 3730bce0c23SAlexander V. Chernikov } a6; 37481cac390SArseny Smalyuk struct { 37581cac390SArseny Smalyuk struct sa_mac sa; 37681cac390SArseny Smalyuk struct sa_mac ma; 37781cac390SArseny Smalyuk } mac; 3780bce0c23SAlexander V. Chernikov } addr; 3790bce0c23SAlexander V. Chernikov }; 3800bce0c23SAlexander V. Chernikov 38181cac390SArseny Smalyuk static int ta_lookup_addr_radix(struct table_info *ti, void *key, uint32_t keylen, 3829fe15d06SAlexander V. Chernikov uint32_t *val); 38381cac390SArseny Smalyuk static int ta_init_addr_radix(struct ip_fw_chain *ch, void **ta_state, 3849fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 3859fe15d06SAlexander V. Chernikov static int flush_radix_entry(struct radix_node *rn, void *arg); 38681cac390SArseny Smalyuk static void ta_destroy_addr_radix(void *ta_state, struct table_info *ti); 38781cac390SArseny Smalyuk static void ta_dump_addr_radix_tinfo(void *ta_state, struct table_info *ti, 3889fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 38981cac390SArseny Smalyuk static int ta_dump_addr_radix_tentry(void *ta_state, struct table_info *ti, 3909fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent); 39181cac390SArseny Smalyuk static int ta_find_addr_radix_tentry(void *ta_state, struct table_info *ti, 3929fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 39381cac390SArseny Smalyuk static void ta_foreach_addr_radix(void *ta_state, struct table_info *ti, 3949fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 39581cac390SArseny Smalyuk static void tei_to_sockaddr_ent_addr(struct tentry_info *tei, struct sockaddr *sa, 3969fe15d06SAlexander V. Chernikov struct sockaddr *ma, int *set_mask); 39781cac390SArseny Smalyuk static int ta_prepare_add_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 3989fe15d06SAlexander V. Chernikov void *ta_buf); 39981cac390SArseny Smalyuk static int ta_add_addr_radix(void *ta_state, struct table_info *ti, 4009fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 40181cac390SArseny Smalyuk static int ta_prepare_del_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 4029fe15d06SAlexander V. Chernikov void *ta_buf); 40381cac390SArseny Smalyuk static int ta_del_addr_radix(void *ta_state, struct table_info *ti, 4049fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 4059fe15d06SAlexander V. Chernikov static void ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 4069fe15d06SAlexander V. Chernikov void *ta_buf); 4079fe15d06SAlexander V. Chernikov static int ta_need_modify_radix(void *ta_state, struct table_info *ti, 4089fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 4099fe15d06SAlexander V. Chernikov 4109f7d47b0SAlexander V. Chernikov static int 41181cac390SArseny Smalyuk ta_lookup_addr_radix(struct table_info *ti, void *key, uint32_t keylen, 4129f7d47b0SAlexander V. Chernikov uint32_t *val) 4139f7d47b0SAlexander V. Chernikov { 4149f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 4159f7d47b0SAlexander V. Chernikov 4169f7d47b0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 41781cac390SArseny Smalyuk struct addr_radix_entry *ent; 4189f7d47b0SAlexander V. Chernikov struct sockaddr_in sa; 4199f7d47b0SAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 4209f7d47b0SAlexander V. Chernikov sa.sin_addr.s_addr = *((in_addr_t *)key); 4219f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 42281cac390SArseny Smalyuk ent = (struct addr_radix_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh)); 4239f7d47b0SAlexander V. Chernikov if (ent != NULL) { 4249f7d47b0SAlexander V. Chernikov *val = ent->value; 4259f7d47b0SAlexander V. Chernikov return (1); 4269f7d47b0SAlexander V. Chernikov } 42781cac390SArseny Smalyuk } else if (keylen == sizeof(struct in6_addr)) { 42881cac390SArseny Smalyuk struct addr_radix_xentry *xent; 429e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 4309f7d47b0SAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 4319f7d47b0SAlexander V. Chernikov memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr)); 4329f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 43381cac390SArseny Smalyuk xent = (struct addr_radix_xentry *)(rnh->rnh_matchaddr(&sa6, &rnh->rh)); 4349f7d47b0SAlexander V. Chernikov if (xent != NULL) { 4359f7d47b0SAlexander V. Chernikov *val = xent->value; 4369f7d47b0SAlexander V. Chernikov return (1); 4379f7d47b0SAlexander V. Chernikov } 4389f7d47b0SAlexander V. Chernikov } 4399f7d47b0SAlexander V. Chernikov 4409f7d47b0SAlexander V. Chernikov return (0); 4419f7d47b0SAlexander V. Chernikov } 4429f7d47b0SAlexander V. Chernikov 4439f7d47b0SAlexander V. Chernikov /* 4449f7d47b0SAlexander V. Chernikov * New table 4459f7d47b0SAlexander V. Chernikov */ 4469f7d47b0SAlexander V. Chernikov static int 44781cac390SArseny Smalyuk ta_init_addr_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 448914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 4499f7d47b0SAlexander V. Chernikov { 45081cac390SArseny Smalyuk struct addr_radix_cfg *cfg; 4519f7d47b0SAlexander V. Chernikov 4529f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->state, OFF_LEN_INET)) 4539f7d47b0SAlexander V. Chernikov return (ENOMEM); 4549f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) { 4559f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 4569f7d47b0SAlexander V. Chernikov return (ENOMEM); 4579f7d47b0SAlexander V. Chernikov } 4589f7d47b0SAlexander V. Chernikov 45981cac390SArseny Smalyuk cfg = malloc(sizeof(struct addr_radix_cfg), M_IPFW, M_WAITOK | M_ZERO); 4605f379342SAlexander V. Chernikov 4615f379342SAlexander V. Chernikov *ta_state = cfg; 46281cac390SArseny Smalyuk ti->lookup = ta_lookup_addr_radix; 4639f7d47b0SAlexander V. Chernikov 4649f7d47b0SAlexander V. Chernikov return (0); 4659f7d47b0SAlexander V. Chernikov } 4669f7d47b0SAlexander V. Chernikov 4679f7d47b0SAlexander V. Chernikov static int 468a399f8beSAlexander V. Chernikov flush_radix_entry(struct radix_node *rn, void *arg) 4699f7d47b0SAlexander V. Chernikov { 4709f7d47b0SAlexander V. Chernikov struct radix_node_head * const rnh = arg; 47181cac390SArseny Smalyuk struct addr_radix_entry *ent; 4729f7d47b0SAlexander V. Chernikov 47381cac390SArseny Smalyuk ent = (struct addr_radix_entry *) 47461eee0e2SAlexander V. Chernikov rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, &rnh->rh); 4759f7d47b0SAlexander V. Chernikov if (ent != NULL) 4769f7d47b0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 4779f7d47b0SAlexander V. Chernikov return (0); 4789f7d47b0SAlexander V. Chernikov } 4799f7d47b0SAlexander V. Chernikov 4809f7d47b0SAlexander V. Chernikov static void 48181cac390SArseny Smalyuk ta_destroy_addr_radix(void *ta_state, struct table_info *ti) 4829f7d47b0SAlexander V. Chernikov { 48381cac390SArseny Smalyuk struct addr_radix_cfg *cfg; 4849f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 4859f7d47b0SAlexander V. Chernikov 48681cac390SArseny Smalyuk cfg = (struct addr_radix_cfg *)ta_state; 4875f379342SAlexander V. Chernikov 4889f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 48961eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh); 4909f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 4919f7d47b0SAlexander V. Chernikov 4929f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 49361eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh); 4949f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->xstate); 4955f379342SAlexander V. Chernikov 4965f379342SAlexander V. Chernikov free(cfg, M_IPFW); 4975f379342SAlexander V. Chernikov } 4985f379342SAlexander V. Chernikov 4995f379342SAlexander V. Chernikov /* 5005f379342SAlexander V. Chernikov * Provide algo-specific table info 5015f379342SAlexander V. Chernikov */ 5025f379342SAlexander V. Chernikov static void 50381cac390SArseny Smalyuk ta_dump_addr_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 5045f379342SAlexander V. Chernikov { 50581cac390SArseny Smalyuk struct addr_radix_cfg *cfg; 5065f379342SAlexander V. Chernikov 50781cac390SArseny Smalyuk cfg = (struct addr_radix_cfg *)ta_state; 5085f379342SAlexander V. Chernikov 5095f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM; 5105f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_RADIX; 5115f379342SAlexander V. Chernikov tinfo->count4 = cfg->count4; 51281cac390SArseny Smalyuk tinfo->itemsize4 = sizeof(struct addr_radix_entry); 5135f379342SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_RADIX; 5145f379342SAlexander V. Chernikov tinfo->count6 = cfg->count6; 51581cac390SArseny Smalyuk tinfo->itemsize6 = sizeof(struct addr_radix_xentry); 5169f7d47b0SAlexander V. Chernikov } 5179f7d47b0SAlexander V. Chernikov 5189f7d47b0SAlexander V. Chernikov static int 51981cac390SArseny Smalyuk ta_dump_addr_radix_tentry(void *ta_state, struct table_info *ti, void *e, 52081d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 5219f7d47b0SAlexander V. Chernikov { 52281cac390SArseny Smalyuk struct addr_radix_entry *n; 5239fe15d06SAlexander V. Chernikov #ifdef INET6 52481cac390SArseny Smalyuk struct addr_radix_xentry *xn; 5259fe15d06SAlexander V. Chernikov #endif 5269f7d47b0SAlexander V. Chernikov 52781cac390SArseny Smalyuk n = (struct addr_radix_entry *)e; 5289f7d47b0SAlexander V. Chernikov 5299f7d47b0SAlexander V. Chernikov /* Guess IPv4/IPv6 radix by sockaddr family */ 5309f7d47b0SAlexander V. Chernikov if (n->addr.sin_family == AF_INET) { 53181d3153dSAlexander V. Chernikov tent->k.addr.s_addr = n->addr.sin_addr.s_addr; 532e0a8b9eeSAlexander V. Chernikov tent->masklen = n->masklen; 53381d3153dSAlexander V. Chernikov tent->subtype = AF_INET; 5340cba2b28SAlexander V. Chernikov tent->v.kidx = n->value; 5359f7d47b0SAlexander V. Chernikov #ifdef INET6 5369f7d47b0SAlexander V. Chernikov } else { 53781cac390SArseny Smalyuk xn = (struct addr_radix_xentry *)e; 538ba3e1361SAndrey V. Elsukov memcpy(&tent->k.addr6, &xn->addr6.sin6_addr, 539ba3e1361SAndrey V. Elsukov sizeof(struct in6_addr)); 540e0a8b9eeSAlexander V. Chernikov tent->masklen = xn->masklen; 54181d3153dSAlexander V. Chernikov tent->subtype = AF_INET6; 5420cba2b28SAlexander V. Chernikov tent->v.kidx = xn->value; 5439f7d47b0SAlexander V. Chernikov #endif 5449f7d47b0SAlexander V. Chernikov } 5459f7d47b0SAlexander V. Chernikov 5469f7d47b0SAlexander V. Chernikov return (0); 5479f7d47b0SAlexander V. Chernikov } 5489f7d47b0SAlexander V. Chernikov 54981d3153dSAlexander V. Chernikov static int 55081cac390SArseny Smalyuk ta_find_addr_radix_tentry(void *ta_state, struct table_info *ti, 551914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 55281d3153dSAlexander V. Chernikov { 55381d3153dSAlexander V. Chernikov struct radix_node_head *rnh; 55481d3153dSAlexander V. Chernikov void *e; 55581d3153dSAlexander V. Chernikov 55681d3153dSAlexander V. Chernikov e = NULL; 557914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) { 55881d3153dSAlexander V. Chernikov struct sockaddr_in sa; 55981d3153dSAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 560914bffb6SAlexander V. Chernikov sa.sin_addr.s_addr = tent->k.addr.s_addr; 56181d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 56261eee0e2SAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa, &rnh->rh); 56381cac390SArseny Smalyuk } else if (tent->subtype == AF_INET6) { 564e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 56581d3153dSAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 566914bffb6SAlexander V. Chernikov memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr)); 56781d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 56861eee0e2SAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa6, &rnh->rh); 56981d3153dSAlexander V. Chernikov } 57081d3153dSAlexander V. Chernikov 57181d3153dSAlexander V. Chernikov if (e != NULL) { 57281cac390SArseny Smalyuk ta_dump_addr_radix_tentry(ta_state, ti, e, tent); 57381d3153dSAlexander V. Chernikov return (0); 57481d3153dSAlexander V. Chernikov } 57581d3153dSAlexander V. Chernikov 57681d3153dSAlexander V. Chernikov return (ENOENT); 57781d3153dSAlexander V. Chernikov } 57881d3153dSAlexander V. Chernikov 5799f7d47b0SAlexander V. Chernikov static void 58081cac390SArseny Smalyuk ta_foreach_addr_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f, 5819f7d47b0SAlexander V. Chernikov void *arg) 5829f7d47b0SAlexander V. Chernikov { 5839f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 5849f7d47b0SAlexander V. Chernikov 5859f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 58661eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg); 5879f7d47b0SAlexander V. Chernikov 5889f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 58961eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg); 5909f7d47b0SAlexander V. Chernikov } 5919f7d47b0SAlexander V. Chernikov 5929f7d47b0SAlexander V. Chernikov #ifdef INET6 593d699ee2dSAlexander V. Chernikov static inline void ipv6_writemask(struct in6_addr *addr6, uint8_t mask); 594d699ee2dSAlexander V. Chernikov 5959f7d47b0SAlexander V. Chernikov static inline void 5969f7d47b0SAlexander V. Chernikov ipv6_writemask(struct in6_addr *addr6, uint8_t mask) 5979f7d47b0SAlexander V. Chernikov { 5989f7d47b0SAlexander V. Chernikov uint32_t *cp; 5999f7d47b0SAlexander V. Chernikov 6009f7d47b0SAlexander V. Chernikov for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32) 6019f7d47b0SAlexander V. Chernikov *cp++ = 0xFFFFFFFF; 60237aefa2aSAlexander V. Chernikov if (mask > 0) 6039f7d47b0SAlexander V. Chernikov *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0); 6049f7d47b0SAlexander V. Chernikov } 6059f7d47b0SAlexander V. Chernikov #endif 6069f7d47b0SAlexander V. Chernikov 6072e324d29SAlexander V. Chernikov static void 60881cac390SArseny Smalyuk tei_to_sockaddr_ent_addr(struct tentry_info *tei, struct sockaddr *sa, 6092e324d29SAlexander V. Chernikov struct sockaddr *ma, int *set_mask) 6102e324d29SAlexander V. Chernikov { 6112e324d29SAlexander V. Chernikov int mlen; 6129fe15d06SAlexander V. Chernikov #ifdef INET 6132e324d29SAlexander V. Chernikov struct sockaddr_in *addr, *mask; 6149fe15d06SAlexander V. Chernikov #endif 6159fe15d06SAlexander V. Chernikov #ifdef INET6 616720ee730SAlexander V. Chernikov struct sa_in6 *addr6, *mask6; 6179fe15d06SAlexander V. Chernikov #endif 6182e324d29SAlexander V. Chernikov in_addr_t a4; 6192e324d29SAlexander V. Chernikov 6202e324d29SAlexander V. Chernikov mlen = tei->masklen; 6212e324d29SAlexander V. Chernikov 6222e324d29SAlexander V. Chernikov if (tei->subtype == AF_INET) { 6232e324d29SAlexander V. Chernikov #ifdef INET 6242e324d29SAlexander V. Chernikov addr = (struct sockaddr_in *)sa; 6252e324d29SAlexander V. Chernikov mask = (struct sockaddr_in *)ma; 6262e324d29SAlexander V. Chernikov /* Set 'total' structure length */ 6272e324d29SAlexander V. Chernikov KEY_LEN(*addr) = KEY_LEN_INET; 6282e324d29SAlexander V. Chernikov KEY_LEN(*mask) = KEY_LEN_INET; 6292e324d29SAlexander V. Chernikov addr->sin_family = AF_INET; 6302e324d29SAlexander V. Chernikov mask->sin_addr.s_addr = 6312e324d29SAlexander V. Chernikov htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 6322e324d29SAlexander V. Chernikov a4 = *((in_addr_t *)tei->paddr); 6332e324d29SAlexander V. Chernikov addr->sin_addr.s_addr = a4 & mask->sin_addr.s_addr; 6342e324d29SAlexander V. Chernikov if (mlen != 32) 6352e324d29SAlexander V. Chernikov *set_mask = 1; 6362e324d29SAlexander V. Chernikov else 6372e324d29SAlexander V. Chernikov *set_mask = 0; 6382e324d29SAlexander V. Chernikov #endif 6392e324d29SAlexander V. Chernikov #ifdef INET6 6402e324d29SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 6412e324d29SAlexander V. Chernikov /* IPv6 case */ 642720ee730SAlexander V. Chernikov addr6 = (struct sa_in6 *)sa; 643720ee730SAlexander V. Chernikov mask6 = (struct sa_in6 *)ma; 6442e324d29SAlexander V. Chernikov /* Set 'total' structure length */ 6452e324d29SAlexander V. Chernikov KEY_LEN(*addr6) = KEY_LEN_INET6; 6462e324d29SAlexander V. Chernikov KEY_LEN(*mask6) = KEY_LEN_INET6; 6472e324d29SAlexander V. Chernikov addr6->sin6_family = AF_INET6; 6482e324d29SAlexander V. Chernikov ipv6_writemask(&mask6->sin6_addr, mlen); 6492e324d29SAlexander V. Chernikov memcpy(&addr6->sin6_addr, tei->paddr, sizeof(struct in6_addr)); 6502e324d29SAlexander V. Chernikov APPLY_MASK(&addr6->sin6_addr, &mask6->sin6_addr); 6512e324d29SAlexander V. Chernikov if (mlen != 128) 6522e324d29SAlexander V. Chernikov *set_mask = 1; 6532e324d29SAlexander V. Chernikov else 6542e324d29SAlexander V. Chernikov *set_mask = 0; 6552e324d29SAlexander V. Chernikov #endif 6562e324d29SAlexander V. Chernikov } 657d699ee2dSAlexander V. Chernikov } 6589f7d47b0SAlexander V. Chernikov 6599f7d47b0SAlexander V. Chernikov static int 66081cac390SArseny Smalyuk ta_prepare_add_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 66168394ec8SAlexander V. Chernikov void *ta_buf) 6629f7d47b0SAlexander V. Chernikov { 663c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 66481cac390SArseny Smalyuk struct addr_radix_entry *ent; 665d699ee2dSAlexander V. Chernikov #ifdef INET6 66681cac390SArseny Smalyuk struct addr_radix_xentry *xent; 667d699ee2dSAlexander V. Chernikov #endif 6682e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask; 6692e324d29SAlexander V. Chernikov int mlen, set_mask; 6709f7d47b0SAlexander V. Chernikov 671c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 6729f7d47b0SAlexander V. Chernikov 6739f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 6742e324d29SAlexander V. Chernikov set_mask = 0; 6759f7d47b0SAlexander V. Chernikov 676ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 6779f7d47b0SAlexander V. Chernikov #ifdef INET 6789f7d47b0SAlexander V. Chernikov if (mlen > 32) 6799f7d47b0SAlexander V. Chernikov return (EINVAL); 6809f7d47b0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 681e0a8b9eeSAlexander V. Chernikov ent->masklen = mlen; 6822e324d29SAlexander V. Chernikov 6832e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&ent->addr; 6842e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma; 6859f7d47b0SAlexander V. Chernikov tb->ent_ptr = ent; 6869f7d47b0SAlexander V. Chernikov #endif 6879f7d47b0SAlexander V. Chernikov #ifdef INET6 688ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 6899f7d47b0SAlexander V. Chernikov /* IPv6 case */ 6909f7d47b0SAlexander V. Chernikov if (mlen > 128) 6919f7d47b0SAlexander V. Chernikov return (EINVAL); 6929f7d47b0SAlexander V. Chernikov xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO); 693e0a8b9eeSAlexander V. Chernikov xent->masklen = mlen; 6942e324d29SAlexander V. Chernikov 6952e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&xent->addr6; 6962e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma; 6979f7d47b0SAlexander V. Chernikov tb->ent_ptr = xent; 6989f7d47b0SAlexander V. Chernikov #endif 6999f7d47b0SAlexander V. Chernikov } else { 7009f7d47b0SAlexander V. Chernikov /* Unknown CIDR type */ 7019f7d47b0SAlexander V. Chernikov return (EINVAL); 7029f7d47b0SAlexander V. Chernikov } 7039f7d47b0SAlexander V. Chernikov 70481cac390SArseny Smalyuk tei_to_sockaddr_ent_addr(tei, addr, mask, &set_mask); 7052e324d29SAlexander V. Chernikov /* Set pointers */ 7062e324d29SAlexander V. Chernikov tb->addr_ptr = addr; 7072e324d29SAlexander V. Chernikov if (set_mask != 0) 7082e324d29SAlexander V. Chernikov tb->mask_ptr = mask; 7092e324d29SAlexander V. Chernikov 7109f7d47b0SAlexander V. Chernikov return (0); 7119f7d47b0SAlexander V. Chernikov } 7129f7d47b0SAlexander V. Chernikov 7139f7d47b0SAlexander V. Chernikov static int 71481cac390SArseny Smalyuk ta_add_addr_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, 715b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 7169f7d47b0SAlexander V. Chernikov { 71781cac390SArseny Smalyuk struct addr_radix_cfg *cfg; 7189f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 7199f7d47b0SAlexander V. Chernikov struct radix_node *rn; 720c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 721648e8380SAlexander V. Chernikov uint32_t *old_value, value; 7229f7d47b0SAlexander V. Chernikov 72381cac390SArseny Smalyuk cfg = (struct addr_radix_cfg *)ta_state; 724c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 7259f7d47b0SAlexander V. Chernikov 72613263632SAlexander V. Chernikov /* Save current entry value from @tei */ 72713263632SAlexander V. Chernikov if (tei->subtype == AF_INET) { 7289f7d47b0SAlexander V. Chernikov rnh = ti->state; 72981cac390SArseny Smalyuk ((struct addr_radix_entry *)tb->ent_ptr)->value = tei->value; 73013263632SAlexander V. Chernikov } else { 7319f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 73281cac390SArseny Smalyuk ((struct addr_radix_xentry *)tb->ent_ptr)->value = tei->value; 73313263632SAlexander V. Chernikov } 7349f7d47b0SAlexander V. Chernikov 7354c0c07a5SAlexander V. Chernikov /* Search for an entry first */ 73661eee0e2SAlexander V. Chernikov rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, &rnh->rh); 7374c0c07a5SAlexander V. Chernikov if (rn != NULL) { 738ac35ff17SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 7399f7d47b0SAlexander V. Chernikov return (EEXIST); 740ac35ff17SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 741648e8380SAlexander V. Chernikov if (tei->subtype == AF_INET) 74281cac390SArseny Smalyuk old_value = &((struct addr_radix_entry *)rn)->value; 743648e8380SAlexander V. Chernikov else 74481cac390SArseny Smalyuk old_value = &((struct addr_radix_xentry *)rn)->value; 745648e8380SAlexander V. Chernikov 746648e8380SAlexander V. Chernikov value = *old_value; 747648e8380SAlexander V. Chernikov *old_value = tei->value; 748648e8380SAlexander V. Chernikov tei->value = value; 749ac35ff17SAlexander V. Chernikov 750ac35ff17SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 751ac35ff17SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 752adea6201SAlexander V. Chernikov *pnum = 0; 753e0a8b9eeSAlexander V. Chernikov 754e0a8b9eeSAlexander V. Chernikov return (0); 755ac35ff17SAlexander V. Chernikov } 756ac35ff17SAlexander V. Chernikov 7574c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 7584c0c07a5SAlexander V. Chernikov return (EFBIG); 7594c0c07a5SAlexander V. Chernikov 76061eee0e2SAlexander V. Chernikov rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, &rnh->rh,tb->ent_ptr); 7614c0c07a5SAlexander V. Chernikov if (rn == NULL) { 7624c0c07a5SAlexander V. Chernikov /* Unknown error */ 7634c0c07a5SAlexander V. Chernikov return (EINVAL); 7644c0c07a5SAlexander V. Chernikov } 7654c0c07a5SAlexander V. Chernikov 7665f379342SAlexander V. Chernikov if (tei->subtype == AF_INET) 7675f379342SAlexander V. Chernikov cfg->count4++; 7685f379342SAlexander V. Chernikov else 7695f379342SAlexander V. Chernikov cfg->count6++; 770ac35ff17SAlexander V. Chernikov tb->ent_ptr = NULL; 771adea6201SAlexander V. Chernikov *pnum = 1; 7729f7d47b0SAlexander V. Chernikov 7739f7d47b0SAlexander V. Chernikov return (0); 7749f7d47b0SAlexander V. Chernikov } 7759f7d47b0SAlexander V. Chernikov 7769f7d47b0SAlexander V. Chernikov static int 77781cac390SArseny Smalyuk ta_prepare_del_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 77868394ec8SAlexander V. Chernikov void *ta_buf) 7799f7d47b0SAlexander V. Chernikov { 780c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 7812e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask; 7822e324d29SAlexander V. Chernikov int mlen, set_mask; 7839f7d47b0SAlexander V. Chernikov 784c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 7859f7d47b0SAlexander V. Chernikov 7869f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 7872e324d29SAlexander V. Chernikov set_mask = 0; 7889f7d47b0SAlexander V. Chernikov 789ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 790e0a8b9eeSAlexander V. Chernikov if (mlen > 32) 791e0a8b9eeSAlexander V. Chernikov return (EINVAL); 7922e324d29SAlexander V. Chernikov 7932e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a4.sa; 7942e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma; 7959f7d47b0SAlexander V. Chernikov #ifdef INET6 796ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 7979f7d47b0SAlexander V. Chernikov if (mlen > 128) 7989f7d47b0SAlexander V. Chernikov return (EINVAL); 7992e324d29SAlexander V. Chernikov 8002e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a6.sa; 8012e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma; 8029f7d47b0SAlexander V. Chernikov #endif 8039f7d47b0SAlexander V. Chernikov } else 8049f7d47b0SAlexander V. Chernikov return (EINVAL); 8059f7d47b0SAlexander V. Chernikov 80681cac390SArseny Smalyuk tei_to_sockaddr_ent_addr(tei, addr, mask, &set_mask); 8072e324d29SAlexander V. Chernikov tb->addr_ptr = addr; 8082e324d29SAlexander V. Chernikov if (set_mask != 0) 8092e324d29SAlexander V. Chernikov tb->mask_ptr = mask; 8102e324d29SAlexander V. Chernikov 8119f7d47b0SAlexander V. Chernikov return (0); 8129f7d47b0SAlexander V. Chernikov } 8139f7d47b0SAlexander V. Chernikov 8149f7d47b0SAlexander V. Chernikov static int 81581cac390SArseny Smalyuk ta_del_addr_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, 816b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 8179f7d47b0SAlexander V. Chernikov { 81881cac390SArseny Smalyuk struct addr_radix_cfg *cfg; 8199f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 8209f7d47b0SAlexander V. Chernikov struct radix_node *rn; 821c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 8229f7d47b0SAlexander V. Chernikov 82381cac390SArseny Smalyuk cfg = (struct addr_radix_cfg *)ta_state; 824c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 8259f7d47b0SAlexander V. Chernikov 826ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) 8279f7d47b0SAlexander V. Chernikov rnh = ti->state; 8289f7d47b0SAlexander V. Chernikov else 8299f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 8309f7d47b0SAlexander V. Chernikov 83161eee0e2SAlexander V. Chernikov rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, &rnh->rh); 8329f7d47b0SAlexander V. Chernikov 8333a845e10SAlexander V. Chernikov if (rn == NULL) 8343a845e10SAlexander V. Chernikov return (ENOENT); 8353a845e10SAlexander V. Chernikov 836648e8380SAlexander V. Chernikov /* Save entry value to @tei */ 837648e8380SAlexander V. Chernikov if (tei->subtype == AF_INET) 83881cac390SArseny Smalyuk tei->value = ((struct addr_radix_entry *)rn)->value; 839648e8380SAlexander V. Chernikov else 84081cac390SArseny Smalyuk tei->value = ((struct addr_radix_xentry *)rn)->value; 841648e8380SAlexander V. Chernikov 8429f7d47b0SAlexander V. Chernikov tb->ent_ptr = rn; 8439f7d47b0SAlexander V. Chernikov 8445f379342SAlexander V. Chernikov if (tei->subtype == AF_INET) 8455f379342SAlexander V. Chernikov cfg->count4--; 8465f379342SAlexander V. Chernikov else 8475f379342SAlexander V. Chernikov cfg->count6--; 848adea6201SAlexander V. Chernikov *pnum = 1; 849adea6201SAlexander V. Chernikov 8509f7d47b0SAlexander V. Chernikov return (0); 8519f7d47b0SAlexander V. Chernikov } 8529f7d47b0SAlexander V. Chernikov 8539f7d47b0SAlexander V. Chernikov static void 854a399f8beSAlexander V. Chernikov ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 85568394ec8SAlexander V. Chernikov void *ta_buf) 8569f7d47b0SAlexander V. Chernikov { 857c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb; 8589f7d47b0SAlexander V. Chernikov 859c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf; 8609f7d47b0SAlexander V. Chernikov 861ac35ff17SAlexander V. Chernikov if (tb->ent_ptr != NULL) 8629f7d47b0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 8639f7d47b0SAlexander V. Chernikov } 8649f7d47b0SAlexander V. Chernikov 865b6ee846eSAlexander V. Chernikov static int 866301290bcSAlexander V. Chernikov ta_need_modify_radix(void *ta_state, struct table_info *ti, uint32_t count, 867b6ee846eSAlexander V. Chernikov uint64_t *pflags) 868b6ee846eSAlexander V. Chernikov { 869b6ee846eSAlexander V. Chernikov 870b6ee846eSAlexander V. Chernikov /* 8710bce0c23SAlexander V. Chernikov * radix does not require additional memory allocations 872b6ee846eSAlexander V. Chernikov * other than nodes itself. Adding new masks to the tree do 873b6ee846eSAlexander V. Chernikov * but we don't have any API to call (and we don't known which 874b6ee846eSAlexander V. Chernikov * sizes do we need). 875b6ee846eSAlexander V. Chernikov */ 876301290bcSAlexander V. Chernikov return (0); 877b6ee846eSAlexander V. Chernikov } 878b6ee846eSAlexander V. Chernikov 879c21034b7SAlexander V. Chernikov struct table_algo addr_radix = { 880c21034b7SAlexander V. Chernikov .name = "addr:radix", 881c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR, 88257a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 883c21034b7SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_radix), 88481cac390SArseny Smalyuk .init = ta_init_addr_radix, 88581cac390SArseny Smalyuk .destroy = ta_destroy_addr_radix, 88681cac390SArseny Smalyuk .prepare_add = ta_prepare_add_addr_radix, 88781cac390SArseny Smalyuk .prepare_del = ta_prepare_del_addr_radix, 88881cac390SArseny Smalyuk .add = ta_add_addr_radix, 88981cac390SArseny Smalyuk .del = ta_del_addr_radix, 890a399f8beSAlexander V. Chernikov .flush_entry = ta_flush_radix_entry, 89181cac390SArseny Smalyuk .foreach = ta_foreach_addr_radix, 89281cac390SArseny Smalyuk .dump_tentry = ta_dump_addr_radix_tentry, 89381cac390SArseny Smalyuk .find_tentry = ta_find_addr_radix_tentry, 89481cac390SArseny Smalyuk .dump_tinfo = ta_dump_addr_radix_tinfo, 895301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_radix, 8969f7d47b0SAlexander V. Chernikov }; 8979f7d47b0SAlexander V. Chernikov 8989f7d47b0SAlexander V. Chernikov /* 899c21034b7SAlexander V. Chernikov * addr:hash cmds 90074b941f0SAlexander V. Chernikov * 90174b941f0SAlexander V. Chernikov * 90274b941f0SAlexander V. Chernikov * ti->data: 90374b941f0SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6] 90474b941f0SAlexander V. Chernikov * [ 8][ 8[ 8][ 8] 90574b941f0SAlexander V. Chernikov * 90674b941f0SAlexander V. Chernikov * inv.mask4: 32 - mask 90774b941f0SAlexander V. Chernikov * inv.mask6: 90874b941f0SAlexander V. Chernikov * 1) _slow lookup: mask 90974b941f0SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8 91074b941f0SAlexander V. Chernikov * 3) _64: 8 911ce2817b5SAlexander V. Chernikov * 912ce2817b5SAlexander V. Chernikov * 913ce2817b5SAlexander V. Chernikov * pflags: 914ce2817b5SAlexander V. Chernikov * [v4=1/v6=0][hsize] 915ce2817b5SAlexander V. Chernikov * [ 32][ 32] 91674b941f0SAlexander V. Chernikov */ 91774b941f0SAlexander V. Chernikov 91874b941f0SAlexander V. Chernikov struct chashentry; 91974b941f0SAlexander V. Chernikov 92074b941f0SAlexander V. Chernikov SLIST_HEAD(chashbhead, chashentry); 92174b941f0SAlexander V. Chernikov 92274b941f0SAlexander V. Chernikov struct chash_cfg { 92374b941f0SAlexander V. Chernikov struct chashbhead *head4; 92474b941f0SAlexander V. Chernikov struct chashbhead *head6; 92574b941f0SAlexander V. Chernikov size_t size4; 92674b941f0SAlexander V. Chernikov size_t size6; 927ce2817b5SAlexander V. Chernikov size_t items4; 928ce2817b5SAlexander V. Chernikov size_t items6; 92974b941f0SAlexander V. Chernikov uint8_t mask4; 93074b941f0SAlexander V. Chernikov uint8_t mask6; 93174b941f0SAlexander V. Chernikov }; 93274b941f0SAlexander V. Chernikov 93374b941f0SAlexander V. Chernikov struct chashentry { 93474b941f0SAlexander V. Chernikov SLIST_ENTRY(chashentry) next; 93574b941f0SAlexander V. Chernikov uint32_t value; 93674b941f0SAlexander V. Chernikov uint32_t type; 93774b941f0SAlexander V. Chernikov union { 93874b941f0SAlexander V. Chernikov uint32_t a4; /* Host format */ 93974b941f0SAlexander V. Chernikov struct in6_addr a6; /* Network format */ 94074b941f0SAlexander V. Chernikov } a; 94174b941f0SAlexander V. Chernikov }; 94274b941f0SAlexander V. Chernikov 9430bce0c23SAlexander V. Chernikov struct ta_buf_chash 9440bce0c23SAlexander V. Chernikov { 9450bce0c23SAlexander V. Chernikov void *ent_ptr; 9460bce0c23SAlexander V. Chernikov struct chashentry ent; 9470bce0c23SAlexander V. Chernikov }; 9480bce0c23SAlexander V. Chernikov 949d699ee2dSAlexander V. Chernikov #ifdef INET 9509fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip(uint32_t addr, int hsize); 951d699ee2dSAlexander V. Chernikov #endif 952d699ee2dSAlexander V. Chernikov #ifdef INET6 9539fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip6(struct in6_addr *addr6, int hsize); 9549fe15d06SAlexander V. Chernikov static __inline uint16_t hash_ip64(struct in6_addr *addr6, int hsize); 9559fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip6_slow(struct in6_addr *addr6, void *key, 9569fe15d06SAlexander V. Chernikov int mask, int hsize); 9579fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip6_al(struct in6_addr *addr6, void *key, int mask, 9589fe15d06SAlexander V. Chernikov int hsize); 959d699ee2dSAlexander V. Chernikov #endif 9609fe15d06SAlexander V. Chernikov static int ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen, 9619fe15d06SAlexander V. Chernikov uint32_t *val); 9629fe15d06SAlexander V. Chernikov static int ta_lookup_chash_aligned(struct table_info *ti, void *key, 9639fe15d06SAlexander V. Chernikov uint32_t keylen, uint32_t *val); 9649fe15d06SAlexander V. Chernikov static int ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen, 9659fe15d06SAlexander V. Chernikov uint32_t *val); 9669fe15d06SAlexander V. Chernikov static int chash_parse_opts(struct chash_cfg *cfg, char *data); 9679fe15d06SAlexander V. Chernikov static void ta_print_chash_config(void *ta_state, struct table_info *ti, 9689fe15d06SAlexander V. Chernikov char *buf, size_t bufsize); 9699e3a53fdSAlexander V. Chernikov static int ta_log2(uint32_t v); 9709fe15d06SAlexander V. Chernikov static int ta_init_chash(struct ip_fw_chain *ch, void **ta_state, 9719fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 9729fe15d06SAlexander V. Chernikov static void ta_destroy_chash(void *ta_state, struct table_info *ti); 9739fe15d06SAlexander V. Chernikov static void ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, 9749fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 9759fe15d06SAlexander V. Chernikov static int ta_dump_chash_tentry(void *ta_state, struct table_info *ti, 9769fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent); 9779fe15d06SAlexander V. Chernikov static uint32_t hash_ent(struct chashentry *ent, int af, int mlen, 9789fe15d06SAlexander V. Chernikov uint32_t size); 9799fe15d06SAlexander V. Chernikov static int tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent); 9809fe15d06SAlexander V. Chernikov static int ta_find_chash_tentry(void *ta_state, struct table_info *ti, 9819fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 9829fe15d06SAlexander V. Chernikov static void ta_foreach_chash(void *ta_state, struct table_info *ti, 9839fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 9849fe15d06SAlexander V. Chernikov static int ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 9859fe15d06SAlexander V. Chernikov void *ta_buf); 9869fe15d06SAlexander V. Chernikov static int ta_add_chash(void *ta_state, struct table_info *ti, 9879fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 9889fe15d06SAlexander V. Chernikov static int ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 9899fe15d06SAlexander V. Chernikov void *ta_buf); 9909fe15d06SAlexander V. Chernikov static int ta_del_chash(void *ta_state, struct table_info *ti, 9919fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 9929fe15d06SAlexander V. Chernikov static void ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 9939fe15d06SAlexander V. Chernikov void *ta_buf); 9949fe15d06SAlexander V. Chernikov static int ta_need_modify_chash(void *ta_state, struct table_info *ti, 9959fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 9969fe15d06SAlexander V. Chernikov static int ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags); 9979fe15d06SAlexander V. Chernikov static int ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf, 9989fe15d06SAlexander V. Chernikov uint64_t *pflags); 9999fe15d06SAlexander V. Chernikov static void ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf, 10009fe15d06SAlexander V. Chernikov uint64_t pflags); 10019fe15d06SAlexander V. Chernikov static void ta_flush_mod_chash(void *ta_buf); 10029fe15d06SAlexander V. Chernikov 1003d699ee2dSAlexander V. Chernikov #ifdef INET 100474b941f0SAlexander V. Chernikov static __inline uint32_t 100574b941f0SAlexander V. Chernikov hash_ip(uint32_t addr, int hsize) 100674b941f0SAlexander V. Chernikov { 100774b941f0SAlexander V. Chernikov 100874b941f0SAlexander V. Chernikov return (addr % (hsize - 1)); 100974b941f0SAlexander V. Chernikov } 1010d699ee2dSAlexander V. Chernikov #endif 101174b941f0SAlexander V. Chernikov 1012d699ee2dSAlexander V. Chernikov #ifdef INET6 101374b941f0SAlexander V. Chernikov static __inline uint32_t 101474b941f0SAlexander V. Chernikov hash_ip6(struct in6_addr *addr6, int hsize) 101574b941f0SAlexander V. Chernikov { 101674b941f0SAlexander V. Chernikov uint32_t i; 101774b941f0SAlexander V. Chernikov 101874b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^ 101974b941f0SAlexander V. Chernikov addr6->s6_addr32[2] ^ addr6->s6_addr32[3]; 102074b941f0SAlexander V. Chernikov 102174b941f0SAlexander V. Chernikov return (i % (hsize - 1)); 102274b941f0SAlexander V. Chernikov } 102374b941f0SAlexander V. Chernikov 102474b941f0SAlexander V. Chernikov static __inline uint16_t 102574b941f0SAlexander V. Chernikov hash_ip64(struct in6_addr *addr6, int hsize) 102674b941f0SAlexander V. Chernikov { 102774b941f0SAlexander V. Chernikov uint32_t i; 102874b941f0SAlexander V. Chernikov 102974b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1]; 103074b941f0SAlexander V. Chernikov 103174b941f0SAlexander V. Chernikov return (i % (hsize - 1)); 103274b941f0SAlexander V. Chernikov } 103374b941f0SAlexander V. Chernikov 103474b941f0SAlexander V. Chernikov static __inline uint32_t 103574b941f0SAlexander V. Chernikov hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize) 103674b941f0SAlexander V. Chernikov { 103774b941f0SAlexander V. Chernikov struct in6_addr mask6; 103874b941f0SAlexander V. Chernikov 103974b941f0SAlexander V. Chernikov ipv6_writemask(&mask6, mask); 104074b941f0SAlexander V. Chernikov memcpy(addr6, key, sizeof(struct in6_addr)); 104174b941f0SAlexander V. Chernikov APPLY_MASK(addr6, &mask6); 104274b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize)); 104374b941f0SAlexander V. Chernikov } 104474b941f0SAlexander V. Chernikov 104574b941f0SAlexander V. Chernikov static __inline uint32_t 104674b941f0SAlexander V. Chernikov hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize) 104774b941f0SAlexander V. Chernikov { 104874b941f0SAlexander V. Chernikov uint64_t *paddr; 104974b941f0SAlexander V. Chernikov 105074b941f0SAlexander V. Chernikov paddr = (uint64_t *)addr6; 105174b941f0SAlexander V. Chernikov *paddr = 0; 105274b941f0SAlexander V. Chernikov *(paddr + 1) = 0; 105374b941f0SAlexander V. Chernikov memcpy(addr6, key, mask); 105474b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize)); 105574b941f0SAlexander V. Chernikov } 1056d699ee2dSAlexander V. Chernikov #endif 105774b941f0SAlexander V. Chernikov 105874b941f0SAlexander V. Chernikov static int 105974b941f0SAlexander V. Chernikov ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen, 106074b941f0SAlexander V. Chernikov uint32_t *val) 106174b941f0SAlexander V. Chernikov { 106274b941f0SAlexander V. Chernikov struct chashbhead *head; 106374b941f0SAlexander V. Chernikov struct chashentry *ent; 106474b941f0SAlexander V. Chernikov uint16_t hash, hsize; 106574b941f0SAlexander V. Chernikov uint8_t imask; 106674b941f0SAlexander V. Chernikov 106774b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 1068d699ee2dSAlexander V. Chernikov #ifdef INET 106974b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 107074b941f0SAlexander V. Chernikov imask = ti->data >> 24; 107174b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 107274b941f0SAlexander V. Chernikov uint32_t a; 107374b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 107474b941f0SAlexander V. Chernikov a = a >> imask; 107574b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 107674b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 107774b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 107874b941f0SAlexander V. Chernikov *val = ent->value; 107974b941f0SAlexander V. Chernikov return (1); 108074b941f0SAlexander V. Chernikov } 108174b941f0SAlexander V. Chernikov } 1082d699ee2dSAlexander V. Chernikov #endif 108374b941f0SAlexander V. Chernikov } else { 1084d699ee2dSAlexander V. Chernikov #ifdef INET6 108574b941f0SAlexander V. Chernikov /* IPv6: worst scenario: non-round mask */ 108674b941f0SAlexander V. Chernikov struct in6_addr addr6; 108774b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 108874b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16; 108974b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 109074b941f0SAlexander V. Chernikov hash = hash_ip6_slow(&addr6, key, imask, hsize); 109174b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 109274b941f0SAlexander V. Chernikov if (memcmp(&ent->a.a6, &addr6, 16) == 0) { 109374b941f0SAlexander V. Chernikov *val = ent->value; 109474b941f0SAlexander V. Chernikov return (1); 109574b941f0SAlexander V. Chernikov } 109674b941f0SAlexander V. Chernikov } 1097d699ee2dSAlexander V. Chernikov #endif 109874b941f0SAlexander V. Chernikov } 109974b941f0SAlexander V. Chernikov 110074b941f0SAlexander V. Chernikov return (0); 110174b941f0SAlexander V. Chernikov } 110274b941f0SAlexander V. Chernikov 110374b941f0SAlexander V. Chernikov static int 110474b941f0SAlexander V. Chernikov ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen, 110574b941f0SAlexander V. Chernikov uint32_t *val) 110674b941f0SAlexander V. Chernikov { 110774b941f0SAlexander V. Chernikov struct chashbhead *head; 110874b941f0SAlexander V. Chernikov struct chashentry *ent; 110974b941f0SAlexander V. Chernikov uint16_t hash, hsize; 111074b941f0SAlexander V. Chernikov uint8_t imask; 111174b941f0SAlexander V. Chernikov 111274b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 1113d699ee2dSAlexander V. Chernikov #ifdef INET 111474b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 111574b941f0SAlexander V. Chernikov imask = ti->data >> 24; 111674b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 111774b941f0SAlexander V. Chernikov uint32_t a; 111874b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 111974b941f0SAlexander V. Chernikov a = a >> imask; 112074b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 112174b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 112274b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 112374b941f0SAlexander V. Chernikov *val = ent->value; 112474b941f0SAlexander V. Chernikov return (1); 112574b941f0SAlexander V. Chernikov } 112674b941f0SAlexander V. Chernikov } 1127d699ee2dSAlexander V. Chernikov #endif 112874b941f0SAlexander V. Chernikov } else { 1129d699ee2dSAlexander V. Chernikov #ifdef INET6 113074b941f0SAlexander V. Chernikov /* IPv6: aligned to 8bit mask */ 113174b941f0SAlexander V. Chernikov struct in6_addr addr6; 113274b941f0SAlexander V. Chernikov uint64_t *paddr, *ptmp; 113374b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 113474b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16; 113574b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 113674b941f0SAlexander V. Chernikov 113774b941f0SAlexander V. Chernikov hash = hash_ip6_al(&addr6, key, imask, hsize); 113874b941f0SAlexander V. Chernikov paddr = (uint64_t *)&addr6; 113974b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 114074b941f0SAlexander V. Chernikov ptmp = (uint64_t *)&ent->a.a6; 114174b941f0SAlexander V. Chernikov if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) { 114274b941f0SAlexander V. Chernikov *val = ent->value; 114374b941f0SAlexander V. Chernikov return (1); 114474b941f0SAlexander V. Chernikov } 114574b941f0SAlexander V. Chernikov } 1146d699ee2dSAlexander V. Chernikov #endif 114774b941f0SAlexander V. Chernikov } 114874b941f0SAlexander V. Chernikov 114974b941f0SAlexander V. Chernikov return (0); 115074b941f0SAlexander V. Chernikov } 115174b941f0SAlexander V. Chernikov 115274b941f0SAlexander V. Chernikov static int 115374b941f0SAlexander V. Chernikov ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen, 115474b941f0SAlexander V. Chernikov uint32_t *val) 115574b941f0SAlexander V. Chernikov { 115674b941f0SAlexander V. Chernikov struct chashbhead *head; 115774b941f0SAlexander V. Chernikov struct chashentry *ent; 115874b941f0SAlexander V. Chernikov uint16_t hash, hsize; 115974b941f0SAlexander V. Chernikov uint8_t imask; 116074b941f0SAlexander V. Chernikov 116174b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 1162d699ee2dSAlexander V. Chernikov #ifdef INET 116374b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state; 116474b941f0SAlexander V. Chernikov imask = ti->data >> 24; 116574b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8); 116674b941f0SAlexander V. Chernikov uint32_t a; 116774b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key)); 116874b941f0SAlexander V. Chernikov a = a >> imask; 116974b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize); 117074b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 117174b941f0SAlexander V. Chernikov if (ent->a.a4 == a) { 117274b941f0SAlexander V. Chernikov *val = ent->value; 117374b941f0SAlexander V. Chernikov return (1); 117474b941f0SAlexander V. Chernikov } 117574b941f0SAlexander V. Chernikov } 1176d699ee2dSAlexander V. Chernikov #endif 117774b941f0SAlexander V. Chernikov } else { 1178d699ee2dSAlexander V. Chernikov #ifdef INET6 117974b941f0SAlexander V. Chernikov /* IPv6: /64 */ 118074b941f0SAlexander V. Chernikov uint64_t a6, *paddr; 118174b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate; 118274b941f0SAlexander V. Chernikov paddr = (uint64_t *)key; 118374b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF); 118474b941f0SAlexander V. Chernikov a6 = *paddr; 118574b941f0SAlexander V. Chernikov hash = hash_ip64((struct in6_addr *)key, hsize); 118674b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 118774b941f0SAlexander V. Chernikov paddr = (uint64_t *)&ent->a.a6; 118874b941f0SAlexander V. Chernikov if (a6 == *paddr) { 118974b941f0SAlexander V. Chernikov *val = ent->value; 119074b941f0SAlexander V. Chernikov return (1); 119174b941f0SAlexander V. Chernikov } 119274b941f0SAlexander V. Chernikov } 1193d699ee2dSAlexander V. Chernikov #endif 119474b941f0SAlexander V. Chernikov } 119574b941f0SAlexander V. Chernikov 119674b941f0SAlexander V. Chernikov return (0); 119774b941f0SAlexander V. Chernikov } 119874b941f0SAlexander V. Chernikov 119974b941f0SAlexander V. Chernikov static int 12000bce0c23SAlexander V. Chernikov chash_parse_opts(struct chash_cfg *cfg, char *data) 120174b941f0SAlexander V. Chernikov { 120274b941f0SAlexander V. Chernikov char *pdel, *pend, *s; 120374b941f0SAlexander V. Chernikov int mask4, mask6; 120474b941f0SAlexander V. Chernikov 12050bce0c23SAlexander V. Chernikov mask4 = cfg->mask4; 12060bce0c23SAlexander V. Chernikov mask6 = cfg->mask6; 120774b941f0SAlexander V. Chernikov 120874b941f0SAlexander V. Chernikov if (data == NULL) 120974b941f0SAlexander V. Chernikov return (0); 121074b941f0SAlexander V. Chernikov if ((pdel = strchr(data, ' ')) == NULL) 121174b941f0SAlexander V. Chernikov return (0); 121274b941f0SAlexander V. Chernikov while (*pdel == ' ') 121374b941f0SAlexander V. Chernikov pdel++; 121474b941f0SAlexander V. Chernikov if (strncmp(pdel, "masks=", 6) != 0) 121574b941f0SAlexander V. Chernikov return (EINVAL); 121674b941f0SAlexander V. Chernikov if ((s = strchr(pdel, ' ')) != NULL) 121774b941f0SAlexander V. Chernikov *s++ = '\0'; 121874b941f0SAlexander V. Chernikov 121974b941f0SAlexander V. Chernikov pdel += 6; 122074b941f0SAlexander V. Chernikov /* Need /XX[,/YY] */ 122174b941f0SAlexander V. Chernikov if (*pdel++ != '/') 122274b941f0SAlexander V. Chernikov return (EINVAL); 122374b941f0SAlexander V. Chernikov mask4 = strtol(pdel, &pend, 10); 122474b941f0SAlexander V. Chernikov if (*pend == ',') { 122574b941f0SAlexander V. Chernikov /* ,/YY */ 122674b941f0SAlexander V. Chernikov pdel = pend + 1; 122774b941f0SAlexander V. Chernikov if (*pdel++ != '/') 122874b941f0SAlexander V. Chernikov return (EINVAL); 122974b941f0SAlexander V. Chernikov mask6 = strtol(pdel, &pend, 10); 123074b941f0SAlexander V. Chernikov if (*pend != '\0') 123174b941f0SAlexander V. Chernikov return (EINVAL); 123274b941f0SAlexander V. Chernikov } else if (*pend != '\0') 123374b941f0SAlexander V. Chernikov return (EINVAL); 123474b941f0SAlexander V. Chernikov 123574b941f0SAlexander V. Chernikov if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128) 123674b941f0SAlexander V. Chernikov return (EINVAL); 123774b941f0SAlexander V. Chernikov 12380bce0c23SAlexander V. Chernikov cfg->mask4 = mask4; 12390bce0c23SAlexander V. Chernikov cfg->mask6 = mask6; 124074b941f0SAlexander V. Chernikov 124174b941f0SAlexander V. Chernikov return (0); 124274b941f0SAlexander V. Chernikov } 124374b941f0SAlexander V. Chernikov 124474b941f0SAlexander V. Chernikov static void 124574b941f0SAlexander V. Chernikov ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf, 124674b941f0SAlexander V. Chernikov size_t bufsize) 124774b941f0SAlexander V. Chernikov { 12480bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 124974b941f0SAlexander V. Chernikov 12500bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 125174b941f0SAlexander V. Chernikov 12520bce0c23SAlexander V. Chernikov if (cfg->mask4 != 32 || cfg->mask6 != 128) 1253c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s masks=/%d,/%d", "addr:hash", 12540bce0c23SAlexander V. Chernikov cfg->mask4, cfg->mask6); 125574b941f0SAlexander V. Chernikov else 1256c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s", "addr:hash"); 125774b941f0SAlexander V. Chernikov } 125874b941f0SAlexander V. Chernikov 1259914bffb6SAlexander V. Chernikov static int 12609e3a53fdSAlexander V. Chernikov ta_log2(uint32_t v) 1261914bffb6SAlexander V. Chernikov { 1262914bffb6SAlexander V. Chernikov uint32_t r; 1263914bffb6SAlexander V. Chernikov 1264914bffb6SAlexander V. Chernikov r = 0; 1265914bffb6SAlexander V. Chernikov while (v >>= 1) 1266914bffb6SAlexander V. Chernikov r++; 1267914bffb6SAlexander V. Chernikov 1268914bffb6SAlexander V. Chernikov return (r); 1269914bffb6SAlexander V. Chernikov } 127074b941f0SAlexander V. Chernikov 127174b941f0SAlexander V. Chernikov /* 127274b941f0SAlexander V. Chernikov * New table. 127374b941f0SAlexander V. Chernikov * We assume 'data' to be either NULL or the following format: 1274c21034b7SAlexander V. Chernikov * 'addr:hash [masks=/32[,/128]]' 127574b941f0SAlexander V. Chernikov */ 127674b941f0SAlexander V. Chernikov static int 127774b941f0SAlexander V. Chernikov ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 1278914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 127974b941f0SAlexander V. Chernikov { 128074b941f0SAlexander V. Chernikov int error, i; 1281914bffb6SAlexander V. Chernikov uint32_t hsize; 12820bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 128374b941f0SAlexander V. Chernikov 12840bce0c23SAlexander V. Chernikov cfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO); 128574b941f0SAlexander V. Chernikov 12860bce0c23SAlexander V. Chernikov cfg->mask4 = 32; 12870bce0c23SAlexander V. Chernikov cfg->mask6 = 128; 128874b941f0SAlexander V. Chernikov 12890bce0c23SAlexander V. Chernikov if ((error = chash_parse_opts(cfg, data)) != 0) { 12900bce0c23SAlexander V. Chernikov free(cfg, M_IPFW); 129174b941f0SAlexander V. Chernikov return (error); 129274b941f0SAlexander V. Chernikov } 129374b941f0SAlexander V. Chernikov 12940bce0c23SAlexander V. Chernikov cfg->size4 = 128; 12950bce0c23SAlexander V. Chernikov cfg->size6 = 128; 129674b941f0SAlexander V. Chernikov 12970bce0c23SAlexander V. Chernikov cfg->head4 = malloc(sizeof(struct chashbhead) * cfg->size4, M_IPFW, 129874b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO); 12990bce0c23SAlexander V. Chernikov cfg->head6 = malloc(sizeof(struct chashbhead) * cfg->size6, M_IPFW, 130074b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO); 13010bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 13020bce0c23SAlexander V. Chernikov SLIST_INIT(&cfg->head4[i]); 13030bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 13040bce0c23SAlexander V. Chernikov SLIST_INIT(&cfg->head6[i]); 130574b941f0SAlexander V. Chernikov 13060bce0c23SAlexander V. Chernikov *ta_state = cfg; 13070bce0c23SAlexander V. Chernikov ti->state = cfg->head4; 13080bce0c23SAlexander V. Chernikov ti->xstate = cfg->head6; 130974b941f0SAlexander V. Chernikov 131074b941f0SAlexander V. Chernikov /* Store data depending on v6 mask length */ 13119e3a53fdSAlexander V. Chernikov hsize = ta_log2(cfg->size4) << 8 | ta_log2(cfg->size6); 13120bce0c23SAlexander V. Chernikov if (cfg->mask6 == 64) { 13130bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | (128 - cfg->mask6) << 16| 1314914bffb6SAlexander V. Chernikov hsize; 131574b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_64; 13160bce0c23SAlexander V. Chernikov } else if ((cfg->mask6 % 8) == 0) { 13170bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | 13180bce0c23SAlexander V. Chernikov cfg->mask6 << 13 | hsize; 131974b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_aligned; 132074b941f0SAlexander V. Chernikov } else { 132174b941f0SAlexander V. Chernikov /* don't do that! */ 13220bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | 13230bce0c23SAlexander V. Chernikov cfg->mask6 << 16 | hsize; 132474b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_slow; 132574b941f0SAlexander V. Chernikov } 132674b941f0SAlexander V. Chernikov 132774b941f0SAlexander V. Chernikov return (0); 132874b941f0SAlexander V. Chernikov } 132974b941f0SAlexander V. Chernikov 133074b941f0SAlexander V. Chernikov static void 133174b941f0SAlexander V. Chernikov ta_destroy_chash(void *ta_state, struct table_info *ti) 133274b941f0SAlexander V. Chernikov { 13330bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 133474b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next; 133574b941f0SAlexander V. Chernikov int i; 133674b941f0SAlexander V. Chernikov 13370bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 133874b941f0SAlexander V. Chernikov 13390bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 13400bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next) 134174b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 134274b941f0SAlexander V. Chernikov 13430bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 13440bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next) 134574b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 134674b941f0SAlexander V. Chernikov 13470bce0c23SAlexander V. Chernikov free(cfg->head4, M_IPFW); 13480bce0c23SAlexander V. Chernikov free(cfg->head6, M_IPFW); 1349ce2817b5SAlexander V. Chernikov 13500bce0c23SAlexander V. Chernikov free(cfg, M_IPFW); 135174b941f0SAlexander V. Chernikov } 135274b941f0SAlexander V. Chernikov 13535f379342SAlexander V. Chernikov static void 13545f379342SAlexander V. Chernikov ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 13555f379342SAlexander V. Chernikov { 13565f379342SAlexander V. Chernikov struct chash_cfg *cfg; 13575f379342SAlexander V. Chernikov 13585f379342SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 13595f379342SAlexander V. Chernikov 13605f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM; 13615f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_HASH; 13625f379342SAlexander V. Chernikov tinfo->size4 = cfg->size4; 13635f379342SAlexander V. Chernikov tinfo->count4 = cfg->items4; 13645f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct chashentry); 13655f379342SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_HASH; 13665f379342SAlexander V. Chernikov tinfo->size6 = cfg->size6; 13675f379342SAlexander V. Chernikov tinfo->count6 = cfg->items6; 13685f379342SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct chashentry); 13695f379342SAlexander V. Chernikov } 13705f379342SAlexander V. Chernikov 137174b941f0SAlexander V. Chernikov static int 137274b941f0SAlexander V. Chernikov ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e, 137374b941f0SAlexander V. Chernikov ipfw_obj_tentry *tent) 137474b941f0SAlexander V. Chernikov { 13750bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 137674b941f0SAlexander V. Chernikov struct chashentry *ent; 137774b941f0SAlexander V. Chernikov 13780bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 137974b941f0SAlexander V. Chernikov ent = (struct chashentry *)e; 138074b941f0SAlexander V. Chernikov 138174b941f0SAlexander V. Chernikov if (ent->type == AF_INET) { 13820bce0c23SAlexander V. Chernikov tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - cfg->mask4)); 13830bce0c23SAlexander V. Chernikov tent->masklen = cfg->mask4; 138474b941f0SAlexander V. Chernikov tent->subtype = AF_INET; 13850cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value; 138674b941f0SAlexander V. Chernikov #ifdef INET6 138774b941f0SAlexander V. Chernikov } else { 1388ba3e1361SAndrey V. Elsukov memcpy(&tent->k.addr6, &ent->a.a6, sizeof(struct in6_addr)); 13890bce0c23SAlexander V. Chernikov tent->masklen = cfg->mask6; 139074b941f0SAlexander V. Chernikov tent->subtype = AF_INET6; 13910cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value; 139274b941f0SAlexander V. Chernikov #endif 139374b941f0SAlexander V. Chernikov } 139474b941f0SAlexander V. Chernikov 139574b941f0SAlexander V. Chernikov return (0); 139674b941f0SAlexander V. Chernikov } 139774b941f0SAlexander V. Chernikov 1398ce2817b5SAlexander V. Chernikov static uint32_t 1399ce2817b5SAlexander V. Chernikov hash_ent(struct chashentry *ent, int af, int mlen, uint32_t size) 1400ce2817b5SAlexander V. Chernikov { 1401ce2817b5SAlexander V. Chernikov uint32_t hash; 1402ce2817b5SAlexander V. Chernikov 1403d699ee2dSAlexander V. Chernikov hash = 0; 1404d699ee2dSAlexander V. Chernikov 1405ce2817b5SAlexander V. Chernikov if (af == AF_INET) { 1406d699ee2dSAlexander V. Chernikov #ifdef INET 1407ce2817b5SAlexander V. Chernikov hash = hash_ip(ent->a.a4, size); 1408d699ee2dSAlexander V. Chernikov #endif 1409ce2817b5SAlexander V. Chernikov } else { 1410d699ee2dSAlexander V. Chernikov #ifdef INET6 1411ce2817b5SAlexander V. Chernikov if (mlen == 64) 1412ce2817b5SAlexander V. Chernikov hash = hash_ip64(&ent->a.a6, size); 1413ce2817b5SAlexander V. Chernikov else 1414ce2817b5SAlexander V. Chernikov hash = hash_ip6(&ent->a.a6, size); 1415d699ee2dSAlexander V. Chernikov #endif 1416ce2817b5SAlexander V. Chernikov } 1417ce2817b5SAlexander V. Chernikov 1418ce2817b5SAlexander V. Chernikov return (hash); 1419ce2817b5SAlexander V. Chernikov } 1420ce2817b5SAlexander V. Chernikov 1421ce2817b5SAlexander V. Chernikov static int 1422ce2817b5SAlexander V. Chernikov tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent) 1423ce2817b5SAlexander V. Chernikov { 1424ce2817b5SAlexander V. Chernikov int mlen; 1425d699ee2dSAlexander V. Chernikov #ifdef INET6 1426d699ee2dSAlexander V. Chernikov struct in6_addr mask6; 1427d699ee2dSAlexander V. Chernikov #endif 1428ce2817b5SAlexander V. Chernikov 1429ce2817b5SAlexander V. Chernikov mlen = tei->masklen; 1430ce2817b5SAlexander V. Chernikov 1431ce2817b5SAlexander V. Chernikov if (tei->subtype == AF_INET) { 1432ce2817b5SAlexander V. Chernikov #ifdef INET 1433ce2817b5SAlexander V. Chernikov if (mlen > 32) 1434ce2817b5SAlexander V. Chernikov return (EINVAL); 1435ce2817b5SAlexander V. Chernikov ent->type = AF_INET; 1436ce2817b5SAlexander V. Chernikov 1437ce2817b5SAlexander V. Chernikov /* Calculate masked address */ 1438ce2817b5SAlexander V. Chernikov ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen); 1439ce2817b5SAlexander V. Chernikov #endif 1440ce2817b5SAlexander V. Chernikov #ifdef INET6 1441ce2817b5SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 1442ce2817b5SAlexander V. Chernikov /* IPv6 case */ 1443ce2817b5SAlexander V. Chernikov if (mlen > 128) 1444ce2817b5SAlexander V. Chernikov return (EINVAL); 1445ce2817b5SAlexander V. Chernikov ent->type = AF_INET6; 1446ce2817b5SAlexander V. Chernikov 1447ce2817b5SAlexander V. Chernikov ipv6_writemask(&mask6, mlen); 1448ce2817b5SAlexander V. Chernikov memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr)); 1449ce2817b5SAlexander V. Chernikov APPLY_MASK(&ent->a.a6, &mask6); 1450ce2817b5SAlexander V. Chernikov #endif 1451ce2817b5SAlexander V. Chernikov } else { 1452ce2817b5SAlexander V. Chernikov /* Unknown CIDR type */ 1453ce2817b5SAlexander V. Chernikov return (EINVAL); 1454ce2817b5SAlexander V. Chernikov } 1455ce2817b5SAlexander V. Chernikov 1456ce2817b5SAlexander V. Chernikov return (0); 1457ce2817b5SAlexander V. Chernikov } 1458ce2817b5SAlexander V. Chernikov 145974b941f0SAlexander V. Chernikov static int 1460914bffb6SAlexander V. Chernikov ta_find_chash_tentry(void *ta_state, struct table_info *ti, 1461914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 146274b941f0SAlexander V. Chernikov { 14630bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 1464ce2817b5SAlexander V. Chernikov struct chashbhead *head; 1465ce2817b5SAlexander V. Chernikov struct chashentry ent, *tmp; 1466ce2817b5SAlexander V. Chernikov struct tentry_info tei; 1467ce2817b5SAlexander V. Chernikov int error; 1468ce2817b5SAlexander V. Chernikov uint32_t hash; 146974b941f0SAlexander V. Chernikov 14700bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1471ce2817b5SAlexander V. Chernikov 1472ce2817b5SAlexander V. Chernikov memset(&ent, 0, sizeof(ent)); 1473ce2817b5SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 1474ce2817b5SAlexander V. Chernikov 1475914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) { 1476914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr; 14770bce0c23SAlexander V. Chernikov tei.masklen = cfg->mask4; 1478ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET; 147974b941f0SAlexander V. Chernikov 1480ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0) 1481ce2817b5SAlexander V. Chernikov return (error); 1482ce2817b5SAlexander V. Chernikov 14830bce0c23SAlexander V. Chernikov head = cfg->head4; 14840bce0c23SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET, cfg->mask4, cfg->size4); 1485ce2817b5SAlexander V. Chernikov /* Check for existence */ 1486ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1487ce2817b5SAlexander V. Chernikov if (tmp->a.a4 != ent.a.a4) 1488ce2817b5SAlexander V. Chernikov continue; 1489ce2817b5SAlexander V. Chernikov 1490ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent); 149174b941f0SAlexander V. Chernikov return (0); 149274b941f0SAlexander V. Chernikov } 1493ce2817b5SAlexander V. Chernikov } else { 1494914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr6; 14950bce0c23SAlexander V. Chernikov tei.masklen = cfg->mask6; 1496ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET6; 1497ce2817b5SAlexander V. Chernikov 1498ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0) 1499ce2817b5SAlexander V. Chernikov return (error); 1500ce2817b5SAlexander V. Chernikov 15010bce0c23SAlexander V. Chernikov head = cfg->head6; 15020bce0c23SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET6, cfg->mask6, cfg->size6); 1503ce2817b5SAlexander V. Chernikov /* Check for existence */ 1504ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1505ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0) 1506ce2817b5SAlexander V. Chernikov continue; 1507ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent); 1508ce2817b5SAlexander V. Chernikov return (0); 1509ce2817b5SAlexander V. Chernikov } 1510ce2817b5SAlexander V. Chernikov } 1511ce2817b5SAlexander V. Chernikov 151274b941f0SAlexander V. Chernikov return (ENOENT); 151374b941f0SAlexander V. Chernikov } 151474b941f0SAlexander V. Chernikov 151574b941f0SAlexander V. Chernikov static void 151674b941f0SAlexander V. Chernikov ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f, 151774b941f0SAlexander V. Chernikov void *arg) 151874b941f0SAlexander V. Chernikov { 15190bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 152074b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next; 152174b941f0SAlexander V. Chernikov int i; 152274b941f0SAlexander V. Chernikov 15230bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 152474b941f0SAlexander V. Chernikov 15250bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++) 15260bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next) 152774b941f0SAlexander V. Chernikov f(ent, arg); 152874b941f0SAlexander V. Chernikov 15290bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++) 15300bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next) 153174b941f0SAlexander V. Chernikov f(ent, arg); 153274b941f0SAlexander V. Chernikov } 153374b941f0SAlexander V. Chernikov 153474b941f0SAlexander V. Chernikov static int 153574b941f0SAlexander V. Chernikov ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 153674b941f0SAlexander V. Chernikov void *ta_buf) 153774b941f0SAlexander V. Chernikov { 153874b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 153974b941f0SAlexander V. Chernikov struct chashentry *ent; 1540ce2817b5SAlexander V. Chernikov int error; 154174b941f0SAlexander V. Chernikov 154274b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 154374b941f0SAlexander V. Chernikov 154474b941f0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 154574b941f0SAlexander V. Chernikov 1546ce2817b5SAlexander V. Chernikov error = tei_to_chash_ent(tei, ent); 1547ce2817b5SAlexander V. Chernikov if (error != 0) { 1548ce2817b5SAlexander V. Chernikov free(ent, M_IPFW_TBL); 1549ce2817b5SAlexander V. Chernikov return (error); 155074b941f0SAlexander V. Chernikov } 1551ce2817b5SAlexander V. Chernikov tb->ent_ptr = ent; 155274b941f0SAlexander V. Chernikov 155374b941f0SAlexander V. Chernikov return (0); 155474b941f0SAlexander V. Chernikov } 155574b941f0SAlexander V. Chernikov 155674b941f0SAlexander V. Chernikov static int 155774b941f0SAlexander V. Chernikov ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1558b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 155974b941f0SAlexander V. Chernikov { 15600bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 156174b941f0SAlexander V. Chernikov struct chashbhead *head; 156274b941f0SAlexander V. Chernikov struct chashentry *ent, *tmp; 156374b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 156474b941f0SAlexander V. Chernikov int exists; 1565648e8380SAlexander V. Chernikov uint32_t hash, value; 156674b941f0SAlexander V. Chernikov 15670bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 156874b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 156974b941f0SAlexander V. Chernikov ent = (struct chashentry *)tb->ent_ptr; 157074b941f0SAlexander V. Chernikov hash = 0; 157174b941f0SAlexander V. Chernikov exists = 0; 157274b941f0SAlexander V. Chernikov 157313263632SAlexander V. Chernikov /* Read current value from @tei */ 157413263632SAlexander V. Chernikov ent->value = tei->value; 157513263632SAlexander V. Chernikov 157613263632SAlexander V. Chernikov /* Read cuurrent value */ 157774b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) { 15780bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask4) 157974b941f0SAlexander V. Chernikov return (EINVAL); 15800bce0c23SAlexander V. Chernikov head = cfg->head4; 15810bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4); 1582ce2817b5SAlexander V. Chernikov 158374b941f0SAlexander V. Chernikov /* Check for existence */ 158474b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 158574b941f0SAlexander V. Chernikov if (tmp->a.a4 == ent->a.a4) { 158674b941f0SAlexander V. Chernikov exists = 1; 158774b941f0SAlexander V. Chernikov break; 158874b941f0SAlexander V. Chernikov } 158974b941f0SAlexander V. Chernikov } 159074b941f0SAlexander V. Chernikov } else { 15910bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask6) 159274b941f0SAlexander V. Chernikov return (EINVAL); 15930bce0c23SAlexander V. Chernikov head = cfg->head6; 15940bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6); 159574b941f0SAlexander V. Chernikov /* Check for existence */ 159674b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 1597ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) == 0) { 159874b941f0SAlexander V. Chernikov exists = 1; 159974b941f0SAlexander V. Chernikov break; 160074b941f0SAlexander V. Chernikov } 160174b941f0SAlexander V. Chernikov } 160274b941f0SAlexander V. Chernikov } 160374b941f0SAlexander V. Chernikov 160474b941f0SAlexander V. Chernikov if (exists == 1) { 160574b941f0SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 160674b941f0SAlexander V. Chernikov return (EEXIST); 160774b941f0SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 1608648e8380SAlexander V. Chernikov value = tmp->value; 160974b941f0SAlexander V. Chernikov tmp->value = tei->value; 1610648e8380SAlexander V. Chernikov tei->value = value; 161174b941f0SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 161274b941f0SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 161374b941f0SAlexander V. Chernikov *pnum = 0; 161474b941f0SAlexander V. Chernikov } else { 16154c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 16164c0c07a5SAlexander V. Chernikov return (EFBIG); 161774b941f0SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next); 161874b941f0SAlexander V. Chernikov tb->ent_ptr = NULL; 161974b941f0SAlexander V. Chernikov *pnum = 1; 1620ce2817b5SAlexander V. Chernikov 1621b6ee846eSAlexander V. Chernikov /* Update counters */ 1622b6ee846eSAlexander V. Chernikov if (tei->subtype == AF_INET) 16230bce0c23SAlexander V. Chernikov cfg->items4++; 1624b6ee846eSAlexander V. Chernikov else 16250bce0c23SAlexander V. Chernikov cfg->items6++; 162674b941f0SAlexander V. Chernikov } 162774b941f0SAlexander V. Chernikov 162874b941f0SAlexander V. Chernikov return (0); 162974b941f0SAlexander V. Chernikov } 163074b941f0SAlexander V. Chernikov 163174b941f0SAlexander V. Chernikov static int 163274b941f0SAlexander V. Chernikov ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 163374b941f0SAlexander V. Chernikov void *ta_buf) 163474b941f0SAlexander V. Chernikov { 163574b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 163674b941f0SAlexander V. Chernikov 163774b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 163874b941f0SAlexander V. Chernikov 1639ce2817b5SAlexander V. Chernikov return (tei_to_chash_ent(tei, &tb->ent)); 164074b941f0SAlexander V. Chernikov } 164174b941f0SAlexander V. Chernikov 164274b941f0SAlexander V. Chernikov static int 164374b941f0SAlexander V. Chernikov ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 1644b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 164574b941f0SAlexander V. Chernikov { 16460bce0c23SAlexander V. Chernikov struct chash_cfg *cfg; 164774b941f0SAlexander V. Chernikov struct chashbhead *head; 16480bce0c23SAlexander V. Chernikov struct chashentry *tmp, *tmp_next, *ent; 164974b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 165074b941f0SAlexander V. Chernikov uint32_t hash; 165174b941f0SAlexander V. Chernikov 16520bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 165374b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 16540bce0c23SAlexander V. Chernikov ent = &tb->ent; 165574b941f0SAlexander V. Chernikov 165674b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) { 16570bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask4) 165874b941f0SAlexander V. Chernikov return (EINVAL); 16590bce0c23SAlexander V. Chernikov head = cfg->head4; 16600bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4); 166174b941f0SAlexander V. Chernikov 16620bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) { 16630bce0c23SAlexander V. Chernikov if (tmp->a.a4 != ent->a.a4) 1664648e8380SAlexander V. Chernikov continue; 1665648e8380SAlexander V. Chernikov 16660bce0c23SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, chashentry, next); 16670bce0c23SAlexander V. Chernikov cfg->items4--; 16680bce0c23SAlexander V. Chernikov tb->ent_ptr = tmp; 16690bce0c23SAlexander V. Chernikov tei->value = tmp->value; 1670648e8380SAlexander V. Chernikov *pnum = 1; 167174b941f0SAlexander V. Chernikov return (0); 167274b941f0SAlexander V. Chernikov } 167374b941f0SAlexander V. Chernikov } else { 16740bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask6) 167574b941f0SAlexander V. Chernikov return (EINVAL); 16760bce0c23SAlexander V. Chernikov head = cfg->head6; 16770bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6); 16780bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) { 16790bce0c23SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) != 0) 1680648e8380SAlexander V. Chernikov continue; 1681648e8380SAlexander V. Chernikov 16820bce0c23SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, chashentry, next); 16830bce0c23SAlexander V. Chernikov cfg->items6--; 16840bce0c23SAlexander V. Chernikov tb->ent_ptr = tmp; 16850bce0c23SAlexander V. Chernikov tei->value = tmp->value; 168674b941f0SAlexander V. Chernikov *pnum = 1; 168774b941f0SAlexander V. Chernikov return (0); 168874b941f0SAlexander V. Chernikov } 168974b941f0SAlexander V. Chernikov } 169074b941f0SAlexander V. Chernikov 169174b941f0SAlexander V. Chernikov return (ENOENT); 169274b941f0SAlexander V. Chernikov } 169374b941f0SAlexander V. Chernikov 169474b941f0SAlexander V. Chernikov static void 169574b941f0SAlexander V. Chernikov ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 169674b941f0SAlexander V. Chernikov void *ta_buf) 169774b941f0SAlexander V. Chernikov { 169874b941f0SAlexander V. Chernikov struct ta_buf_chash *tb; 169974b941f0SAlexander V. Chernikov 170074b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf; 170174b941f0SAlexander V. Chernikov 170274b941f0SAlexander V. Chernikov if (tb->ent_ptr != NULL) 170374b941f0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 170474b941f0SAlexander V. Chernikov } 170574b941f0SAlexander V. Chernikov 1706ce2817b5SAlexander V. Chernikov /* 1707ce2817b5SAlexander V. Chernikov * Hash growing callbacks. 1708ce2817b5SAlexander V. Chernikov */ 1709ce2817b5SAlexander V. Chernikov 1710b6ee846eSAlexander V. Chernikov static int 1711301290bcSAlexander V. Chernikov ta_need_modify_chash(void *ta_state, struct table_info *ti, uint32_t count, 1712b6ee846eSAlexander V. Chernikov uint64_t *pflags) 1713b6ee846eSAlexander V. Chernikov { 1714b6ee846eSAlexander V. Chernikov struct chash_cfg *cfg; 1715b6ee846eSAlexander V. Chernikov uint64_t data; 1716b6ee846eSAlexander V. Chernikov 1717b6ee846eSAlexander V. Chernikov /* 1718b6ee846eSAlexander V. Chernikov * Since we don't know exact number of IPv4/IPv6 records in @count, 1719b6ee846eSAlexander V. Chernikov * ignore non-zero @count value at all. Check current hash sizes 1720b6ee846eSAlexander V. Chernikov * and return appropriate data. 1721b6ee846eSAlexander V. Chernikov */ 1722b6ee846eSAlexander V. Chernikov 1723b6ee846eSAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1724b6ee846eSAlexander V. Chernikov 1725b6ee846eSAlexander V. Chernikov data = 0; 1726b6ee846eSAlexander V. Chernikov if (cfg->items4 > cfg->size4 && cfg->size4 < 65536) 1727b6ee846eSAlexander V. Chernikov data |= (cfg->size4 * 2) << 16; 1728b6ee846eSAlexander V. Chernikov if (cfg->items6 > cfg->size6 && cfg->size6 < 65536) 1729b6ee846eSAlexander V. Chernikov data |= cfg->size6 * 2; 1730b6ee846eSAlexander V. Chernikov 1731b6ee846eSAlexander V. Chernikov if (data != 0) { 1732b6ee846eSAlexander V. Chernikov *pflags = data; 1733301290bcSAlexander V. Chernikov return (1); 1734b6ee846eSAlexander V. Chernikov } 1735b6ee846eSAlexander V. Chernikov 1736301290bcSAlexander V. Chernikov return (0); 1737b6ee846eSAlexander V. Chernikov } 1738b6ee846eSAlexander V. Chernikov 1739ce2817b5SAlexander V. Chernikov /* 1740ce2817b5SAlexander V. Chernikov * Allocate new, larger chash. 1741ce2817b5SAlexander V. Chernikov */ 1742ce2817b5SAlexander V. Chernikov static int 1743ce2817b5SAlexander V. Chernikov ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags) 1744ce2817b5SAlexander V. Chernikov { 1745ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1746ce2817b5SAlexander V. Chernikov struct chashbhead *head; 1747ce2817b5SAlexander V. Chernikov int i; 1748ce2817b5SAlexander V. Chernikov 1749ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1750ce2817b5SAlexander V. Chernikov 1751ce2817b5SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 1752b6ee846eSAlexander V. Chernikov mi->size = (*pflags >> 16) & 0xFFFF; 1753b6ee846eSAlexander V. Chernikov mi->size6 = *pflags & 0xFFFF; 1754b6ee846eSAlexander V. Chernikov if (mi->size > 0) { 1755b6ee846eSAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size, 1756b6ee846eSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1757ce2817b5SAlexander V. Chernikov for (i = 0; i < mi->size; i++) 1758ce2817b5SAlexander V. Chernikov SLIST_INIT(&head[i]); 1759ce2817b5SAlexander V. Chernikov mi->main_ptr = head; 1760b6ee846eSAlexander V. Chernikov } 1761b6ee846eSAlexander V. Chernikov 1762b6ee846eSAlexander V. Chernikov if (mi->size6 > 0) { 1763b6ee846eSAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size6, 1764b6ee846eSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1765b6ee846eSAlexander V. Chernikov for (i = 0; i < mi->size6; i++) 1766b6ee846eSAlexander V. Chernikov SLIST_INIT(&head[i]); 1767b6ee846eSAlexander V. Chernikov mi->main_ptr6 = head; 1768b6ee846eSAlexander V. Chernikov } 1769ce2817b5SAlexander V. Chernikov 1770ce2817b5SAlexander V. Chernikov return (0); 1771ce2817b5SAlexander V. Chernikov } 1772ce2817b5SAlexander V. Chernikov 1773ce2817b5SAlexander V. Chernikov /* 1774ce2817b5SAlexander V. Chernikov * Copy data from old runtime array to new one. 1775ce2817b5SAlexander V. Chernikov */ 1776ce2817b5SAlexander V. Chernikov static int 1777ce2817b5SAlexander V. Chernikov ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1778ce2817b5SAlexander V. Chernikov uint64_t *pflags) 1779ce2817b5SAlexander V. Chernikov { 1780ce2817b5SAlexander V. Chernikov 1781ce2817b5SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */ 1782ce2817b5SAlexander V. Chernikov return (0); 1783ce2817b5SAlexander V. Chernikov } 1784ce2817b5SAlexander V. Chernikov 1785ce2817b5SAlexander V. Chernikov /* 1786ce2817b5SAlexander V. Chernikov * Switch old & new arrays. 1787ce2817b5SAlexander V. Chernikov */ 1788301290bcSAlexander V. Chernikov static void 1789ce2817b5SAlexander V. Chernikov ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1790ce2817b5SAlexander V. Chernikov uint64_t pflags) 1791ce2817b5SAlexander V. Chernikov { 1792ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1793b6ee846eSAlexander V. Chernikov struct chash_cfg *cfg; 1794ce2817b5SAlexander V. Chernikov struct chashbhead *old_head, *new_head; 1795ce2817b5SAlexander V. Chernikov struct chashentry *ent, *ent_next; 1796ce2817b5SAlexander V. Chernikov int af, i, mlen; 1797ce2817b5SAlexander V. Chernikov uint32_t nhash; 1798b6ee846eSAlexander V. Chernikov size_t old_size, new_size; 1799ce2817b5SAlexander V. Chernikov 1800ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1801b6ee846eSAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state; 1802ce2817b5SAlexander V. Chernikov 1803ce2817b5SAlexander V. Chernikov /* Check which hash we need to grow and do we still need that */ 1804b6ee846eSAlexander V. Chernikov if (mi->size > 0 && cfg->size4 < mi->size) { 1805ce2817b5SAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr; 1806b6ee846eSAlexander V. Chernikov new_size = mi->size; 1807b6ee846eSAlexander V. Chernikov old_size = cfg->size4; 1808b6ee846eSAlexander V. Chernikov old_head = ti->state; 1809b6ee846eSAlexander V. Chernikov mlen = cfg->mask4; 1810b6ee846eSAlexander V. Chernikov af = AF_INET; 1811b6ee846eSAlexander V. Chernikov 1812ce2817b5SAlexander V. Chernikov for (i = 0; i < old_size; i++) { 1813ce2817b5SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 1814b6ee846eSAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, new_size); 1815ce2817b5SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 1816ce2817b5SAlexander V. Chernikov } 1817ce2817b5SAlexander V. Chernikov } 1818ce2817b5SAlexander V. Chernikov 1819ce2817b5SAlexander V. Chernikov ti->state = new_head; 1820b6ee846eSAlexander V. Chernikov cfg->head4 = new_head; 1821b6ee846eSAlexander V. Chernikov cfg->size4 = mi->size; 1822b6ee846eSAlexander V. Chernikov mi->main_ptr = old_head; 1823ce2817b5SAlexander V. Chernikov } 1824ce2817b5SAlexander V. Chernikov 1825b6ee846eSAlexander V. Chernikov if (mi->size6 > 0 && cfg->size6 < mi->size6) { 1826b6ee846eSAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr6; 1827b6ee846eSAlexander V. Chernikov new_size = mi->size6; 1828b6ee846eSAlexander V. Chernikov old_size = cfg->size6; 1829b6ee846eSAlexander V. Chernikov old_head = ti->xstate; 1830b6ee846eSAlexander V. Chernikov mlen = cfg->mask6; 1831b6ee846eSAlexander V. Chernikov af = AF_INET6; 1832914bffb6SAlexander V. Chernikov 1833b6ee846eSAlexander V. Chernikov for (i = 0; i < old_size; i++) { 1834b6ee846eSAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 1835b6ee846eSAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, new_size); 1836b6ee846eSAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 1837b6ee846eSAlexander V. Chernikov } 1838b6ee846eSAlexander V. Chernikov } 1839b6ee846eSAlexander V. Chernikov 1840b6ee846eSAlexander V. Chernikov ti->xstate = new_head; 1841b6ee846eSAlexander V. Chernikov cfg->head6 = new_head; 1842b6ee846eSAlexander V. Chernikov cfg->size6 = mi->size6; 1843b6ee846eSAlexander V. Chernikov mi->main_ptr6 = old_head; 1844b6ee846eSAlexander V. Chernikov } 1845b6ee846eSAlexander V. Chernikov 1846b6ee846eSAlexander V. Chernikov /* Update lower 32 bits with new values */ 1847b6ee846eSAlexander V. Chernikov ti->data &= 0xFFFFFFFF00000000; 18489e3a53fdSAlexander V. Chernikov ti->data |= ta_log2(cfg->size4) << 8 | ta_log2(cfg->size6); 1849ce2817b5SAlexander V. Chernikov } 1850ce2817b5SAlexander V. Chernikov 1851ce2817b5SAlexander V. Chernikov /* 1852ce2817b5SAlexander V. Chernikov * Free unneded array. 1853ce2817b5SAlexander V. Chernikov */ 1854ce2817b5SAlexander V. Chernikov static void 1855ce2817b5SAlexander V. Chernikov ta_flush_mod_chash(void *ta_buf) 1856ce2817b5SAlexander V. Chernikov { 1857ce2817b5SAlexander V. Chernikov struct mod_item *mi; 1858ce2817b5SAlexander V. Chernikov 1859ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 1860ce2817b5SAlexander V. Chernikov if (mi->main_ptr != NULL) 1861ce2817b5SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 1862b6ee846eSAlexander V. Chernikov if (mi->main_ptr6 != NULL) 1863b6ee846eSAlexander V. Chernikov free(mi->main_ptr6, M_IPFW); 1864ce2817b5SAlexander V. Chernikov } 1865ce2817b5SAlexander V. Chernikov 1866c21034b7SAlexander V. Chernikov struct table_algo addr_hash = { 1867c21034b7SAlexander V. Chernikov .name = "addr:hash", 1868c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR, 186957a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_chash), 187074b941f0SAlexander V. Chernikov .init = ta_init_chash, 187174b941f0SAlexander V. Chernikov .destroy = ta_destroy_chash, 187274b941f0SAlexander V. Chernikov .prepare_add = ta_prepare_add_chash, 187374b941f0SAlexander V. Chernikov .prepare_del = ta_prepare_del_chash, 187474b941f0SAlexander V. Chernikov .add = ta_add_chash, 187574b941f0SAlexander V. Chernikov .del = ta_del_chash, 187674b941f0SAlexander V. Chernikov .flush_entry = ta_flush_chash_entry, 187774b941f0SAlexander V. Chernikov .foreach = ta_foreach_chash, 187874b941f0SAlexander V. Chernikov .dump_tentry = ta_dump_chash_tentry, 187974b941f0SAlexander V. Chernikov .find_tentry = ta_find_chash_tentry, 188074b941f0SAlexander V. Chernikov .print_config = ta_print_chash_config, 18815f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_chash_tinfo, 1882301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_chash, 1883ce2817b5SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_chash, 1884ce2817b5SAlexander V. Chernikov .fill_mod = ta_fill_mod_chash, 1885ce2817b5SAlexander V. Chernikov .modify = ta_modify_chash, 1886ce2817b5SAlexander V. Chernikov .flush_mod = ta_flush_mod_chash, 188774b941f0SAlexander V. Chernikov }; 188874b941f0SAlexander V. Chernikov 188974b941f0SAlexander V. Chernikov /* 189068394ec8SAlexander V. Chernikov * Iface table cmds. 189168394ec8SAlexander V. Chernikov * 189268394ec8SAlexander V. Chernikov * Implementation: 189368394ec8SAlexander V. Chernikov * 189468394ec8SAlexander V. Chernikov * Runtime part: 189568394ec8SAlexander V. Chernikov * - sorted array of "struct ifidx" pointed by ti->state. 1896b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to IFIDX_CHUNK. Only existing 189768394ec8SAlexander V. Chernikov * interfaces are stored in array, however its allocated size is 189868394ec8SAlexander V. Chernikov * sufficient to hold all table records if needed. 189968394ec8SAlexander V. Chernikov * - current array size is stored in ti->data 190068394ec8SAlexander V. Chernikov * 190168394ec8SAlexander V. Chernikov * Table data: 190268394ec8SAlexander V. Chernikov * - "struct iftable_cfg" is allocated to store table state (ta_state). 190368394ec8SAlexander V. Chernikov * - All table records are stored inside namedobj instance. 19049f7d47b0SAlexander V. Chernikov * 19059f7d47b0SAlexander V. Chernikov */ 19069f7d47b0SAlexander V. Chernikov 190768394ec8SAlexander V. Chernikov struct ifidx { 190868394ec8SAlexander V. Chernikov uint16_t kidx; 190968394ec8SAlexander V. Chernikov uint16_t spare; 191068394ec8SAlexander V. Chernikov uint32_t value; 191168394ec8SAlexander V. Chernikov }; 19120cba2b28SAlexander V. Chernikov #define DEFAULT_IFIDX_SIZE 64 191368394ec8SAlexander V. Chernikov 191468394ec8SAlexander V. Chernikov struct iftable_cfg; 191568394ec8SAlexander V. Chernikov 191668394ec8SAlexander V. Chernikov struct ifentry { 191768394ec8SAlexander V. Chernikov struct named_object no; 191868394ec8SAlexander V. Chernikov struct ipfw_ifc ic; 191968394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 192068394ec8SAlexander V. Chernikov uint32_t value; 192168394ec8SAlexander V. Chernikov int linked; 192268394ec8SAlexander V. Chernikov }; 192368394ec8SAlexander V. Chernikov 192468394ec8SAlexander V. Chernikov struct iftable_cfg { 192568394ec8SAlexander V. Chernikov struct namedobj_instance *ii; 192668394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 192768394ec8SAlexander V. Chernikov struct table_info *ti; 192868394ec8SAlexander V. Chernikov void *main_ptr; 192968394ec8SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 193068394ec8SAlexander V. Chernikov size_t count; /* Number of all items */ 193168394ec8SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 193268394ec8SAlexander V. Chernikov }; 193368394ec8SAlexander V. Chernikov 19340bce0c23SAlexander V. Chernikov struct ta_buf_ifidx 19350bce0c23SAlexander V. Chernikov { 19360bce0c23SAlexander V. Chernikov struct ifentry *ife; 19370bce0c23SAlexander V. Chernikov uint32_t value; 19380bce0c23SAlexander V. Chernikov }; 193968394ec8SAlexander V. Chernikov 194068394ec8SAlexander V. Chernikov int compare_ifidx(const void *k, const void *v); 19419fe15d06SAlexander V. Chernikov static struct ifidx * ifidx_find(struct table_info *ti, void *key); 19429fe15d06SAlexander V. Chernikov static int ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen, 19439fe15d06SAlexander V. Chernikov uint32_t *val); 19449fe15d06SAlexander V. Chernikov static int ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, 19459fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 19469fe15d06SAlexander V. Chernikov static void ta_change_ti_ifidx(void *ta_state, struct table_info *ti); 1947b309f085SAndrey V. Elsukov static int destroy_ifidx_locked(struct namedobj_instance *ii, 19489fe15d06SAlexander V. Chernikov struct named_object *no, void *arg); 19499fe15d06SAlexander V. Chernikov static void ta_destroy_ifidx(void *ta_state, struct table_info *ti); 19509fe15d06SAlexander V. Chernikov static void ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, 19519fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 19529fe15d06SAlexander V. Chernikov static int ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 19539fe15d06SAlexander V. Chernikov void *ta_buf); 19549fe15d06SAlexander V. Chernikov static int ta_add_ifidx(void *ta_state, struct table_info *ti, 19559fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 19569fe15d06SAlexander V. Chernikov static int ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 19579fe15d06SAlexander V. Chernikov void *ta_buf); 19589fe15d06SAlexander V. Chernikov static int ta_del_ifidx(void *ta_state, struct table_info *ti, 19599fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 19609fe15d06SAlexander V. Chernikov static void ta_flush_ifidx_entry(struct ip_fw_chain *ch, 19619fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf); 19629fe15d06SAlexander V. Chernikov static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex); 19639fe15d06SAlexander V. Chernikov static int ta_need_modify_ifidx(void *ta_state, struct table_info *ti, 19649fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 19659fe15d06SAlexander V. Chernikov static int ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags); 19669fe15d06SAlexander V. Chernikov static int ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, 19679fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t *pflags); 19689fe15d06SAlexander V. Chernikov static void ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 19699fe15d06SAlexander V. Chernikov uint64_t pflags); 19709fe15d06SAlexander V. Chernikov static void ta_flush_mod_ifidx(void *ta_buf); 19719fe15d06SAlexander V. Chernikov static int ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e, 19729fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 19739fe15d06SAlexander V. Chernikov static int ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, 19749fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 1975b309f085SAndrey V. Elsukov static int foreach_ifidx(struct namedobj_instance *ii, struct named_object *no, 19769fe15d06SAlexander V. Chernikov void *arg); 19779fe15d06SAlexander V. Chernikov static void ta_foreach_ifidx(void *ta_state, struct table_info *ti, 19789fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 197968394ec8SAlexander V. Chernikov 198068394ec8SAlexander V. Chernikov int 198168394ec8SAlexander V. Chernikov compare_ifidx(const void *k, const void *v) 198268394ec8SAlexander V. Chernikov { 1983d4e1b515SAlexander V. Chernikov const struct ifidx *ifidx; 198468394ec8SAlexander V. Chernikov uint16_t key; 198568394ec8SAlexander V. Chernikov 1986d4e1b515SAlexander V. Chernikov key = *((const uint16_t *)k); 1987d4e1b515SAlexander V. Chernikov ifidx = (const struct ifidx *)v; 198868394ec8SAlexander V. Chernikov 198968394ec8SAlexander V. Chernikov if (key < ifidx->kidx) 199068394ec8SAlexander V. Chernikov return (-1); 199168394ec8SAlexander V. Chernikov else if (key > ifidx->kidx) 199268394ec8SAlexander V. Chernikov return (1); 199368394ec8SAlexander V. Chernikov 199468394ec8SAlexander V. Chernikov return (0); 199568394ec8SAlexander V. Chernikov } 199668394ec8SAlexander V. Chernikov 199768394ec8SAlexander V. Chernikov /* 199868394ec8SAlexander V. Chernikov * Adds item @item with key @key into ascending-sorted array @base. 199968394ec8SAlexander V. Chernikov * Assumes @base has enough additional storage. 200068394ec8SAlexander V. Chernikov * 200168394ec8SAlexander V. Chernikov * Returns 1 on success, 0 on duplicate key. 200268394ec8SAlexander V. Chernikov */ 20039f7d47b0SAlexander V. Chernikov static int 200468394ec8SAlexander V. Chernikov badd(const void *key, void *item, void *base, size_t nmemb, 200568394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *)) 200668394ec8SAlexander V. Chernikov { 200768394ec8SAlexander V. Chernikov int min, max, mid, shift, res; 200868394ec8SAlexander V. Chernikov caddr_t paddr; 200968394ec8SAlexander V. Chernikov 201068394ec8SAlexander V. Chernikov if (nmemb == 0) { 201168394ec8SAlexander V. Chernikov memcpy(base, item, size); 201268394ec8SAlexander V. Chernikov return (1); 201368394ec8SAlexander V. Chernikov } 201468394ec8SAlexander V. Chernikov 201568394ec8SAlexander V. Chernikov /* Binary search */ 201668394ec8SAlexander V. Chernikov min = 0; 201768394ec8SAlexander V. Chernikov max = nmemb - 1; 201868394ec8SAlexander V. Chernikov mid = 0; 201968394ec8SAlexander V. Chernikov while (min <= max) { 202068394ec8SAlexander V. Chernikov mid = (min + max) / 2; 202168394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 202268394ec8SAlexander V. Chernikov if (res == 0) 202368394ec8SAlexander V. Chernikov return (0); 202468394ec8SAlexander V. Chernikov 202568394ec8SAlexander V. Chernikov if (res > 0) 202668394ec8SAlexander V. Chernikov min = mid + 1; 202768394ec8SAlexander V. Chernikov else 202868394ec8SAlexander V. Chernikov max = mid - 1; 202968394ec8SAlexander V. Chernikov } 203068394ec8SAlexander V. Chernikov 203168394ec8SAlexander V. Chernikov /* Item not found. */ 203268394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 203368394ec8SAlexander V. Chernikov if (res > 0) 203468394ec8SAlexander V. Chernikov shift = mid + 1; 203568394ec8SAlexander V. Chernikov else 203668394ec8SAlexander V. Chernikov shift = mid; 203768394ec8SAlexander V. Chernikov 203868394ec8SAlexander V. Chernikov paddr = (caddr_t)base + shift * size; 203968394ec8SAlexander V. Chernikov if (nmemb > shift) 204068394ec8SAlexander V. Chernikov memmove(paddr + size, paddr, (nmemb - shift) * size); 204168394ec8SAlexander V. Chernikov 204268394ec8SAlexander V. Chernikov memcpy(paddr, item, size); 204368394ec8SAlexander V. Chernikov 204468394ec8SAlexander V. Chernikov return (1); 204568394ec8SAlexander V. Chernikov } 204668394ec8SAlexander V. Chernikov 204768394ec8SAlexander V. Chernikov /* 204868394ec8SAlexander V. Chernikov * Deletes item with key @key from ascending-sorted array @base. 204968394ec8SAlexander V. Chernikov * 205068394ec8SAlexander V. Chernikov * Returns 1 on success, 0 for non-existent key. 205168394ec8SAlexander V. Chernikov */ 205268394ec8SAlexander V. Chernikov static int 205368394ec8SAlexander V. Chernikov bdel(const void *key, void *base, size_t nmemb, size_t size, 205468394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *)) 205568394ec8SAlexander V. Chernikov { 205668394ec8SAlexander V. Chernikov caddr_t item; 205768394ec8SAlexander V. Chernikov size_t sz; 205868394ec8SAlexander V. Chernikov 205968394ec8SAlexander V. Chernikov item = (caddr_t)bsearch(key, base, nmemb, size, compar); 206068394ec8SAlexander V. Chernikov 206168394ec8SAlexander V. Chernikov if (item == NULL) 206268394ec8SAlexander V. Chernikov return (0); 206368394ec8SAlexander V. Chernikov 206468394ec8SAlexander V. Chernikov sz = (caddr_t)base + nmemb * size - item; 206568394ec8SAlexander V. Chernikov 206668394ec8SAlexander V. Chernikov if (sz > 0) 206768394ec8SAlexander V. Chernikov memmove(item, item + size, sz); 206868394ec8SAlexander V. Chernikov 206968394ec8SAlexander V. Chernikov return (1); 207068394ec8SAlexander V. Chernikov } 207168394ec8SAlexander V. Chernikov 207268394ec8SAlexander V. Chernikov static struct ifidx * 207368394ec8SAlexander V. Chernikov ifidx_find(struct table_info *ti, void *key) 207468394ec8SAlexander V. Chernikov { 207568394ec8SAlexander V. Chernikov struct ifidx *ifi; 207668394ec8SAlexander V. Chernikov 207768394ec8SAlexander V. Chernikov ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx), 207868394ec8SAlexander V. Chernikov compare_ifidx); 207968394ec8SAlexander V. Chernikov 208068394ec8SAlexander V. Chernikov return (ifi); 208168394ec8SAlexander V. Chernikov } 208268394ec8SAlexander V. Chernikov 208368394ec8SAlexander V. Chernikov static int 208468394ec8SAlexander V. Chernikov ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen, 20859f7d47b0SAlexander V. Chernikov uint32_t *val) 20869f7d47b0SAlexander V. Chernikov { 208768394ec8SAlexander V. Chernikov struct ifidx *ifi; 20889f7d47b0SAlexander V. Chernikov 208968394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, key); 20909f7d47b0SAlexander V. Chernikov 209168394ec8SAlexander V. Chernikov if (ifi != NULL) { 209268394ec8SAlexander V. Chernikov *val = ifi->value; 20939f7d47b0SAlexander V. Chernikov return (1); 20949f7d47b0SAlexander V. Chernikov } 20959f7d47b0SAlexander V. Chernikov 20969f7d47b0SAlexander V. Chernikov return (0); 20979f7d47b0SAlexander V. Chernikov } 20989f7d47b0SAlexander V. Chernikov 20999f7d47b0SAlexander V. Chernikov static int 210068394ec8SAlexander V. Chernikov ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 2101914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 21029f7d47b0SAlexander V. Chernikov { 210368394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 21049f7d47b0SAlexander V. Chernikov 210568394ec8SAlexander V. Chernikov icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO); 21069f7d47b0SAlexander V. Chernikov 21070cba2b28SAlexander V. Chernikov icfg->ii = ipfw_objhash_create(DEFAULT_IFIDX_SIZE); 21080cba2b28SAlexander V. Chernikov icfg->size = DEFAULT_IFIDX_SIZE; 21090bce0c23SAlexander V. Chernikov icfg->main_ptr = malloc(sizeof(struct ifidx) * icfg->size, M_IPFW, 211068394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 211168394ec8SAlexander V. Chernikov icfg->ch = ch; 21129f7d47b0SAlexander V. Chernikov 211368394ec8SAlexander V. Chernikov *ta_state = icfg; 211468394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 211568394ec8SAlexander V. Chernikov ti->lookup = ta_lookup_ifidx; 21169f7d47b0SAlexander V. Chernikov 21179f7d47b0SAlexander V. Chernikov return (0); 21189f7d47b0SAlexander V. Chernikov } 21199f7d47b0SAlexander V. Chernikov 212068394ec8SAlexander V. Chernikov /* 212168394ec8SAlexander V. Chernikov * Handle tableinfo @ti pointer change (on table array resize). 212268394ec8SAlexander V. Chernikov */ 212368394ec8SAlexander V. Chernikov static void 212468394ec8SAlexander V. Chernikov ta_change_ti_ifidx(void *ta_state, struct table_info *ti) 212568394ec8SAlexander V. Chernikov { 212668394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 212768394ec8SAlexander V. Chernikov 212868394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 212968394ec8SAlexander V. Chernikov icfg->ti = ti; 213068394ec8SAlexander V. Chernikov } 21319f7d47b0SAlexander V. Chernikov 2132b309f085SAndrey V. Elsukov static int 213368394ec8SAlexander V. Chernikov destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no, 213468394ec8SAlexander V. Chernikov void *arg) 21359f7d47b0SAlexander V. Chernikov { 213668394ec8SAlexander V. Chernikov struct ifentry *ife; 213768394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 21389f7d47b0SAlexander V. Chernikov 213968394ec8SAlexander V. Chernikov ch = (struct ip_fw_chain *)arg; 214068394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 214168394ec8SAlexander V. Chernikov 214268394ec8SAlexander V. Chernikov ipfw_iface_del_notify(ch, &ife->ic); 21430caab009SAlexander V. Chernikov ipfw_iface_unref(ch, &ife->ic); 214468394ec8SAlexander V. Chernikov free(ife, M_IPFW_TBL); 2145b309f085SAndrey V. Elsukov return (0); 21469f7d47b0SAlexander V. Chernikov } 21479f7d47b0SAlexander V. Chernikov 214868394ec8SAlexander V. Chernikov /* 214968394ec8SAlexander V. Chernikov * Destroys table @ti 215068394ec8SAlexander V. Chernikov */ 215168394ec8SAlexander V. Chernikov static void 215268394ec8SAlexander V. Chernikov ta_destroy_ifidx(void *ta_state, struct table_info *ti) 21539f7d47b0SAlexander V. Chernikov { 215468394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 215568394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 215668394ec8SAlexander V. Chernikov 215768394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 215868394ec8SAlexander V. Chernikov ch = icfg->ch; 215968394ec8SAlexander V. Chernikov 216068394ec8SAlexander V. Chernikov if (icfg->main_ptr != NULL) 216168394ec8SAlexander V. Chernikov free(icfg->main_ptr, M_IPFW); 216268394ec8SAlexander V. Chernikov 21630caab009SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 216468394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch); 21650caab009SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 216668394ec8SAlexander V. Chernikov 216768394ec8SAlexander V. Chernikov ipfw_objhash_destroy(icfg->ii); 216868394ec8SAlexander V. Chernikov 216968394ec8SAlexander V. Chernikov free(icfg, M_IPFW); 217068394ec8SAlexander V. Chernikov } 217168394ec8SAlexander V. Chernikov 217268394ec8SAlexander V. Chernikov /* 21735f379342SAlexander V. Chernikov * Provide algo-specific table info 21745f379342SAlexander V. Chernikov */ 21755f379342SAlexander V. Chernikov static void 21765f379342SAlexander V. Chernikov ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 21775f379342SAlexander V. Chernikov { 21785f379342SAlexander V. Chernikov struct iftable_cfg *cfg; 21795f379342SAlexander V. Chernikov 21805f379342SAlexander V. Chernikov cfg = (struct iftable_cfg *)ta_state; 21815f379342SAlexander V. Chernikov 21825f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_ARRAY; 21835f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 21845f379342SAlexander V. Chernikov tinfo->count4 = cfg->used; 21855f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct ifidx); 21865f379342SAlexander V. Chernikov } 21875f379342SAlexander V. Chernikov 21885f379342SAlexander V. Chernikov /* 218968394ec8SAlexander V. Chernikov * Prepare state to add to the table: 219068394ec8SAlexander V. Chernikov * allocate ifentry and reference needed interface. 219168394ec8SAlexander V. Chernikov */ 21929f7d47b0SAlexander V. Chernikov static int 219368394ec8SAlexander V. Chernikov ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 219468394ec8SAlexander V. Chernikov void *ta_buf) 219568394ec8SAlexander V. Chernikov { 219668394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 219768394ec8SAlexander V. Chernikov char *ifname; 219868394ec8SAlexander V. Chernikov struct ifentry *ife; 219968394ec8SAlexander V. Chernikov 220068394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 220168394ec8SAlexander V. Chernikov 220268394ec8SAlexander V. Chernikov /* Check if string is terminated */ 220368394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 220468394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 220568394ec8SAlexander V. Chernikov return (EINVAL); 220668394ec8SAlexander V. Chernikov 220768394ec8SAlexander V. Chernikov ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO); 220868394ec8SAlexander V. Chernikov ife->ic.cb = if_notifier; 220968394ec8SAlexander V. Chernikov ife->ic.cbdata = ife; 221068394ec8SAlexander V. Chernikov 22118ebca97fSAlexander V. Chernikov if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0) { 22128ebca97fSAlexander V. Chernikov free(ife, M_IPFW_TBL); 221368394ec8SAlexander V. Chernikov return (EINVAL); 22148ebca97fSAlexander V. Chernikov } 221568394ec8SAlexander V. Chernikov 221668394ec8SAlexander V. Chernikov /* Use ipfw_iface 'ifname' field as stable storage */ 221768394ec8SAlexander V. Chernikov ife->no.name = ife->ic.iface->ifname; 221868394ec8SAlexander V. Chernikov 221968394ec8SAlexander V. Chernikov tb->ife = ife; 222068394ec8SAlexander V. Chernikov 222168394ec8SAlexander V. Chernikov return (0); 222268394ec8SAlexander V. Chernikov } 222368394ec8SAlexander V. Chernikov 222468394ec8SAlexander V. Chernikov static int 2225adea6201SAlexander V. Chernikov ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2226b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 222768394ec8SAlexander V. Chernikov { 222868394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 222968394ec8SAlexander V. Chernikov struct ifentry *ife, *tmp; 223068394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 223168394ec8SAlexander V. Chernikov struct ipfw_iface *iif; 223268394ec8SAlexander V. Chernikov struct ifidx *ifi; 223368394ec8SAlexander V. Chernikov char *ifname; 2234648e8380SAlexander V. Chernikov uint32_t value; 223568394ec8SAlexander V. Chernikov 223668394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 223768394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 223868394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 223968394ec8SAlexander V. Chernikov ife = tb->ife; 224068394ec8SAlexander V. Chernikov 224168394ec8SAlexander V. Chernikov ife->icfg = icfg; 224213263632SAlexander V. Chernikov ife->value = tei->value; 224368394ec8SAlexander V. Chernikov 224468394ec8SAlexander V. Chernikov tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 224568394ec8SAlexander V. Chernikov 224668394ec8SAlexander V. Chernikov if (tmp != NULL) { 224768394ec8SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 224868394ec8SAlexander V. Chernikov return (EEXIST); 224968394ec8SAlexander V. Chernikov 2250648e8380SAlexander V. Chernikov /* Exchange values in @tmp and @tei */ 2251648e8380SAlexander V. Chernikov value = tmp->value; 2252648e8380SAlexander V. Chernikov tmp->value = tei->value; 2253648e8380SAlexander V. Chernikov tei->value = value; 225468394ec8SAlexander V. Chernikov 2255648e8380SAlexander V. Chernikov iif = tmp->ic.iface; 225668394ec8SAlexander V. Chernikov if (iif->resolved != 0) { 2257648e8380SAlexander V. Chernikov /* We have to update runtime value, too */ 225868394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, &iif->ifindex); 225968394ec8SAlexander V. Chernikov ifi->value = ife->value; 226068394ec8SAlexander V. Chernikov } 226168394ec8SAlexander V. Chernikov 226268394ec8SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 226368394ec8SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 2264adea6201SAlexander V. Chernikov *pnum = 0; 226568394ec8SAlexander V. Chernikov return (0); 226668394ec8SAlexander V. Chernikov } 226768394ec8SAlexander V. Chernikov 22684c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 22694c0c07a5SAlexander V. Chernikov return (EFBIG); 22704c0c07a5SAlexander V. Chernikov 227168394ec8SAlexander V. Chernikov /* Link to internal list */ 227268394ec8SAlexander V. Chernikov ipfw_objhash_add(icfg->ii, &ife->no); 227368394ec8SAlexander V. Chernikov 227468394ec8SAlexander V. Chernikov /* Link notifier (possible running its callback) */ 227568394ec8SAlexander V. Chernikov ipfw_iface_add_notify(icfg->ch, &ife->ic); 227668394ec8SAlexander V. Chernikov icfg->count++; 227768394ec8SAlexander V. Chernikov 227868394ec8SAlexander V. Chernikov tb->ife = NULL; 2279adea6201SAlexander V. Chernikov *pnum = 1; 228068394ec8SAlexander V. Chernikov 228168394ec8SAlexander V. Chernikov return (0); 228268394ec8SAlexander V. Chernikov } 228368394ec8SAlexander V. Chernikov 228468394ec8SAlexander V. Chernikov /* 228568394ec8SAlexander V. Chernikov * Prepare to delete key from table. 228668394ec8SAlexander V. Chernikov * Do basic interface name checks. 228768394ec8SAlexander V. Chernikov */ 228868394ec8SAlexander V. Chernikov static int 228968394ec8SAlexander V. Chernikov ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 229068394ec8SAlexander V. Chernikov void *ta_buf) 22919f7d47b0SAlexander V. Chernikov { 2292e0a8b9eeSAlexander V. Chernikov char *ifname; 22939f7d47b0SAlexander V. Chernikov 22949f7d47b0SAlexander V. Chernikov /* Check if string is terminated */ 2295e0a8b9eeSAlexander V. Chernikov ifname = (char *)tei->paddr; 2296e0a8b9eeSAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 22979f7d47b0SAlexander V. Chernikov return (EINVAL); 22989f7d47b0SAlexander V. Chernikov 22999f7d47b0SAlexander V. Chernikov return (0); 23009f7d47b0SAlexander V. Chernikov } 23019f7d47b0SAlexander V. Chernikov 230268394ec8SAlexander V. Chernikov /* 230368394ec8SAlexander V. Chernikov * Remove key from both configuration list and 230468394ec8SAlexander V. Chernikov * runtime array. Removed interface notification. 230568394ec8SAlexander V. Chernikov */ 23069f7d47b0SAlexander V. Chernikov static int 2307adea6201SAlexander V. Chernikov ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2308b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 23099f7d47b0SAlexander V. Chernikov { 231068394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 231168394ec8SAlexander V. Chernikov struct ifentry *ife; 231268394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 231368394ec8SAlexander V. Chernikov char *ifname; 231468394ec8SAlexander V. Chernikov uint16_t ifindex; 231560a28b09SMateusz Guzik int res __diagused; 23169f7d47b0SAlexander V. Chernikov 231768394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 231868394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 231968394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 23209f7d47b0SAlexander V. Chernikov 232168394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 23229f7d47b0SAlexander V. Chernikov 232368394ec8SAlexander V. Chernikov if (ife == NULL) 232481d3153dSAlexander V. Chernikov return (ENOENT); 23259f7d47b0SAlexander V. Chernikov 232668394ec8SAlexander V. Chernikov if (ife->linked != 0) { 232768394ec8SAlexander V. Chernikov /* We have to remove item from runtime */ 232868394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 232968394ec8SAlexander V. Chernikov 233068394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 233168394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 233268394ec8SAlexander V. Chernikov 233368394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 233468394ec8SAlexander V. Chernikov icfg->used--; 233568394ec8SAlexander V. Chernikov ti->data = icfg->used; 233668394ec8SAlexander V. Chernikov ife->linked = 0; 233768394ec8SAlexander V. Chernikov } 233868394ec8SAlexander V. Chernikov 233968394ec8SAlexander V. Chernikov /* Unlink from local list */ 234068394ec8SAlexander V. Chernikov ipfw_objhash_del(icfg->ii, &ife->no); 23410caab009SAlexander V. Chernikov /* Unlink notifier and deref */ 234268394ec8SAlexander V. Chernikov ipfw_iface_del_notify(icfg->ch, &ife->ic); 23430caab009SAlexander V. Chernikov ipfw_iface_unref(icfg->ch, &ife->ic); 234468394ec8SAlexander V. Chernikov 234568394ec8SAlexander V. Chernikov icfg->count--; 2346648e8380SAlexander V. Chernikov tei->value = ife->value; 234768394ec8SAlexander V. Chernikov 234868394ec8SAlexander V. Chernikov tb->ife = ife; 2349adea6201SAlexander V. Chernikov *pnum = 1; 235068394ec8SAlexander V. Chernikov 23519f7d47b0SAlexander V. Chernikov return (0); 23529f7d47b0SAlexander V. Chernikov } 23539f7d47b0SAlexander V. Chernikov 235468394ec8SAlexander V. Chernikov /* 235568394ec8SAlexander V. Chernikov * Flush deleted entry. 235668394ec8SAlexander V. Chernikov * Drops interface reference and frees entry. 235768394ec8SAlexander V. Chernikov */ 23589f7d47b0SAlexander V. Chernikov static void 235968394ec8SAlexander V. Chernikov ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 236068394ec8SAlexander V. Chernikov void *ta_buf) 23619f7d47b0SAlexander V. Chernikov { 236268394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 23639f7d47b0SAlexander V. Chernikov 236468394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 23659f7d47b0SAlexander V. Chernikov 23660caab009SAlexander V. Chernikov if (tb->ife != NULL) 236768394ec8SAlexander V. Chernikov free(tb->ife, M_IPFW_TBL); 236868394ec8SAlexander V. Chernikov } 236968394ec8SAlexander V. Chernikov 237068394ec8SAlexander V. Chernikov /* 237168394ec8SAlexander V. Chernikov * Handle interface announce/withdrawal for particular table. 237268394ec8SAlexander V. Chernikov * Every real runtime array modification happens here. 237368394ec8SAlexander V. Chernikov */ 237468394ec8SAlexander V. Chernikov static void 237568394ec8SAlexander V. Chernikov if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex) 237668394ec8SAlexander V. Chernikov { 237768394ec8SAlexander V. Chernikov struct ifentry *ife; 237868394ec8SAlexander V. Chernikov struct ifidx ifi; 237968394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 238068394ec8SAlexander V. Chernikov struct table_info *ti; 238160a28b09SMateusz Guzik int res __diagused; 238268394ec8SAlexander V. Chernikov 238368394ec8SAlexander V. Chernikov ife = (struct ifentry *)cbdata; 238468394ec8SAlexander V. Chernikov icfg = ife->icfg; 238568394ec8SAlexander V. Chernikov ti = icfg->ti; 238668394ec8SAlexander V. Chernikov 238768394ec8SAlexander V. Chernikov KASSERT(ti != NULL, ("ti=NULL, check change_ti handler")); 238868394ec8SAlexander V. Chernikov 238968394ec8SAlexander V. Chernikov if (ife->linked == 0 && ifindex != 0) { 239068394ec8SAlexander V. Chernikov /* Interface announce */ 239168394ec8SAlexander V. Chernikov ifi.kidx = ifindex; 239268394ec8SAlexander V. Chernikov ifi.spare = 0; 239368394ec8SAlexander V. Chernikov ifi.value = ife->value; 239468394ec8SAlexander V. Chernikov res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used, 239568394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 239668394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d already exists", ifindex)); 239768394ec8SAlexander V. Chernikov icfg->used++; 239868394ec8SAlexander V. Chernikov ti->data = icfg->used; 239968394ec8SAlexander V. Chernikov ife->linked = 1; 240068394ec8SAlexander V. Chernikov } else if (ife->linked != 0 && ifindex == 0) { 240168394ec8SAlexander V. Chernikov /* Interface withdrawal */ 240268394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 240368394ec8SAlexander V. Chernikov 240468394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 240568394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 240668394ec8SAlexander V. Chernikov 240768394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 240868394ec8SAlexander V. Chernikov icfg->used--; 240968394ec8SAlexander V. Chernikov ti->data = icfg->used; 241068394ec8SAlexander V. Chernikov ife->linked = 0; 241168394ec8SAlexander V. Chernikov } 241268394ec8SAlexander V. Chernikov } 241368394ec8SAlexander V. Chernikov 241468394ec8SAlexander V. Chernikov /* 241568394ec8SAlexander V. Chernikov * Table growing callbacks. 241668394ec8SAlexander V. Chernikov */ 241768394ec8SAlexander V. Chernikov 2418b6ee846eSAlexander V. Chernikov static int 2419301290bcSAlexander V. Chernikov ta_need_modify_ifidx(void *ta_state, struct table_info *ti, uint32_t count, 2420b6ee846eSAlexander V. Chernikov uint64_t *pflags) 2421b6ee846eSAlexander V. Chernikov { 2422b6ee846eSAlexander V. Chernikov struct iftable_cfg *cfg; 24230bce0c23SAlexander V. Chernikov uint32_t size; 2424b6ee846eSAlexander V. Chernikov 2425b6ee846eSAlexander V. Chernikov cfg = (struct iftable_cfg *)ta_state; 2426b6ee846eSAlexander V. Chernikov 24270bce0c23SAlexander V. Chernikov size = cfg->size; 24280bce0c23SAlexander V. Chernikov while (size < cfg->count + count) 24290bce0c23SAlexander V. Chernikov size *= 2; 24300bce0c23SAlexander V. Chernikov 24310bce0c23SAlexander V. Chernikov if (size != cfg->size) { 24320bce0c23SAlexander V. Chernikov *pflags = size; 2433301290bcSAlexander V. Chernikov return (1); 2434b6ee846eSAlexander V. Chernikov } 2435b6ee846eSAlexander V. Chernikov 2436301290bcSAlexander V. Chernikov return (0); 2437b6ee846eSAlexander V. Chernikov } 2438b6ee846eSAlexander V. Chernikov 243968394ec8SAlexander V. Chernikov /* 244068394ec8SAlexander V. Chernikov * Allocate ned, larger runtime ifidx array. 244168394ec8SAlexander V. Chernikov */ 244268394ec8SAlexander V. Chernikov static int 244368394ec8SAlexander V. Chernikov ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags) 244468394ec8SAlexander V. Chernikov { 24450bce0c23SAlexander V. Chernikov struct mod_item *mi; 244668394ec8SAlexander V. Chernikov 24470bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 244868394ec8SAlexander V. Chernikov 24490bce0c23SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 245068394ec8SAlexander V. Chernikov mi->size = *pflags; 245168394ec8SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW, 245268394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 245368394ec8SAlexander V. Chernikov 245468394ec8SAlexander V. Chernikov return (0); 245568394ec8SAlexander V. Chernikov } 245668394ec8SAlexander V. Chernikov 245768394ec8SAlexander V. Chernikov /* 245868394ec8SAlexander V. Chernikov * Copy data from old runtime array to new one. 245968394ec8SAlexander V. Chernikov */ 246068394ec8SAlexander V. Chernikov static int 246168394ec8SAlexander V. Chernikov ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 246268394ec8SAlexander V. Chernikov uint64_t *pflags) 246368394ec8SAlexander V. Chernikov { 24640bce0c23SAlexander V. Chernikov struct mod_item *mi; 246568394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 246668394ec8SAlexander V. Chernikov 24670bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 246868394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 246968394ec8SAlexander V. Chernikov 247068394ec8SAlexander V. Chernikov /* Check if we still need to grow array */ 247168394ec8SAlexander V. Chernikov if (icfg->size >= mi->size) { 247268394ec8SAlexander V. Chernikov *pflags = 0; 247368394ec8SAlexander V. Chernikov return (0); 247468394ec8SAlexander V. Chernikov } 247568394ec8SAlexander V. Chernikov 247668394ec8SAlexander V. Chernikov memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx)); 247768394ec8SAlexander V. Chernikov 247868394ec8SAlexander V. Chernikov return (0); 247968394ec8SAlexander V. Chernikov } 248068394ec8SAlexander V. Chernikov 248168394ec8SAlexander V. Chernikov /* 248268394ec8SAlexander V. Chernikov * Switch old & new arrays. 248368394ec8SAlexander V. Chernikov */ 2484301290bcSAlexander V. Chernikov static void 248568394ec8SAlexander V. Chernikov ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 248668394ec8SAlexander V. Chernikov uint64_t pflags) 248768394ec8SAlexander V. Chernikov { 24880bce0c23SAlexander V. Chernikov struct mod_item *mi; 248968394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 249068394ec8SAlexander V. Chernikov void *old_ptr; 249168394ec8SAlexander V. Chernikov 24920bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 249368394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 249468394ec8SAlexander V. Chernikov 249568394ec8SAlexander V. Chernikov old_ptr = icfg->main_ptr; 249668394ec8SAlexander V. Chernikov icfg->main_ptr = mi->main_ptr; 249768394ec8SAlexander V. Chernikov icfg->size = mi->size; 249868394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 249968394ec8SAlexander V. Chernikov 250068394ec8SAlexander V. Chernikov mi->main_ptr = old_ptr; 250168394ec8SAlexander V. Chernikov } 250268394ec8SAlexander V. Chernikov 250368394ec8SAlexander V. Chernikov /* 250468394ec8SAlexander V. Chernikov * Free unneded array. 250568394ec8SAlexander V. Chernikov */ 250668394ec8SAlexander V. Chernikov static void 250768394ec8SAlexander V. Chernikov ta_flush_mod_ifidx(void *ta_buf) 250868394ec8SAlexander V. Chernikov { 25090bce0c23SAlexander V. Chernikov struct mod_item *mi; 251068394ec8SAlexander V. Chernikov 25110bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 251268394ec8SAlexander V. Chernikov if (mi->main_ptr != NULL) 251368394ec8SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 25149f7d47b0SAlexander V. Chernikov } 25159f7d47b0SAlexander V. Chernikov 25169f7d47b0SAlexander V. Chernikov static int 251768394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e, 251881d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 25199f7d47b0SAlexander V. Chernikov { 252068394ec8SAlexander V. Chernikov struct ifentry *ife; 25219f7d47b0SAlexander V. Chernikov 252268394ec8SAlexander V. Chernikov ife = (struct ifentry *)e; 252368394ec8SAlexander V. Chernikov 252481d3153dSAlexander V. Chernikov tent->masklen = 8 * IF_NAMESIZE; 252568394ec8SAlexander V. Chernikov memcpy(&tent->k, ife->no.name, IF_NAMESIZE); 25260cba2b28SAlexander V. Chernikov tent->v.kidx = ife->value; 25279f7d47b0SAlexander V. Chernikov 25289f7d47b0SAlexander V. Chernikov return (0); 25299f7d47b0SAlexander V. Chernikov } 25309f7d47b0SAlexander V. Chernikov 253181d3153dSAlexander V. Chernikov static int 2532914bffb6SAlexander V. Chernikov ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, 2533914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 253481d3153dSAlexander V. Chernikov { 253568394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 253668394ec8SAlexander V. Chernikov struct ifentry *ife; 253768394ec8SAlexander V. Chernikov char *ifname; 253881d3153dSAlexander V. Chernikov 253968394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 2540914bffb6SAlexander V. Chernikov ifname = tent->k.iface; 254181d3153dSAlexander V. Chernikov 254268394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 254368394ec8SAlexander V. Chernikov return (EINVAL); 254481d3153dSAlexander V. Chernikov 254568394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 254668394ec8SAlexander V. Chernikov 254768394ec8SAlexander V. Chernikov if (ife != NULL) { 254868394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(ta_state, ti, ife, tent); 254981d3153dSAlexander V. Chernikov return (0); 255081d3153dSAlexander V. Chernikov } 255181d3153dSAlexander V. Chernikov 255281d3153dSAlexander V. Chernikov return (ENOENT); 255381d3153dSAlexander V. Chernikov } 255481d3153dSAlexander V. Chernikov 255568394ec8SAlexander V. Chernikov struct wa_ifidx { 255668394ec8SAlexander V. Chernikov ta_foreach_f *f; 255768394ec8SAlexander V. Chernikov void *arg; 255868394ec8SAlexander V. Chernikov }; 255968394ec8SAlexander V. Chernikov 2560b309f085SAndrey V. Elsukov static int 256168394ec8SAlexander V. Chernikov foreach_ifidx(struct namedobj_instance *ii, struct named_object *no, 25629f7d47b0SAlexander V. Chernikov void *arg) 25639f7d47b0SAlexander V. Chernikov { 256468394ec8SAlexander V. Chernikov struct ifentry *ife; 256568394ec8SAlexander V. Chernikov struct wa_ifidx *wa; 25669f7d47b0SAlexander V. Chernikov 256768394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 256868394ec8SAlexander V. Chernikov wa = (struct wa_ifidx *)arg; 256968394ec8SAlexander V. Chernikov 257068394ec8SAlexander V. Chernikov wa->f(ife, wa->arg); 2571b309f085SAndrey V. Elsukov return (0); 25729f7d47b0SAlexander V. Chernikov } 25739f7d47b0SAlexander V. Chernikov 257468394ec8SAlexander V. Chernikov static void 257568394ec8SAlexander V. Chernikov ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f, 257668394ec8SAlexander V. Chernikov void *arg) 257768394ec8SAlexander V. Chernikov { 257868394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 257968394ec8SAlexander V. Chernikov struct wa_ifidx wa; 258068394ec8SAlexander V. Chernikov 258168394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 258268394ec8SAlexander V. Chernikov 258368394ec8SAlexander V. Chernikov wa.f = f; 258468394ec8SAlexander V. Chernikov wa.arg = arg; 258568394ec8SAlexander V. Chernikov 258668394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa); 258768394ec8SAlexander V. Chernikov } 258868394ec8SAlexander V. Chernikov 258974b941f0SAlexander V. Chernikov struct table_algo iface_idx = { 2590adea6201SAlexander V. Chernikov .name = "iface:array", 25919d099b4fSAlexander V. Chernikov .type = IPFW_TABLE_INTERFACE, 259257a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 259357a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_ifidx), 259468394ec8SAlexander V. Chernikov .init = ta_init_ifidx, 259568394ec8SAlexander V. Chernikov .destroy = ta_destroy_ifidx, 259668394ec8SAlexander V. Chernikov .prepare_add = ta_prepare_add_ifidx, 259768394ec8SAlexander V. Chernikov .prepare_del = ta_prepare_del_ifidx, 259868394ec8SAlexander V. Chernikov .add = ta_add_ifidx, 259968394ec8SAlexander V. Chernikov .del = ta_del_ifidx, 260068394ec8SAlexander V. Chernikov .flush_entry = ta_flush_ifidx_entry, 260168394ec8SAlexander V. Chernikov .foreach = ta_foreach_ifidx, 260268394ec8SAlexander V. Chernikov .dump_tentry = ta_dump_ifidx_tentry, 260368394ec8SAlexander V. Chernikov .find_tentry = ta_find_ifidx_tentry, 26045f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_ifidx_tinfo, 2605301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_ifidx, 260668394ec8SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_ifidx, 260768394ec8SAlexander V. Chernikov .fill_mod = ta_fill_mod_ifidx, 260868394ec8SAlexander V. Chernikov .modify = ta_modify_ifidx, 260968394ec8SAlexander V. Chernikov .flush_mod = ta_flush_mod_ifidx, 261068394ec8SAlexander V. Chernikov .change_ti = ta_change_ti_ifidx, 26119f7d47b0SAlexander V. Chernikov }; 26129f7d47b0SAlexander V. Chernikov 2613b23d5de9SAlexander V. Chernikov /* 2614b23d5de9SAlexander V. Chernikov * Number array cmds. 2615b23d5de9SAlexander V. Chernikov * 2616b23d5de9SAlexander V. Chernikov * Implementation: 2617b23d5de9SAlexander V. Chernikov * 2618b23d5de9SAlexander V. Chernikov * Runtime part: 2619b23d5de9SAlexander V. Chernikov * - sorted array of "struct numarray" pointed by ti->state. 2620b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to NUMARRAY_CHUNK. 2621b23d5de9SAlexander V. Chernikov * - current array size is stored in ti->data 2622b23d5de9SAlexander V. Chernikov * 2623b23d5de9SAlexander V. Chernikov */ 2624b23d5de9SAlexander V. Chernikov 2625b23d5de9SAlexander V. Chernikov struct numarray { 2626b23d5de9SAlexander V. Chernikov uint32_t number; 2627b23d5de9SAlexander V. Chernikov uint32_t value; 2628b23d5de9SAlexander V. Chernikov }; 2629b23d5de9SAlexander V. Chernikov 2630b23d5de9SAlexander V. Chernikov struct numarray_cfg { 2631b23d5de9SAlexander V. Chernikov void *main_ptr; 2632b23d5de9SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 2633b23d5de9SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 2634b23d5de9SAlexander V. Chernikov }; 2635b23d5de9SAlexander V. Chernikov 26360bce0c23SAlexander V. Chernikov struct ta_buf_numarray 26370bce0c23SAlexander V. Chernikov { 26380bce0c23SAlexander V. Chernikov struct numarray na; 26390bce0c23SAlexander V. Chernikov }; 2640b23d5de9SAlexander V. Chernikov 2641b23d5de9SAlexander V. Chernikov int compare_numarray(const void *k, const void *v); 26429fe15d06SAlexander V. Chernikov static struct numarray *numarray_find(struct table_info *ti, void *key); 26439fe15d06SAlexander V. Chernikov static int ta_lookup_numarray(struct table_info *ti, void *key, 26449fe15d06SAlexander V. Chernikov uint32_t keylen, uint32_t *val); 26459fe15d06SAlexander V. Chernikov static int ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, 26469fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 26479fe15d06SAlexander V. Chernikov static void ta_destroy_numarray(void *ta_state, struct table_info *ti); 26489fe15d06SAlexander V. Chernikov static void ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, 26499fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 26509fe15d06SAlexander V. Chernikov static int ta_prepare_add_numarray(struct ip_fw_chain *ch, 26519fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf); 26529fe15d06SAlexander V. Chernikov static int ta_add_numarray(void *ta_state, struct table_info *ti, 26539fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 26549fe15d06SAlexander V. Chernikov static int ta_del_numarray(void *ta_state, struct table_info *ti, 26559fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 26569fe15d06SAlexander V. Chernikov static void ta_flush_numarray_entry(struct ip_fw_chain *ch, 26579fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf); 26589fe15d06SAlexander V. Chernikov static int ta_need_modify_numarray(void *ta_state, struct table_info *ti, 26599fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 26609fe15d06SAlexander V. Chernikov static int ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags); 26619fe15d06SAlexander V. Chernikov static int ta_fill_mod_numarray(void *ta_state, struct table_info *ti, 26629fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t *pflags); 26639fe15d06SAlexander V. Chernikov static void ta_modify_numarray(void *ta_state, struct table_info *ti, 26649fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t pflags); 26659fe15d06SAlexander V. Chernikov static void ta_flush_mod_numarray(void *ta_buf); 26669fe15d06SAlexander V. Chernikov static int ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, 26679fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent); 26689fe15d06SAlexander V. Chernikov static int ta_find_numarray_tentry(void *ta_state, struct table_info *ti, 26699fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 26709fe15d06SAlexander V. Chernikov static void ta_foreach_numarray(void *ta_state, struct table_info *ti, 26719fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 2672b23d5de9SAlexander V. Chernikov 2673b23d5de9SAlexander V. Chernikov int 2674b23d5de9SAlexander V. Chernikov compare_numarray(const void *k, const void *v) 2675b23d5de9SAlexander V. Chernikov { 2676d4e1b515SAlexander V. Chernikov const struct numarray *na; 2677b23d5de9SAlexander V. Chernikov uint32_t key; 2678b23d5de9SAlexander V. Chernikov 2679d4e1b515SAlexander V. Chernikov key = *((const uint32_t *)k); 2680d4e1b515SAlexander V. Chernikov na = (const struct numarray *)v; 2681b23d5de9SAlexander V. Chernikov 2682b23d5de9SAlexander V. Chernikov if (key < na->number) 2683b23d5de9SAlexander V. Chernikov return (-1); 2684b23d5de9SAlexander V. Chernikov else if (key > na->number) 2685b23d5de9SAlexander V. Chernikov return (1); 2686b23d5de9SAlexander V. Chernikov 2687b23d5de9SAlexander V. Chernikov return (0); 2688b23d5de9SAlexander V. Chernikov } 2689b23d5de9SAlexander V. Chernikov 2690b23d5de9SAlexander V. Chernikov static struct numarray * 2691b23d5de9SAlexander V. Chernikov numarray_find(struct table_info *ti, void *key) 2692b23d5de9SAlexander V. Chernikov { 2693b23d5de9SAlexander V. Chernikov struct numarray *ri; 2694b23d5de9SAlexander V. Chernikov 2695b23d5de9SAlexander V. Chernikov ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray), 2696194df014SAndrey V. Elsukov compare_numarray); 2697b23d5de9SAlexander V. Chernikov 2698b23d5de9SAlexander V. Chernikov return (ri); 2699b23d5de9SAlexander V. Chernikov } 2700b23d5de9SAlexander V. Chernikov 2701b23d5de9SAlexander V. Chernikov static int 2702b23d5de9SAlexander V. Chernikov ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen, 2703b23d5de9SAlexander V. Chernikov uint32_t *val) 2704b23d5de9SAlexander V. Chernikov { 2705b23d5de9SAlexander V. Chernikov struct numarray *ri; 2706b23d5de9SAlexander V. Chernikov 2707b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, key); 2708b23d5de9SAlexander V. Chernikov 2709b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2710b23d5de9SAlexander V. Chernikov *val = ri->value; 2711b23d5de9SAlexander V. Chernikov return (1); 2712b23d5de9SAlexander V. Chernikov } 2713b23d5de9SAlexander V. Chernikov 2714b23d5de9SAlexander V. Chernikov return (0); 2715b23d5de9SAlexander V. Chernikov } 2716b23d5de9SAlexander V. Chernikov 2717b23d5de9SAlexander V. Chernikov static int 2718b23d5de9SAlexander V. Chernikov ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 2719914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 2720b23d5de9SAlexander V. Chernikov { 2721b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2722b23d5de9SAlexander V. Chernikov 2723b23d5de9SAlexander V. Chernikov cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO); 2724b23d5de9SAlexander V. Chernikov 27250bce0c23SAlexander V. Chernikov cfg->size = 16; 2726b23d5de9SAlexander V. Chernikov cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW, 2727b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO); 2728b23d5de9SAlexander V. Chernikov 2729b23d5de9SAlexander V. Chernikov *ta_state = cfg; 2730b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr; 2731b23d5de9SAlexander V. Chernikov ti->lookup = ta_lookup_numarray; 2732b23d5de9SAlexander V. Chernikov 2733b23d5de9SAlexander V. Chernikov return (0); 2734b23d5de9SAlexander V. Chernikov } 2735b23d5de9SAlexander V. Chernikov 2736b23d5de9SAlexander V. Chernikov /* 2737b23d5de9SAlexander V. Chernikov * Destroys table @ti 2738b23d5de9SAlexander V. Chernikov */ 2739b23d5de9SAlexander V. Chernikov static void 2740b23d5de9SAlexander V. Chernikov ta_destroy_numarray(void *ta_state, struct table_info *ti) 2741b23d5de9SAlexander V. Chernikov { 2742b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2743b23d5de9SAlexander V. Chernikov 2744b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2745b23d5de9SAlexander V. Chernikov 2746b23d5de9SAlexander V. Chernikov if (cfg->main_ptr != NULL) 2747b23d5de9SAlexander V. Chernikov free(cfg->main_ptr, M_IPFW); 2748b23d5de9SAlexander V. Chernikov 2749b23d5de9SAlexander V. Chernikov free(cfg, M_IPFW); 2750b23d5de9SAlexander V. Chernikov } 2751b23d5de9SAlexander V. Chernikov 2752b23d5de9SAlexander V. Chernikov /* 27535f379342SAlexander V. Chernikov * Provide algo-specific table info 27545f379342SAlexander V. Chernikov */ 27555f379342SAlexander V. Chernikov static void 27565f379342SAlexander V. Chernikov ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 27575f379342SAlexander V. Chernikov { 27585f379342SAlexander V. Chernikov struct numarray_cfg *cfg; 27595f379342SAlexander V. Chernikov 27605f379342SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 27615f379342SAlexander V. Chernikov 27625f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_ARRAY; 27635f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 27645f379342SAlexander V. Chernikov tinfo->count4 = cfg->used; 27655f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct numarray); 27665f379342SAlexander V. Chernikov } 27675f379342SAlexander V. Chernikov 27685f379342SAlexander V. Chernikov /* 2769b23d5de9SAlexander V. Chernikov * Prepare for addition/deletion to an array. 2770b23d5de9SAlexander V. Chernikov */ 2771b23d5de9SAlexander V. Chernikov static int 2772b23d5de9SAlexander V. Chernikov ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei, 2773b23d5de9SAlexander V. Chernikov void *ta_buf) 2774b23d5de9SAlexander V. Chernikov { 2775b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2776b23d5de9SAlexander V. Chernikov 2777b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2778b23d5de9SAlexander V. Chernikov 2779b23d5de9SAlexander V. Chernikov tb->na.number = *((uint32_t *)tei->paddr); 2780b23d5de9SAlexander V. Chernikov 2781b23d5de9SAlexander V. Chernikov return (0); 2782b23d5de9SAlexander V. Chernikov } 2783b23d5de9SAlexander V. Chernikov 2784b23d5de9SAlexander V. Chernikov static int 2785b23d5de9SAlexander V. Chernikov ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2786b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 2787b23d5de9SAlexander V. Chernikov { 2788b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2789b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2790b23d5de9SAlexander V. Chernikov struct numarray *ri; 279160a28b09SMateusz Guzik int res __diagused; 2792648e8380SAlexander V. Chernikov uint32_t value; 2793b23d5de9SAlexander V. Chernikov 2794b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2795b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2796b23d5de9SAlexander V. Chernikov 279713263632SAlexander V. Chernikov /* Read current value from @tei */ 279813263632SAlexander V. Chernikov tb->na.value = tei->value; 279913263632SAlexander V. Chernikov 2800b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number); 2801b23d5de9SAlexander V. Chernikov 2802b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2803b23d5de9SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 2804b23d5de9SAlexander V. Chernikov return (EEXIST); 2805b23d5de9SAlexander V. Chernikov 2806648e8380SAlexander V. Chernikov /* Exchange values between ri and @tei */ 2807648e8380SAlexander V. Chernikov value = ri->value; 2808648e8380SAlexander V. Chernikov ri->value = tei->value; 2809648e8380SAlexander V. Chernikov tei->value = value; 2810b23d5de9SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 2811b23d5de9SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 2812b23d5de9SAlexander V. Chernikov *pnum = 0; 2813b23d5de9SAlexander V. Chernikov return (0); 2814b23d5de9SAlexander V. Chernikov } 2815b23d5de9SAlexander V. Chernikov 28164c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 28174c0c07a5SAlexander V. Chernikov return (EFBIG); 28184c0c07a5SAlexander V. Chernikov 2819b23d5de9SAlexander V. Chernikov res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used, 2820b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray); 2821b23d5de9SAlexander V. Chernikov 2822b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %d already exists", tb->na.number)); 2823b23d5de9SAlexander V. Chernikov cfg->used++; 2824b23d5de9SAlexander V. Chernikov ti->data = cfg->used; 2825b23d5de9SAlexander V. Chernikov *pnum = 1; 2826b23d5de9SAlexander V. Chernikov 2827b23d5de9SAlexander V. Chernikov return (0); 2828b23d5de9SAlexander V. Chernikov } 2829b23d5de9SAlexander V. Chernikov 2830b23d5de9SAlexander V. Chernikov /* 2831b23d5de9SAlexander V. Chernikov * Remove key from both configuration list and 2832b23d5de9SAlexander V. Chernikov * runtime array. Removed interface notification. 2833b23d5de9SAlexander V. Chernikov */ 2834b23d5de9SAlexander V. Chernikov static int 2835b23d5de9SAlexander V. Chernikov ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei, 2836b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 2837b23d5de9SAlexander V. Chernikov { 2838b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2839b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb; 2840b23d5de9SAlexander V. Chernikov struct numarray *ri; 284160a28b09SMateusz Guzik int res __diagused; 2842b23d5de9SAlexander V. Chernikov 2843b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf; 2844b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2845b23d5de9SAlexander V. Chernikov 2846b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number); 2847b23d5de9SAlexander V. Chernikov if (ri == NULL) 2848b23d5de9SAlexander V. Chernikov return (ENOENT); 2849b23d5de9SAlexander V. Chernikov 2850648e8380SAlexander V. Chernikov tei->value = ri->value; 2851648e8380SAlexander V. Chernikov 2852b23d5de9SAlexander V. Chernikov res = bdel(&tb->na.number, cfg->main_ptr, cfg->used, 2853b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray); 2854b23d5de9SAlexander V. Chernikov 2855b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %u does not exist", tb->na.number)); 2856b23d5de9SAlexander V. Chernikov cfg->used--; 2857b23d5de9SAlexander V. Chernikov ti->data = cfg->used; 2858b23d5de9SAlexander V. Chernikov *pnum = 1; 2859b23d5de9SAlexander V. Chernikov 2860b23d5de9SAlexander V. Chernikov return (0); 2861b23d5de9SAlexander V. Chernikov } 2862b23d5de9SAlexander V. Chernikov 2863b23d5de9SAlexander V. Chernikov static void 2864b23d5de9SAlexander V. Chernikov ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 2865b23d5de9SAlexander V. Chernikov void *ta_buf) 2866b23d5de9SAlexander V. Chernikov { 2867b23d5de9SAlexander V. Chernikov 28680bce0c23SAlexander V. Chernikov /* We don't have any state, do nothing */ 2869b23d5de9SAlexander V. Chernikov } 2870b23d5de9SAlexander V. Chernikov 2871b23d5de9SAlexander V. Chernikov /* 2872b23d5de9SAlexander V. Chernikov * Table growing callbacks. 2873b23d5de9SAlexander V. Chernikov */ 2874b23d5de9SAlexander V. Chernikov 2875b6ee846eSAlexander V. Chernikov static int 2876301290bcSAlexander V. Chernikov ta_need_modify_numarray(void *ta_state, struct table_info *ti, uint32_t count, 2877b6ee846eSAlexander V. Chernikov uint64_t *pflags) 2878b6ee846eSAlexander V. Chernikov { 2879b6ee846eSAlexander V. Chernikov struct numarray_cfg *cfg; 28800bce0c23SAlexander V. Chernikov size_t size; 2881b6ee846eSAlexander V. Chernikov 2882b6ee846eSAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2883b6ee846eSAlexander V. Chernikov 28840bce0c23SAlexander V. Chernikov size = cfg->size; 28850bce0c23SAlexander V. Chernikov while (size < cfg->used + count) 28860bce0c23SAlexander V. Chernikov size *= 2; 28870bce0c23SAlexander V. Chernikov 28880bce0c23SAlexander V. Chernikov if (size != cfg->size) { 28890bce0c23SAlexander V. Chernikov *pflags = size; 2890301290bcSAlexander V. Chernikov return (1); 2891b6ee846eSAlexander V. Chernikov } 2892b6ee846eSAlexander V. Chernikov 2893301290bcSAlexander V. Chernikov return (0); 2894b6ee846eSAlexander V. Chernikov } 2895b6ee846eSAlexander V. Chernikov 2896b23d5de9SAlexander V. Chernikov /* 2897b6ee846eSAlexander V. Chernikov * Allocate new, larger runtime array. 2898b23d5de9SAlexander V. Chernikov */ 2899b23d5de9SAlexander V. Chernikov static int 2900b23d5de9SAlexander V. Chernikov ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags) 2901b23d5de9SAlexander V. Chernikov { 2902b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2903b23d5de9SAlexander V. Chernikov 2904b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2905b23d5de9SAlexander V. Chernikov 2906b23d5de9SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 2907b23d5de9SAlexander V. Chernikov mi->size = *pflags; 2908b23d5de9SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW, 2909b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO); 2910b23d5de9SAlexander V. Chernikov 2911b23d5de9SAlexander V. Chernikov return (0); 2912b23d5de9SAlexander V. Chernikov } 2913b23d5de9SAlexander V. Chernikov 2914b23d5de9SAlexander V. Chernikov /* 2915b23d5de9SAlexander V. Chernikov * Copy data from old runtime array to new one. 2916b23d5de9SAlexander V. Chernikov */ 2917b23d5de9SAlexander V. Chernikov static int 2918b23d5de9SAlexander V. Chernikov ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf, 2919b23d5de9SAlexander V. Chernikov uint64_t *pflags) 2920b23d5de9SAlexander V. Chernikov { 2921b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2922b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2923b23d5de9SAlexander V. Chernikov 2924b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2925b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2926b23d5de9SAlexander V. Chernikov 2927b23d5de9SAlexander V. Chernikov /* Check if we still need to grow array */ 2928b23d5de9SAlexander V. Chernikov if (cfg->size >= mi->size) { 2929b23d5de9SAlexander V. Chernikov *pflags = 0; 2930b23d5de9SAlexander V. Chernikov return (0); 2931b23d5de9SAlexander V. Chernikov } 2932b23d5de9SAlexander V. Chernikov 2933b23d5de9SAlexander V. Chernikov memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray)); 2934b23d5de9SAlexander V. Chernikov 2935b23d5de9SAlexander V. Chernikov return (0); 2936b23d5de9SAlexander V. Chernikov } 2937b23d5de9SAlexander V. Chernikov 2938b23d5de9SAlexander V. Chernikov /* 2939b23d5de9SAlexander V. Chernikov * Switch old & new arrays. 2940b23d5de9SAlexander V. Chernikov */ 2941301290bcSAlexander V. Chernikov static void 2942b23d5de9SAlexander V. Chernikov ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf, 2943b23d5de9SAlexander V. Chernikov uint64_t pflags) 2944b23d5de9SAlexander V. Chernikov { 2945b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2946b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 2947b23d5de9SAlexander V. Chernikov void *old_ptr; 2948b23d5de9SAlexander V. Chernikov 2949b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2950b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 2951b23d5de9SAlexander V. Chernikov 2952b23d5de9SAlexander V. Chernikov old_ptr = cfg->main_ptr; 2953b23d5de9SAlexander V. Chernikov cfg->main_ptr = mi->main_ptr; 2954b23d5de9SAlexander V. Chernikov cfg->size = mi->size; 2955b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr; 2956b23d5de9SAlexander V. Chernikov 2957b23d5de9SAlexander V. Chernikov mi->main_ptr = old_ptr; 2958b23d5de9SAlexander V. Chernikov } 2959b23d5de9SAlexander V. Chernikov 2960b23d5de9SAlexander V. Chernikov /* 2961b23d5de9SAlexander V. Chernikov * Free unneded array. 2962b23d5de9SAlexander V. Chernikov */ 2963b23d5de9SAlexander V. Chernikov static void 2964b23d5de9SAlexander V. Chernikov ta_flush_mod_numarray(void *ta_buf) 2965b23d5de9SAlexander V. Chernikov { 2966b23d5de9SAlexander V. Chernikov struct mod_item *mi; 2967b23d5de9SAlexander V. Chernikov 2968b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 2969b23d5de9SAlexander V. Chernikov if (mi->main_ptr != NULL) 2970b23d5de9SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 2971b23d5de9SAlexander V. Chernikov } 2972b23d5de9SAlexander V. Chernikov 2973b23d5de9SAlexander V. Chernikov static int 2974b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e, 2975b23d5de9SAlexander V. Chernikov ipfw_obj_tentry *tent) 2976b23d5de9SAlexander V. Chernikov { 2977b23d5de9SAlexander V. Chernikov struct numarray *na; 2978b23d5de9SAlexander V. Chernikov 2979b23d5de9SAlexander V. Chernikov na = (struct numarray *)e; 2980b23d5de9SAlexander V. Chernikov 2981b23d5de9SAlexander V. Chernikov tent->k.key = na->number; 29820cba2b28SAlexander V. Chernikov tent->v.kidx = na->value; 2983b23d5de9SAlexander V. Chernikov 2984b23d5de9SAlexander V. Chernikov return (0); 2985b23d5de9SAlexander V. Chernikov } 2986b23d5de9SAlexander V. Chernikov 2987b23d5de9SAlexander V. Chernikov static int 2988914bffb6SAlexander V. Chernikov ta_find_numarray_tentry(void *ta_state, struct table_info *ti, 2989914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 2990b23d5de9SAlexander V. Chernikov { 2991b23d5de9SAlexander V. Chernikov struct numarray *ri; 2992b23d5de9SAlexander V. Chernikov 2993914bffb6SAlexander V. Chernikov ri = numarray_find(ti, &tent->k.key); 2994b23d5de9SAlexander V. Chernikov 2995b23d5de9SAlexander V. Chernikov if (ri != NULL) { 2996b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(ta_state, ti, ri, tent); 2997b23d5de9SAlexander V. Chernikov return (0); 2998b23d5de9SAlexander V. Chernikov } 2999b23d5de9SAlexander V. Chernikov 3000b23d5de9SAlexander V. Chernikov return (ENOENT); 3001b23d5de9SAlexander V. Chernikov } 3002b23d5de9SAlexander V. Chernikov 3003b23d5de9SAlexander V. Chernikov static void 3004b23d5de9SAlexander V. Chernikov ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f, 3005b23d5de9SAlexander V. Chernikov void *arg) 3006b23d5de9SAlexander V. Chernikov { 3007b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg; 3008b23d5de9SAlexander V. Chernikov struct numarray *array; 3009b23d5de9SAlexander V. Chernikov int i; 3010b23d5de9SAlexander V. Chernikov 3011b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state; 3012b23d5de9SAlexander V. Chernikov array = cfg->main_ptr; 3013b23d5de9SAlexander V. Chernikov 3014b23d5de9SAlexander V. Chernikov for (i = 0; i < cfg->used; i++) 3015b23d5de9SAlexander V. Chernikov f(&array[i], arg); 3016b23d5de9SAlexander V. Chernikov } 3017b23d5de9SAlexander V. Chernikov 3018b23d5de9SAlexander V. Chernikov struct table_algo number_array = { 3019b23d5de9SAlexander V. Chernikov .name = "number:array", 3020b23d5de9SAlexander V. Chernikov .type = IPFW_TABLE_NUMBER, 302157a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_numarray), 3022b23d5de9SAlexander V. Chernikov .init = ta_init_numarray, 3023b23d5de9SAlexander V. Chernikov .destroy = ta_destroy_numarray, 3024b23d5de9SAlexander V. Chernikov .prepare_add = ta_prepare_add_numarray, 3025b23d5de9SAlexander V. Chernikov .prepare_del = ta_prepare_add_numarray, 3026b23d5de9SAlexander V. Chernikov .add = ta_add_numarray, 3027b23d5de9SAlexander V. Chernikov .del = ta_del_numarray, 3028b23d5de9SAlexander V. Chernikov .flush_entry = ta_flush_numarray_entry, 3029b23d5de9SAlexander V. Chernikov .foreach = ta_foreach_numarray, 3030b23d5de9SAlexander V. Chernikov .dump_tentry = ta_dump_numarray_tentry, 3031b23d5de9SAlexander V. Chernikov .find_tentry = ta_find_numarray_tentry, 30325f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_numarray_tinfo, 3033301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_numarray, 3034b23d5de9SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_numarray, 3035b23d5de9SAlexander V. Chernikov .fill_mod = ta_fill_mod_numarray, 3036b23d5de9SAlexander V. Chernikov .modify = ta_modify_numarray, 3037b23d5de9SAlexander V. Chernikov .flush_mod = ta_flush_mod_numarray, 3038b23d5de9SAlexander V. Chernikov }; 3039b23d5de9SAlexander V. Chernikov 3040914bffb6SAlexander V. Chernikov /* 3041914bffb6SAlexander V. Chernikov * flow:hash cmds 3042914bffb6SAlexander V. Chernikov * 3043914bffb6SAlexander V. Chernikov * 3044914bffb6SAlexander V. Chernikov * ti->data: 3045914bffb6SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6] 3046914bffb6SAlexander V. Chernikov * [ 8][ 8[ 8][ 8] 3047914bffb6SAlexander V. Chernikov * 3048914bffb6SAlexander V. Chernikov * inv.mask4: 32 - mask 3049914bffb6SAlexander V. Chernikov * inv.mask6: 3050914bffb6SAlexander V. Chernikov * 1) _slow lookup: mask 3051914bffb6SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8 3052914bffb6SAlexander V. Chernikov * 3) _64: 8 3053914bffb6SAlexander V. Chernikov * 3054914bffb6SAlexander V. Chernikov * 3055914bffb6SAlexander V. Chernikov * pflags: 3056b6ee846eSAlexander V. Chernikov * [hsize4][hsize6] 3057b6ee846eSAlexander V. Chernikov * [ 16][ 16] 3058914bffb6SAlexander V. Chernikov */ 3059914bffb6SAlexander V. Chernikov 3060914bffb6SAlexander V. Chernikov struct fhashentry; 3061914bffb6SAlexander V. Chernikov 3062914bffb6SAlexander V. Chernikov SLIST_HEAD(fhashbhead, fhashentry); 3063914bffb6SAlexander V. Chernikov 3064914bffb6SAlexander V. Chernikov struct fhashentry { 3065914bffb6SAlexander V. Chernikov SLIST_ENTRY(fhashentry) next; 3066914bffb6SAlexander V. Chernikov uint8_t af; 3067914bffb6SAlexander V. Chernikov uint8_t proto; 3068914bffb6SAlexander V. Chernikov uint16_t spare0; 3069914bffb6SAlexander V. Chernikov uint16_t dport; 3070914bffb6SAlexander V. Chernikov uint16_t sport; 3071914bffb6SAlexander V. Chernikov uint32_t value; 3072914bffb6SAlexander V. Chernikov uint32_t spare1; 3073914bffb6SAlexander V. Chernikov }; 3074914bffb6SAlexander V. Chernikov 3075914bffb6SAlexander V. Chernikov struct fhashentry4 { 3076914bffb6SAlexander V. Chernikov struct fhashentry e; 3077914bffb6SAlexander V. Chernikov struct in_addr dip; 3078914bffb6SAlexander V. Chernikov struct in_addr sip; 3079914bffb6SAlexander V. Chernikov }; 3080914bffb6SAlexander V. Chernikov 3081914bffb6SAlexander V. Chernikov struct fhashentry6 { 3082914bffb6SAlexander V. Chernikov struct fhashentry e; 3083914bffb6SAlexander V. Chernikov struct in6_addr dip6; 3084914bffb6SAlexander V. Chernikov struct in6_addr sip6; 3085914bffb6SAlexander V. Chernikov }; 3086914bffb6SAlexander V. Chernikov 3087914bffb6SAlexander V. Chernikov struct fhash_cfg { 3088914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3089914bffb6SAlexander V. Chernikov size_t size; 3090914bffb6SAlexander V. Chernikov size_t items; 3091914bffb6SAlexander V. Chernikov struct fhashentry4 fe4; 3092914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 3093914bffb6SAlexander V. Chernikov }; 3094914bffb6SAlexander V. Chernikov 30953fe2ef91SAlexander V. Chernikov struct ta_buf_fhash { 30960bce0c23SAlexander V. Chernikov void *ent_ptr; 30970bce0c23SAlexander V. Chernikov struct fhashentry6 fe6; 30980bce0c23SAlexander V. Chernikov }; 30990bce0c23SAlexander V. Chernikov 31009fe15d06SAlexander V. Chernikov static __inline int cmp_flow_ent(struct fhashentry *a, 31019fe15d06SAlexander V. Chernikov struct fhashentry *b, size_t sz); 31029fe15d06SAlexander V. Chernikov static __inline uint32_t hash_flow4(struct fhashentry4 *f, int hsize); 31039fe15d06SAlexander V. Chernikov static __inline uint32_t hash_flow6(struct fhashentry6 *f, int hsize); 31049fe15d06SAlexander V. Chernikov static uint32_t hash_flow_ent(struct fhashentry *ent, uint32_t size); 31059fe15d06SAlexander V. Chernikov static int ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen, 31069fe15d06SAlexander V. Chernikov uint32_t *val); 31079fe15d06SAlexander V. Chernikov static int ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, 31089fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 31099fe15d06SAlexander V. Chernikov static void ta_destroy_fhash(void *ta_state, struct table_info *ti); 31109fe15d06SAlexander V. Chernikov static void ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, 31119fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 31129fe15d06SAlexander V. Chernikov static int ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, 31139fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent); 31149fe15d06SAlexander V. Chernikov static int tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent); 31159fe15d06SAlexander V. Chernikov static int ta_find_fhash_tentry(void *ta_state, struct table_info *ti, 31169fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 31179fe15d06SAlexander V. Chernikov static void ta_foreach_fhash(void *ta_state, struct table_info *ti, 31189fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 31199fe15d06SAlexander V. Chernikov static int ta_prepare_add_fhash(struct ip_fw_chain *ch, 31209fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf); 31219fe15d06SAlexander V. Chernikov static int ta_add_fhash(void *ta_state, struct table_info *ti, 31229fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 31239fe15d06SAlexander V. Chernikov static int ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 31249fe15d06SAlexander V. Chernikov void *ta_buf); 31259fe15d06SAlexander V. Chernikov static int ta_del_fhash(void *ta_state, struct table_info *ti, 31269fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 31279fe15d06SAlexander V. Chernikov static void ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 31289fe15d06SAlexander V. Chernikov void *ta_buf); 31299fe15d06SAlexander V. Chernikov static int ta_need_modify_fhash(void *ta_state, struct table_info *ti, 31309fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags); 31319fe15d06SAlexander V. Chernikov static int ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags); 31329fe15d06SAlexander V. Chernikov static int ta_fill_mod_fhash(void *ta_state, struct table_info *ti, 31339fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t *pflags); 31349fe15d06SAlexander V. Chernikov static void ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 31359fe15d06SAlexander V. Chernikov uint64_t pflags); 31369fe15d06SAlexander V. Chernikov static void ta_flush_mod_fhash(void *ta_buf); 31379fe15d06SAlexander V. Chernikov 3138914bffb6SAlexander V. Chernikov static __inline int 3139914bffb6SAlexander V. Chernikov cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz) 3140914bffb6SAlexander V. Chernikov { 3141914bffb6SAlexander V. Chernikov uint64_t *ka, *kb; 3142914bffb6SAlexander V. Chernikov 3143914bffb6SAlexander V. Chernikov ka = (uint64_t *)(&a->next + 1); 3144914bffb6SAlexander V. Chernikov kb = (uint64_t *)(&b->next + 1); 3145914bffb6SAlexander V. Chernikov 3146914bffb6SAlexander V. Chernikov if (*ka == *kb && (memcmp(a + 1, b + 1, sz) == 0)) 3147914bffb6SAlexander V. Chernikov return (1); 3148914bffb6SAlexander V. Chernikov 3149914bffb6SAlexander V. Chernikov return (0); 3150914bffb6SAlexander V. Chernikov } 3151914bffb6SAlexander V. Chernikov 3152914bffb6SAlexander V. Chernikov static __inline uint32_t 3153914bffb6SAlexander V. Chernikov hash_flow4(struct fhashentry4 *f, int hsize) 3154914bffb6SAlexander V. Chernikov { 3155914bffb6SAlexander V. Chernikov uint32_t i; 3156914bffb6SAlexander V. Chernikov 3157914bffb6SAlexander V. Chernikov i = (f->dip.s_addr) ^ (f->sip.s_addr) ^ (f->e.dport) ^ (f->e.sport); 3158914bffb6SAlexander V. Chernikov 3159914bffb6SAlexander V. Chernikov return (i % (hsize - 1)); 3160914bffb6SAlexander V. Chernikov } 3161914bffb6SAlexander V. Chernikov 3162914bffb6SAlexander V. Chernikov static __inline uint32_t 3163914bffb6SAlexander V. Chernikov hash_flow6(struct fhashentry6 *f, int hsize) 3164914bffb6SAlexander V. Chernikov { 3165914bffb6SAlexander V. Chernikov uint32_t i; 3166914bffb6SAlexander V. Chernikov 3167914bffb6SAlexander V. Chernikov i = (f->dip6.__u6_addr.__u6_addr32[2]) ^ 3168914bffb6SAlexander V. Chernikov (f->dip6.__u6_addr.__u6_addr32[3]) ^ 3169914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[2]) ^ 3170914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[3]) ^ 3171914bffb6SAlexander V. Chernikov (f->e.dport) ^ (f->e.sport); 3172914bffb6SAlexander V. Chernikov 3173914bffb6SAlexander V. Chernikov return (i % (hsize - 1)); 3174914bffb6SAlexander V. Chernikov } 3175914bffb6SAlexander V. Chernikov 3176914bffb6SAlexander V. Chernikov static uint32_t 3177914bffb6SAlexander V. Chernikov hash_flow_ent(struct fhashentry *ent, uint32_t size) 3178914bffb6SAlexander V. Chernikov { 3179914bffb6SAlexander V. Chernikov uint32_t hash; 3180914bffb6SAlexander V. Chernikov 3181914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) { 3182914bffb6SAlexander V. Chernikov hash = hash_flow4((struct fhashentry4 *)ent, size); 3183914bffb6SAlexander V. Chernikov } else { 3184914bffb6SAlexander V. Chernikov hash = hash_flow6((struct fhashentry6 *)ent, size); 3185914bffb6SAlexander V. Chernikov } 3186914bffb6SAlexander V. Chernikov 3187914bffb6SAlexander V. Chernikov return (hash); 3188914bffb6SAlexander V. Chernikov } 3189914bffb6SAlexander V. Chernikov 3190914bffb6SAlexander V. Chernikov static int 3191914bffb6SAlexander V. Chernikov ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen, 3192914bffb6SAlexander V. Chernikov uint32_t *val) 3193914bffb6SAlexander V. Chernikov { 3194914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3195914bffb6SAlexander V. Chernikov struct fhashentry *ent; 3196914bffb6SAlexander V. Chernikov struct fhashentry4 *m4; 3197914bffb6SAlexander V. Chernikov struct ipfw_flow_id *id; 319847cb0632SEugene Grosbein uint32_t hsize; 319947cb0632SEugene Grosbein uint16_t hash; 3200914bffb6SAlexander V. Chernikov 3201914bffb6SAlexander V. Chernikov id = (struct ipfw_flow_id *)key; 3202914bffb6SAlexander V. Chernikov head = (struct fhashbhead *)ti->state; 3203914bffb6SAlexander V. Chernikov hsize = ti->data; 3204914bffb6SAlexander V. Chernikov m4 = (struct fhashentry4 *)ti->xstate; 3205914bffb6SAlexander V. Chernikov 3206914bffb6SAlexander V. Chernikov if (id->addr_type == 4) { 3207914bffb6SAlexander V. Chernikov struct fhashentry4 f; 3208914bffb6SAlexander V. Chernikov 3209914bffb6SAlexander V. Chernikov /* Copy hash mask */ 3210914bffb6SAlexander V. Chernikov f = *m4; 3211914bffb6SAlexander V. Chernikov 3212914bffb6SAlexander V. Chernikov f.dip.s_addr &= id->dst_ip; 3213914bffb6SAlexander V. Chernikov f.sip.s_addr &= id->src_ip; 3214914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port; 3215914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port; 3216914bffb6SAlexander V. Chernikov f.e.proto &= id->proto; 3217914bffb6SAlexander V. Chernikov hash = hash_flow4(&f, hsize); 3218914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 3219914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) { 3220914bffb6SAlexander V. Chernikov *val = ent->value; 3221914bffb6SAlexander V. Chernikov return (1); 3222914bffb6SAlexander V. Chernikov } 3223914bffb6SAlexander V. Chernikov } 3224914bffb6SAlexander V. Chernikov } else if (id->addr_type == 6) { 3225914bffb6SAlexander V. Chernikov struct fhashentry6 f; 3226914bffb6SAlexander V. Chernikov uint64_t *fp, *idp; 3227914bffb6SAlexander V. Chernikov 3228914bffb6SAlexander V. Chernikov /* Copy hash mask */ 3229914bffb6SAlexander V. Chernikov f = *((struct fhashentry6 *)(m4 + 1)); 3230914bffb6SAlexander V. Chernikov 3231914bffb6SAlexander V. Chernikov /* Handle lack of __u6_addr.__u6_addr64 */ 3232914bffb6SAlexander V. Chernikov fp = (uint64_t *)&f.dip6; 3233914bffb6SAlexander V. Chernikov idp = (uint64_t *)&id->dst_ip6; 3234914bffb6SAlexander V. Chernikov /* src IPv6 is stored after dst IPv6 */ 3235914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 3236914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 3237914bffb6SAlexander V. Chernikov *fp++ &= *idp++; 3238914bffb6SAlexander V. Chernikov *fp &= *idp; 3239914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port; 3240914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port; 3241914bffb6SAlexander V. Chernikov f.e.proto &= id->proto; 3242914bffb6SAlexander V. Chernikov hash = hash_flow6(&f, hsize); 3243914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) { 3244914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) { 3245914bffb6SAlexander V. Chernikov *val = ent->value; 3246914bffb6SAlexander V. Chernikov return (1); 3247914bffb6SAlexander V. Chernikov } 3248914bffb6SAlexander V. Chernikov } 3249914bffb6SAlexander V. Chernikov } 3250914bffb6SAlexander V. Chernikov 3251914bffb6SAlexander V. Chernikov return (0); 3252914bffb6SAlexander V. Chernikov } 3253914bffb6SAlexander V. Chernikov 3254914bffb6SAlexander V. Chernikov /* 3255914bffb6SAlexander V. Chernikov * New table. 3256914bffb6SAlexander V. Chernikov */ 3257914bffb6SAlexander V. Chernikov static int 3258914bffb6SAlexander V. Chernikov ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 3259914bffb6SAlexander V. Chernikov char *data, uint8_t tflags) 3260914bffb6SAlexander V. Chernikov { 3261914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3262914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 3263914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 3264d821d364SPedro F. Giffuni u_int i; 3265914bffb6SAlexander V. Chernikov 3266914bffb6SAlexander V. Chernikov cfg = malloc(sizeof(struct fhash_cfg), M_IPFW, M_WAITOK | M_ZERO); 3267914bffb6SAlexander V. Chernikov 3268914bffb6SAlexander V. Chernikov cfg->size = 512; 3269914bffb6SAlexander V. Chernikov 3270914bffb6SAlexander V. Chernikov cfg->head = malloc(sizeof(struct fhashbhead) * cfg->size, M_IPFW, 3271914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO); 3272914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 3273914bffb6SAlexander V. Chernikov SLIST_INIT(&cfg->head[i]); 3274914bffb6SAlexander V. Chernikov 3275914bffb6SAlexander V. Chernikov /* Fill in fe masks based on @tflags */ 3276914bffb6SAlexander V. Chernikov fe4 = &cfg->fe4; 3277914bffb6SAlexander V. Chernikov fe6 = &cfg->fe6; 3278914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCIP) { 3279914bffb6SAlexander V. Chernikov memset(&fe4->sip, 0xFF, sizeof(fe4->sip)); 3280914bffb6SAlexander V. Chernikov memset(&fe6->sip6, 0xFF, sizeof(fe6->sip6)); 3281914bffb6SAlexander V. Chernikov } 3282914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTIP) { 3283914bffb6SAlexander V. Chernikov memset(&fe4->dip, 0xFF, sizeof(fe4->dip)); 3284914bffb6SAlexander V. Chernikov memset(&fe6->dip6, 0xFF, sizeof(fe6->dip6)); 3285914bffb6SAlexander V. Chernikov } 3286914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCPORT) { 3287914bffb6SAlexander V. Chernikov memset(&fe4->e.sport, 0xFF, sizeof(fe4->e.sport)); 3288914bffb6SAlexander V. Chernikov memset(&fe6->e.sport, 0xFF, sizeof(fe6->e.sport)); 3289914bffb6SAlexander V. Chernikov } 3290914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTPORT) { 3291914bffb6SAlexander V. Chernikov memset(&fe4->e.dport, 0xFF, sizeof(fe4->e.dport)); 3292914bffb6SAlexander V. Chernikov memset(&fe6->e.dport, 0xFF, sizeof(fe6->e.dport)); 3293914bffb6SAlexander V. Chernikov } 3294914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_PROTO) { 3295914bffb6SAlexander V. Chernikov memset(&fe4->e.proto, 0xFF, sizeof(fe4->e.proto)); 3296914bffb6SAlexander V. Chernikov memset(&fe6->e.proto, 0xFF, sizeof(fe6->e.proto)); 3297914bffb6SAlexander V. Chernikov } 3298914bffb6SAlexander V. Chernikov 3299914bffb6SAlexander V. Chernikov fe4->e.af = AF_INET; 3300914bffb6SAlexander V. Chernikov fe6->e.af = AF_INET6; 3301914bffb6SAlexander V. Chernikov 3302914bffb6SAlexander V. Chernikov *ta_state = cfg; 3303914bffb6SAlexander V. Chernikov ti->state = cfg->head; 3304914bffb6SAlexander V. Chernikov ti->xstate = &cfg->fe4; 3305914bffb6SAlexander V. Chernikov ti->data = cfg->size; 3306914bffb6SAlexander V. Chernikov ti->lookup = ta_lookup_fhash; 3307914bffb6SAlexander V. Chernikov 3308914bffb6SAlexander V. Chernikov return (0); 3309914bffb6SAlexander V. Chernikov } 3310914bffb6SAlexander V. Chernikov 3311914bffb6SAlexander V. Chernikov static void 3312914bffb6SAlexander V. Chernikov ta_destroy_fhash(void *ta_state, struct table_info *ti) 3313914bffb6SAlexander V. Chernikov { 3314914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3315914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3316914bffb6SAlexander V. Chernikov int i; 3317914bffb6SAlexander V. Chernikov 3318914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3319914bffb6SAlexander V. Chernikov 3320914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 3321914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) 3322914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL); 3323914bffb6SAlexander V. Chernikov 3324914bffb6SAlexander V. Chernikov free(cfg->head, M_IPFW); 3325914bffb6SAlexander V. Chernikov free(cfg, M_IPFW); 3326914bffb6SAlexander V. Chernikov } 3327914bffb6SAlexander V. Chernikov 33285f379342SAlexander V. Chernikov /* 33295f379342SAlexander V. Chernikov * Provide algo-specific table info 33305f379342SAlexander V. Chernikov */ 33315f379342SAlexander V. Chernikov static void 33325f379342SAlexander V. Chernikov ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 33335f379342SAlexander V. Chernikov { 33345f379342SAlexander V. Chernikov struct fhash_cfg *cfg; 33355f379342SAlexander V. Chernikov 33365f379342SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 33375f379342SAlexander V. Chernikov 33385f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFITEM; 33395f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_HASH; 33405f379342SAlexander V. Chernikov tinfo->size4 = cfg->size; 33415f379342SAlexander V. Chernikov tinfo->count4 = cfg->items; 33425f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct fhashentry4); 33435f379342SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct fhashentry6); 33445f379342SAlexander V. Chernikov } 33455f379342SAlexander V. Chernikov 3346914bffb6SAlexander V. Chernikov static int 3347914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e, 3348914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 3349914bffb6SAlexander V. Chernikov { 3350914bffb6SAlexander V. Chernikov struct fhashentry *ent; 3351914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 33529fe15d06SAlexander V. Chernikov #ifdef INET6 3353914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 33549fe15d06SAlexander V. Chernikov #endif 3355914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 3356914bffb6SAlexander V. Chernikov 3357914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)e; 3358914bffb6SAlexander V. Chernikov tfe = &tent->k.flow; 3359914bffb6SAlexander V. Chernikov 3360914bffb6SAlexander V. Chernikov tfe->af = ent->af; 3361914bffb6SAlexander V. Chernikov tfe->proto = ent->proto; 3362914bffb6SAlexander V. Chernikov tfe->dport = htons(ent->dport); 3363914bffb6SAlexander V. Chernikov tfe->sport = htons(ent->sport); 33640cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value; 3365914bffb6SAlexander V. Chernikov tent->subtype = ent->af; 3366914bffb6SAlexander V. Chernikov 3367914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) { 3368914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent; 3369914bffb6SAlexander V. Chernikov tfe->a.a4.sip.s_addr = htonl(fe4->sip.s_addr); 3370914bffb6SAlexander V. Chernikov tfe->a.a4.dip.s_addr = htonl(fe4->dip.s_addr); 3371914bffb6SAlexander V. Chernikov tent->masklen = 32; 3372914bffb6SAlexander V. Chernikov #ifdef INET6 3373914bffb6SAlexander V. Chernikov } else { 3374914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent; 3375914bffb6SAlexander V. Chernikov tfe->a.a6.sip6 = fe6->sip6; 3376914bffb6SAlexander V. Chernikov tfe->a.a6.dip6 = fe6->dip6; 3377914bffb6SAlexander V. Chernikov tent->masklen = 128; 3378914bffb6SAlexander V. Chernikov #endif 3379914bffb6SAlexander V. Chernikov } 3380914bffb6SAlexander V. Chernikov 3381914bffb6SAlexander V. Chernikov return (0); 3382914bffb6SAlexander V. Chernikov } 3383914bffb6SAlexander V. Chernikov 3384914bffb6SAlexander V. Chernikov static int 3385914bffb6SAlexander V. Chernikov tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent) 3386914bffb6SAlexander V. Chernikov { 3387d699ee2dSAlexander V. Chernikov #ifdef INET 3388914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4; 3389d699ee2dSAlexander V. Chernikov #endif 3390d699ee2dSAlexander V. Chernikov #ifdef INET6 3391914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6; 3392d699ee2dSAlexander V. Chernikov #endif 3393914bffb6SAlexander V. Chernikov struct tflow_entry *tfe; 3394914bffb6SAlexander V. Chernikov 3395914bffb6SAlexander V. Chernikov tfe = (struct tflow_entry *)tei->paddr; 3396914bffb6SAlexander V. Chernikov 3397914bffb6SAlexander V. Chernikov ent->af = tei->subtype; 3398914bffb6SAlexander V. Chernikov ent->proto = tfe->proto; 3399914bffb6SAlexander V. Chernikov ent->dport = ntohs(tfe->dport); 3400914bffb6SAlexander V. Chernikov ent->sport = ntohs(tfe->sport); 3401914bffb6SAlexander V. Chernikov 3402914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) { 3403914bffb6SAlexander V. Chernikov #ifdef INET 3404914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent; 3405914bffb6SAlexander V. Chernikov fe4->sip.s_addr = ntohl(tfe->a.a4.sip.s_addr); 3406914bffb6SAlexander V. Chernikov fe4->dip.s_addr = ntohl(tfe->a.a4.dip.s_addr); 3407914bffb6SAlexander V. Chernikov #endif 3408914bffb6SAlexander V. Chernikov #ifdef INET6 3409914bffb6SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 3410914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent; 3411914bffb6SAlexander V. Chernikov fe6->sip6 = tfe->a.a6.sip6; 3412914bffb6SAlexander V. Chernikov fe6->dip6 = tfe->a.a6.dip6; 3413914bffb6SAlexander V. Chernikov #endif 3414914bffb6SAlexander V. Chernikov } else { 3415914bffb6SAlexander V. Chernikov /* Unknown CIDR type */ 3416914bffb6SAlexander V. Chernikov return (EINVAL); 3417914bffb6SAlexander V. Chernikov } 3418914bffb6SAlexander V. Chernikov 3419914bffb6SAlexander V. Chernikov return (0); 3420914bffb6SAlexander V. Chernikov } 3421914bffb6SAlexander V. Chernikov 3422914bffb6SAlexander V. Chernikov static int 3423914bffb6SAlexander V. Chernikov ta_find_fhash_tentry(void *ta_state, struct table_info *ti, 3424914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent) 3425914bffb6SAlexander V. Chernikov { 3426914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3427914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3428914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3429914bffb6SAlexander V. Chernikov struct fhashentry6 fe6; 3430914bffb6SAlexander V. Chernikov struct tentry_info tei; 3431914bffb6SAlexander V. Chernikov int error; 3432914bffb6SAlexander V. Chernikov uint32_t hash; 3433914bffb6SAlexander V. Chernikov size_t sz; 3434914bffb6SAlexander V. Chernikov 3435914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3436914bffb6SAlexander V. Chernikov 3437914bffb6SAlexander V. Chernikov ent = &fe6.e; 3438914bffb6SAlexander V. Chernikov 3439914bffb6SAlexander V. Chernikov memset(&fe6, 0, sizeof(fe6)); 3440914bffb6SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 3441914bffb6SAlexander V. Chernikov 3442914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.flow; 3443914bffb6SAlexander V. Chernikov tei.subtype = tent->subtype; 3444914bffb6SAlexander V. Chernikov 3445914bffb6SAlexander V. Chernikov if ((error = tei_to_fhash_ent(&tei, ent)) != 0) 3446914bffb6SAlexander V. Chernikov return (error); 3447914bffb6SAlexander V. Chernikov 3448914bffb6SAlexander V. Chernikov head = cfg->head; 3449914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3450914bffb6SAlexander V. Chernikov 3451914bffb6SAlexander V. Chernikov if (tei.subtype == AF_INET) 3452914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3453914bffb6SAlexander V. Chernikov else 3454914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3455914bffb6SAlexander V. Chernikov 3456914bffb6SAlexander V. Chernikov /* Check for existence */ 3457914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3458914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 3459914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(ta_state, ti, tmp, tent); 3460914bffb6SAlexander V. Chernikov return (0); 3461914bffb6SAlexander V. Chernikov } 3462914bffb6SAlexander V. Chernikov } 3463914bffb6SAlexander V. Chernikov 3464914bffb6SAlexander V. Chernikov return (ENOENT); 3465914bffb6SAlexander V. Chernikov } 3466914bffb6SAlexander V. Chernikov 3467914bffb6SAlexander V. Chernikov static void 3468914bffb6SAlexander V. Chernikov ta_foreach_fhash(void *ta_state, struct table_info *ti, ta_foreach_f *f, 3469914bffb6SAlexander V. Chernikov void *arg) 3470914bffb6SAlexander V. Chernikov { 3471914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3472914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3473914bffb6SAlexander V. Chernikov int i; 3474914bffb6SAlexander V. Chernikov 3475914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3476914bffb6SAlexander V. Chernikov 3477914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++) 3478914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next) 3479914bffb6SAlexander V. Chernikov f(ent, arg); 3480914bffb6SAlexander V. Chernikov } 3481914bffb6SAlexander V. Chernikov 3482914bffb6SAlexander V. Chernikov static int 3483914bffb6SAlexander V. Chernikov ta_prepare_add_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 3484914bffb6SAlexander V. Chernikov void *ta_buf) 3485914bffb6SAlexander V. Chernikov { 3486914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3487914bffb6SAlexander V. Chernikov struct fhashentry *ent; 3488914bffb6SAlexander V. Chernikov size_t sz; 3489914bffb6SAlexander V. Chernikov int error; 3490914bffb6SAlexander V. Chernikov 3491914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3492914bffb6SAlexander V. Chernikov 3493914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3494914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry4); 3495914bffb6SAlexander V. Chernikov else if (tei->subtype == AF_INET6) 3496914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry6); 3497914bffb6SAlexander V. Chernikov else 3498914bffb6SAlexander V. Chernikov return (EINVAL); 3499914bffb6SAlexander V. Chernikov 3500914bffb6SAlexander V. Chernikov ent = malloc(sz, M_IPFW_TBL, M_WAITOK | M_ZERO); 3501914bffb6SAlexander V. Chernikov 3502914bffb6SAlexander V. Chernikov error = tei_to_fhash_ent(tei, ent); 3503914bffb6SAlexander V. Chernikov if (error != 0) { 3504914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL); 3505914bffb6SAlexander V. Chernikov return (error); 3506914bffb6SAlexander V. Chernikov } 3507914bffb6SAlexander V. Chernikov tb->ent_ptr = ent; 3508914bffb6SAlexander V. Chernikov 3509914bffb6SAlexander V. Chernikov return (0); 3510914bffb6SAlexander V. Chernikov } 3511914bffb6SAlexander V. Chernikov 3512914bffb6SAlexander V. Chernikov static int 3513914bffb6SAlexander V. Chernikov ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 3514b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 3515914bffb6SAlexander V. Chernikov { 3516914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3517914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3518914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3519914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3520914bffb6SAlexander V. Chernikov int exists; 3521648e8380SAlexander V. Chernikov uint32_t hash, value; 3522914bffb6SAlexander V. Chernikov size_t sz; 3523914bffb6SAlexander V. Chernikov 3524914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3525914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3526914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)tb->ent_ptr; 3527914bffb6SAlexander V. Chernikov exists = 0; 3528914bffb6SAlexander V. Chernikov 352913263632SAlexander V. Chernikov /* Read current value from @tei */ 353013263632SAlexander V. Chernikov ent->value = tei->value; 353113263632SAlexander V. Chernikov 3532914bffb6SAlexander V. Chernikov head = cfg->head; 3533914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3534914bffb6SAlexander V. Chernikov 3535914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3536914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3537914bffb6SAlexander V. Chernikov else 3538914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3539914bffb6SAlexander V. Chernikov 3540914bffb6SAlexander V. Chernikov /* Check for existence */ 3541914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3542914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) { 3543914bffb6SAlexander V. Chernikov exists = 1; 3544914bffb6SAlexander V. Chernikov break; 3545914bffb6SAlexander V. Chernikov } 3546914bffb6SAlexander V. Chernikov } 3547914bffb6SAlexander V. Chernikov 3548914bffb6SAlexander V. Chernikov if (exists == 1) { 3549914bffb6SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 3550914bffb6SAlexander V. Chernikov return (EEXIST); 3551914bffb6SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 3552648e8380SAlexander V. Chernikov /* Exchange values between tmp and @tei */ 3553648e8380SAlexander V. Chernikov value = tmp->value; 3554914bffb6SAlexander V. Chernikov tmp->value = tei->value; 3555648e8380SAlexander V. Chernikov tei->value = value; 3556914bffb6SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 3557914bffb6SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 3558914bffb6SAlexander V. Chernikov *pnum = 0; 3559914bffb6SAlexander V. Chernikov } else { 35604c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 35614c0c07a5SAlexander V. Chernikov return (EFBIG); 35624c0c07a5SAlexander V. Chernikov 3563914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next); 3564914bffb6SAlexander V. Chernikov tb->ent_ptr = NULL; 3565914bffb6SAlexander V. Chernikov *pnum = 1; 3566914bffb6SAlexander V. Chernikov 3567914bffb6SAlexander V. Chernikov /* Update counters and check if we need to grow hash */ 3568914bffb6SAlexander V. Chernikov cfg->items++; 3569914bffb6SAlexander V. Chernikov } 3570914bffb6SAlexander V. Chernikov 3571914bffb6SAlexander V. Chernikov return (0); 3572914bffb6SAlexander V. Chernikov } 3573914bffb6SAlexander V. Chernikov 3574914bffb6SAlexander V. Chernikov static int 3575914bffb6SAlexander V. Chernikov ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 3576914bffb6SAlexander V. Chernikov void *ta_buf) 3577914bffb6SAlexander V. Chernikov { 3578914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3579914bffb6SAlexander V. Chernikov 3580914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3581914bffb6SAlexander V. Chernikov 3582914bffb6SAlexander V. Chernikov return (tei_to_fhash_ent(tei, &tb->fe6.e)); 3583914bffb6SAlexander V. Chernikov } 3584914bffb6SAlexander V. Chernikov 3585914bffb6SAlexander V. Chernikov static int 3586914bffb6SAlexander V. Chernikov ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei, 3587b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum) 3588914bffb6SAlexander V. Chernikov { 3589914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3590914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3591914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp; 3592914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3593914bffb6SAlexander V. Chernikov uint32_t hash; 3594914bffb6SAlexander V. Chernikov size_t sz; 3595914bffb6SAlexander V. Chernikov 3596914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3597914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3598914bffb6SAlexander V. Chernikov ent = &tb->fe6.e; 3599914bffb6SAlexander V. Chernikov 3600914bffb6SAlexander V. Chernikov head = cfg->head; 3601914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size); 3602914bffb6SAlexander V. Chernikov 3603914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) 3604914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr); 3605914bffb6SAlexander V. Chernikov else 3606914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr); 3607914bffb6SAlexander V. Chernikov 3608914bffb6SAlexander V. Chernikov /* Check for existence */ 3609914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) { 3610648e8380SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) == 0) 3611648e8380SAlexander V. Chernikov continue; 3612648e8380SAlexander V. Chernikov 3613914bffb6SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, fhashentry, next); 3614648e8380SAlexander V. Chernikov tei->value = tmp->value; 3615914bffb6SAlexander V. Chernikov *pnum = 1; 3616914bffb6SAlexander V. Chernikov cfg->items--; 3617648e8380SAlexander V. Chernikov tb->ent_ptr = tmp; 3618914bffb6SAlexander V. Chernikov return (0); 3619914bffb6SAlexander V. Chernikov } 3620914bffb6SAlexander V. Chernikov 3621914bffb6SAlexander V. Chernikov return (ENOENT); 3622914bffb6SAlexander V. Chernikov } 3623914bffb6SAlexander V. Chernikov 3624914bffb6SAlexander V. Chernikov static void 3625914bffb6SAlexander V. Chernikov ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 3626914bffb6SAlexander V. Chernikov void *ta_buf) 3627914bffb6SAlexander V. Chernikov { 3628914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb; 3629914bffb6SAlexander V. Chernikov 3630914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf; 3631914bffb6SAlexander V. Chernikov 3632914bffb6SAlexander V. Chernikov if (tb->ent_ptr != NULL) 3633914bffb6SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 3634914bffb6SAlexander V. Chernikov } 3635914bffb6SAlexander V. Chernikov 3636914bffb6SAlexander V. Chernikov /* 3637914bffb6SAlexander V. Chernikov * Hash growing callbacks. 3638914bffb6SAlexander V. Chernikov */ 3639914bffb6SAlexander V. Chernikov 3640b6ee846eSAlexander V. Chernikov static int 3641301290bcSAlexander V. Chernikov ta_need_modify_fhash(void *ta_state, struct table_info *ti, uint32_t count, 3642b6ee846eSAlexander V. Chernikov uint64_t *pflags) 3643b6ee846eSAlexander V. Chernikov { 3644b6ee846eSAlexander V. Chernikov struct fhash_cfg *cfg; 3645b6ee846eSAlexander V. Chernikov 3646b6ee846eSAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3647b6ee846eSAlexander V. Chernikov 3648b6ee846eSAlexander V. Chernikov if (cfg->items > cfg->size && cfg->size < 65536) { 3649b6ee846eSAlexander V. Chernikov *pflags = cfg->size * 2; 3650301290bcSAlexander V. Chernikov return (1); 3651b6ee846eSAlexander V. Chernikov } 3652b6ee846eSAlexander V. Chernikov 3653301290bcSAlexander V. Chernikov return (0); 3654b6ee846eSAlexander V. Chernikov } 3655b6ee846eSAlexander V. Chernikov 3656914bffb6SAlexander V. Chernikov /* 3657914bffb6SAlexander V. Chernikov * Allocate new, larger fhash. 3658914bffb6SAlexander V. Chernikov */ 3659914bffb6SAlexander V. Chernikov static int 3660914bffb6SAlexander V. Chernikov ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags) 3661914bffb6SAlexander V. Chernikov { 3662914bffb6SAlexander V. Chernikov struct mod_item *mi; 3663914bffb6SAlexander V. Chernikov struct fhashbhead *head; 3664d821d364SPedro F. Giffuni u_int i; 3665914bffb6SAlexander V. Chernikov 3666914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3667914bffb6SAlexander V. Chernikov 3668914bffb6SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item)); 3669914bffb6SAlexander V. Chernikov mi->size = *pflags; 3670914bffb6SAlexander V. Chernikov head = malloc(sizeof(struct fhashbhead) * mi->size, M_IPFW, 3671914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO); 3672914bffb6SAlexander V. Chernikov for (i = 0; i < mi->size; i++) 3673914bffb6SAlexander V. Chernikov SLIST_INIT(&head[i]); 3674914bffb6SAlexander V. Chernikov 3675914bffb6SAlexander V. Chernikov mi->main_ptr = head; 3676914bffb6SAlexander V. Chernikov 3677914bffb6SAlexander V. Chernikov return (0); 3678914bffb6SAlexander V. Chernikov } 3679914bffb6SAlexander V. Chernikov 3680914bffb6SAlexander V. Chernikov /* 3681914bffb6SAlexander V. Chernikov * Copy data from old runtime array to new one. 3682914bffb6SAlexander V. Chernikov */ 3683914bffb6SAlexander V. Chernikov static int 3684914bffb6SAlexander V. Chernikov ta_fill_mod_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3685914bffb6SAlexander V. Chernikov uint64_t *pflags) 3686914bffb6SAlexander V. Chernikov { 3687914bffb6SAlexander V. Chernikov 3688914bffb6SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */ 3689914bffb6SAlexander V. Chernikov return (0); 3690914bffb6SAlexander V. Chernikov } 3691914bffb6SAlexander V. Chernikov 3692914bffb6SAlexander V. Chernikov /* 3693914bffb6SAlexander V. Chernikov * Switch old & new arrays. 3694914bffb6SAlexander V. Chernikov */ 3695301290bcSAlexander V. Chernikov static void 3696914bffb6SAlexander V. Chernikov ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3697914bffb6SAlexander V. Chernikov uint64_t pflags) 3698914bffb6SAlexander V. Chernikov { 3699914bffb6SAlexander V. Chernikov struct mod_item *mi; 3700914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg; 3701914bffb6SAlexander V. Chernikov struct fhashbhead *old_head, *new_head; 3702914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next; 3703914bffb6SAlexander V. Chernikov int i; 3704914bffb6SAlexander V. Chernikov uint32_t nhash; 3705914bffb6SAlexander V. Chernikov size_t old_size; 3706914bffb6SAlexander V. Chernikov 3707914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3708914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state; 3709914bffb6SAlexander V. Chernikov 3710914bffb6SAlexander V. Chernikov old_size = cfg->size; 3711914bffb6SAlexander V. Chernikov old_head = ti->state; 3712914bffb6SAlexander V. Chernikov 3713914bffb6SAlexander V. Chernikov new_head = (struct fhashbhead *)mi->main_ptr; 3714914bffb6SAlexander V. Chernikov for (i = 0; i < old_size; i++) { 3715914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) { 3716914bffb6SAlexander V. Chernikov nhash = hash_flow_ent(ent, mi->size); 3717914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next); 3718914bffb6SAlexander V. Chernikov } 3719914bffb6SAlexander V. Chernikov } 3720914bffb6SAlexander V. Chernikov 3721914bffb6SAlexander V. Chernikov ti->state = new_head; 3722914bffb6SAlexander V. Chernikov ti->data = mi->size; 3723914bffb6SAlexander V. Chernikov cfg->head = new_head; 3724914bffb6SAlexander V. Chernikov cfg->size = mi->size; 3725914bffb6SAlexander V. Chernikov 3726914bffb6SAlexander V. Chernikov mi->main_ptr = old_head; 3727914bffb6SAlexander V. Chernikov } 3728914bffb6SAlexander V. Chernikov 3729914bffb6SAlexander V. Chernikov /* 3730914bffb6SAlexander V. Chernikov * Free unneded array. 3731914bffb6SAlexander V. Chernikov */ 3732914bffb6SAlexander V. Chernikov static void 3733914bffb6SAlexander V. Chernikov ta_flush_mod_fhash(void *ta_buf) 3734914bffb6SAlexander V. Chernikov { 3735914bffb6SAlexander V. Chernikov struct mod_item *mi; 3736914bffb6SAlexander V. Chernikov 3737914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf; 3738914bffb6SAlexander V. Chernikov if (mi->main_ptr != NULL) 3739914bffb6SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 3740914bffb6SAlexander V. Chernikov } 3741914bffb6SAlexander V. Chernikov 3742914bffb6SAlexander V. Chernikov struct table_algo flow_hash = { 3743914bffb6SAlexander V. Chernikov .name = "flow:hash", 3744914bffb6SAlexander V. Chernikov .type = IPFW_TABLE_FLOW, 374557a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT, 374657a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_fhash), 3747914bffb6SAlexander V. Chernikov .init = ta_init_fhash, 3748914bffb6SAlexander V. Chernikov .destroy = ta_destroy_fhash, 3749914bffb6SAlexander V. Chernikov .prepare_add = ta_prepare_add_fhash, 3750914bffb6SAlexander V. Chernikov .prepare_del = ta_prepare_del_fhash, 3751914bffb6SAlexander V. Chernikov .add = ta_add_fhash, 3752914bffb6SAlexander V. Chernikov .del = ta_del_fhash, 3753914bffb6SAlexander V. Chernikov .flush_entry = ta_flush_fhash_entry, 3754914bffb6SAlexander V. Chernikov .foreach = ta_foreach_fhash, 3755914bffb6SAlexander V. Chernikov .dump_tentry = ta_dump_fhash_tentry, 3756914bffb6SAlexander V. Chernikov .find_tentry = ta_find_fhash_tentry, 37575f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_fhash_tinfo, 3758301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_fhash, 3759914bffb6SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_fhash, 3760914bffb6SAlexander V. Chernikov .fill_mod = ta_fill_mod_fhash, 3761914bffb6SAlexander V. Chernikov .modify = ta_modify_fhash, 3762914bffb6SAlexander V. Chernikov .flush_mod = ta_flush_mod_fhash, 3763914bffb6SAlexander V. Chernikov }; 37643fe2ef91SAlexander V. Chernikov 3765d3b00c08SAlexander V. Chernikov /* 3766d3b00c08SAlexander V. Chernikov * Kernel fibs bindings. 3767d3b00c08SAlexander V. Chernikov * 3768d3b00c08SAlexander V. Chernikov * Implementation: 3769d3b00c08SAlexander V. Chernikov * 3770d3b00c08SAlexander V. Chernikov * Runtime part: 3771d3b00c08SAlexander V. Chernikov * - fully relies on route API 3772d3b00c08SAlexander V. Chernikov * - fib number is stored in ti->data 3773d3b00c08SAlexander V. Chernikov * 3774d3b00c08SAlexander V. Chernikov */ 3775d3b00c08SAlexander V. Chernikov 37769fe15d06SAlexander V. Chernikov static int ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen, 37779fe15d06SAlexander V. Chernikov uint32_t *val); 37789fe15d06SAlexander V. Chernikov static int kfib_parse_opts(int *pfib, char *data); 37799fe15d06SAlexander V. Chernikov static void ta_print_kfib_config(void *ta_state, struct table_info *ti, 37809fe15d06SAlexander V. Chernikov char *buf, size_t bufsize); 37819fe15d06SAlexander V. Chernikov static int ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, 37829fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags); 37839fe15d06SAlexander V. Chernikov static void ta_destroy_kfib(void *ta_state, struct table_info *ti); 37849fe15d06SAlexander V. Chernikov static void ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, 37859fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo); 37869fe15d06SAlexander V. Chernikov static int ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e, 37879fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 37884451d893SAlexander V. Chernikov static int ta_dump_kfib_tentry_int(int familt, const struct rtentry *rt, 37894451d893SAlexander V. Chernikov ipfw_obj_tentry *tent); 37909fe15d06SAlexander V. Chernikov static int ta_find_kfib_tentry(void *ta_state, struct table_info *ti, 37919fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent); 37929fe15d06SAlexander V. Chernikov static void ta_foreach_kfib(void *ta_state, struct table_info *ti, 37939fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg); 37949fe15d06SAlexander V. Chernikov 3795d3b00c08SAlexander V. Chernikov static int 3796d3b00c08SAlexander V. Chernikov ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen, 3797d3b00c08SAlexander V. Chernikov uint32_t *val) 3798d3b00c08SAlexander V. Chernikov { 3799004d3e30SAlexander V. Chernikov #ifdef INET 3800004d3e30SAlexander V. Chernikov struct in_addr in; 3801004d3e30SAlexander V. Chernikov #endif 3802004d3e30SAlexander V. Chernikov int error; 3803d3b00c08SAlexander V. Chernikov 380489fc126aSAlexander V. Chernikov error = ENOENT; 3805004d3e30SAlexander V. Chernikov #ifdef INET 3806004d3e30SAlexander V. Chernikov if (keylen == 4) { 3807004d3e30SAlexander V. Chernikov in.s_addr = *(in_addr_t *)key; 38086ad7446cSAlexander V. Chernikov NET_EPOCH_ASSERT(); 38096ad7446cSAlexander V. Chernikov error = fib4_lookup(ti->data, in, 0, NHR_NONE, 0) != NULL; 3810004d3e30SAlexander V. Chernikov } 3811004d3e30SAlexander V. Chernikov #endif 3812004d3e30SAlexander V. Chernikov #ifdef INET6 3813004d3e30SAlexander V. Chernikov if (keylen == 6) 38146ad7446cSAlexander V. Chernikov error = fib6_lookup(ti->data, (struct in6_addr *)key, 38156ad7446cSAlexander V. Chernikov 0, NHR_NONE, 0) != NULL; 3816004d3e30SAlexander V. Chernikov #endif 3817004d3e30SAlexander V. Chernikov 3818004d3e30SAlexander V. Chernikov if (error != 0) 3819d3b00c08SAlexander V. Chernikov return (0); 3820d3b00c08SAlexander V. Chernikov 3821d3b00c08SAlexander V. Chernikov *val = 0; 3822d3b00c08SAlexander V. Chernikov 3823d3b00c08SAlexander V. Chernikov return (1); 3824d3b00c08SAlexander V. Chernikov } 3825d3b00c08SAlexander V. Chernikov 3826d3b00c08SAlexander V. Chernikov /* Parse 'fib=%d' */ 3827d3b00c08SAlexander V. Chernikov static int 3828d3b00c08SAlexander V. Chernikov kfib_parse_opts(int *pfib, char *data) 3829d3b00c08SAlexander V. Chernikov { 3830d3b00c08SAlexander V. Chernikov char *pdel, *pend, *s; 3831d3b00c08SAlexander V. Chernikov int fibnum; 3832d3b00c08SAlexander V. Chernikov 3833d3b00c08SAlexander V. Chernikov if (data == NULL) 3834d3b00c08SAlexander V. Chernikov return (0); 3835d3b00c08SAlexander V. Chernikov if ((pdel = strchr(data, ' ')) == NULL) 3836d3b00c08SAlexander V. Chernikov return (0); 3837d3b00c08SAlexander V. Chernikov while (*pdel == ' ') 3838d3b00c08SAlexander V. Chernikov pdel++; 3839d3b00c08SAlexander V. Chernikov if (strncmp(pdel, "fib=", 4) != 0) 3840d3b00c08SAlexander V. Chernikov return (EINVAL); 3841d3b00c08SAlexander V. Chernikov if ((s = strchr(pdel, ' ')) != NULL) 3842d3b00c08SAlexander V. Chernikov *s++ = '\0'; 3843d3b00c08SAlexander V. Chernikov 3844d3b00c08SAlexander V. Chernikov pdel += 4; 3845d3b00c08SAlexander V. Chernikov /* Need \d+ */ 3846d3b00c08SAlexander V. Chernikov fibnum = strtol(pdel, &pend, 10); 3847d3b00c08SAlexander V. Chernikov if (*pend != '\0') 3848d3b00c08SAlexander V. Chernikov return (EINVAL); 3849d3b00c08SAlexander V. Chernikov 3850d3b00c08SAlexander V. Chernikov *pfib = fibnum; 3851d3b00c08SAlexander V. Chernikov 3852d3b00c08SAlexander V. Chernikov return (0); 3853d3b00c08SAlexander V. Chernikov } 3854d3b00c08SAlexander V. Chernikov 3855d3b00c08SAlexander V. Chernikov static void 3856d3b00c08SAlexander V. Chernikov ta_print_kfib_config(void *ta_state, struct table_info *ti, char *buf, 3857d3b00c08SAlexander V. Chernikov size_t bufsize) 3858d3b00c08SAlexander V. Chernikov { 3859d3b00c08SAlexander V. Chernikov 3860d3b00c08SAlexander V. Chernikov if (ti->data != 0) 3861c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s fib=%lu", "addr:kfib", ti->data); 3862d3b00c08SAlexander V. Chernikov else 3863c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s", "addr:kfib"); 3864d3b00c08SAlexander V. Chernikov } 3865d3b00c08SAlexander V. Chernikov 3866d3b00c08SAlexander V. Chernikov static int 3867d3b00c08SAlexander V. Chernikov ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 3868d3b00c08SAlexander V. Chernikov char *data, uint8_t tflags) 3869d3b00c08SAlexander V. Chernikov { 3870d3b00c08SAlexander V. Chernikov int error, fibnum; 3871d3b00c08SAlexander V. Chernikov 3872d3b00c08SAlexander V. Chernikov fibnum = 0; 3873d3b00c08SAlexander V. Chernikov if ((error = kfib_parse_opts(&fibnum, data)) != 0) 3874d3b00c08SAlexander V. Chernikov return (error); 3875d3b00c08SAlexander V. Chernikov 3876d3b00c08SAlexander V. Chernikov if (fibnum >= rt_numfibs) 3877d3b00c08SAlexander V. Chernikov return (E2BIG); 3878d3b00c08SAlexander V. Chernikov 3879d3b00c08SAlexander V. Chernikov ti->data = fibnum; 3880d3b00c08SAlexander V. Chernikov ti->lookup = ta_lookup_kfib; 3881d3b00c08SAlexander V. Chernikov 3882d3b00c08SAlexander V. Chernikov return (0); 3883d3b00c08SAlexander V. Chernikov } 3884d3b00c08SAlexander V. Chernikov 3885d3b00c08SAlexander V. Chernikov /* 3886d3b00c08SAlexander V. Chernikov * Destroys table @ti 3887d3b00c08SAlexander V. Chernikov */ 3888d3b00c08SAlexander V. Chernikov static void 3889d3b00c08SAlexander V. Chernikov ta_destroy_kfib(void *ta_state, struct table_info *ti) 3890d3b00c08SAlexander V. Chernikov { 3891d3b00c08SAlexander V. Chernikov 3892d3b00c08SAlexander V. Chernikov } 3893d3b00c08SAlexander V. Chernikov 3894d3b00c08SAlexander V. Chernikov /* 3895d3b00c08SAlexander V. Chernikov * Provide algo-specific table info 3896d3b00c08SAlexander V. Chernikov */ 3897d3b00c08SAlexander V. Chernikov static void 3898d3b00c08SAlexander V. Chernikov ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 3899d3b00c08SAlexander V. Chernikov { 3900d3b00c08SAlexander V. Chernikov 3901d3b00c08SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA; 3902d3b00c08SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_RADIX; 3903d3b00c08SAlexander V. Chernikov tinfo->count4 = 0; 39044451d893SAlexander V. Chernikov tinfo->itemsize4 = 128; /* table is readonly, value does not matter */ 3905d3b00c08SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_RADIX; 3906d3b00c08SAlexander V. Chernikov tinfo->count6 = 0; 39074451d893SAlexander V. Chernikov tinfo->itemsize6 = 128; 3908d3b00c08SAlexander V. Chernikov } 3909d3b00c08SAlexander V. Chernikov 3910d3b00c08SAlexander V. Chernikov static int 39114451d893SAlexander V. Chernikov ta_dump_kfib_tentry_int(int family, const struct rtentry *rt, 3912d3b00c08SAlexander V. Chernikov ipfw_obj_tentry *tent) 3913d3b00c08SAlexander V. Chernikov { 39144451d893SAlexander V. Chernikov uint32_t scopeid; 39154451d893SAlexander V. Chernikov int plen; 3916004d3e30SAlexander V. Chernikov 3917d699ee2dSAlexander V. Chernikov #ifdef INET 39184451d893SAlexander V. Chernikov if (family == AF_INET) { 39194451d893SAlexander V. Chernikov rt_get_inet_prefix_plen(rt, &tent->k.addr, &plen, &scopeid); 39204451d893SAlexander V. Chernikov tent->masklen = plen; 3921d3b00c08SAlexander V. Chernikov tent->subtype = AF_INET; 39224451d893SAlexander V. Chernikov tent->v.kidx = 0; 3923d699ee2dSAlexander V. Chernikov } 3924d699ee2dSAlexander V. Chernikov #endif 39252616eaa3SAlexander V. Chernikov #ifdef INET6 39264451d893SAlexander V. Chernikov if (family == AF_INET6) { 39274451d893SAlexander V. Chernikov rt_get_inet6_prefix_plen(rt, &tent->k.addr6, &plen, &scopeid); 39284451d893SAlexander V. Chernikov tent->masklen = plen; 3929d3b00c08SAlexander V. Chernikov tent->subtype = AF_INET6; 39300cba2b28SAlexander V. Chernikov tent->v.kidx = 0; 3931d3b00c08SAlexander V. Chernikov } 3932d699ee2dSAlexander V. Chernikov #endif 3933d3b00c08SAlexander V. Chernikov return (0); 3934d3b00c08SAlexander V. Chernikov } 3935d3b00c08SAlexander V. Chernikov 3936d3b00c08SAlexander V. Chernikov static int 3937d3b00c08SAlexander V. Chernikov ta_find_kfib_tentry(void *ta_state, struct table_info *ti, 3938d3b00c08SAlexander V. Chernikov ipfw_obj_tentry *tent) 3939d3b00c08SAlexander V. Chernikov { 39403ad80c65SAlexander V. Chernikov struct rtentry *rt = NULL; 39414451d893SAlexander V. Chernikov struct route_nhop_data rnd; 39424451d893SAlexander V. Chernikov struct epoch_tracker et; 39434451d893SAlexander V. Chernikov int error; 3944004d3e30SAlexander V. Chernikov 39454451d893SAlexander V. Chernikov NET_EPOCH_ENTER(et); 39463ad80c65SAlexander V. Chernikov 39473ad80c65SAlexander V. Chernikov switch (tent->subtype) { 39483ad80c65SAlexander V. Chernikov #ifdef INET 39493ad80c65SAlexander V. Chernikov case AF_INET: 39504451d893SAlexander V. Chernikov rt = fib4_lookup_rt(ti->data, tent->k.addr, 0, 0, &rnd); 39513ad80c65SAlexander V. Chernikov break; 39523ad80c65SAlexander V. Chernikov #endif 39533ad80c65SAlexander V. Chernikov #ifdef INET6 39543ad80c65SAlexander V. Chernikov case AF_INET6: 39554451d893SAlexander V. Chernikov rt = fib6_lookup_rt(ti->data, &tent->k.addr6, 0, 0, &rnd); 39563ad80c65SAlexander V. Chernikov break; 39573ad80c65SAlexander V. Chernikov #endif 39584451d893SAlexander V. Chernikov } 39594451d893SAlexander V. Chernikov if (rt != NULL) 39604451d893SAlexander V. Chernikov error = ta_dump_kfib_tentry_int(tent->subtype, rt, tent); 39614451d893SAlexander V. Chernikov else 39624451d893SAlexander V. Chernikov error = ENOENT; 39634451d893SAlexander V. Chernikov NET_EPOCH_EXIT(et); 39644451d893SAlexander V. Chernikov 39654451d893SAlexander V. Chernikov return (error); 3966d3b00c08SAlexander V. Chernikov } 3967d3b00c08SAlexander V. Chernikov 39684451d893SAlexander V. Chernikov struct kfib_dump_arg { 39694451d893SAlexander V. Chernikov struct rtentry *rt; 39704451d893SAlexander V. Chernikov int family; 39714451d893SAlexander V. Chernikov ta_foreach_f *f; 39724451d893SAlexander V. Chernikov void *arg; 39734451d893SAlexander V. Chernikov }; 3974004d3e30SAlexander V. Chernikov 39754451d893SAlexander V. Chernikov static int 39764451d893SAlexander V. Chernikov ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e, 39774451d893SAlexander V. Chernikov ipfw_obj_tentry *tent) 39784451d893SAlexander V. Chernikov { 39794451d893SAlexander V. Chernikov struct kfib_dump_arg *karg = (struct kfib_dump_arg *)e; 3980004d3e30SAlexander V. Chernikov 39814451d893SAlexander V. Chernikov return (ta_dump_kfib_tentry_int(karg->family, karg->rt, tent)); 39824451d893SAlexander V. Chernikov } 39834451d893SAlexander V. Chernikov 39844451d893SAlexander V. Chernikov static int 39854451d893SAlexander V. Chernikov walk_wrapper_f(struct rtentry *rt, void *arg) 39864451d893SAlexander V. Chernikov { 39874451d893SAlexander V. Chernikov struct kfib_dump_arg *karg = (struct kfib_dump_arg *)arg; 39884451d893SAlexander V. Chernikov 39894451d893SAlexander V. Chernikov karg->rt = rt; 39904451d893SAlexander V. Chernikov return (karg->f(karg, karg->arg)); 3991d3b00c08SAlexander V. Chernikov } 3992d3b00c08SAlexander V. Chernikov 3993d3b00c08SAlexander V. Chernikov static void 3994d3b00c08SAlexander V. Chernikov ta_foreach_kfib(void *ta_state, struct table_info *ti, ta_foreach_f *f, 3995d3b00c08SAlexander V. Chernikov void *arg) 3996d3b00c08SAlexander V. Chernikov { 39974451d893SAlexander V. Chernikov struct kfib_dump_arg karg = { .f = f, .arg = arg }; 3998d3b00c08SAlexander V. Chernikov 39994451d893SAlexander V. Chernikov karg.family = AF_INET; 40004451d893SAlexander V. Chernikov rib_walk(ti->data, AF_INET, false, walk_wrapper_f, &karg); 40014451d893SAlexander V. Chernikov karg.family = AF_INET6; 40024451d893SAlexander V. Chernikov rib_walk(ti->data, AF_INET6, false, walk_wrapper_f, &karg); 4003d3b00c08SAlexander V. Chernikov } 4004d3b00c08SAlexander V. Chernikov 4005c21034b7SAlexander V. Chernikov struct table_algo addr_kfib = { 4006c21034b7SAlexander V. Chernikov .name = "addr:kfib", 4007c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR, 4008d3b00c08SAlexander V. Chernikov .flags = TA_FLAG_READONLY, 4009d3b00c08SAlexander V. Chernikov .ta_buf_size = 0, 4010d3b00c08SAlexander V. Chernikov .init = ta_init_kfib, 4011d3b00c08SAlexander V. Chernikov .destroy = ta_destroy_kfib, 4012d3b00c08SAlexander V. Chernikov .foreach = ta_foreach_kfib, 4013d3b00c08SAlexander V. Chernikov .dump_tentry = ta_dump_kfib_tentry, 4014d3b00c08SAlexander V. Chernikov .find_tentry = ta_find_kfib_tentry, 4015d3b00c08SAlexander V. Chernikov .dump_tinfo = ta_dump_kfib_tinfo, 4016d3b00c08SAlexander V. Chernikov .print_config = ta_print_kfib_config, 4017d3b00c08SAlexander V. Chernikov }; 4018d3b00c08SAlexander V. Chernikov 401981cac390SArseny Smalyuk struct mac_radix_entry { 402081cac390SArseny Smalyuk struct radix_node rn[2]; 402181cac390SArseny Smalyuk uint32_t value; 402281cac390SArseny Smalyuk uint8_t masklen; 402381cac390SArseny Smalyuk struct sa_mac sa; 402481cac390SArseny Smalyuk }; 402581cac390SArseny Smalyuk 402681cac390SArseny Smalyuk struct mac_radix_cfg { 402781cac390SArseny Smalyuk struct radix_node_head *head; 402881cac390SArseny Smalyuk size_t count; 402981cac390SArseny Smalyuk }; 403081cac390SArseny Smalyuk 403181cac390SArseny Smalyuk static int 403281cac390SArseny Smalyuk ta_lookup_mac_radix(struct table_info *ti, void *key, uint32_t keylen, 403381cac390SArseny Smalyuk uint32_t *val) 403481cac390SArseny Smalyuk { 403581cac390SArseny Smalyuk struct radix_node_head *rnh; 403681cac390SArseny Smalyuk 403781cac390SArseny Smalyuk if (keylen == ETHER_ADDR_LEN) { 403881cac390SArseny Smalyuk struct mac_radix_entry *ent; 403981cac390SArseny Smalyuk struct sa_mac sa; 404081cac390SArseny Smalyuk KEY_LEN(sa) = KEY_LEN_MAC; 404181cac390SArseny Smalyuk memcpy(sa.mac_addr.octet, key, ETHER_ADDR_LEN); 404281cac390SArseny Smalyuk rnh = (struct radix_node_head *)ti->state; 404381cac390SArseny Smalyuk ent = (struct mac_radix_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh)); 404481cac390SArseny Smalyuk if (ent != NULL) { 404581cac390SArseny Smalyuk *val = ent->value; 404681cac390SArseny Smalyuk return (1); 404781cac390SArseny Smalyuk } 404881cac390SArseny Smalyuk } 404981cac390SArseny Smalyuk return (0); 405081cac390SArseny Smalyuk } 405181cac390SArseny Smalyuk 405281cac390SArseny Smalyuk static int 405381cac390SArseny Smalyuk ta_init_mac_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 405481cac390SArseny Smalyuk char *data, uint8_t tflags) 405581cac390SArseny Smalyuk { 405681cac390SArseny Smalyuk struct mac_radix_cfg *cfg; 405781cac390SArseny Smalyuk 405881cac390SArseny Smalyuk if (!rn_inithead(&ti->state, OFF_LEN_MAC)) 405981cac390SArseny Smalyuk return (ENOMEM); 406081cac390SArseny Smalyuk 406181cac390SArseny Smalyuk cfg = malloc(sizeof(struct mac_radix_cfg), M_IPFW, M_WAITOK | M_ZERO); 406281cac390SArseny Smalyuk 406381cac390SArseny Smalyuk *ta_state = cfg; 406481cac390SArseny Smalyuk ti->lookup = ta_lookup_mac_radix; 406581cac390SArseny Smalyuk 406681cac390SArseny Smalyuk return (0); 406781cac390SArseny Smalyuk } 406881cac390SArseny Smalyuk 406981cac390SArseny Smalyuk static void 407081cac390SArseny Smalyuk ta_destroy_mac_radix(void *ta_state, struct table_info *ti) 407181cac390SArseny Smalyuk { 407281cac390SArseny Smalyuk struct mac_radix_cfg *cfg; 407381cac390SArseny Smalyuk struct radix_node_head *rnh; 407481cac390SArseny Smalyuk 407581cac390SArseny Smalyuk cfg = (struct mac_radix_cfg *)ta_state; 407681cac390SArseny Smalyuk 407781cac390SArseny Smalyuk rnh = (struct radix_node_head *)(ti->state); 407881cac390SArseny Smalyuk rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh); 407981cac390SArseny Smalyuk rn_detachhead(&ti->state); 408081cac390SArseny Smalyuk 408181cac390SArseny Smalyuk free(cfg, M_IPFW); 408281cac390SArseny Smalyuk } 408381cac390SArseny Smalyuk 408481cac390SArseny Smalyuk static void 408581cac390SArseny Smalyuk tei_to_sockaddr_ent_mac(struct tentry_info *tei, struct sockaddr *sa, 408681cac390SArseny Smalyuk struct sockaddr *ma, int *set_mask) 408781cac390SArseny Smalyuk { 408881cac390SArseny Smalyuk int mlen, i; 408981cac390SArseny Smalyuk struct sa_mac *addr, *mask; 409081cac390SArseny Smalyuk u_char *cp; 409181cac390SArseny Smalyuk 409281cac390SArseny Smalyuk mlen = tei->masklen; 409381cac390SArseny Smalyuk addr = (struct sa_mac *)sa; 409481cac390SArseny Smalyuk mask = (struct sa_mac *)ma; 409581cac390SArseny Smalyuk /* Set 'total' structure length */ 409681cac390SArseny Smalyuk KEY_LEN(*addr) = KEY_LEN_MAC; 409781cac390SArseny Smalyuk KEY_LEN(*mask) = KEY_LEN_MAC; 409881cac390SArseny Smalyuk 409981cac390SArseny Smalyuk for (i = mlen, cp = mask->mac_addr.octet; i >= 8; i -= 8) 410081cac390SArseny Smalyuk *cp++ = 0xFF; 410181cac390SArseny Smalyuk if (i > 0) 410281cac390SArseny Smalyuk *cp = ~((1 << (8 - i)) - 1); 410381cac390SArseny Smalyuk 410481cac390SArseny Smalyuk addr->mac_addr = *((struct ether_addr *)tei->paddr); 410581cac390SArseny Smalyuk for (i = 0; i < ETHER_ADDR_LEN; ++i) 410681cac390SArseny Smalyuk addr->mac_addr.octet[i] &= mask->mac_addr.octet[i]; 410781cac390SArseny Smalyuk 410881cac390SArseny Smalyuk if (mlen != 8 * ETHER_ADDR_LEN) 410981cac390SArseny Smalyuk *set_mask = 1; 411081cac390SArseny Smalyuk else 411181cac390SArseny Smalyuk *set_mask = 0; 411281cac390SArseny Smalyuk } 411381cac390SArseny Smalyuk 411481cac390SArseny Smalyuk static int 411581cac390SArseny Smalyuk ta_prepare_add_mac_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 411681cac390SArseny Smalyuk void *ta_buf) 411781cac390SArseny Smalyuk { 411881cac390SArseny Smalyuk struct ta_buf_radix *tb; 411981cac390SArseny Smalyuk struct mac_radix_entry *ent; 412081cac390SArseny Smalyuk struct sockaddr *addr, *mask; 412181cac390SArseny Smalyuk int mlen, set_mask; 412281cac390SArseny Smalyuk 412381cac390SArseny Smalyuk tb = (struct ta_buf_radix *)ta_buf; 412481cac390SArseny Smalyuk 412581cac390SArseny Smalyuk mlen = tei->masklen; 412681cac390SArseny Smalyuk set_mask = 0; 412781cac390SArseny Smalyuk 412881cac390SArseny Smalyuk if (tei->subtype == AF_LINK) { 412981cac390SArseny Smalyuk if (mlen > 8 * ETHER_ADDR_LEN) 413081cac390SArseny Smalyuk return (EINVAL); 413181cac390SArseny Smalyuk ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 413281cac390SArseny Smalyuk ent->masklen = mlen; 413381cac390SArseny Smalyuk 413481cac390SArseny Smalyuk addr = (struct sockaddr *)&ent->sa; 413581cac390SArseny Smalyuk mask = (struct sockaddr *)&tb->addr.mac.ma; 413681cac390SArseny Smalyuk tb->ent_ptr = ent; 413781cac390SArseny Smalyuk } else { 413881cac390SArseny Smalyuk /* Unknown CIDR type */ 413981cac390SArseny Smalyuk return (EINVAL); 414081cac390SArseny Smalyuk } 414181cac390SArseny Smalyuk 414281cac390SArseny Smalyuk tei_to_sockaddr_ent_mac(tei, addr, mask, &set_mask); 414381cac390SArseny Smalyuk /* Set pointers */ 414481cac390SArseny Smalyuk tb->addr_ptr = addr; 414581cac390SArseny Smalyuk if (set_mask != 0) 414681cac390SArseny Smalyuk tb->mask_ptr = mask; 414781cac390SArseny Smalyuk 414881cac390SArseny Smalyuk return (0); 414981cac390SArseny Smalyuk } 415081cac390SArseny Smalyuk 415181cac390SArseny Smalyuk static int 415281cac390SArseny Smalyuk ta_add_mac_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, 415381cac390SArseny Smalyuk void *ta_buf, uint32_t *pnum) 415481cac390SArseny Smalyuk { 415581cac390SArseny Smalyuk struct mac_radix_cfg *cfg; 415681cac390SArseny Smalyuk struct radix_node_head *rnh; 415781cac390SArseny Smalyuk struct radix_node *rn; 415881cac390SArseny Smalyuk struct ta_buf_radix *tb; 415981cac390SArseny Smalyuk uint32_t *old_value, value; 416081cac390SArseny Smalyuk 416181cac390SArseny Smalyuk cfg = (struct mac_radix_cfg *)ta_state; 416281cac390SArseny Smalyuk tb = (struct ta_buf_radix *)ta_buf; 416381cac390SArseny Smalyuk 416481cac390SArseny Smalyuk /* Save current entry value from @tei */ 416581cac390SArseny Smalyuk rnh = ti->state; 416681cac390SArseny Smalyuk ((struct mac_radix_entry *)tb->ent_ptr)->value = tei->value; 416781cac390SArseny Smalyuk 416881cac390SArseny Smalyuk /* Search for an entry first */ 416981cac390SArseny Smalyuk rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, &rnh->rh); 417081cac390SArseny Smalyuk if (rn != NULL) { 417181cac390SArseny Smalyuk if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 417281cac390SArseny Smalyuk return (EEXIST); 417381cac390SArseny Smalyuk /* Record already exists. Update value if we're asked to */ 417481cac390SArseny Smalyuk old_value = &((struct mac_radix_entry *)rn)->value; 417581cac390SArseny Smalyuk 417681cac390SArseny Smalyuk value = *old_value; 417781cac390SArseny Smalyuk *old_value = tei->value; 417881cac390SArseny Smalyuk tei->value = value; 417981cac390SArseny Smalyuk 418081cac390SArseny Smalyuk /* Indicate that update has happened instead of addition */ 418181cac390SArseny Smalyuk tei->flags |= TEI_FLAGS_UPDATED; 418281cac390SArseny Smalyuk *pnum = 0; 418381cac390SArseny Smalyuk 418481cac390SArseny Smalyuk return (0); 418581cac390SArseny Smalyuk } 418681cac390SArseny Smalyuk 418781cac390SArseny Smalyuk if ((tei->flags & TEI_FLAGS_DONTADD) != 0) 418881cac390SArseny Smalyuk return (EFBIG); 418981cac390SArseny Smalyuk 419081cac390SArseny Smalyuk rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, &rnh->rh, tb->ent_ptr); 419181cac390SArseny Smalyuk if (rn == NULL) { 419281cac390SArseny Smalyuk /* Unknown error */ 419381cac390SArseny Smalyuk return (EINVAL); 419481cac390SArseny Smalyuk } 419581cac390SArseny Smalyuk 419681cac390SArseny Smalyuk cfg->count++; 419781cac390SArseny Smalyuk tb->ent_ptr = NULL; 419881cac390SArseny Smalyuk *pnum = 1; 419981cac390SArseny Smalyuk 420081cac390SArseny Smalyuk return (0); 420181cac390SArseny Smalyuk } 420281cac390SArseny Smalyuk 420381cac390SArseny Smalyuk static int 420481cac390SArseny Smalyuk ta_prepare_del_mac_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 420581cac390SArseny Smalyuk void *ta_buf) 420681cac390SArseny Smalyuk { 420781cac390SArseny Smalyuk struct ta_buf_radix *tb; 420881cac390SArseny Smalyuk struct sockaddr *addr, *mask; 420981cac390SArseny Smalyuk int mlen, set_mask; 421081cac390SArseny Smalyuk 421181cac390SArseny Smalyuk tb = (struct ta_buf_radix *)ta_buf; 421281cac390SArseny Smalyuk 421381cac390SArseny Smalyuk mlen = tei->masklen; 421481cac390SArseny Smalyuk set_mask = 0; 421581cac390SArseny Smalyuk 421681cac390SArseny Smalyuk if (tei->subtype == AF_LINK) { 421781cac390SArseny Smalyuk if (mlen > 8 * ETHER_ADDR_LEN) 421881cac390SArseny Smalyuk return (EINVAL); 421981cac390SArseny Smalyuk 422081cac390SArseny Smalyuk addr = (struct sockaddr *)&tb->addr.mac.sa; 422181cac390SArseny Smalyuk mask = (struct sockaddr *)&tb->addr.mac.ma; 422281cac390SArseny Smalyuk } else 422381cac390SArseny Smalyuk return (EINVAL); 422481cac390SArseny Smalyuk 422581cac390SArseny Smalyuk tei_to_sockaddr_ent_mac(tei, addr, mask, &set_mask); 422681cac390SArseny Smalyuk tb->addr_ptr = addr; 422781cac390SArseny Smalyuk if (set_mask != 0) 422881cac390SArseny Smalyuk tb->mask_ptr = mask; 422981cac390SArseny Smalyuk 423081cac390SArseny Smalyuk return (0); 423181cac390SArseny Smalyuk } 423281cac390SArseny Smalyuk 423381cac390SArseny Smalyuk static int 423481cac390SArseny Smalyuk ta_del_mac_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei, 423581cac390SArseny Smalyuk void *ta_buf, uint32_t *pnum) 423681cac390SArseny Smalyuk { 423781cac390SArseny Smalyuk struct mac_radix_cfg *cfg; 423881cac390SArseny Smalyuk struct radix_node_head *rnh; 423981cac390SArseny Smalyuk struct radix_node *rn; 424081cac390SArseny Smalyuk struct ta_buf_radix *tb; 424181cac390SArseny Smalyuk 424281cac390SArseny Smalyuk cfg = (struct mac_radix_cfg *)ta_state; 424381cac390SArseny Smalyuk tb = (struct ta_buf_radix *)ta_buf; 424481cac390SArseny Smalyuk rnh = ti->state; 424581cac390SArseny Smalyuk 424681cac390SArseny Smalyuk rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, &rnh->rh); 424781cac390SArseny Smalyuk 424881cac390SArseny Smalyuk if (rn == NULL) 424981cac390SArseny Smalyuk return (ENOENT); 425081cac390SArseny Smalyuk 425181cac390SArseny Smalyuk /* Save entry value to @tei */ 425281cac390SArseny Smalyuk tei->value = ((struct mac_radix_entry *)rn)->value; 425381cac390SArseny Smalyuk 425481cac390SArseny Smalyuk tb->ent_ptr = rn; 425581cac390SArseny Smalyuk cfg->count--; 425681cac390SArseny Smalyuk *pnum = 1; 425781cac390SArseny Smalyuk 425881cac390SArseny Smalyuk return (0); 425981cac390SArseny Smalyuk } 426081cac390SArseny Smalyuk 426181cac390SArseny Smalyuk static void 426281cac390SArseny Smalyuk ta_foreach_mac_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f, 426381cac390SArseny Smalyuk void *arg) 426481cac390SArseny Smalyuk { 426581cac390SArseny Smalyuk struct radix_node_head *rnh; 426681cac390SArseny Smalyuk 426781cac390SArseny Smalyuk rnh = (struct radix_node_head *)(ti->state); 426881cac390SArseny Smalyuk rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg); 426981cac390SArseny Smalyuk } 427081cac390SArseny Smalyuk 427181cac390SArseny Smalyuk static void 427281cac390SArseny Smalyuk ta_dump_mac_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) 427381cac390SArseny Smalyuk { 427481cac390SArseny Smalyuk struct mac_radix_cfg *cfg; 427581cac390SArseny Smalyuk 427681cac390SArseny Smalyuk cfg = (struct mac_radix_cfg *)ta_state; 427781cac390SArseny Smalyuk 427881cac390SArseny Smalyuk tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM; 427981cac390SArseny Smalyuk tinfo->taclass4 = IPFW_TACLASS_RADIX; 428081cac390SArseny Smalyuk tinfo->count4 = cfg->count; 428181cac390SArseny Smalyuk tinfo->itemsize4 = sizeof(struct mac_radix_entry); 428281cac390SArseny Smalyuk } 428381cac390SArseny Smalyuk 428481cac390SArseny Smalyuk static int 428581cac390SArseny Smalyuk ta_dump_mac_radix_tentry(void *ta_state, struct table_info *ti, void *e, 428681cac390SArseny Smalyuk ipfw_obj_tentry *tent) 428781cac390SArseny Smalyuk { 428881cac390SArseny Smalyuk struct mac_radix_entry *n = (struct mac_radix_entry *)e; 428981cac390SArseny Smalyuk 429081cac390SArseny Smalyuk memcpy(tent->k.mac, n->sa.mac_addr.octet, ETHER_ADDR_LEN); 429181cac390SArseny Smalyuk tent->masklen = n->masklen; 429281cac390SArseny Smalyuk tent->subtype = AF_LINK; 429381cac390SArseny Smalyuk tent->v.kidx = n->value; 429481cac390SArseny Smalyuk 429581cac390SArseny Smalyuk return (0); 429681cac390SArseny Smalyuk } 429781cac390SArseny Smalyuk 429881cac390SArseny Smalyuk static int 429981cac390SArseny Smalyuk ta_find_mac_radix_tentry(void *ta_state, struct table_info *ti, 430081cac390SArseny Smalyuk ipfw_obj_tentry *tent) 430181cac390SArseny Smalyuk { 430281cac390SArseny Smalyuk struct radix_node_head *rnh; 430381cac390SArseny Smalyuk void *e; 430481cac390SArseny Smalyuk 430581cac390SArseny Smalyuk e = NULL; 430681cac390SArseny Smalyuk if (tent->subtype == AF_LINK) { 430781cac390SArseny Smalyuk struct sa_mac sa; 430881cac390SArseny Smalyuk KEY_LEN(sa) = KEY_LEN_MAC; 4309*e012d79cSAndrey V. Elsukov memcpy(sa.mac_addr.octet, tent->k.mac, ETHER_ADDR_LEN); 431081cac390SArseny Smalyuk rnh = (struct radix_node_head *)ti->state; 431181cac390SArseny Smalyuk e = rnh->rnh_matchaddr(&sa, &rnh->rh); 431281cac390SArseny Smalyuk } 431381cac390SArseny Smalyuk 431481cac390SArseny Smalyuk if (e != NULL) { 431581cac390SArseny Smalyuk ta_dump_mac_radix_tentry(ta_state, ti, e, tent); 431681cac390SArseny Smalyuk return (0); 431781cac390SArseny Smalyuk } 431881cac390SArseny Smalyuk 431981cac390SArseny Smalyuk return (ENOENT); 432081cac390SArseny Smalyuk } 432181cac390SArseny Smalyuk 432281cac390SArseny Smalyuk struct table_algo mac_radix = { 432381cac390SArseny Smalyuk .name = "mac:radix", 432481cac390SArseny Smalyuk .type = IPFW_TABLE_MAC, 432581cac390SArseny Smalyuk .flags = TA_FLAG_DEFAULT, 432681cac390SArseny Smalyuk .ta_buf_size = sizeof(struct ta_buf_radix), 432781cac390SArseny Smalyuk .init = ta_init_mac_radix, 432881cac390SArseny Smalyuk .destroy = ta_destroy_mac_radix, 432981cac390SArseny Smalyuk .prepare_add = ta_prepare_add_mac_radix, 433081cac390SArseny Smalyuk .prepare_del = ta_prepare_del_mac_radix, 433181cac390SArseny Smalyuk .add = ta_add_mac_radix, 433281cac390SArseny Smalyuk .del = ta_del_mac_radix, 433381cac390SArseny Smalyuk .flush_entry = ta_flush_radix_entry, 433481cac390SArseny Smalyuk .foreach = ta_foreach_mac_radix, 433581cac390SArseny Smalyuk .dump_tentry = ta_dump_mac_radix_tentry, 433681cac390SArseny Smalyuk .find_tentry = ta_find_mac_radix_tentry, 433781cac390SArseny Smalyuk .dump_tinfo = ta_dump_mac_radix_tinfo, 433881cac390SArseny Smalyuk .need_modify = ta_need_modify_radix, 433981cac390SArseny Smalyuk }; 434081cac390SArseny Smalyuk 43419f7d47b0SAlexander V. Chernikov void 43420b565ac0SAlexander V. Chernikov ipfw_table_algo_init(struct ip_fw_chain *ch) 43439f7d47b0SAlexander V. Chernikov { 43440b565ac0SAlexander V. Chernikov size_t sz; 43450b565ac0SAlexander V. Chernikov 43469f7d47b0SAlexander V. Chernikov /* 43479f7d47b0SAlexander V. Chernikov * Register all algorithms presented here. 43489f7d47b0SAlexander V. Chernikov */ 43490b565ac0SAlexander V. Chernikov sz = sizeof(struct table_algo); 4350c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_radix, sz, &addr_radix.idx); 4351c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_hash, sz, &addr_hash.idx); 43520b565ac0SAlexander V. Chernikov ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx); 4353b23d5de9SAlexander V. Chernikov ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx); 4354914bffb6SAlexander V. Chernikov ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx); 4355c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_kfib, sz, &addr_kfib.idx); 435681cac390SArseny Smalyuk ipfw_add_table_algo(ch, &mac_radix, sz, &mac_radix.idx); 43579f7d47b0SAlexander V. Chernikov } 43589f7d47b0SAlexander V. Chernikov 43599f7d47b0SAlexander V. Chernikov void 43600b565ac0SAlexander V. Chernikov ipfw_table_algo_destroy(struct ip_fw_chain *ch) 43619f7d47b0SAlexander V. Chernikov { 43620b565ac0SAlexander V. Chernikov 4363c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_radix.idx); 4364c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_hash.idx); 43650b565ac0SAlexander V. Chernikov ipfw_del_table_algo(ch, iface_idx.idx); 4366b23d5de9SAlexander V. Chernikov ipfw_del_table_algo(ch, number_array.idx); 4367914bffb6SAlexander V. Chernikov ipfw_del_table_algo(ch, flow_hash.idx); 4368c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_kfib.idx); 436981cac390SArseny Smalyuk ipfw_del_table_algo(ch, mac_radix.idx); 43709f7d47b0SAlexander V. Chernikov } 4371