19f7d47b0SAlexander V. Chernikov /*-
2*4a77657cSAndrey V. Elsukov * SPDX-License-Identifier: BSD-2-Clause
3*4a77657cSAndrey V. Elsukov *
4*4a77657cSAndrey V. Elsukov * Copyright (c) 2014-2025 Yandex LLC
51a33e799SAlexander V. Chernikov * Copyright (c) 2014 Alexander V. Chernikov
69f7d47b0SAlexander V. Chernikov *
79f7d47b0SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without
89f7d47b0SAlexander V. Chernikov * modification, are permitted provided that the following conditions
99f7d47b0SAlexander V. Chernikov * are met:
109f7d47b0SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright
119f7d47b0SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer.
129f7d47b0SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright
139f7d47b0SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the
149f7d47b0SAlexander V. Chernikov * documentation and/or other materials provided with the distribution.
159f7d47b0SAlexander V. Chernikov *
169f7d47b0SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
179f7d47b0SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
189f7d47b0SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
199f7d47b0SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
209f7d47b0SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
219f7d47b0SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
229f7d47b0SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
239f7d47b0SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
249f7d47b0SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
259f7d47b0SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
269f7d47b0SAlexander V. Chernikov * SUCH DAMAGE.
279f7d47b0SAlexander V. Chernikov */
289f7d47b0SAlexander V. Chernikov
299f7d47b0SAlexander V. Chernikov #include <sys/cdefs.h>
309f7d47b0SAlexander V. Chernikov /*
319f7d47b0SAlexander V. Chernikov * Lookup table algorithms.
329f7d47b0SAlexander V. Chernikov *
339f7d47b0SAlexander V. Chernikov */
349f7d47b0SAlexander V. Chernikov
359f7d47b0SAlexander V. Chernikov #include "opt_ipfw.h"
369f7d47b0SAlexander V. Chernikov #include "opt_inet.h"
379f7d47b0SAlexander V. Chernikov #ifndef INET
389f7d47b0SAlexander V. Chernikov #error IPFIREWALL requires INET.
399f7d47b0SAlexander V. Chernikov #endif /* INET */
409f7d47b0SAlexander V. Chernikov #include "opt_inet6.h"
419f7d47b0SAlexander V. Chernikov
429f7d47b0SAlexander V. Chernikov #include <sys/param.h>
439f7d47b0SAlexander V. Chernikov #include <sys/systm.h>
449f7d47b0SAlexander V. Chernikov #include <sys/malloc.h>
459f7d47b0SAlexander V. Chernikov #include <sys/kernel.h>
469f7d47b0SAlexander V. Chernikov #include <sys/lock.h>
479f7d47b0SAlexander V. Chernikov #include <sys/rwlock.h>
48d4e1b515SAlexander V. Chernikov #include <sys/rmlock.h>
499f7d47b0SAlexander V. Chernikov #include <sys/socket.h>
509f7d47b0SAlexander V. Chernikov #include <sys/queue.h>
5181cac390SArseny Smalyuk #include <net/ethernet.h>
529f7d47b0SAlexander V. Chernikov #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */
539f7d47b0SAlexander V. Chernikov #include <net/radix.h>
54d3b00c08SAlexander V. Chernikov #include <net/route.h>
556ad7446cSAlexander V. Chernikov #include <net/route/nhop.h>
564451d893SAlexander V. Chernikov #include <net/route/route_ctl.h>
579f7d47b0SAlexander V. Chernikov
589f7d47b0SAlexander V. Chernikov #include <netinet/in.h>
59004d3e30SAlexander V. Chernikov #include <netinet/in_fib.h>
609f7d47b0SAlexander V. Chernikov #include <netinet/ip_var.h> /* struct ipfw_rule_ref */
619f7d47b0SAlexander V. Chernikov #include <netinet/ip_fw.h>
62004d3e30SAlexander V. Chernikov #include <netinet6/in6_fib.h>
639f7d47b0SAlexander V. Chernikov
649f7d47b0SAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_private.h>
65ea761a5dSAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_table.h>
669f7d47b0SAlexander V. Chernikov
67301290bcSAlexander V. Chernikov /*
68301290bcSAlexander V. Chernikov * IPFW table lookup algorithms.
69301290bcSAlexander V. Chernikov *
70301290bcSAlexander V. Chernikov * What is needed to add another table algo?
71301290bcSAlexander V. Chernikov *
72301290bcSAlexander V. Chernikov * Algo init:
73301290bcSAlexander V. Chernikov * * struct table_algo has to be filled with:
74c21034b7SAlexander V. Chernikov * name: "type:algoname" format, e.g. "addr:radix". Currently
75c21034b7SAlexander V. Chernikov * there are the following types: "addr", "iface", "number" and "flow".
76301290bcSAlexander V. Chernikov * type: one of IPFW_TABLE_* types
77301290bcSAlexander V. Chernikov * flags: one or more TA_FLAGS_*
78301290bcSAlexander V. Chernikov * ta_buf_size: size of structure used to store add/del item state.
79301290bcSAlexander V. Chernikov * Needs to be less than TA_BUF_SZ.
80301290bcSAlexander V. Chernikov * callbacks: see below for description.
81301290bcSAlexander V. Chernikov * * ipfw_add_table_algo / ipfw_del_table_algo has to be called
82301290bcSAlexander V. Chernikov *
83301290bcSAlexander V. Chernikov * Callbacks description:
84301290bcSAlexander V. Chernikov *
85301290bcSAlexander V. Chernikov * -init: request to initialize new table instance.
86301290bcSAlexander V. Chernikov * typedef int (ta_init)(struct ip_fw_chain *ch, void **ta_state,
87301290bcSAlexander V. Chernikov * struct table_info *ti, char *data, uint8_t tflags);
88301290bcSAlexander V. Chernikov * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success.
89301290bcSAlexander V. Chernikov *
90301290bcSAlexander V. Chernikov * Allocate all structures needed for normal operations.
91301290bcSAlexander V. Chernikov * * Caller may want to parse @data for some algo-specific
92301290bcSAlexander V. Chernikov * options provided by userland.
93301290bcSAlexander V. Chernikov * * Caller may want to save configuration state pointer to @ta_state
94301290bcSAlexander V. Chernikov * * Caller needs to save desired runtime structure pointer(s)
95301290bcSAlexander V. Chernikov * inside @ti fields. Note that it is not correct to save
96301290bcSAlexander V. Chernikov * @ti pointer at this moment. Use -change_ti hook for that.
97301290bcSAlexander V. Chernikov * * Caller has to fill in ti->lookup to appropriate function
98301290bcSAlexander V. Chernikov * pointer.
99301290bcSAlexander V. Chernikov *
100301290bcSAlexander V. Chernikov *
101301290bcSAlexander V. Chernikov *
102301290bcSAlexander V. Chernikov * -destroy: request to destroy table instance.
103301290bcSAlexander V. Chernikov * typedef void (ta_destroy)(void *ta_state, struct table_info *ti);
1040caab009SAlexander V. Chernikov * MANDATORY, unlocked. (M_WAITOK).
105301290bcSAlexander V. Chernikov *
106301290bcSAlexander V. Chernikov * Frees all table entries and all tables structures allocated by -init.
107301290bcSAlexander V. Chernikov *
108301290bcSAlexander V. Chernikov *
109301290bcSAlexander V. Chernikov *
110301290bcSAlexander V. Chernikov * -prepare_add: request to allocate state for adding new entry.
111301290bcSAlexander V. Chernikov * typedef int (ta_prepare_add)(struct ip_fw_chain *ch, struct tentry_info *tei,
112301290bcSAlexander V. Chernikov * void *ta_buf);
113301290bcSAlexander V. Chernikov * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success.
114301290bcSAlexander V. Chernikov *
11513263632SAlexander V. Chernikov * Allocates state and fills it in with all necessary data (EXCEPT value)
11613263632SAlexander V. Chernikov * from @tei to minimize operations needed to be done under WLOCK.
11713263632SAlexander V. Chernikov * "value" field has to be copied to new entry in @add callback.
118301290bcSAlexander V. Chernikov * Buffer ta_buf of size ta->ta_buf_sz may be used to store
119301290bcSAlexander V. Chernikov * allocated state.
120301290bcSAlexander V. Chernikov *
121301290bcSAlexander V. Chernikov *
122301290bcSAlexander V. Chernikov *
123301290bcSAlexander V. Chernikov * -prepare_del: request to set state for deleting existing entry.
124301290bcSAlexander V. Chernikov * typedef int (ta_prepare_del)(struct ip_fw_chain *ch, struct tentry_info *tei,
125301290bcSAlexander V. Chernikov * void *ta_buf);
126301290bcSAlexander V. Chernikov * MANDATORY, locked, UH. (M_NOWAIT). Returns 0 on success.
127301290bcSAlexander V. Chernikov *
128301290bcSAlexander V. Chernikov * Buffer ta_buf of size ta->ta_buf_sz may be used to store
129301290bcSAlexander V. Chernikov * allocated state. Caller should use on-stack ta_buf allocation
130301290bcSAlexander V. Chernikov * instead of doing malloc().
131301290bcSAlexander V. Chernikov *
132301290bcSAlexander V. Chernikov *
133301290bcSAlexander V. Chernikov *
134301290bcSAlexander V. Chernikov * -add: request to insert new entry into runtime/config structures.
135301290bcSAlexander V. Chernikov * typedef int (ta_add)(void *ta_state, struct table_info *ti,
136301290bcSAlexander V. Chernikov * struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
137301290bcSAlexander V. Chernikov * MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success.
138301290bcSAlexander V. Chernikov *
139301290bcSAlexander V. Chernikov * Insert new entry using previously-allocated state in @ta_buf.
140301290bcSAlexander V. Chernikov * * @tei may have the following flags:
141301290bcSAlexander V. Chernikov * TEI_FLAGS_UPDATE: request to add or update entry.
142301290bcSAlexander V. Chernikov * TEI_FLAGS_DONTADD: request to update (but not add) entry.
143301290bcSAlexander V. Chernikov * * Caller is required to do the following:
14413263632SAlexander V. Chernikov * copy real entry value from @tei
145301290bcSAlexander V. Chernikov * entry added: return 0, set 1 to @pnum
146301290bcSAlexander V. Chernikov * entry updated: return 0, store 0 to @pnum, store old value in @tei,
147301290bcSAlexander V. Chernikov * add TEI_FLAGS_UPDATED flag to @tei.
148301290bcSAlexander V. Chernikov * entry exists: return EEXIST
149301290bcSAlexander V. Chernikov * entry not found: return ENOENT
150301290bcSAlexander V. Chernikov * other error: return non-zero error code.
151301290bcSAlexander V. Chernikov *
152301290bcSAlexander V. Chernikov *
153301290bcSAlexander V. Chernikov *
154301290bcSAlexander V. Chernikov * -del: request to delete existing entry from runtime/config structures.
155301290bcSAlexander V. Chernikov * typedef int (ta_del)(void *ta_state, struct table_info *ti,
156301290bcSAlexander V. Chernikov * struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
157301290bcSAlexander V. Chernikov * MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success.
158301290bcSAlexander V. Chernikov *
159301290bcSAlexander V. Chernikov * Delete entry using previously set up in @ta_buf.
160301290bcSAlexander V. Chernikov * * Caller is required to do the following:
16113263632SAlexander V. Chernikov * entry deleted: return 0, set 1 to @pnum, store old value in @tei.
162301290bcSAlexander V. Chernikov * entry not found: return ENOENT
163301290bcSAlexander V. Chernikov * other error: return non-zero error code.
164301290bcSAlexander V. Chernikov *
165301290bcSAlexander V. Chernikov *
166301290bcSAlexander V. Chernikov *
167301290bcSAlexander V. Chernikov * -flush_entry: flush entry state created by -prepare_add / -del / others
168301290bcSAlexander V. Chernikov * typedef void (ta_flush_entry)(struct ip_fw_chain *ch,
169301290bcSAlexander V. Chernikov * struct tentry_info *tei, void *ta_buf);
170301290bcSAlexander V. Chernikov * MANDATORY, may be locked. (M_NOWAIT).
171301290bcSAlexander V. Chernikov *
172301290bcSAlexander V. Chernikov * Delete state allocated by:
173301290bcSAlexander V. Chernikov * -prepare_add (-add returned EEXIST|UPDATED)
174301290bcSAlexander V. Chernikov * -prepare_del (if any)
175301290bcSAlexander V. Chernikov * -del
176301290bcSAlexander V. Chernikov * * Caller is required to handle empty @ta_buf correctly.
177301290bcSAlexander V. Chernikov *
178301290bcSAlexander V. Chernikov *
179301290bcSAlexander V. Chernikov * -find_tentry: finds entry specified by key @tei
180301290bcSAlexander V. Chernikov * typedef int ta_find_tentry(void *ta_state, struct table_info *ti,
181301290bcSAlexander V. Chernikov * ipfw_obj_tentry *tent);
182301290bcSAlexander V. Chernikov * OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 on success.
183301290bcSAlexander V. Chernikov *
184301290bcSAlexander V. Chernikov * Finds entry specified by given key.
185a4641f4eSPedro F. Giffuni * * Caller is required to do the following:
186301290bcSAlexander V. Chernikov * entry found: returns 0, export entry to @tent
187301290bcSAlexander V. Chernikov * entry not found: returns ENOENT
188301290bcSAlexander V. Chernikov *
189301290bcSAlexander V. Chernikov *
190301290bcSAlexander V. Chernikov * -need_modify: checks if @ti has enough space to hold another @count items.
191301290bcSAlexander V. Chernikov * typedef int (ta_need_modify)(void *ta_state, struct table_info *ti,
192301290bcSAlexander V. Chernikov * uint32_t count, uint64_t *pflags);
193fd0869d5SAlexander V. Chernikov * OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 if has.
194301290bcSAlexander V. Chernikov *
195301290bcSAlexander V. Chernikov * Checks if given table has enough space to add @count items without
196301290bcSAlexander V. Chernikov * resize. Caller may use @pflags to store desired modification data.
197301290bcSAlexander V. Chernikov *
198301290bcSAlexander V. Chernikov *
199301290bcSAlexander V. Chernikov *
200301290bcSAlexander V. Chernikov * -prepare_mod: allocate structures for table modification.
201301290bcSAlexander V. Chernikov * typedef int (ta_prepare_mod)(void *ta_buf, uint64_t *pflags);
202fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), unlocked. (M_WAITOK). Returns 0 on success.
203301290bcSAlexander V. Chernikov *
204301290bcSAlexander V. Chernikov * Allocate all needed state for table modification. Caller
205301290bcSAlexander V. Chernikov * should use `struct mod_item` to store new state in @ta_buf.
206301290bcSAlexander V. Chernikov * Up to TA_BUF_SZ (128 bytes) can be stored in @ta_buf.
207301290bcSAlexander V. Chernikov *
208301290bcSAlexander V. Chernikov *
209301290bcSAlexander V. Chernikov *
210301290bcSAlexander V. Chernikov * -fill_mod: copy some data to new state/
211301290bcSAlexander V. Chernikov * typedef int (ta_fill_mod)(void *ta_state, struct table_info *ti,
212301290bcSAlexander V. Chernikov * void *ta_buf, uint64_t *pflags);
213fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), locked (UH). (M_NOWAIT). Returns 0 on success.
214301290bcSAlexander V. Chernikov *
215301290bcSAlexander V. Chernikov * Copy as much data as we can to minimize changes under WLOCK.
216301290bcSAlexander V. Chernikov * For example, array can be merged inside this callback.
217301290bcSAlexander V. Chernikov *
218301290bcSAlexander V. Chernikov *
219301290bcSAlexander V. Chernikov *
220301290bcSAlexander V. Chernikov * -modify: perform final modification.
221301290bcSAlexander V. Chernikov * typedef void (ta_modify)(void *ta_state, struct table_info *ti,
222301290bcSAlexander V. Chernikov * void *ta_buf, uint64_t pflags);
223fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), locked (UH+WLOCK). (M_NOWAIT).
224301290bcSAlexander V. Chernikov *
225301290bcSAlexander V. Chernikov * Performs all changes necessary to switch to new structures.
226301290bcSAlexander V. Chernikov * * Caller should save old pointers to @ta_buf storage.
227301290bcSAlexander V. Chernikov *
228301290bcSAlexander V. Chernikov *
229301290bcSAlexander V. Chernikov *
230301290bcSAlexander V. Chernikov * -flush_mod: flush table modification state.
231301290bcSAlexander V. Chernikov * typedef void (ta_flush_mod)(void *ta_buf);
232fd0869d5SAlexander V. Chernikov * OPTIONAL(need_modify), unlocked. (M_WAITOK).
233301290bcSAlexander V. Chernikov *
234301290bcSAlexander V. Chernikov * Performs flush for the following:
235301290bcSAlexander V. Chernikov * - prepare_mod (modification was not necessary)
236301290bcSAlexander V. Chernikov * - modify (for the old state)
237301290bcSAlexander V. Chernikov *
238301290bcSAlexander V. Chernikov *
239301290bcSAlexander V. Chernikov *
240301290bcSAlexander V. Chernikov * -change_gi: monitor table info pointer changes
241301290bcSAlexander V. Chernikov * typedef void (ta_change_ti)(void *ta_state, struct table_info *ti);
242301290bcSAlexander V. Chernikov * OPTIONAL, locked (UH). (M_NOWAIT).
243301290bcSAlexander V. Chernikov *
244301290bcSAlexander V. Chernikov * Called on @ti pointer changed. Called immediately after -init
245301290bcSAlexander V. Chernikov * to set initial state.
246301290bcSAlexander V. Chernikov *
247301290bcSAlexander V. Chernikov *
248301290bcSAlexander V. Chernikov *
249301290bcSAlexander V. Chernikov * -foreach: calls @f for each table entry
250301290bcSAlexander V. Chernikov * typedef void ta_foreach(void *ta_state, struct table_info *ti,
251301290bcSAlexander V. Chernikov * ta_foreach_f *f, void *arg);
252301290bcSAlexander V. Chernikov * MANDATORY, locked(UH). (M_NOWAIT).
253301290bcSAlexander V. Chernikov *
254301290bcSAlexander V. Chernikov * Runs callback with specified argument for each table entry,
255301290bcSAlexander V. Chernikov * Typically used for dumping table entries.
256301290bcSAlexander V. Chernikov *
257301290bcSAlexander V. Chernikov *
258301290bcSAlexander V. Chernikov *
259301290bcSAlexander V. Chernikov * -dump_tentry: dump table entry in current @tentry format.
260301290bcSAlexander V. Chernikov * typedef int ta_dump_tentry(void *ta_state, struct table_info *ti, void *e,
261301290bcSAlexander V. Chernikov * ipfw_obj_tentry *tent);
262301290bcSAlexander V. Chernikov * MANDATORY, locked(UH). (M_NOWAIT). Returns 0 on success.
263301290bcSAlexander V. Chernikov *
264301290bcSAlexander V. Chernikov * Dumps entry @e to @tent.
265301290bcSAlexander V. Chernikov *
266301290bcSAlexander V. Chernikov *
267a4641f4eSPedro F. Giffuni * -print_config: prints custom algorithm options into buffer.
268301290bcSAlexander V. Chernikov * typedef void (ta_print_config)(void *ta_state, struct table_info *ti,
269301290bcSAlexander V. Chernikov * char *buf, size_t bufsize);
270301290bcSAlexander V. Chernikov * OPTIONAL. locked(UH). (M_NOWAIT).
271301290bcSAlexander V. Chernikov *
272301290bcSAlexander V. Chernikov * Prints custom algorithm options in the format suitable to pass
273301290bcSAlexander V. Chernikov * back to -init callback.
274301290bcSAlexander V. Chernikov *
275301290bcSAlexander V. Chernikov *
276301290bcSAlexander V. Chernikov *
277301290bcSAlexander V. Chernikov * -dump_tinfo: dumps algo-specific info.
278301290bcSAlexander V. Chernikov * typedef void ta_dump_tinfo(void *ta_state, struct table_info *ti,
279301290bcSAlexander V. Chernikov * ipfw_ta_tinfo *tinfo);
280301290bcSAlexander V. Chernikov * OPTIONAL. locked(UH). (M_NOWAIT).
281301290bcSAlexander V. Chernikov *
282301290bcSAlexander V. Chernikov * Dumps options like items size/hash size, etc.
283301290bcSAlexander V. Chernikov */
284301290bcSAlexander V. Chernikov
285b1d105bcSAlexander V. Chernikov MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
2869f7d47b0SAlexander V. Chernikov
2870bce0c23SAlexander V. Chernikov /*
2880bce0c23SAlexander V. Chernikov * Utility structures/functions common to more than one algo
2890bce0c23SAlexander V. Chernikov */
2900bce0c23SAlexander V. Chernikov
2910bce0c23SAlexander V. Chernikov struct mod_item {
2920bce0c23SAlexander V. Chernikov void *main_ptr;
2930bce0c23SAlexander V. Chernikov size_t size;
2940bce0c23SAlexander V. Chernikov void *main_ptr6;
2950bce0c23SAlexander V. Chernikov size_t size6;
2960bce0c23SAlexander V. Chernikov };
2970bce0c23SAlexander V. Chernikov
29868394ec8SAlexander V. Chernikov static int badd(const void *key, void *item, void *base, size_t nmemb,
29968394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *));
30068394ec8SAlexander V. Chernikov static int bdel(const void *key, void *base, size_t nmemb, size_t size,
30168394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *));
30268394ec8SAlexander V. Chernikov
30368394ec8SAlexander V. Chernikov /*
304c21034b7SAlexander V. Chernikov * ADDR implementation using radix
30568394ec8SAlexander V. Chernikov *
30668394ec8SAlexander V. Chernikov */
30768394ec8SAlexander V. Chernikov
3089f7d47b0SAlexander V. Chernikov /*
3099f7d47b0SAlexander V. Chernikov * The radix code expects addr and mask to be array of bytes,
3109f7d47b0SAlexander V. Chernikov * with the first byte being the length of the array. rn_inithead
3119f7d47b0SAlexander V. Chernikov * is called with the offset in bits of the lookup key within the
3129f7d47b0SAlexander V. Chernikov * array. If we use a sockaddr_in as the underlying type,
3139f7d47b0SAlexander V. Chernikov * sin_len is conveniently located at offset 0, sin_addr is at
3149f7d47b0SAlexander V. Chernikov * offset 4 and normally aligned.
3159f7d47b0SAlexander V. Chernikov * But for portability, let's avoid assumption and make the code explicit
3169f7d47b0SAlexander V. Chernikov */
3179f7d47b0SAlexander V. Chernikov #define KEY_LEN(v) *((uint8_t *)&(v))
3189f7d47b0SAlexander V. Chernikov /*
31981cac390SArseny Smalyuk * Do not require radix to compare more than actual IPv4/IPv6/MAC address
3209f7d47b0SAlexander V. Chernikov */
3219f7d47b0SAlexander V. Chernikov #define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t))
322e0a8b9eeSAlexander V. Chernikov #define KEY_LEN_INET6 (offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr))
32381cac390SArseny Smalyuk #define KEY_LEN_MAC (offsetof(struct sa_mac, mac_addr) + ETHER_ADDR_LEN)
3249f7d47b0SAlexander V. Chernikov
3259f7d47b0SAlexander V. Chernikov #define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr))
326e0a8b9eeSAlexander V. Chernikov #define OFF_LEN_INET6 (8 * offsetof(struct sa_in6, sin6_addr))
32781cac390SArseny Smalyuk #define OFF_LEN_MAC (8 * offsetof(struct sa_mac, mac_addr))
3289f7d47b0SAlexander V. Chernikov
32981cac390SArseny Smalyuk struct addr_radix_entry {
3309f7d47b0SAlexander V. Chernikov struct radix_node rn[2];
331e0a8b9eeSAlexander V. Chernikov struct sockaddr_in addr;
332e0a8b9eeSAlexander V. Chernikov uint32_t value;
333e0a8b9eeSAlexander V. Chernikov uint8_t masklen;
334e0a8b9eeSAlexander V. Chernikov };
335e0a8b9eeSAlexander V. Chernikov
336e0a8b9eeSAlexander V. Chernikov struct sa_in6 {
337e0a8b9eeSAlexander V. Chernikov uint8_t sin6_len;
338e0a8b9eeSAlexander V. Chernikov uint8_t sin6_family;
339e0a8b9eeSAlexander V. Chernikov uint8_t pad[2];
340e0a8b9eeSAlexander V. Chernikov struct in6_addr sin6_addr;
341e0a8b9eeSAlexander V. Chernikov };
342e0a8b9eeSAlexander V. Chernikov
34381cac390SArseny Smalyuk struct addr_radix_xentry {
344e0a8b9eeSAlexander V. Chernikov struct radix_node rn[2];
345e0a8b9eeSAlexander V. Chernikov struct sa_in6 addr6;
346e0a8b9eeSAlexander V. Chernikov uint32_t value;
347e0a8b9eeSAlexander V. Chernikov uint8_t masklen;
3489f7d47b0SAlexander V. Chernikov };
3499f7d47b0SAlexander V. Chernikov
35081cac390SArseny Smalyuk struct addr_radix_cfg {
3515f379342SAlexander V. Chernikov struct radix_node_head *head4;
3525f379342SAlexander V. Chernikov struct radix_node_head *head6;
3535f379342SAlexander V. Chernikov size_t count4;
3545f379342SAlexander V. Chernikov size_t count6;
3555f379342SAlexander V. Chernikov };
3565f379342SAlexander V. Chernikov
35781cac390SArseny Smalyuk struct sa_mac {
35881cac390SArseny Smalyuk uint8_t mac_len;
35981cac390SArseny Smalyuk struct ether_addr mac_addr;
36081cac390SArseny Smalyuk };
36181cac390SArseny Smalyuk
362c21034b7SAlexander V. Chernikov struct ta_buf_radix
3630bce0c23SAlexander V. Chernikov {
3640bce0c23SAlexander V. Chernikov void *ent_ptr;
3650bce0c23SAlexander V. Chernikov struct sockaddr *addr_ptr;
3660bce0c23SAlexander V. Chernikov struct sockaddr *mask_ptr;
3670bce0c23SAlexander V. Chernikov union {
3680bce0c23SAlexander V. Chernikov struct {
3690bce0c23SAlexander V. Chernikov struct sockaddr_in sa;
3700bce0c23SAlexander V. Chernikov struct sockaddr_in ma;
3710bce0c23SAlexander V. Chernikov } a4;
3720bce0c23SAlexander V. Chernikov struct {
3730bce0c23SAlexander V. Chernikov struct sa_in6 sa;
3740bce0c23SAlexander V. Chernikov struct sa_in6 ma;
3750bce0c23SAlexander V. Chernikov } a6;
37681cac390SArseny Smalyuk struct {
37781cac390SArseny Smalyuk struct sa_mac sa;
37881cac390SArseny Smalyuk struct sa_mac ma;
37981cac390SArseny Smalyuk } mac;
3800bce0c23SAlexander V. Chernikov } addr;
3810bce0c23SAlexander V. Chernikov };
3820bce0c23SAlexander V. Chernikov
38381cac390SArseny Smalyuk static int ta_lookup_addr_radix(struct table_info *ti, void *key, uint32_t keylen,
3849fe15d06SAlexander V. Chernikov uint32_t *val);
38581cac390SArseny Smalyuk static int ta_init_addr_radix(struct ip_fw_chain *ch, void **ta_state,
3869fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags);
3879fe15d06SAlexander V. Chernikov static int flush_radix_entry(struct radix_node *rn, void *arg);
38881cac390SArseny Smalyuk static void ta_destroy_addr_radix(void *ta_state, struct table_info *ti);
38981cac390SArseny Smalyuk static void ta_dump_addr_radix_tinfo(void *ta_state, struct table_info *ti,
3909fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo);
39181cac390SArseny Smalyuk static int ta_dump_addr_radix_tentry(void *ta_state, struct table_info *ti,
3929fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent);
39381cac390SArseny Smalyuk static int ta_find_addr_radix_tentry(void *ta_state, struct table_info *ti,
3949fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent);
39581cac390SArseny Smalyuk static void ta_foreach_addr_radix(void *ta_state, struct table_info *ti,
3969fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg);
39781cac390SArseny Smalyuk static void tei_to_sockaddr_ent_addr(struct tentry_info *tei, struct sockaddr *sa,
3989fe15d06SAlexander V. Chernikov struct sockaddr *ma, int *set_mask);
39981cac390SArseny Smalyuk static int ta_prepare_add_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
4009fe15d06SAlexander V. Chernikov void *ta_buf);
40181cac390SArseny Smalyuk static int ta_add_addr_radix(void *ta_state, struct table_info *ti,
4029fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
40381cac390SArseny Smalyuk static int ta_prepare_del_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
4049fe15d06SAlexander V. Chernikov void *ta_buf);
40581cac390SArseny Smalyuk static int ta_del_addr_radix(void *ta_state, struct table_info *ti,
4069fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
4079fe15d06SAlexander V. Chernikov static void ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
4089fe15d06SAlexander V. Chernikov void *ta_buf);
4099fe15d06SAlexander V. Chernikov static int ta_need_modify_radix(void *ta_state, struct table_info *ti,
4109fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags);
4119fe15d06SAlexander V. Chernikov
4129f7d47b0SAlexander V. Chernikov static int
ta_lookup_addr_radix(struct table_info * ti,void * key,uint32_t keylen,uint32_t * val)41381cac390SArseny Smalyuk ta_lookup_addr_radix(struct table_info *ti, void *key, uint32_t keylen,
4149f7d47b0SAlexander V. Chernikov uint32_t *val)
4159f7d47b0SAlexander V. Chernikov {
4169f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh;
4179f7d47b0SAlexander V. Chernikov
4189f7d47b0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) {
41981cac390SArseny Smalyuk struct addr_radix_entry *ent;
4209f7d47b0SAlexander V. Chernikov struct sockaddr_in sa;
4219f7d47b0SAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET;
4229f7d47b0SAlexander V. Chernikov sa.sin_addr.s_addr = *((in_addr_t *)key);
4239f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state;
42481cac390SArseny Smalyuk ent = (struct addr_radix_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh));
4259f7d47b0SAlexander V. Chernikov if (ent != NULL) {
4269f7d47b0SAlexander V. Chernikov *val = ent->value;
4279f7d47b0SAlexander V. Chernikov return (1);
4289f7d47b0SAlexander V. Chernikov }
42981cac390SArseny Smalyuk } else if (keylen == sizeof(struct in6_addr)) {
43081cac390SArseny Smalyuk struct addr_radix_xentry *xent;
431e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6;
4329f7d47b0SAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6;
4339f7d47b0SAlexander V. Chernikov memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
4349f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate;
43581cac390SArseny Smalyuk xent = (struct addr_radix_xentry *)(rnh->rnh_matchaddr(&sa6, &rnh->rh));
4369f7d47b0SAlexander V. Chernikov if (xent != NULL) {
4379f7d47b0SAlexander V. Chernikov *val = xent->value;
4389f7d47b0SAlexander V. Chernikov return (1);
4399f7d47b0SAlexander V. Chernikov }
4409f7d47b0SAlexander V. Chernikov }
4419f7d47b0SAlexander V. Chernikov
4429f7d47b0SAlexander V. Chernikov return (0);
4439f7d47b0SAlexander V. Chernikov }
4449f7d47b0SAlexander V. Chernikov
4459f7d47b0SAlexander V. Chernikov /*
4469f7d47b0SAlexander V. Chernikov * New table
4479f7d47b0SAlexander V. Chernikov */
4489f7d47b0SAlexander V. Chernikov static int
ta_init_addr_radix(struct ip_fw_chain * ch,void ** ta_state,struct table_info * ti,char * data,uint8_t tflags)44981cac390SArseny Smalyuk ta_init_addr_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
450914bffb6SAlexander V. Chernikov char *data, uint8_t tflags)
4519f7d47b0SAlexander V. Chernikov {
45281cac390SArseny Smalyuk struct addr_radix_cfg *cfg;
4539f7d47b0SAlexander V. Chernikov
4549f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->state, OFF_LEN_INET))
4559f7d47b0SAlexander V. Chernikov return (ENOMEM);
4569f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) {
4579f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state);
4589f7d47b0SAlexander V. Chernikov return (ENOMEM);
4599f7d47b0SAlexander V. Chernikov }
4609f7d47b0SAlexander V. Chernikov
46181cac390SArseny Smalyuk cfg = malloc(sizeof(struct addr_radix_cfg), M_IPFW, M_WAITOK | M_ZERO);
4625f379342SAlexander V. Chernikov
4635f379342SAlexander V. Chernikov *ta_state = cfg;
46481cac390SArseny Smalyuk ti->lookup = ta_lookup_addr_radix;
4659f7d47b0SAlexander V. Chernikov
4669f7d47b0SAlexander V. Chernikov return (0);
4679f7d47b0SAlexander V. Chernikov }
4689f7d47b0SAlexander V. Chernikov
4699f7d47b0SAlexander V. Chernikov static int
flush_radix_entry(struct radix_node * rn,void * arg)470a399f8beSAlexander V. Chernikov flush_radix_entry(struct radix_node *rn, void *arg)
4719f7d47b0SAlexander V. Chernikov {
4729f7d47b0SAlexander V. Chernikov struct radix_node_head * const rnh = arg;
47381cac390SArseny Smalyuk struct addr_radix_entry *ent;
4749f7d47b0SAlexander V. Chernikov
47581cac390SArseny Smalyuk ent = (struct addr_radix_entry *)
47661eee0e2SAlexander V. Chernikov rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, &rnh->rh);
4779f7d47b0SAlexander V. Chernikov if (ent != NULL)
4789f7d47b0SAlexander V. Chernikov free(ent, M_IPFW_TBL);
4799f7d47b0SAlexander V. Chernikov return (0);
4809f7d47b0SAlexander V. Chernikov }
4819f7d47b0SAlexander V. Chernikov
4829f7d47b0SAlexander V. Chernikov static void
ta_destroy_addr_radix(void * ta_state,struct table_info * ti)48381cac390SArseny Smalyuk ta_destroy_addr_radix(void *ta_state, struct table_info *ti)
4849f7d47b0SAlexander V. Chernikov {
48581cac390SArseny Smalyuk struct addr_radix_cfg *cfg;
4869f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh;
4879f7d47b0SAlexander V. Chernikov
48881cac390SArseny Smalyuk cfg = (struct addr_radix_cfg *)ta_state;
4895f379342SAlexander V. Chernikov
4909f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state);
49161eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
4929f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state);
4939f7d47b0SAlexander V. Chernikov
4949f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate);
49561eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
4969f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->xstate);
4975f379342SAlexander V. Chernikov
4985f379342SAlexander V. Chernikov free(cfg, M_IPFW);
4995f379342SAlexander V. Chernikov }
5005f379342SAlexander V. Chernikov
5015f379342SAlexander V. Chernikov /*
5025f379342SAlexander V. Chernikov * Provide algo-specific table info
5035f379342SAlexander V. Chernikov */
5045f379342SAlexander V. Chernikov static void
ta_dump_addr_radix_tinfo(void * ta_state,struct table_info * ti,ipfw_ta_tinfo * tinfo)50581cac390SArseny Smalyuk ta_dump_addr_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
5065f379342SAlexander V. Chernikov {
50781cac390SArseny Smalyuk struct addr_radix_cfg *cfg;
5085f379342SAlexander V. Chernikov
50981cac390SArseny Smalyuk cfg = (struct addr_radix_cfg *)ta_state;
5105f379342SAlexander V. Chernikov
5115f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
5125f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_RADIX;
5135f379342SAlexander V. Chernikov tinfo->count4 = cfg->count4;
51481cac390SArseny Smalyuk tinfo->itemsize4 = sizeof(struct addr_radix_entry);
5155f379342SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_RADIX;
5165f379342SAlexander V. Chernikov tinfo->count6 = cfg->count6;
51781cac390SArseny Smalyuk tinfo->itemsize6 = sizeof(struct addr_radix_xentry);
5189f7d47b0SAlexander V. Chernikov }
5199f7d47b0SAlexander V. Chernikov
5209f7d47b0SAlexander V. Chernikov static int
ta_dump_addr_radix_tentry(void * ta_state,struct table_info * ti,void * e,ipfw_obj_tentry * tent)52181cac390SArseny Smalyuk ta_dump_addr_radix_tentry(void *ta_state, struct table_info *ti, void *e,
52281d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent)
5239f7d47b0SAlexander V. Chernikov {
52481cac390SArseny Smalyuk struct addr_radix_entry *n;
5259fe15d06SAlexander V. Chernikov #ifdef INET6
52681cac390SArseny Smalyuk struct addr_radix_xentry *xn;
5279fe15d06SAlexander V. Chernikov #endif
5289f7d47b0SAlexander V. Chernikov
52981cac390SArseny Smalyuk n = (struct addr_radix_entry *)e;
5309f7d47b0SAlexander V. Chernikov
5319f7d47b0SAlexander V. Chernikov /* Guess IPv4/IPv6 radix by sockaddr family */
5329f7d47b0SAlexander V. Chernikov if (n->addr.sin_family == AF_INET) {
53381d3153dSAlexander V. Chernikov tent->k.addr.s_addr = n->addr.sin_addr.s_addr;
534e0a8b9eeSAlexander V. Chernikov tent->masklen = n->masklen;
53581d3153dSAlexander V. Chernikov tent->subtype = AF_INET;
5360cba2b28SAlexander V. Chernikov tent->v.kidx = n->value;
5379f7d47b0SAlexander V. Chernikov #ifdef INET6
5389f7d47b0SAlexander V. Chernikov } else {
53981cac390SArseny Smalyuk xn = (struct addr_radix_xentry *)e;
540ba3e1361SAndrey V. Elsukov memcpy(&tent->k.addr6, &xn->addr6.sin6_addr,
541ba3e1361SAndrey V. Elsukov sizeof(struct in6_addr));
542e0a8b9eeSAlexander V. Chernikov tent->masklen = xn->masklen;
54381d3153dSAlexander V. Chernikov tent->subtype = AF_INET6;
5440cba2b28SAlexander V. Chernikov tent->v.kidx = xn->value;
5459f7d47b0SAlexander V. Chernikov #endif
5469f7d47b0SAlexander V. Chernikov }
5479f7d47b0SAlexander V. Chernikov
5489f7d47b0SAlexander V. Chernikov return (0);
5499f7d47b0SAlexander V. Chernikov }
5509f7d47b0SAlexander V. Chernikov
55181d3153dSAlexander V. Chernikov static int
ta_find_addr_radix_tentry(void * ta_state,struct table_info * ti,ipfw_obj_tentry * tent)55281cac390SArseny Smalyuk ta_find_addr_radix_tentry(void *ta_state, struct table_info *ti,
553914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent)
55481d3153dSAlexander V. Chernikov {
55581d3153dSAlexander V. Chernikov struct radix_node_head *rnh;
55681d3153dSAlexander V. Chernikov void *e;
55781d3153dSAlexander V. Chernikov
55881d3153dSAlexander V. Chernikov e = NULL;
559914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) {
56081d3153dSAlexander V. Chernikov struct sockaddr_in sa;
56181d3153dSAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET;
562914bffb6SAlexander V. Chernikov sa.sin_addr.s_addr = tent->k.addr.s_addr;
56381d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state;
56461eee0e2SAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa, &rnh->rh);
56581cac390SArseny Smalyuk } else if (tent->subtype == AF_INET6) {
566e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6;
56781d3153dSAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6;
568914bffb6SAlexander V. Chernikov memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr));
56981d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate;
57061eee0e2SAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa6, &rnh->rh);
57181d3153dSAlexander V. Chernikov }
57281d3153dSAlexander V. Chernikov
57381d3153dSAlexander V. Chernikov if (e != NULL) {
57481cac390SArseny Smalyuk ta_dump_addr_radix_tentry(ta_state, ti, e, tent);
57581d3153dSAlexander V. Chernikov return (0);
57681d3153dSAlexander V. Chernikov }
57781d3153dSAlexander V. Chernikov
57881d3153dSAlexander V. Chernikov return (ENOENT);
57981d3153dSAlexander V. Chernikov }
58081d3153dSAlexander V. Chernikov
5819f7d47b0SAlexander V. Chernikov static void
ta_foreach_addr_radix(void * ta_state,struct table_info * ti,ta_foreach_f * f,void * arg)58281cac390SArseny Smalyuk ta_foreach_addr_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
5839f7d47b0SAlexander V. Chernikov void *arg)
5849f7d47b0SAlexander V. Chernikov {
5859f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh;
5869f7d47b0SAlexander V. Chernikov
5879f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state);
58861eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg);
5899f7d47b0SAlexander V. Chernikov
5909f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate);
59161eee0e2SAlexander V. Chernikov rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg);
5929f7d47b0SAlexander V. Chernikov }
5939f7d47b0SAlexander V. Chernikov
5949f7d47b0SAlexander V. Chernikov #ifdef INET6
595d699ee2dSAlexander V. Chernikov static inline void ipv6_writemask(struct in6_addr *addr6, uint8_t mask);
596d699ee2dSAlexander V. Chernikov
5979f7d47b0SAlexander V. Chernikov static inline void
ipv6_writemask(struct in6_addr * addr6,uint8_t mask)5989f7d47b0SAlexander V. Chernikov ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
5999f7d47b0SAlexander V. Chernikov {
6009f7d47b0SAlexander V. Chernikov uint32_t *cp;
6019f7d47b0SAlexander V. Chernikov
6029f7d47b0SAlexander V. Chernikov for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32)
6039f7d47b0SAlexander V. Chernikov *cp++ = 0xFFFFFFFF;
60437aefa2aSAlexander V. Chernikov if (mask > 0)
6059f7d47b0SAlexander V. Chernikov *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
6069f7d47b0SAlexander V. Chernikov }
6079f7d47b0SAlexander V. Chernikov #endif
6089f7d47b0SAlexander V. Chernikov
6092e324d29SAlexander V. Chernikov static void
tei_to_sockaddr_ent_addr(struct tentry_info * tei,struct sockaddr * sa,struct sockaddr * ma,int * set_mask)61081cac390SArseny Smalyuk tei_to_sockaddr_ent_addr(struct tentry_info *tei, struct sockaddr *sa,
6112e324d29SAlexander V. Chernikov struct sockaddr *ma, int *set_mask)
6122e324d29SAlexander V. Chernikov {
6132e324d29SAlexander V. Chernikov int mlen;
6149fe15d06SAlexander V. Chernikov #ifdef INET
6152e324d29SAlexander V. Chernikov struct sockaddr_in *addr, *mask;
6169fe15d06SAlexander V. Chernikov #endif
6179fe15d06SAlexander V. Chernikov #ifdef INET6
618720ee730SAlexander V. Chernikov struct sa_in6 *addr6, *mask6;
6199fe15d06SAlexander V. Chernikov #endif
6202e324d29SAlexander V. Chernikov in_addr_t a4;
6212e324d29SAlexander V. Chernikov
6222e324d29SAlexander V. Chernikov mlen = tei->masklen;
6232e324d29SAlexander V. Chernikov
6242e324d29SAlexander V. Chernikov if (tei->subtype == AF_INET) {
6252e324d29SAlexander V. Chernikov #ifdef INET
6262e324d29SAlexander V. Chernikov addr = (struct sockaddr_in *)sa;
6272e324d29SAlexander V. Chernikov mask = (struct sockaddr_in *)ma;
6282e324d29SAlexander V. Chernikov /* Set 'total' structure length */
6292e324d29SAlexander V. Chernikov KEY_LEN(*addr) = KEY_LEN_INET;
6302e324d29SAlexander V. Chernikov KEY_LEN(*mask) = KEY_LEN_INET;
6312e324d29SAlexander V. Chernikov addr->sin_family = AF_INET;
6322e324d29SAlexander V. Chernikov mask->sin_addr.s_addr =
6332e324d29SAlexander V. Chernikov htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
6342e324d29SAlexander V. Chernikov a4 = *((in_addr_t *)tei->paddr);
6352e324d29SAlexander V. Chernikov addr->sin_addr.s_addr = a4 & mask->sin_addr.s_addr;
6362e324d29SAlexander V. Chernikov if (mlen != 32)
6372e324d29SAlexander V. Chernikov *set_mask = 1;
6382e324d29SAlexander V. Chernikov else
6392e324d29SAlexander V. Chernikov *set_mask = 0;
6402e324d29SAlexander V. Chernikov #endif
6412e324d29SAlexander V. Chernikov #ifdef INET6
6422e324d29SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) {
6432e324d29SAlexander V. Chernikov /* IPv6 case */
644720ee730SAlexander V. Chernikov addr6 = (struct sa_in6 *)sa;
645720ee730SAlexander V. Chernikov mask6 = (struct sa_in6 *)ma;
6462e324d29SAlexander V. Chernikov /* Set 'total' structure length */
6472e324d29SAlexander V. Chernikov KEY_LEN(*addr6) = KEY_LEN_INET6;
6482e324d29SAlexander V. Chernikov KEY_LEN(*mask6) = KEY_LEN_INET6;
6492e324d29SAlexander V. Chernikov addr6->sin6_family = AF_INET6;
6502e324d29SAlexander V. Chernikov ipv6_writemask(&mask6->sin6_addr, mlen);
6512e324d29SAlexander V. Chernikov memcpy(&addr6->sin6_addr, tei->paddr, sizeof(struct in6_addr));
6522e324d29SAlexander V. Chernikov APPLY_MASK(&addr6->sin6_addr, &mask6->sin6_addr);
6532e324d29SAlexander V. Chernikov if (mlen != 128)
6542e324d29SAlexander V. Chernikov *set_mask = 1;
6552e324d29SAlexander V. Chernikov else
6562e324d29SAlexander V. Chernikov *set_mask = 0;
6572e324d29SAlexander V. Chernikov #endif
6582e324d29SAlexander V. Chernikov }
659d699ee2dSAlexander V. Chernikov }
6609f7d47b0SAlexander V. Chernikov
6619f7d47b0SAlexander V. Chernikov static int
ta_prepare_add_addr_radix(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)66281cac390SArseny Smalyuk ta_prepare_add_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
66368394ec8SAlexander V. Chernikov void *ta_buf)
6649f7d47b0SAlexander V. Chernikov {
665c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb;
66681cac390SArseny Smalyuk struct addr_radix_entry *ent;
667d699ee2dSAlexander V. Chernikov #ifdef INET6
66881cac390SArseny Smalyuk struct addr_radix_xentry *xent;
669d699ee2dSAlexander V. Chernikov #endif
6702e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask;
6712e324d29SAlexander V. Chernikov int mlen, set_mask;
6729f7d47b0SAlexander V. Chernikov
673c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf;
6749f7d47b0SAlexander V. Chernikov
6759f7d47b0SAlexander V. Chernikov mlen = tei->masklen;
6762e324d29SAlexander V. Chernikov set_mask = 0;
6779f7d47b0SAlexander V. Chernikov
678ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) {
6799f7d47b0SAlexander V. Chernikov #ifdef INET
6809f7d47b0SAlexander V. Chernikov if (mlen > 32)
6819f7d47b0SAlexander V. Chernikov return (EINVAL);
6829f7d47b0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
683e0a8b9eeSAlexander V. Chernikov ent->masklen = mlen;
6842e324d29SAlexander V. Chernikov
6852e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&ent->addr;
6862e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma;
6879f7d47b0SAlexander V. Chernikov tb->ent_ptr = ent;
6889f7d47b0SAlexander V. Chernikov #endif
6899f7d47b0SAlexander V. Chernikov #ifdef INET6
690ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) {
6919f7d47b0SAlexander V. Chernikov /* IPv6 case */
6929f7d47b0SAlexander V. Chernikov if (mlen > 128)
6939f7d47b0SAlexander V. Chernikov return (EINVAL);
6949f7d47b0SAlexander V. Chernikov xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
695e0a8b9eeSAlexander V. Chernikov xent->masklen = mlen;
6962e324d29SAlexander V. Chernikov
6972e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&xent->addr6;
6982e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma;
6999f7d47b0SAlexander V. Chernikov tb->ent_ptr = xent;
7009f7d47b0SAlexander V. Chernikov #endif
7019f7d47b0SAlexander V. Chernikov } else {
7029f7d47b0SAlexander V. Chernikov /* Unknown CIDR type */
7039f7d47b0SAlexander V. Chernikov return (EINVAL);
7049f7d47b0SAlexander V. Chernikov }
7059f7d47b0SAlexander V. Chernikov
70681cac390SArseny Smalyuk tei_to_sockaddr_ent_addr(tei, addr, mask, &set_mask);
7072e324d29SAlexander V. Chernikov /* Set pointers */
7082e324d29SAlexander V. Chernikov tb->addr_ptr = addr;
7092e324d29SAlexander V. Chernikov if (set_mask != 0)
7102e324d29SAlexander V. Chernikov tb->mask_ptr = mask;
7112e324d29SAlexander V. Chernikov
7129f7d47b0SAlexander V. Chernikov return (0);
7139f7d47b0SAlexander V. Chernikov }
7149f7d47b0SAlexander V. Chernikov
7159f7d47b0SAlexander V. Chernikov static int
ta_add_addr_radix(void * ta_state,struct table_info * ti,struct tentry_info * tei,void * ta_buf,uint32_t * pnum)71681cac390SArseny Smalyuk ta_add_addr_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
717b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum)
7189f7d47b0SAlexander V. Chernikov {
71981cac390SArseny Smalyuk struct addr_radix_cfg *cfg;
7209f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh;
7219f7d47b0SAlexander V. Chernikov struct radix_node *rn;
722c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb;
723648e8380SAlexander V. Chernikov uint32_t *old_value, value;
7249f7d47b0SAlexander V. Chernikov
72581cac390SArseny Smalyuk cfg = (struct addr_radix_cfg *)ta_state;
726c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf;
7279f7d47b0SAlexander V. Chernikov
72813263632SAlexander V. Chernikov /* Save current entry value from @tei */
72913263632SAlexander V. Chernikov if (tei->subtype == AF_INET) {
7309f7d47b0SAlexander V. Chernikov rnh = ti->state;
73181cac390SArseny Smalyuk ((struct addr_radix_entry *)tb->ent_ptr)->value = tei->value;
73213263632SAlexander V. Chernikov } else {
7339f7d47b0SAlexander V. Chernikov rnh = ti->xstate;
73481cac390SArseny Smalyuk ((struct addr_radix_xentry *)tb->ent_ptr)->value = tei->value;
73513263632SAlexander V. Chernikov }
7369f7d47b0SAlexander V. Chernikov
7374c0c07a5SAlexander V. Chernikov /* Search for an entry first */
73861eee0e2SAlexander V. Chernikov rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
7394c0c07a5SAlexander V. Chernikov if (rn != NULL) {
740ac35ff17SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
7419f7d47b0SAlexander V. Chernikov return (EEXIST);
742ac35ff17SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */
743648e8380SAlexander V. Chernikov if (tei->subtype == AF_INET)
74481cac390SArseny Smalyuk old_value = &((struct addr_radix_entry *)rn)->value;
745648e8380SAlexander V. Chernikov else
74681cac390SArseny Smalyuk old_value = &((struct addr_radix_xentry *)rn)->value;
747648e8380SAlexander V. Chernikov
748648e8380SAlexander V. Chernikov value = *old_value;
749648e8380SAlexander V. Chernikov *old_value = tei->value;
750648e8380SAlexander V. Chernikov tei->value = value;
751ac35ff17SAlexander V. Chernikov
752ac35ff17SAlexander V. Chernikov /* Indicate that update has happened instead of addition */
753ac35ff17SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED;
754adea6201SAlexander V. Chernikov *pnum = 0;
755e0a8b9eeSAlexander V. Chernikov
756e0a8b9eeSAlexander V. Chernikov return (0);
757ac35ff17SAlexander V. Chernikov }
758ac35ff17SAlexander V. Chernikov
7594c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
7604c0c07a5SAlexander V. Chernikov return (EFBIG);
7614c0c07a5SAlexander V. Chernikov
76261eee0e2SAlexander V. Chernikov rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, &rnh->rh,tb->ent_ptr);
7634c0c07a5SAlexander V. Chernikov if (rn == NULL) {
7644c0c07a5SAlexander V. Chernikov /* Unknown error */
7654c0c07a5SAlexander V. Chernikov return (EINVAL);
7664c0c07a5SAlexander V. Chernikov }
7674c0c07a5SAlexander V. Chernikov
7685f379342SAlexander V. Chernikov if (tei->subtype == AF_INET)
7695f379342SAlexander V. Chernikov cfg->count4++;
7705f379342SAlexander V. Chernikov else
7715f379342SAlexander V. Chernikov cfg->count6++;
772ac35ff17SAlexander V. Chernikov tb->ent_ptr = NULL;
773adea6201SAlexander V. Chernikov *pnum = 1;
7749f7d47b0SAlexander V. Chernikov
7759f7d47b0SAlexander V. Chernikov return (0);
7769f7d47b0SAlexander V. Chernikov }
7779f7d47b0SAlexander V. Chernikov
7789f7d47b0SAlexander V. Chernikov static int
ta_prepare_del_addr_radix(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)77981cac390SArseny Smalyuk ta_prepare_del_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
78068394ec8SAlexander V. Chernikov void *ta_buf)
7819f7d47b0SAlexander V. Chernikov {
782c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb;
7832e324d29SAlexander V. Chernikov struct sockaddr *addr, *mask;
7842e324d29SAlexander V. Chernikov int mlen, set_mask;
7859f7d47b0SAlexander V. Chernikov
786c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf;
7879f7d47b0SAlexander V. Chernikov
7889f7d47b0SAlexander V. Chernikov mlen = tei->masklen;
7892e324d29SAlexander V. Chernikov set_mask = 0;
7909f7d47b0SAlexander V. Chernikov
791ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) {
792e0a8b9eeSAlexander V. Chernikov if (mlen > 32)
793e0a8b9eeSAlexander V. Chernikov return (EINVAL);
7942e324d29SAlexander V. Chernikov
7952e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a4.sa;
7962e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a4.ma;
7979f7d47b0SAlexander V. Chernikov #ifdef INET6
798ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) {
7999f7d47b0SAlexander V. Chernikov if (mlen > 128)
8009f7d47b0SAlexander V. Chernikov return (EINVAL);
8012e324d29SAlexander V. Chernikov
8022e324d29SAlexander V. Chernikov addr = (struct sockaddr *)&tb->addr.a6.sa;
8032e324d29SAlexander V. Chernikov mask = (struct sockaddr *)&tb->addr.a6.ma;
8049f7d47b0SAlexander V. Chernikov #endif
8059f7d47b0SAlexander V. Chernikov } else
8069f7d47b0SAlexander V. Chernikov return (EINVAL);
8079f7d47b0SAlexander V. Chernikov
80881cac390SArseny Smalyuk tei_to_sockaddr_ent_addr(tei, addr, mask, &set_mask);
8092e324d29SAlexander V. Chernikov tb->addr_ptr = addr;
8102e324d29SAlexander V. Chernikov if (set_mask != 0)
8112e324d29SAlexander V. Chernikov tb->mask_ptr = mask;
8122e324d29SAlexander V. Chernikov
8139f7d47b0SAlexander V. Chernikov return (0);
8149f7d47b0SAlexander V. Chernikov }
8159f7d47b0SAlexander V. Chernikov
8169f7d47b0SAlexander V. Chernikov static int
ta_del_addr_radix(void * ta_state,struct table_info * ti,struct tentry_info * tei,void * ta_buf,uint32_t * pnum)81781cac390SArseny Smalyuk ta_del_addr_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
818b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum)
8199f7d47b0SAlexander V. Chernikov {
82081cac390SArseny Smalyuk struct addr_radix_cfg *cfg;
8219f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh;
8229f7d47b0SAlexander V. Chernikov struct radix_node *rn;
823c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb;
8249f7d47b0SAlexander V. Chernikov
82581cac390SArseny Smalyuk cfg = (struct addr_radix_cfg *)ta_state;
826c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf;
8279f7d47b0SAlexander V. Chernikov
828ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET)
8299f7d47b0SAlexander V. Chernikov rnh = ti->state;
8309f7d47b0SAlexander V. Chernikov else
8319f7d47b0SAlexander V. Chernikov rnh = ti->xstate;
8329f7d47b0SAlexander V. Chernikov
83361eee0e2SAlexander V. Chernikov rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
8349f7d47b0SAlexander V. Chernikov
8353a845e10SAlexander V. Chernikov if (rn == NULL)
8363a845e10SAlexander V. Chernikov return (ENOENT);
8373a845e10SAlexander V. Chernikov
838648e8380SAlexander V. Chernikov /* Save entry value to @tei */
839648e8380SAlexander V. Chernikov if (tei->subtype == AF_INET)
84081cac390SArseny Smalyuk tei->value = ((struct addr_radix_entry *)rn)->value;
841648e8380SAlexander V. Chernikov else
84281cac390SArseny Smalyuk tei->value = ((struct addr_radix_xentry *)rn)->value;
843648e8380SAlexander V. Chernikov
8449f7d47b0SAlexander V. Chernikov tb->ent_ptr = rn;
8459f7d47b0SAlexander V. Chernikov
8465f379342SAlexander V. Chernikov if (tei->subtype == AF_INET)
8475f379342SAlexander V. Chernikov cfg->count4--;
8485f379342SAlexander V. Chernikov else
8495f379342SAlexander V. Chernikov cfg->count6--;
850adea6201SAlexander V. Chernikov *pnum = 1;
851adea6201SAlexander V. Chernikov
8529f7d47b0SAlexander V. Chernikov return (0);
8539f7d47b0SAlexander V. Chernikov }
8549f7d47b0SAlexander V. Chernikov
8559f7d47b0SAlexander V. Chernikov static void
ta_flush_radix_entry(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)856a399f8beSAlexander V. Chernikov ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
85768394ec8SAlexander V. Chernikov void *ta_buf)
8589f7d47b0SAlexander V. Chernikov {
859c21034b7SAlexander V. Chernikov struct ta_buf_radix *tb;
8609f7d47b0SAlexander V. Chernikov
861c21034b7SAlexander V. Chernikov tb = (struct ta_buf_radix *)ta_buf;
8629f7d47b0SAlexander V. Chernikov
863ac35ff17SAlexander V. Chernikov if (tb->ent_ptr != NULL)
8649f7d47b0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL);
8659f7d47b0SAlexander V. Chernikov }
8669f7d47b0SAlexander V. Chernikov
867b6ee846eSAlexander V. Chernikov static int
ta_need_modify_radix(void * ta_state,struct table_info * ti,uint32_t count,uint64_t * pflags)868301290bcSAlexander V. Chernikov ta_need_modify_radix(void *ta_state, struct table_info *ti, uint32_t count,
869b6ee846eSAlexander V. Chernikov uint64_t *pflags)
870b6ee846eSAlexander V. Chernikov {
871b6ee846eSAlexander V. Chernikov
872b6ee846eSAlexander V. Chernikov /*
8730bce0c23SAlexander V. Chernikov * radix does not require additional memory allocations
874b6ee846eSAlexander V. Chernikov * other than nodes itself. Adding new masks to the tree do
875b6ee846eSAlexander V. Chernikov * but we don't have any API to call (and we don't known which
876b6ee846eSAlexander V. Chernikov * sizes do we need).
877b6ee846eSAlexander V. Chernikov */
878301290bcSAlexander V. Chernikov return (0);
879b6ee846eSAlexander V. Chernikov }
880b6ee846eSAlexander V. Chernikov
881c21034b7SAlexander V. Chernikov struct table_algo addr_radix = {
882c21034b7SAlexander V. Chernikov .name = "addr:radix",
883c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR,
88457a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT,
885c21034b7SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_radix),
88681cac390SArseny Smalyuk .init = ta_init_addr_radix,
88781cac390SArseny Smalyuk .destroy = ta_destroy_addr_radix,
88881cac390SArseny Smalyuk .prepare_add = ta_prepare_add_addr_radix,
88981cac390SArseny Smalyuk .prepare_del = ta_prepare_del_addr_radix,
89081cac390SArseny Smalyuk .add = ta_add_addr_radix,
89181cac390SArseny Smalyuk .del = ta_del_addr_radix,
892a399f8beSAlexander V. Chernikov .flush_entry = ta_flush_radix_entry,
89381cac390SArseny Smalyuk .foreach = ta_foreach_addr_radix,
89481cac390SArseny Smalyuk .dump_tentry = ta_dump_addr_radix_tentry,
89581cac390SArseny Smalyuk .find_tentry = ta_find_addr_radix_tentry,
89681cac390SArseny Smalyuk .dump_tinfo = ta_dump_addr_radix_tinfo,
897301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_radix,
8989f7d47b0SAlexander V. Chernikov };
8999f7d47b0SAlexander V. Chernikov
9009f7d47b0SAlexander V. Chernikov /*
901c21034b7SAlexander V. Chernikov * addr:hash cmds
90274b941f0SAlexander V. Chernikov *
90374b941f0SAlexander V. Chernikov *
90474b941f0SAlexander V. Chernikov * ti->data:
90574b941f0SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
90674b941f0SAlexander V. Chernikov * [ 8][ 8[ 8][ 8]
90774b941f0SAlexander V. Chernikov *
90874b941f0SAlexander V. Chernikov * inv.mask4: 32 - mask
90974b941f0SAlexander V. Chernikov * inv.mask6:
91074b941f0SAlexander V. Chernikov * 1) _slow lookup: mask
91174b941f0SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8
91274b941f0SAlexander V. Chernikov * 3) _64: 8
913ce2817b5SAlexander V. Chernikov *
914ce2817b5SAlexander V. Chernikov *
915ce2817b5SAlexander V. Chernikov * pflags:
916ce2817b5SAlexander V. Chernikov * [v4=1/v6=0][hsize]
917ce2817b5SAlexander V. Chernikov * [ 32][ 32]
91874b941f0SAlexander V. Chernikov */
91974b941f0SAlexander V. Chernikov
92074b941f0SAlexander V. Chernikov struct chashentry;
92174b941f0SAlexander V. Chernikov
92274b941f0SAlexander V. Chernikov SLIST_HEAD(chashbhead, chashentry);
92374b941f0SAlexander V. Chernikov
92474b941f0SAlexander V. Chernikov struct chash_cfg {
92574b941f0SAlexander V. Chernikov struct chashbhead *head4;
92674b941f0SAlexander V. Chernikov struct chashbhead *head6;
92774b941f0SAlexander V. Chernikov size_t size4;
92874b941f0SAlexander V. Chernikov size_t size6;
929ce2817b5SAlexander V. Chernikov size_t items4;
930ce2817b5SAlexander V. Chernikov size_t items6;
93174b941f0SAlexander V. Chernikov uint8_t mask4;
93274b941f0SAlexander V. Chernikov uint8_t mask6;
93374b941f0SAlexander V. Chernikov };
93474b941f0SAlexander V. Chernikov
93574b941f0SAlexander V. Chernikov struct chashentry {
93674b941f0SAlexander V. Chernikov SLIST_ENTRY(chashentry) next;
93774b941f0SAlexander V. Chernikov uint32_t value;
93874b941f0SAlexander V. Chernikov uint32_t type;
93974b941f0SAlexander V. Chernikov union {
94074b941f0SAlexander V. Chernikov uint32_t a4; /* Host format */
94174b941f0SAlexander V. Chernikov struct in6_addr a6; /* Network format */
94274b941f0SAlexander V. Chernikov } a;
94374b941f0SAlexander V. Chernikov };
94474b941f0SAlexander V. Chernikov
9450bce0c23SAlexander V. Chernikov struct ta_buf_chash
9460bce0c23SAlexander V. Chernikov {
9470bce0c23SAlexander V. Chernikov void *ent_ptr;
9480bce0c23SAlexander V. Chernikov struct chashentry ent;
9490bce0c23SAlexander V. Chernikov };
9500bce0c23SAlexander V. Chernikov
951d699ee2dSAlexander V. Chernikov #ifdef INET
9529fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip(uint32_t addr, int hsize);
953d699ee2dSAlexander V. Chernikov #endif
954d699ee2dSAlexander V. Chernikov #ifdef INET6
9559fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip6(struct in6_addr *addr6, int hsize);
9569fe15d06SAlexander V. Chernikov static __inline uint16_t hash_ip64(struct in6_addr *addr6, int hsize);
9579fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip6_slow(struct in6_addr *addr6, void *key,
9589fe15d06SAlexander V. Chernikov int mask, int hsize);
9599fe15d06SAlexander V. Chernikov static __inline uint32_t hash_ip6_al(struct in6_addr *addr6, void *key, int mask,
9609fe15d06SAlexander V. Chernikov int hsize);
961d699ee2dSAlexander V. Chernikov #endif
9629fe15d06SAlexander V. Chernikov static int ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
9639fe15d06SAlexander V. Chernikov uint32_t *val);
9649fe15d06SAlexander V. Chernikov static int ta_lookup_chash_aligned(struct table_info *ti, void *key,
9659fe15d06SAlexander V. Chernikov uint32_t keylen, uint32_t *val);
9669fe15d06SAlexander V. Chernikov static int ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
9679fe15d06SAlexander V. Chernikov uint32_t *val);
9689fe15d06SAlexander V. Chernikov static int chash_parse_opts(struct chash_cfg *cfg, char *data);
9699fe15d06SAlexander V. Chernikov static void ta_print_chash_config(void *ta_state, struct table_info *ti,
9709fe15d06SAlexander V. Chernikov char *buf, size_t bufsize);
9719e3a53fdSAlexander V. Chernikov static int ta_log2(uint32_t v);
9729fe15d06SAlexander V. Chernikov static int ta_init_chash(struct ip_fw_chain *ch, void **ta_state,
9739fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags);
9749fe15d06SAlexander V. Chernikov static void ta_destroy_chash(void *ta_state, struct table_info *ti);
9759fe15d06SAlexander V. Chernikov static void ta_dump_chash_tinfo(void *ta_state, struct table_info *ti,
9769fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo);
9779fe15d06SAlexander V. Chernikov static int ta_dump_chash_tentry(void *ta_state, struct table_info *ti,
9789fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent);
9799fe15d06SAlexander V. Chernikov static uint32_t hash_ent(struct chashentry *ent, int af, int mlen,
9809fe15d06SAlexander V. Chernikov uint32_t size);
9819fe15d06SAlexander V. Chernikov static int tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent);
9829fe15d06SAlexander V. Chernikov static int ta_find_chash_tentry(void *ta_state, struct table_info *ti,
9839fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent);
9849fe15d06SAlexander V. Chernikov static void ta_foreach_chash(void *ta_state, struct table_info *ti,
9859fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg);
9869fe15d06SAlexander V. Chernikov static int ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
9879fe15d06SAlexander V. Chernikov void *ta_buf);
9889fe15d06SAlexander V. Chernikov static int ta_add_chash(void *ta_state, struct table_info *ti,
9899fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
9909fe15d06SAlexander V. Chernikov static int ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
9919fe15d06SAlexander V. Chernikov void *ta_buf);
9929fe15d06SAlexander V. Chernikov static int ta_del_chash(void *ta_state, struct table_info *ti,
9939fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
9949fe15d06SAlexander V. Chernikov static void ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
9959fe15d06SAlexander V. Chernikov void *ta_buf);
9969fe15d06SAlexander V. Chernikov static int ta_need_modify_chash(void *ta_state, struct table_info *ti,
9979fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags);
9989fe15d06SAlexander V. Chernikov static int ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags);
9999fe15d06SAlexander V. Chernikov static int ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf,
10009fe15d06SAlexander V. Chernikov uint64_t *pflags);
10019fe15d06SAlexander V. Chernikov static void ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf,
10029fe15d06SAlexander V. Chernikov uint64_t pflags);
10039fe15d06SAlexander V. Chernikov static void ta_flush_mod_chash(void *ta_buf);
10049fe15d06SAlexander V. Chernikov
1005d699ee2dSAlexander V. Chernikov #ifdef INET
100674b941f0SAlexander V. Chernikov static __inline uint32_t
hash_ip(uint32_t addr,int hsize)100774b941f0SAlexander V. Chernikov hash_ip(uint32_t addr, int hsize)
100874b941f0SAlexander V. Chernikov {
100974b941f0SAlexander V. Chernikov
101074b941f0SAlexander V. Chernikov return (addr % (hsize - 1));
101174b941f0SAlexander V. Chernikov }
1012d699ee2dSAlexander V. Chernikov #endif
101374b941f0SAlexander V. Chernikov
1014d699ee2dSAlexander V. Chernikov #ifdef INET6
101574b941f0SAlexander V. Chernikov static __inline uint32_t
hash_ip6(struct in6_addr * addr6,int hsize)101674b941f0SAlexander V. Chernikov hash_ip6(struct in6_addr *addr6, int hsize)
101774b941f0SAlexander V. Chernikov {
101874b941f0SAlexander V. Chernikov uint32_t i;
101974b941f0SAlexander V. Chernikov
102074b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^
102174b941f0SAlexander V. Chernikov addr6->s6_addr32[2] ^ addr6->s6_addr32[3];
102274b941f0SAlexander V. Chernikov
102374b941f0SAlexander V. Chernikov return (i % (hsize - 1));
102474b941f0SAlexander V. Chernikov }
102574b941f0SAlexander V. Chernikov
102674b941f0SAlexander V. Chernikov static __inline uint16_t
hash_ip64(struct in6_addr * addr6,int hsize)102774b941f0SAlexander V. Chernikov hash_ip64(struct in6_addr *addr6, int hsize)
102874b941f0SAlexander V. Chernikov {
102974b941f0SAlexander V. Chernikov uint32_t i;
103074b941f0SAlexander V. Chernikov
103174b941f0SAlexander V. Chernikov i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1];
103274b941f0SAlexander V. Chernikov
103374b941f0SAlexander V. Chernikov return (i % (hsize - 1));
103474b941f0SAlexander V. Chernikov }
103574b941f0SAlexander V. Chernikov
103674b941f0SAlexander V. Chernikov static __inline uint32_t
hash_ip6_slow(struct in6_addr * addr6,void * key,int mask,int hsize)103774b941f0SAlexander V. Chernikov hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize)
103874b941f0SAlexander V. Chernikov {
103974b941f0SAlexander V. Chernikov struct in6_addr mask6;
104074b941f0SAlexander V. Chernikov
104174b941f0SAlexander V. Chernikov ipv6_writemask(&mask6, mask);
104274b941f0SAlexander V. Chernikov memcpy(addr6, key, sizeof(struct in6_addr));
104374b941f0SAlexander V. Chernikov APPLY_MASK(addr6, &mask6);
104474b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize));
104574b941f0SAlexander V. Chernikov }
104674b941f0SAlexander V. Chernikov
104774b941f0SAlexander V. Chernikov static __inline uint32_t
hash_ip6_al(struct in6_addr * addr6,void * key,int mask,int hsize)104874b941f0SAlexander V. Chernikov hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize)
104974b941f0SAlexander V. Chernikov {
105074b941f0SAlexander V. Chernikov uint64_t *paddr;
105174b941f0SAlexander V. Chernikov
105274b941f0SAlexander V. Chernikov paddr = (uint64_t *)addr6;
105374b941f0SAlexander V. Chernikov *paddr = 0;
105474b941f0SAlexander V. Chernikov *(paddr + 1) = 0;
105574b941f0SAlexander V. Chernikov memcpy(addr6, key, mask);
105674b941f0SAlexander V. Chernikov return (hash_ip6(addr6, hsize));
105774b941f0SAlexander V. Chernikov }
1058d699ee2dSAlexander V. Chernikov #endif
105974b941f0SAlexander V. Chernikov
106074b941f0SAlexander V. Chernikov static int
ta_lookup_chash_slow(struct table_info * ti,void * key,uint32_t keylen,uint32_t * val)106174b941f0SAlexander V. Chernikov ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
106274b941f0SAlexander V. Chernikov uint32_t *val)
106374b941f0SAlexander V. Chernikov {
106474b941f0SAlexander V. Chernikov struct chashbhead *head;
106574b941f0SAlexander V. Chernikov struct chashentry *ent;
106674b941f0SAlexander V. Chernikov uint16_t hash, hsize;
106774b941f0SAlexander V. Chernikov uint8_t imask;
106874b941f0SAlexander V. Chernikov
106974b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) {
1070d699ee2dSAlexander V. Chernikov #ifdef INET
107174b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state;
107274b941f0SAlexander V. Chernikov imask = ti->data >> 24;
107374b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8);
107474b941f0SAlexander V. Chernikov uint32_t a;
107574b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key));
107674b941f0SAlexander V. Chernikov a = a >> imask;
107774b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize);
107874b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) {
107974b941f0SAlexander V. Chernikov if (ent->a.a4 == a) {
108074b941f0SAlexander V. Chernikov *val = ent->value;
108174b941f0SAlexander V. Chernikov return (1);
108274b941f0SAlexander V. Chernikov }
108374b941f0SAlexander V. Chernikov }
1084d699ee2dSAlexander V. Chernikov #endif
108574b941f0SAlexander V. Chernikov } else {
1086d699ee2dSAlexander V. Chernikov #ifdef INET6
108774b941f0SAlexander V. Chernikov /* IPv6: worst scenario: non-round mask */
108874b941f0SAlexander V. Chernikov struct in6_addr addr6;
108974b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate;
109074b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16;
109174b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF);
109274b941f0SAlexander V. Chernikov hash = hash_ip6_slow(&addr6, key, imask, hsize);
109374b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) {
109474b941f0SAlexander V. Chernikov if (memcmp(&ent->a.a6, &addr6, 16) == 0) {
109574b941f0SAlexander V. Chernikov *val = ent->value;
109674b941f0SAlexander V. Chernikov return (1);
109774b941f0SAlexander V. Chernikov }
109874b941f0SAlexander V. Chernikov }
1099d699ee2dSAlexander V. Chernikov #endif
110074b941f0SAlexander V. Chernikov }
110174b941f0SAlexander V. Chernikov
110274b941f0SAlexander V. Chernikov return (0);
110374b941f0SAlexander V. Chernikov }
110474b941f0SAlexander V. Chernikov
110574b941f0SAlexander V. Chernikov static int
ta_lookup_chash_aligned(struct table_info * ti,void * key,uint32_t keylen,uint32_t * val)110674b941f0SAlexander V. Chernikov ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
110774b941f0SAlexander V. Chernikov uint32_t *val)
110874b941f0SAlexander V. Chernikov {
110974b941f0SAlexander V. Chernikov struct chashbhead *head;
111074b941f0SAlexander V. Chernikov struct chashentry *ent;
111174b941f0SAlexander V. Chernikov uint16_t hash, hsize;
111274b941f0SAlexander V. Chernikov uint8_t imask;
111374b941f0SAlexander V. Chernikov
111474b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) {
1115d699ee2dSAlexander V. Chernikov #ifdef INET
111674b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state;
111774b941f0SAlexander V. Chernikov imask = ti->data >> 24;
111874b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8);
111974b941f0SAlexander V. Chernikov uint32_t a;
112074b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key));
112174b941f0SAlexander V. Chernikov a = a >> imask;
112274b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize);
112374b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) {
112474b941f0SAlexander V. Chernikov if (ent->a.a4 == a) {
112574b941f0SAlexander V. Chernikov *val = ent->value;
112674b941f0SAlexander V. Chernikov return (1);
112774b941f0SAlexander V. Chernikov }
112874b941f0SAlexander V. Chernikov }
1129d699ee2dSAlexander V. Chernikov #endif
113074b941f0SAlexander V. Chernikov } else {
1131d699ee2dSAlexander V. Chernikov #ifdef INET6
113274b941f0SAlexander V. Chernikov /* IPv6: aligned to 8bit mask */
113374b941f0SAlexander V. Chernikov struct in6_addr addr6;
113474b941f0SAlexander V. Chernikov uint64_t *paddr, *ptmp;
113574b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate;
113674b941f0SAlexander V. Chernikov imask = (ti->data & 0xFF0000) >> 16;
113774b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF);
113874b941f0SAlexander V. Chernikov
113974b941f0SAlexander V. Chernikov hash = hash_ip6_al(&addr6, key, imask, hsize);
114074b941f0SAlexander V. Chernikov paddr = (uint64_t *)&addr6;
114174b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) {
114274b941f0SAlexander V. Chernikov ptmp = (uint64_t *)&ent->a.a6;
114374b941f0SAlexander V. Chernikov if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) {
114474b941f0SAlexander V. Chernikov *val = ent->value;
114574b941f0SAlexander V. Chernikov return (1);
114674b941f0SAlexander V. Chernikov }
114774b941f0SAlexander V. Chernikov }
1148d699ee2dSAlexander V. Chernikov #endif
114974b941f0SAlexander V. Chernikov }
115074b941f0SAlexander V. Chernikov
115174b941f0SAlexander V. Chernikov return (0);
115274b941f0SAlexander V. Chernikov }
115374b941f0SAlexander V. Chernikov
115474b941f0SAlexander V. Chernikov static int
ta_lookup_chash_64(struct table_info * ti,void * key,uint32_t keylen,uint32_t * val)115574b941f0SAlexander V. Chernikov ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
115674b941f0SAlexander V. Chernikov uint32_t *val)
115774b941f0SAlexander V. Chernikov {
115874b941f0SAlexander V. Chernikov struct chashbhead *head;
115974b941f0SAlexander V. Chernikov struct chashentry *ent;
116074b941f0SAlexander V. Chernikov uint16_t hash, hsize;
116174b941f0SAlexander V. Chernikov uint8_t imask;
116274b941f0SAlexander V. Chernikov
116374b941f0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) {
1164d699ee2dSAlexander V. Chernikov #ifdef INET
116574b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->state;
116674b941f0SAlexander V. Chernikov imask = ti->data >> 24;
116774b941f0SAlexander V. Chernikov hsize = 1 << ((ti->data & 0xFFFF) >> 8);
116874b941f0SAlexander V. Chernikov uint32_t a;
116974b941f0SAlexander V. Chernikov a = ntohl(*((in_addr_t *)key));
117074b941f0SAlexander V. Chernikov a = a >> imask;
117174b941f0SAlexander V. Chernikov hash = hash_ip(a, hsize);
117274b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) {
117374b941f0SAlexander V. Chernikov if (ent->a.a4 == a) {
117474b941f0SAlexander V. Chernikov *val = ent->value;
117574b941f0SAlexander V. Chernikov return (1);
117674b941f0SAlexander V. Chernikov }
117774b941f0SAlexander V. Chernikov }
1178d699ee2dSAlexander V. Chernikov #endif
117974b941f0SAlexander V. Chernikov } else {
1180d699ee2dSAlexander V. Chernikov #ifdef INET6
118174b941f0SAlexander V. Chernikov /* IPv6: /64 */
118274b941f0SAlexander V. Chernikov uint64_t a6, *paddr;
118374b941f0SAlexander V. Chernikov head = (struct chashbhead *)ti->xstate;
118474b941f0SAlexander V. Chernikov paddr = (uint64_t *)key;
118574b941f0SAlexander V. Chernikov hsize = 1 << (ti->data & 0xFF);
118674b941f0SAlexander V. Chernikov a6 = *paddr;
118774b941f0SAlexander V. Chernikov hash = hash_ip64((struct in6_addr *)key, hsize);
118874b941f0SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) {
118974b941f0SAlexander V. Chernikov paddr = (uint64_t *)&ent->a.a6;
119074b941f0SAlexander V. Chernikov if (a6 == *paddr) {
119174b941f0SAlexander V. Chernikov *val = ent->value;
119274b941f0SAlexander V. Chernikov return (1);
119374b941f0SAlexander V. Chernikov }
119474b941f0SAlexander V. Chernikov }
1195d699ee2dSAlexander V. Chernikov #endif
119674b941f0SAlexander V. Chernikov }
119774b941f0SAlexander V. Chernikov
119874b941f0SAlexander V. Chernikov return (0);
119974b941f0SAlexander V. Chernikov }
120074b941f0SAlexander V. Chernikov
120174b941f0SAlexander V. Chernikov static int
chash_parse_opts(struct chash_cfg * cfg,char * data)12020bce0c23SAlexander V. Chernikov chash_parse_opts(struct chash_cfg *cfg, char *data)
120374b941f0SAlexander V. Chernikov {
120474b941f0SAlexander V. Chernikov char *pdel, *pend, *s;
120574b941f0SAlexander V. Chernikov int mask4, mask6;
120674b941f0SAlexander V. Chernikov
12070bce0c23SAlexander V. Chernikov mask4 = cfg->mask4;
12080bce0c23SAlexander V. Chernikov mask6 = cfg->mask6;
120974b941f0SAlexander V. Chernikov
121074b941f0SAlexander V. Chernikov if (data == NULL)
121174b941f0SAlexander V. Chernikov return (0);
121274b941f0SAlexander V. Chernikov if ((pdel = strchr(data, ' ')) == NULL)
121374b941f0SAlexander V. Chernikov return (0);
121474b941f0SAlexander V. Chernikov while (*pdel == ' ')
121574b941f0SAlexander V. Chernikov pdel++;
121674b941f0SAlexander V. Chernikov if (strncmp(pdel, "masks=", 6) != 0)
121774b941f0SAlexander V. Chernikov return (EINVAL);
121874b941f0SAlexander V. Chernikov if ((s = strchr(pdel, ' ')) != NULL)
121974b941f0SAlexander V. Chernikov *s++ = '\0';
122074b941f0SAlexander V. Chernikov
122174b941f0SAlexander V. Chernikov pdel += 6;
122274b941f0SAlexander V. Chernikov /* Need /XX[,/YY] */
122374b941f0SAlexander V. Chernikov if (*pdel++ != '/')
122474b941f0SAlexander V. Chernikov return (EINVAL);
122574b941f0SAlexander V. Chernikov mask4 = strtol(pdel, &pend, 10);
122674b941f0SAlexander V. Chernikov if (*pend == ',') {
122774b941f0SAlexander V. Chernikov /* ,/YY */
122874b941f0SAlexander V. Chernikov pdel = pend + 1;
122974b941f0SAlexander V. Chernikov if (*pdel++ != '/')
123074b941f0SAlexander V. Chernikov return (EINVAL);
123174b941f0SAlexander V. Chernikov mask6 = strtol(pdel, &pend, 10);
123274b941f0SAlexander V. Chernikov if (*pend != '\0')
123374b941f0SAlexander V. Chernikov return (EINVAL);
123474b941f0SAlexander V. Chernikov } else if (*pend != '\0')
123574b941f0SAlexander V. Chernikov return (EINVAL);
123674b941f0SAlexander V. Chernikov
123774b941f0SAlexander V. Chernikov if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128)
123874b941f0SAlexander V. Chernikov return (EINVAL);
123974b941f0SAlexander V. Chernikov
12400bce0c23SAlexander V. Chernikov cfg->mask4 = mask4;
12410bce0c23SAlexander V. Chernikov cfg->mask6 = mask6;
124274b941f0SAlexander V. Chernikov
124374b941f0SAlexander V. Chernikov return (0);
124474b941f0SAlexander V. Chernikov }
124574b941f0SAlexander V. Chernikov
124674b941f0SAlexander V. Chernikov static void
ta_print_chash_config(void * ta_state,struct table_info * ti,char * buf,size_t bufsize)124774b941f0SAlexander V. Chernikov ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf,
124874b941f0SAlexander V. Chernikov size_t bufsize)
124974b941f0SAlexander V. Chernikov {
12500bce0c23SAlexander V. Chernikov struct chash_cfg *cfg;
125174b941f0SAlexander V. Chernikov
12520bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state;
125374b941f0SAlexander V. Chernikov
12540bce0c23SAlexander V. Chernikov if (cfg->mask4 != 32 || cfg->mask6 != 128)
1255c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s masks=/%d,/%d", "addr:hash",
12560bce0c23SAlexander V. Chernikov cfg->mask4, cfg->mask6);
125774b941f0SAlexander V. Chernikov else
1258c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s", "addr:hash");
125974b941f0SAlexander V. Chernikov }
126074b941f0SAlexander V. Chernikov
1261914bffb6SAlexander V. Chernikov static int
ta_log2(uint32_t v)12629e3a53fdSAlexander V. Chernikov ta_log2(uint32_t v)
1263914bffb6SAlexander V. Chernikov {
1264914bffb6SAlexander V. Chernikov uint32_t r;
1265914bffb6SAlexander V. Chernikov
1266914bffb6SAlexander V. Chernikov r = 0;
1267914bffb6SAlexander V. Chernikov while (v >>= 1)
1268914bffb6SAlexander V. Chernikov r++;
1269914bffb6SAlexander V. Chernikov
1270914bffb6SAlexander V. Chernikov return (r);
1271914bffb6SAlexander V. Chernikov }
127274b941f0SAlexander V. Chernikov
127374b941f0SAlexander V. Chernikov /*
127474b941f0SAlexander V. Chernikov * New table.
127574b941f0SAlexander V. Chernikov * We assume 'data' to be either NULL or the following format:
1276c21034b7SAlexander V. Chernikov * 'addr:hash [masks=/32[,/128]]'
127774b941f0SAlexander V. Chernikov */
127874b941f0SAlexander V. Chernikov static int
ta_init_chash(struct ip_fw_chain * ch,void ** ta_state,struct table_info * ti,char * data,uint8_t tflags)127974b941f0SAlexander V. Chernikov ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
1280914bffb6SAlexander V. Chernikov char *data, uint8_t tflags)
128174b941f0SAlexander V. Chernikov {
128274b941f0SAlexander V. Chernikov int error, i;
1283914bffb6SAlexander V. Chernikov uint32_t hsize;
12840bce0c23SAlexander V. Chernikov struct chash_cfg *cfg;
128574b941f0SAlexander V. Chernikov
12860bce0c23SAlexander V. Chernikov cfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO);
128774b941f0SAlexander V. Chernikov
12880bce0c23SAlexander V. Chernikov cfg->mask4 = 32;
12890bce0c23SAlexander V. Chernikov cfg->mask6 = 128;
129074b941f0SAlexander V. Chernikov
12910bce0c23SAlexander V. Chernikov if ((error = chash_parse_opts(cfg, data)) != 0) {
12920bce0c23SAlexander V. Chernikov free(cfg, M_IPFW);
129374b941f0SAlexander V. Chernikov return (error);
129474b941f0SAlexander V. Chernikov }
129574b941f0SAlexander V. Chernikov
12960bce0c23SAlexander V. Chernikov cfg->size4 = 128;
12970bce0c23SAlexander V. Chernikov cfg->size6 = 128;
129874b941f0SAlexander V. Chernikov
12990bce0c23SAlexander V. Chernikov cfg->head4 = malloc(sizeof(struct chashbhead) * cfg->size4, M_IPFW,
130074b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO);
13010bce0c23SAlexander V. Chernikov cfg->head6 = malloc(sizeof(struct chashbhead) * cfg->size6, M_IPFW,
130274b941f0SAlexander V. Chernikov M_WAITOK | M_ZERO);
13030bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++)
13040bce0c23SAlexander V. Chernikov SLIST_INIT(&cfg->head4[i]);
13050bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++)
13060bce0c23SAlexander V. Chernikov SLIST_INIT(&cfg->head6[i]);
130774b941f0SAlexander V. Chernikov
13080bce0c23SAlexander V. Chernikov *ta_state = cfg;
13090bce0c23SAlexander V. Chernikov ti->state = cfg->head4;
13100bce0c23SAlexander V. Chernikov ti->xstate = cfg->head6;
131174b941f0SAlexander V. Chernikov
131274b941f0SAlexander V. Chernikov /* Store data depending on v6 mask length */
13139e3a53fdSAlexander V. Chernikov hsize = ta_log2(cfg->size4) << 8 | ta_log2(cfg->size6);
13140bce0c23SAlexander V. Chernikov if (cfg->mask6 == 64) {
13150bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 | (128 - cfg->mask6) << 16|
1316914bffb6SAlexander V. Chernikov hsize;
131774b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_64;
13180bce0c23SAlexander V. Chernikov } else if ((cfg->mask6 % 8) == 0) {
13190bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 |
13200bce0c23SAlexander V. Chernikov cfg->mask6 << 13 | hsize;
132174b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_aligned;
132274b941f0SAlexander V. Chernikov } else {
132374b941f0SAlexander V. Chernikov /* don't do that! */
13240bce0c23SAlexander V. Chernikov ti->data = (32 - cfg->mask4) << 24 |
13250bce0c23SAlexander V. Chernikov cfg->mask6 << 16 | hsize;
132674b941f0SAlexander V. Chernikov ti->lookup = ta_lookup_chash_slow;
132774b941f0SAlexander V. Chernikov }
132874b941f0SAlexander V. Chernikov
132974b941f0SAlexander V. Chernikov return (0);
133074b941f0SAlexander V. Chernikov }
133174b941f0SAlexander V. Chernikov
133274b941f0SAlexander V. Chernikov static void
ta_destroy_chash(void * ta_state,struct table_info * ti)133374b941f0SAlexander V. Chernikov ta_destroy_chash(void *ta_state, struct table_info *ti)
133474b941f0SAlexander V. Chernikov {
13350bce0c23SAlexander V. Chernikov struct chash_cfg *cfg;
133674b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next;
133774b941f0SAlexander V. Chernikov int i;
133874b941f0SAlexander V. Chernikov
13390bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state;
134074b941f0SAlexander V. Chernikov
13410bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++)
13420bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next)
134374b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL);
134474b941f0SAlexander V. Chernikov
13450bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++)
13460bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next)
134774b941f0SAlexander V. Chernikov free(ent, M_IPFW_TBL);
134874b941f0SAlexander V. Chernikov
13490bce0c23SAlexander V. Chernikov free(cfg->head4, M_IPFW);
13500bce0c23SAlexander V. Chernikov free(cfg->head6, M_IPFW);
1351ce2817b5SAlexander V. Chernikov
13520bce0c23SAlexander V. Chernikov free(cfg, M_IPFW);
135374b941f0SAlexander V. Chernikov }
135474b941f0SAlexander V. Chernikov
13555f379342SAlexander V. Chernikov static void
ta_dump_chash_tinfo(void * ta_state,struct table_info * ti,ipfw_ta_tinfo * tinfo)13565f379342SAlexander V. Chernikov ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
13575f379342SAlexander V. Chernikov {
13585f379342SAlexander V. Chernikov struct chash_cfg *cfg;
13595f379342SAlexander V. Chernikov
13605f379342SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state;
13615f379342SAlexander V. Chernikov
13625f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
13635f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_HASH;
13645f379342SAlexander V. Chernikov tinfo->size4 = cfg->size4;
13655f379342SAlexander V. Chernikov tinfo->count4 = cfg->items4;
13665f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct chashentry);
13675f379342SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_HASH;
13685f379342SAlexander V. Chernikov tinfo->size6 = cfg->size6;
13695f379342SAlexander V. Chernikov tinfo->count6 = cfg->items6;
13705f379342SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct chashentry);
13715f379342SAlexander V. Chernikov }
13725f379342SAlexander V. Chernikov
137374b941f0SAlexander V. Chernikov static int
ta_dump_chash_tentry(void * ta_state,struct table_info * ti,void * e,ipfw_obj_tentry * tent)137474b941f0SAlexander V. Chernikov ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e,
137574b941f0SAlexander V. Chernikov ipfw_obj_tentry *tent)
137674b941f0SAlexander V. Chernikov {
13770bce0c23SAlexander V. Chernikov struct chash_cfg *cfg;
137874b941f0SAlexander V. Chernikov struct chashentry *ent;
137974b941f0SAlexander V. Chernikov
13800bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state;
138174b941f0SAlexander V. Chernikov ent = (struct chashentry *)e;
138274b941f0SAlexander V. Chernikov
138374b941f0SAlexander V. Chernikov if (ent->type == AF_INET) {
13840bce0c23SAlexander V. Chernikov tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - cfg->mask4));
13850bce0c23SAlexander V. Chernikov tent->masklen = cfg->mask4;
138674b941f0SAlexander V. Chernikov tent->subtype = AF_INET;
13870cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value;
138874b941f0SAlexander V. Chernikov #ifdef INET6
138974b941f0SAlexander V. Chernikov } else {
1390ba3e1361SAndrey V. Elsukov memcpy(&tent->k.addr6, &ent->a.a6, sizeof(struct in6_addr));
13910bce0c23SAlexander V. Chernikov tent->masklen = cfg->mask6;
139274b941f0SAlexander V. Chernikov tent->subtype = AF_INET6;
13930cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value;
139474b941f0SAlexander V. Chernikov #endif
139574b941f0SAlexander V. Chernikov }
139674b941f0SAlexander V. Chernikov
139774b941f0SAlexander V. Chernikov return (0);
139874b941f0SAlexander V. Chernikov }
139974b941f0SAlexander V. Chernikov
1400ce2817b5SAlexander V. Chernikov static uint32_t
hash_ent(struct chashentry * ent,int af,int mlen,uint32_t size)1401ce2817b5SAlexander V. Chernikov hash_ent(struct chashentry *ent, int af, int mlen, uint32_t size)
1402ce2817b5SAlexander V. Chernikov {
1403ce2817b5SAlexander V. Chernikov uint32_t hash;
1404ce2817b5SAlexander V. Chernikov
1405d699ee2dSAlexander V. Chernikov hash = 0;
1406d699ee2dSAlexander V. Chernikov
1407ce2817b5SAlexander V. Chernikov if (af == AF_INET) {
1408d699ee2dSAlexander V. Chernikov #ifdef INET
1409ce2817b5SAlexander V. Chernikov hash = hash_ip(ent->a.a4, size);
1410d699ee2dSAlexander V. Chernikov #endif
1411ce2817b5SAlexander V. Chernikov } else {
1412d699ee2dSAlexander V. Chernikov #ifdef INET6
1413ce2817b5SAlexander V. Chernikov if (mlen == 64)
1414ce2817b5SAlexander V. Chernikov hash = hash_ip64(&ent->a.a6, size);
1415ce2817b5SAlexander V. Chernikov else
1416ce2817b5SAlexander V. Chernikov hash = hash_ip6(&ent->a.a6, size);
1417d699ee2dSAlexander V. Chernikov #endif
1418ce2817b5SAlexander V. Chernikov }
1419ce2817b5SAlexander V. Chernikov
1420ce2817b5SAlexander V. Chernikov return (hash);
1421ce2817b5SAlexander V. Chernikov }
1422ce2817b5SAlexander V. Chernikov
1423ce2817b5SAlexander V. Chernikov static int
tei_to_chash_ent(struct tentry_info * tei,struct chashentry * ent)1424ce2817b5SAlexander V. Chernikov tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent)
1425ce2817b5SAlexander V. Chernikov {
1426ce2817b5SAlexander V. Chernikov int mlen;
1427d699ee2dSAlexander V. Chernikov #ifdef INET6
1428d699ee2dSAlexander V. Chernikov struct in6_addr mask6;
1429d699ee2dSAlexander V. Chernikov #endif
1430ce2817b5SAlexander V. Chernikov
1431ce2817b5SAlexander V. Chernikov mlen = tei->masklen;
1432ce2817b5SAlexander V. Chernikov
1433ce2817b5SAlexander V. Chernikov if (tei->subtype == AF_INET) {
1434ce2817b5SAlexander V. Chernikov #ifdef INET
1435ce2817b5SAlexander V. Chernikov if (mlen > 32)
1436ce2817b5SAlexander V. Chernikov return (EINVAL);
1437ce2817b5SAlexander V. Chernikov ent->type = AF_INET;
1438ce2817b5SAlexander V. Chernikov
1439ce2817b5SAlexander V. Chernikov /* Calculate masked address */
1440ce2817b5SAlexander V. Chernikov ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
1441ce2817b5SAlexander V. Chernikov #endif
1442ce2817b5SAlexander V. Chernikov #ifdef INET6
1443ce2817b5SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) {
1444ce2817b5SAlexander V. Chernikov /* IPv6 case */
1445ce2817b5SAlexander V. Chernikov if (mlen > 128)
1446ce2817b5SAlexander V. Chernikov return (EINVAL);
1447ce2817b5SAlexander V. Chernikov ent->type = AF_INET6;
1448ce2817b5SAlexander V. Chernikov
1449ce2817b5SAlexander V. Chernikov ipv6_writemask(&mask6, mlen);
1450ce2817b5SAlexander V. Chernikov memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr));
1451ce2817b5SAlexander V. Chernikov APPLY_MASK(&ent->a.a6, &mask6);
1452ce2817b5SAlexander V. Chernikov #endif
1453ce2817b5SAlexander V. Chernikov } else {
1454ce2817b5SAlexander V. Chernikov /* Unknown CIDR type */
1455ce2817b5SAlexander V. Chernikov return (EINVAL);
1456ce2817b5SAlexander V. Chernikov }
1457ce2817b5SAlexander V. Chernikov
1458ce2817b5SAlexander V. Chernikov return (0);
1459ce2817b5SAlexander V. Chernikov }
1460ce2817b5SAlexander V. Chernikov
146174b941f0SAlexander V. Chernikov static int
ta_find_chash_tentry(void * ta_state,struct table_info * ti,ipfw_obj_tentry * tent)1462914bffb6SAlexander V. Chernikov ta_find_chash_tentry(void *ta_state, struct table_info *ti,
1463914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent)
146474b941f0SAlexander V. Chernikov {
14650bce0c23SAlexander V. Chernikov struct chash_cfg *cfg;
1466ce2817b5SAlexander V. Chernikov struct chashbhead *head;
1467ce2817b5SAlexander V. Chernikov struct chashentry ent, *tmp;
1468ce2817b5SAlexander V. Chernikov struct tentry_info tei;
1469ce2817b5SAlexander V. Chernikov int error;
1470ce2817b5SAlexander V. Chernikov uint32_t hash;
147174b941f0SAlexander V. Chernikov
14720bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state;
1473ce2817b5SAlexander V. Chernikov
1474ce2817b5SAlexander V. Chernikov memset(&ent, 0, sizeof(ent));
1475ce2817b5SAlexander V. Chernikov memset(&tei, 0, sizeof(tei));
1476ce2817b5SAlexander V. Chernikov
1477914bffb6SAlexander V. Chernikov if (tent->subtype == AF_INET) {
1478914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr;
14790bce0c23SAlexander V. Chernikov tei.masklen = cfg->mask4;
1480ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET;
148174b941f0SAlexander V. Chernikov
1482ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
1483ce2817b5SAlexander V. Chernikov return (error);
1484ce2817b5SAlexander V. Chernikov
14850bce0c23SAlexander V. Chernikov head = cfg->head4;
14860bce0c23SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET, cfg->mask4, cfg->size4);
1487ce2817b5SAlexander V. Chernikov /* Check for existence */
1488ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) {
1489ce2817b5SAlexander V. Chernikov if (tmp->a.a4 != ent.a.a4)
1490ce2817b5SAlexander V. Chernikov continue;
1491ce2817b5SAlexander V. Chernikov
1492ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent);
149374b941f0SAlexander V. Chernikov return (0);
149474b941f0SAlexander V. Chernikov }
1495ce2817b5SAlexander V. Chernikov } else {
1496914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.addr6;
14970bce0c23SAlexander V. Chernikov tei.masklen = cfg->mask6;
1498ce2817b5SAlexander V. Chernikov tei.subtype = AF_INET6;
1499ce2817b5SAlexander V. Chernikov
1500ce2817b5SAlexander V. Chernikov if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
1501ce2817b5SAlexander V. Chernikov return (error);
1502ce2817b5SAlexander V. Chernikov
15030bce0c23SAlexander V. Chernikov head = cfg->head6;
15040bce0c23SAlexander V. Chernikov hash = hash_ent(&ent, AF_INET6, cfg->mask6, cfg->size6);
1505ce2817b5SAlexander V. Chernikov /* Check for existence */
1506ce2817b5SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) {
1507ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0)
1508ce2817b5SAlexander V. Chernikov continue;
1509ce2817b5SAlexander V. Chernikov ta_dump_chash_tentry(ta_state, ti, tmp, tent);
1510ce2817b5SAlexander V. Chernikov return (0);
1511ce2817b5SAlexander V. Chernikov }
1512ce2817b5SAlexander V. Chernikov }
1513ce2817b5SAlexander V. Chernikov
151474b941f0SAlexander V. Chernikov return (ENOENT);
151574b941f0SAlexander V. Chernikov }
151674b941f0SAlexander V. Chernikov
151774b941f0SAlexander V. Chernikov static void
ta_foreach_chash(void * ta_state,struct table_info * ti,ta_foreach_f * f,void * arg)151874b941f0SAlexander V. Chernikov ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
151974b941f0SAlexander V. Chernikov void *arg)
152074b941f0SAlexander V. Chernikov {
15210bce0c23SAlexander V. Chernikov struct chash_cfg *cfg;
152274b941f0SAlexander V. Chernikov struct chashentry *ent, *ent_next;
152374b941f0SAlexander V. Chernikov int i;
152474b941f0SAlexander V. Chernikov
15250bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state;
152674b941f0SAlexander V. Chernikov
15270bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size4; i++)
15280bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next)
152974b941f0SAlexander V. Chernikov f(ent, arg);
153074b941f0SAlexander V. Chernikov
15310bce0c23SAlexander V. Chernikov for (i = 0; i < cfg->size6; i++)
15320bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next)
153374b941f0SAlexander V. Chernikov f(ent, arg);
153474b941f0SAlexander V. Chernikov }
153574b941f0SAlexander V. Chernikov
153674b941f0SAlexander V. Chernikov static int
ta_prepare_add_chash(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)153774b941f0SAlexander V. Chernikov ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
153874b941f0SAlexander V. Chernikov void *ta_buf)
153974b941f0SAlexander V. Chernikov {
154074b941f0SAlexander V. Chernikov struct ta_buf_chash *tb;
154174b941f0SAlexander V. Chernikov struct chashentry *ent;
1542ce2817b5SAlexander V. Chernikov int error;
154374b941f0SAlexander V. Chernikov
154474b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf;
154574b941f0SAlexander V. Chernikov
154674b941f0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
154774b941f0SAlexander V. Chernikov
1548ce2817b5SAlexander V. Chernikov error = tei_to_chash_ent(tei, ent);
1549ce2817b5SAlexander V. Chernikov if (error != 0) {
1550ce2817b5SAlexander V. Chernikov free(ent, M_IPFW_TBL);
1551ce2817b5SAlexander V. Chernikov return (error);
155274b941f0SAlexander V. Chernikov }
1553ce2817b5SAlexander V. Chernikov tb->ent_ptr = ent;
155474b941f0SAlexander V. Chernikov
155574b941f0SAlexander V. Chernikov return (0);
155674b941f0SAlexander V. Chernikov }
155774b941f0SAlexander V. Chernikov
155874b941f0SAlexander V. Chernikov static int
ta_add_chash(void * ta_state,struct table_info * ti,struct tentry_info * tei,void * ta_buf,uint32_t * pnum)155974b941f0SAlexander V. Chernikov ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1560b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum)
156174b941f0SAlexander V. Chernikov {
15620bce0c23SAlexander V. Chernikov struct chash_cfg *cfg;
156374b941f0SAlexander V. Chernikov struct chashbhead *head;
156474b941f0SAlexander V. Chernikov struct chashentry *ent, *tmp;
156574b941f0SAlexander V. Chernikov struct ta_buf_chash *tb;
156674b941f0SAlexander V. Chernikov int exists;
1567648e8380SAlexander V. Chernikov uint32_t hash, value;
156874b941f0SAlexander V. Chernikov
15690bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state;
157074b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf;
157174b941f0SAlexander V. Chernikov ent = (struct chashentry *)tb->ent_ptr;
157274b941f0SAlexander V. Chernikov hash = 0;
157374b941f0SAlexander V. Chernikov exists = 0;
157474b941f0SAlexander V. Chernikov
157513263632SAlexander V. Chernikov /* Read current value from @tei */
157613263632SAlexander V. Chernikov ent->value = tei->value;
157713263632SAlexander V. Chernikov
157813263632SAlexander V. Chernikov /* Read cuurrent value */
157974b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) {
15800bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask4)
158174b941f0SAlexander V. Chernikov return (EINVAL);
15820bce0c23SAlexander V. Chernikov head = cfg->head4;
15830bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4);
1584ce2817b5SAlexander V. Chernikov
158574b941f0SAlexander V. Chernikov /* Check for existence */
158674b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) {
158774b941f0SAlexander V. Chernikov if (tmp->a.a4 == ent->a.a4) {
158874b941f0SAlexander V. Chernikov exists = 1;
158974b941f0SAlexander V. Chernikov break;
159074b941f0SAlexander V. Chernikov }
159174b941f0SAlexander V. Chernikov }
159274b941f0SAlexander V. Chernikov } else {
15930bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask6)
159474b941f0SAlexander V. Chernikov return (EINVAL);
15950bce0c23SAlexander V. Chernikov head = cfg->head6;
15960bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6);
159774b941f0SAlexander V. Chernikov /* Check for existence */
159874b941f0SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) {
1599ce2817b5SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) == 0) {
160074b941f0SAlexander V. Chernikov exists = 1;
160174b941f0SAlexander V. Chernikov break;
160274b941f0SAlexander V. Chernikov }
160374b941f0SAlexander V. Chernikov }
160474b941f0SAlexander V. Chernikov }
160574b941f0SAlexander V. Chernikov
160674b941f0SAlexander V. Chernikov if (exists == 1) {
160774b941f0SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
160874b941f0SAlexander V. Chernikov return (EEXIST);
160974b941f0SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */
1610648e8380SAlexander V. Chernikov value = tmp->value;
161174b941f0SAlexander V. Chernikov tmp->value = tei->value;
1612648e8380SAlexander V. Chernikov tei->value = value;
161374b941f0SAlexander V. Chernikov /* Indicate that update has happened instead of addition */
161474b941f0SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED;
161574b941f0SAlexander V. Chernikov *pnum = 0;
161674b941f0SAlexander V. Chernikov } else {
16174c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
16184c0c07a5SAlexander V. Chernikov return (EFBIG);
161974b941f0SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next);
162074b941f0SAlexander V. Chernikov tb->ent_ptr = NULL;
162174b941f0SAlexander V. Chernikov *pnum = 1;
1622ce2817b5SAlexander V. Chernikov
1623b6ee846eSAlexander V. Chernikov /* Update counters */
1624b6ee846eSAlexander V. Chernikov if (tei->subtype == AF_INET)
16250bce0c23SAlexander V. Chernikov cfg->items4++;
1626b6ee846eSAlexander V. Chernikov else
16270bce0c23SAlexander V. Chernikov cfg->items6++;
162874b941f0SAlexander V. Chernikov }
162974b941f0SAlexander V. Chernikov
163074b941f0SAlexander V. Chernikov return (0);
163174b941f0SAlexander V. Chernikov }
163274b941f0SAlexander V. Chernikov
163374b941f0SAlexander V. Chernikov static int
ta_prepare_del_chash(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)163474b941f0SAlexander V. Chernikov ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
163574b941f0SAlexander V. Chernikov void *ta_buf)
163674b941f0SAlexander V. Chernikov {
163774b941f0SAlexander V. Chernikov struct ta_buf_chash *tb;
163874b941f0SAlexander V. Chernikov
163974b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf;
164074b941f0SAlexander V. Chernikov
1641ce2817b5SAlexander V. Chernikov return (tei_to_chash_ent(tei, &tb->ent));
164274b941f0SAlexander V. Chernikov }
164374b941f0SAlexander V. Chernikov
164474b941f0SAlexander V. Chernikov static int
ta_del_chash(void * ta_state,struct table_info * ti,struct tentry_info * tei,void * ta_buf,uint32_t * pnum)164574b941f0SAlexander V. Chernikov ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1646b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum)
164774b941f0SAlexander V. Chernikov {
16480bce0c23SAlexander V. Chernikov struct chash_cfg *cfg;
164974b941f0SAlexander V. Chernikov struct chashbhead *head;
16500bce0c23SAlexander V. Chernikov struct chashentry *tmp, *tmp_next, *ent;
165174b941f0SAlexander V. Chernikov struct ta_buf_chash *tb;
165274b941f0SAlexander V. Chernikov uint32_t hash;
165374b941f0SAlexander V. Chernikov
16540bce0c23SAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state;
165574b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf;
16560bce0c23SAlexander V. Chernikov ent = &tb->ent;
165774b941f0SAlexander V. Chernikov
165874b941f0SAlexander V. Chernikov if (tei->subtype == AF_INET) {
16590bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask4)
166074b941f0SAlexander V. Chernikov return (EINVAL);
16610bce0c23SAlexander V. Chernikov head = cfg->head4;
16620bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4);
166374b941f0SAlexander V. Chernikov
16640bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) {
16650bce0c23SAlexander V. Chernikov if (tmp->a.a4 != ent->a.a4)
1666648e8380SAlexander V. Chernikov continue;
1667648e8380SAlexander V. Chernikov
16680bce0c23SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, chashentry, next);
16690bce0c23SAlexander V. Chernikov cfg->items4--;
16700bce0c23SAlexander V. Chernikov tb->ent_ptr = tmp;
16710bce0c23SAlexander V. Chernikov tei->value = tmp->value;
1672648e8380SAlexander V. Chernikov *pnum = 1;
167374b941f0SAlexander V. Chernikov return (0);
167474b941f0SAlexander V. Chernikov }
167574b941f0SAlexander V. Chernikov } else {
16760bce0c23SAlexander V. Chernikov if (tei->masklen != cfg->mask6)
167774b941f0SAlexander V. Chernikov return (EINVAL);
16780bce0c23SAlexander V. Chernikov head = cfg->head6;
16790bce0c23SAlexander V. Chernikov hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6);
16800bce0c23SAlexander V. Chernikov SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) {
16810bce0c23SAlexander V. Chernikov if (memcmp(&tmp->a.a6, &ent->a.a6, 16) != 0)
1682648e8380SAlexander V. Chernikov continue;
1683648e8380SAlexander V. Chernikov
16840bce0c23SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, chashentry, next);
16850bce0c23SAlexander V. Chernikov cfg->items6--;
16860bce0c23SAlexander V. Chernikov tb->ent_ptr = tmp;
16870bce0c23SAlexander V. Chernikov tei->value = tmp->value;
168874b941f0SAlexander V. Chernikov *pnum = 1;
168974b941f0SAlexander V. Chernikov return (0);
169074b941f0SAlexander V. Chernikov }
169174b941f0SAlexander V. Chernikov }
169274b941f0SAlexander V. Chernikov
169374b941f0SAlexander V. Chernikov return (ENOENT);
169474b941f0SAlexander V. Chernikov }
169574b941f0SAlexander V. Chernikov
169674b941f0SAlexander V. Chernikov static void
ta_flush_chash_entry(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)169774b941f0SAlexander V. Chernikov ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
169874b941f0SAlexander V. Chernikov void *ta_buf)
169974b941f0SAlexander V. Chernikov {
170074b941f0SAlexander V. Chernikov struct ta_buf_chash *tb;
170174b941f0SAlexander V. Chernikov
170274b941f0SAlexander V. Chernikov tb = (struct ta_buf_chash *)ta_buf;
170374b941f0SAlexander V. Chernikov
170474b941f0SAlexander V. Chernikov if (tb->ent_ptr != NULL)
170574b941f0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL);
170674b941f0SAlexander V. Chernikov }
170774b941f0SAlexander V. Chernikov
1708ce2817b5SAlexander V. Chernikov /*
1709ce2817b5SAlexander V. Chernikov * Hash growing callbacks.
1710ce2817b5SAlexander V. Chernikov */
1711ce2817b5SAlexander V. Chernikov
1712b6ee846eSAlexander V. Chernikov static int
ta_need_modify_chash(void * ta_state,struct table_info * ti,uint32_t count,uint64_t * pflags)1713301290bcSAlexander V. Chernikov ta_need_modify_chash(void *ta_state, struct table_info *ti, uint32_t count,
1714b6ee846eSAlexander V. Chernikov uint64_t *pflags)
1715b6ee846eSAlexander V. Chernikov {
1716b6ee846eSAlexander V. Chernikov struct chash_cfg *cfg;
1717b6ee846eSAlexander V. Chernikov uint64_t data;
1718b6ee846eSAlexander V. Chernikov
1719b6ee846eSAlexander V. Chernikov /*
1720b6ee846eSAlexander V. Chernikov * Since we don't know exact number of IPv4/IPv6 records in @count,
1721b6ee846eSAlexander V. Chernikov * ignore non-zero @count value at all. Check current hash sizes
1722b6ee846eSAlexander V. Chernikov * and return appropriate data.
1723b6ee846eSAlexander V. Chernikov */
1724b6ee846eSAlexander V. Chernikov
1725b6ee846eSAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state;
1726b6ee846eSAlexander V. Chernikov
1727b6ee846eSAlexander V. Chernikov data = 0;
1728b6ee846eSAlexander V. Chernikov if (cfg->items4 > cfg->size4 && cfg->size4 < 65536)
1729b6ee846eSAlexander V. Chernikov data |= (cfg->size4 * 2) << 16;
1730b6ee846eSAlexander V. Chernikov if (cfg->items6 > cfg->size6 && cfg->size6 < 65536)
1731b6ee846eSAlexander V. Chernikov data |= cfg->size6 * 2;
1732b6ee846eSAlexander V. Chernikov
1733b6ee846eSAlexander V. Chernikov if (data != 0) {
1734b6ee846eSAlexander V. Chernikov *pflags = data;
1735301290bcSAlexander V. Chernikov return (1);
1736b6ee846eSAlexander V. Chernikov }
1737b6ee846eSAlexander V. Chernikov
1738301290bcSAlexander V. Chernikov return (0);
1739b6ee846eSAlexander V. Chernikov }
1740b6ee846eSAlexander V. Chernikov
1741ce2817b5SAlexander V. Chernikov /*
1742ce2817b5SAlexander V. Chernikov * Allocate new, larger chash.
1743ce2817b5SAlexander V. Chernikov */
1744ce2817b5SAlexander V. Chernikov static int
ta_prepare_mod_chash(void * ta_buf,uint64_t * pflags)1745ce2817b5SAlexander V. Chernikov ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags)
1746ce2817b5SAlexander V. Chernikov {
1747ce2817b5SAlexander V. Chernikov struct mod_item *mi;
1748ce2817b5SAlexander V. Chernikov struct chashbhead *head;
1749ce2817b5SAlexander V. Chernikov int i;
1750ce2817b5SAlexander V. Chernikov
1751ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf;
1752ce2817b5SAlexander V. Chernikov
1753ce2817b5SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item));
1754b6ee846eSAlexander V. Chernikov mi->size = (*pflags >> 16) & 0xFFFF;
1755b6ee846eSAlexander V. Chernikov mi->size6 = *pflags & 0xFFFF;
1756b6ee846eSAlexander V. Chernikov if (mi->size > 0) {
1757b6ee846eSAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size,
1758b6ee846eSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO);
1759ce2817b5SAlexander V. Chernikov for (i = 0; i < mi->size; i++)
1760ce2817b5SAlexander V. Chernikov SLIST_INIT(&head[i]);
1761ce2817b5SAlexander V. Chernikov mi->main_ptr = head;
1762b6ee846eSAlexander V. Chernikov }
1763b6ee846eSAlexander V. Chernikov
1764b6ee846eSAlexander V. Chernikov if (mi->size6 > 0) {
1765b6ee846eSAlexander V. Chernikov head = malloc(sizeof(struct chashbhead) * mi->size6,
1766b6ee846eSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO);
1767b6ee846eSAlexander V. Chernikov for (i = 0; i < mi->size6; i++)
1768b6ee846eSAlexander V. Chernikov SLIST_INIT(&head[i]);
1769b6ee846eSAlexander V. Chernikov mi->main_ptr6 = head;
1770b6ee846eSAlexander V. Chernikov }
1771ce2817b5SAlexander V. Chernikov
1772ce2817b5SAlexander V. Chernikov return (0);
1773ce2817b5SAlexander V. Chernikov }
1774ce2817b5SAlexander V. Chernikov
1775ce2817b5SAlexander V. Chernikov /*
1776ce2817b5SAlexander V. Chernikov * Copy data from old runtime array to new one.
1777ce2817b5SAlexander V. Chernikov */
1778ce2817b5SAlexander V. Chernikov static int
ta_fill_mod_chash(void * ta_state,struct table_info * ti,void * ta_buf,uint64_t * pflags)1779ce2817b5SAlexander V. Chernikov ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1780ce2817b5SAlexander V. Chernikov uint64_t *pflags)
1781ce2817b5SAlexander V. Chernikov {
1782ce2817b5SAlexander V. Chernikov
1783ce2817b5SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */
1784ce2817b5SAlexander V. Chernikov return (0);
1785ce2817b5SAlexander V. Chernikov }
1786ce2817b5SAlexander V. Chernikov
1787ce2817b5SAlexander V. Chernikov /*
1788ce2817b5SAlexander V. Chernikov * Switch old & new arrays.
1789ce2817b5SAlexander V. Chernikov */
1790301290bcSAlexander V. Chernikov static void
ta_modify_chash(void * ta_state,struct table_info * ti,void * ta_buf,uint64_t pflags)1791ce2817b5SAlexander V. Chernikov ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1792ce2817b5SAlexander V. Chernikov uint64_t pflags)
1793ce2817b5SAlexander V. Chernikov {
1794ce2817b5SAlexander V. Chernikov struct mod_item *mi;
1795b6ee846eSAlexander V. Chernikov struct chash_cfg *cfg;
1796ce2817b5SAlexander V. Chernikov struct chashbhead *old_head, *new_head;
1797ce2817b5SAlexander V. Chernikov struct chashentry *ent, *ent_next;
1798ce2817b5SAlexander V. Chernikov int af, i, mlen;
1799ce2817b5SAlexander V. Chernikov uint32_t nhash;
1800b6ee846eSAlexander V. Chernikov size_t old_size, new_size;
1801ce2817b5SAlexander V. Chernikov
1802ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf;
1803b6ee846eSAlexander V. Chernikov cfg = (struct chash_cfg *)ta_state;
1804ce2817b5SAlexander V. Chernikov
1805ce2817b5SAlexander V. Chernikov /* Check which hash we need to grow and do we still need that */
1806b6ee846eSAlexander V. Chernikov if (mi->size > 0 && cfg->size4 < mi->size) {
1807ce2817b5SAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr;
1808b6ee846eSAlexander V. Chernikov new_size = mi->size;
1809b6ee846eSAlexander V. Chernikov old_size = cfg->size4;
1810b6ee846eSAlexander V. Chernikov old_head = ti->state;
1811b6ee846eSAlexander V. Chernikov mlen = cfg->mask4;
1812b6ee846eSAlexander V. Chernikov af = AF_INET;
1813b6ee846eSAlexander V. Chernikov
1814ce2817b5SAlexander V. Chernikov for (i = 0; i < old_size; i++) {
1815ce2817b5SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
1816b6ee846eSAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, new_size);
1817ce2817b5SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
1818ce2817b5SAlexander V. Chernikov }
1819ce2817b5SAlexander V. Chernikov }
1820ce2817b5SAlexander V. Chernikov
1821ce2817b5SAlexander V. Chernikov ti->state = new_head;
1822b6ee846eSAlexander V. Chernikov cfg->head4 = new_head;
1823b6ee846eSAlexander V. Chernikov cfg->size4 = mi->size;
1824b6ee846eSAlexander V. Chernikov mi->main_ptr = old_head;
1825ce2817b5SAlexander V. Chernikov }
1826ce2817b5SAlexander V. Chernikov
1827b6ee846eSAlexander V. Chernikov if (mi->size6 > 0 && cfg->size6 < mi->size6) {
1828b6ee846eSAlexander V. Chernikov new_head = (struct chashbhead *)mi->main_ptr6;
1829b6ee846eSAlexander V. Chernikov new_size = mi->size6;
1830b6ee846eSAlexander V. Chernikov old_size = cfg->size6;
1831b6ee846eSAlexander V. Chernikov old_head = ti->xstate;
1832b6ee846eSAlexander V. Chernikov mlen = cfg->mask6;
1833b6ee846eSAlexander V. Chernikov af = AF_INET6;
1834914bffb6SAlexander V. Chernikov
1835b6ee846eSAlexander V. Chernikov for (i = 0; i < old_size; i++) {
1836b6ee846eSAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
1837b6ee846eSAlexander V. Chernikov nhash = hash_ent(ent, af, mlen, new_size);
1838b6ee846eSAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
1839b6ee846eSAlexander V. Chernikov }
1840b6ee846eSAlexander V. Chernikov }
1841b6ee846eSAlexander V. Chernikov
1842b6ee846eSAlexander V. Chernikov ti->xstate = new_head;
1843b6ee846eSAlexander V. Chernikov cfg->head6 = new_head;
1844b6ee846eSAlexander V. Chernikov cfg->size6 = mi->size6;
1845b6ee846eSAlexander V. Chernikov mi->main_ptr6 = old_head;
1846b6ee846eSAlexander V. Chernikov }
1847b6ee846eSAlexander V. Chernikov
1848b6ee846eSAlexander V. Chernikov /* Update lower 32 bits with new values */
1849b6ee846eSAlexander V. Chernikov ti->data &= 0xFFFFFFFF00000000;
18509e3a53fdSAlexander V. Chernikov ti->data |= ta_log2(cfg->size4) << 8 | ta_log2(cfg->size6);
1851ce2817b5SAlexander V. Chernikov }
1852ce2817b5SAlexander V. Chernikov
1853ce2817b5SAlexander V. Chernikov /*
1854ce2817b5SAlexander V. Chernikov * Free unneded array.
1855ce2817b5SAlexander V. Chernikov */
1856ce2817b5SAlexander V. Chernikov static void
ta_flush_mod_chash(void * ta_buf)1857ce2817b5SAlexander V. Chernikov ta_flush_mod_chash(void *ta_buf)
1858ce2817b5SAlexander V. Chernikov {
1859ce2817b5SAlexander V. Chernikov struct mod_item *mi;
1860ce2817b5SAlexander V. Chernikov
1861ce2817b5SAlexander V. Chernikov mi = (struct mod_item *)ta_buf;
1862ce2817b5SAlexander V. Chernikov if (mi->main_ptr != NULL)
1863ce2817b5SAlexander V. Chernikov free(mi->main_ptr, M_IPFW);
1864b6ee846eSAlexander V. Chernikov if (mi->main_ptr6 != NULL)
1865b6ee846eSAlexander V. Chernikov free(mi->main_ptr6, M_IPFW);
1866ce2817b5SAlexander V. Chernikov }
1867ce2817b5SAlexander V. Chernikov
1868c21034b7SAlexander V. Chernikov struct table_algo addr_hash = {
1869c21034b7SAlexander V. Chernikov .name = "addr:hash",
1870c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR,
187157a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_chash),
187274b941f0SAlexander V. Chernikov .init = ta_init_chash,
187374b941f0SAlexander V. Chernikov .destroy = ta_destroy_chash,
187474b941f0SAlexander V. Chernikov .prepare_add = ta_prepare_add_chash,
187574b941f0SAlexander V. Chernikov .prepare_del = ta_prepare_del_chash,
187674b941f0SAlexander V. Chernikov .add = ta_add_chash,
187774b941f0SAlexander V. Chernikov .del = ta_del_chash,
187874b941f0SAlexander V. Chernikov .flush_entry = ta_flush_chash_entry,
187974b941f0SAlexander V. Chernikov .foreach = ta_foreach_chash,
188074b941f0SAlexander V. Chernikov .dump_tentry = ta_dump_chash_tentry,
188174b941f0SAlexander V. Chernikov .find_tentry = ta_find_chash_tentry,
188274b941f0SAlexander V. Chernikov .print_config = ta_print_chash_config,
18835f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_chash_tinfo,
1884301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_chash,
1885ce2817b5SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_chash,
1886ce2817b5SAlexander V. Chernikov .fill_mod = ta_fill_mod_chash,
1887ce2817b5SAlexander V. Chernikov .modify = ta_modify_chash,
1888ce2817b5SAlexander V. Chernikov .flush_mod = ta_flush_mod_chash,
188974b941f0SAlexander V. Chernikov };
189074b941f0SAlexander V. Chernikov
189174b941f0SAlexander V. Chernikov /*
189268394ec8SAlexander V. Chernikov * Iface table cmds.
189368394ec8SAlexander V. Chernikov *
189468394ec8SAlexander V. Chernikov * Implementation:
189568394ec8SAlexander V. Chernikov *
189668394ec8SAlexander V. Chernikov * Runtime part:
189768394ec8SAlexander V. Chernikov * - sorted array of "struct ifidx" pointed by ti->state.
1898b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to IFIDX_CHUNK. Only existing
189968394ec8SAlexander V. Chernikov * interfaces are stored in array, however its allocated size is
190068394ec8SAlexander V. Chernikov * sufficient to hold all table records if needed.
190168394ec8SAlexander V. Chernikov * - current array size is stored in ti->data
190268394ec8SAlexander V. Chernikov *
190368394ec8SAlexander V. Chernikov * Table data:
190468394ec8SAlexander V. Chernikov * - "struct iftable_cfg" is allocated to store table state (ta_state).
190568394ec8SAlexander V. Chernikov * - All table records are stored inside namedobj instance.
19069f7d47b0SAlexander V. Chernikov *
19079f7d47b0SAlexander V. Chernikov */
19089f7d47b0SAlexander V. Chernikov
190968394ec8SAlexander V. Chernikov struct ifidx {
191068394ec8SAlexander V. Chernikov uint16_t kidx;
191168394ec8SAlexander V. Chernikov uint16_t spare;
191268394ec8SAlexander V. Chernikov uint32_t value;
191368394ec8SAlexander V. Chernikov };
19140cba2b28SAlexander V. Chernikov #define DEFAULT_IFIDX_SIZE 64
191568394ec8SAlexander V. Chernikov
191668394ec8SAlexander V. Chernikov struct iftable_cfg;
191768394ec8SAlexander V. Chernikov
191868394ec8SAlexander V. Chernikov struct ifentry {
191968394ec8SAlexander V. Chernikov struct named_object no;
192068394ec8SAlexander V. Chernikov struct ipfw_ifc ic;
192168394ec8SAlexander V. Chernikov struct iftable_cfg *icfg;
192268394ec8SAlexander V. Chernikov uint32_t value;
192368394ec8SAlexander V. Chernikov int linked;
192468394ec8SAlexander V. Chernikov };
192568394ec8SAlexander V. Chernikov
192668394ec8SAlexander V. Chernikov struct iftable_cfg {
192768394ec8SAlexander V. Chernikov struct namedobj_instance *ii;
192868394ec8SAlexander V. Chernikov struct ip_fw_chain *ch;
192968394ec8SAlexander V. Chernikov struct table_info *ti;
193068394ec8SAlexander V. Chernikov void *main_ptr;
193168394ec8SAlexander V. Chernikov size_t size; /* Number of items allocated in array */
193268394ec8SAlexander V. Chernikov size_t count; /* Number of all items */
193368394ec8SAlexander V. Chernikov size_t used; /* Number of items _active_ now */
193468394ec8SAlexander V. Chernikov };
193568394ec8SAlexander V. Chernikov
19360bce0c23SAlexander V. Chernikov struct ta_buf_ifidx
19370bce0c23SAlexander V. Chernikov {
19380bce0c23SAlexander V. Chernikov struct ifentry *ife;
19390bce0c23SAlexander V. Chernikov uint32_t value;
19400bce0c23SAlexander V. Chernikov };
194168394ec8SAlexander V. Chernikov
194268394ec8SAlexander V. Chernikov int compare_ifidx(const void *k, const void *v);
19439fe15d06SAlexander V. Chernikov static struct ifidx * ifidx_find(struct table_info *ti, void *key);
19449fe15d06SAlexander V. Chernikov static int ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
19459fe15d06SAlexander V. Chernikov uint32_t *val);
19469fe15d06SAlexander V. Chernikov static int ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state,
19479fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags);
19489fe15d06SAlexander V. Chernikov static void ta_change_ti_ifidx(void *ta_state, struct table_info *ti);
1949b309f085SAndrey V. Elsukov static int destroy_ifidx_locked(struct namedobj_instance *ii,
19509fe15d06SAlexander V. Chernikov struct named_object *no, void *arg);
19519fe15d06SAlexander V. Chernikov static void ta_destroy_ifidx(void *ta_state, struct table_info *ti);
19529fe15d06SAlexander V. Chernikov static void ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti,
19539fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo);
19549fe15d06SAlexander V. Chernikov static int ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
19559fe15d06SAlexander V. Chernikov void *ta_buf);
19569fe15d06SAlexander V. Chernikov static int ta_add_ifidx(void *ta_state, struct table_info *ti,
19579fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
19589fe15d06SAlexander V. Chernikov static int ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
19599fe15d06SAlexander V. Chernikov void *ta_buf);
19609fe15d06SAlexander V. Chernikov static int ta_del_ifidx(void *ta_state, struct table_info *ti,
19619fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
19629fe15d06SAlexander V. Chernikov static void ta_flush_ifidx_entry(struct ip_fw_chain *ch,
19639fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf);
19649fe15d06SAlexander V. Chernikov static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex);
19659fe15d06SAlexander V. Chernikov static int ta_need_modify_ifidx(void *ta_state, struct table_info *ti,
19669fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags);
19679fe15d06SAlexander V. Chernikov static int ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags);
19689fe15d06SAlexander V. Chernikov static int ta_fill_mod_ifidx(void *ta_state, struct table_info *ti,
19699fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t *pflags);
19709fe15d06SAlexander V. Chernikov static void ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
19719fe15d06SAlexander V. Chernikov uint64_t pflags);
19729fe15d06SAlexander V. Chernikov static void ta_flush_mod_ifidx(void *ta_buf);
19739fe15d06SAlexander V. Chernikov static int ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
19749fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent);
19759fe15d06SAlexander V. Chernikov static int ta_find_ifidx_tentry(void *ta_state, struct table_info *ti,
19769fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent);
1977b309f085SAndrey V. Elsukov static int foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
19789fe15d06SAlexander V. Chernikov void *arg);
19799fe15d06SAlexander V. Chernikov static void ta_foreach_ifidx(void *ta_state, struct table_info *ti,
19809fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg);
198168394ec8SAlexander V. Chernikov
198268394ec8SAlexander V. Chernikov int
compare_ifidx(const void * k,const void * v)198368394ec8SAlexander V. Chernikov compare_ifidx(const void *k, const void *v)
198468394ec8SAlexander V. Chernikov {
1985d4e1b515SAlexander V. Chernikov const struct ifidx *ifidx;
198668394ec8SAlexander V. Chernikov uint16_t key;
198768394ec8SAlexander V. Chernikov
1988d4e1b515SAlexander V. Chernikov key = *((const uint16_t *)k);
1989d4e1b515SAlexander V. Chernikov ifidx = (const struct ifidx *)v;
199068394ec8SAlexander V. Chernikov
199168394ec8SAlexander V. Chernikov if (key < ifidx->kidx)
199268394ec8SAlexander V. Chernikov return (-1);
199368394ec8SAlexander V. Chernikov else if (key > ifidx->kidx)
199468394ec8SAlexander V. Chernikov return (1);
199568394ec8SAlexander V. Chernikov
199668394ec8SAlexander V. Chernikov return (0);
199768394ec8SAlexander V. Chernikov }
199868394ec8SAlexander V. Chernikov
199968394ec8SAlexander V. Chernikov /*
200068394ec8SAlexander V. Chernikov * Adds item @item with key @key into ascending-sorted array @base.
200168394ec8SAlexander V. Chernikov * Assumes @base has enough additional storage.
200268394ec8SAlexander V. Chernikov *
200368394ec8SAlexander V. Chernikov * Returns 1 on success, 0 on duplicate key.
200468394ec8SAlexander V. Chernikov */
20059f7d47b0SAlexander V. Chernikov static int
badd(const void * key,void * item,void * base,size_t nmemb,size_t size,int (* compar)(const void *,const void *))200668394ec8SAlexander V. Chernikov badd(const void *key, void *item, void *base, size_t nmemb,
200768394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *))
200868394ec8SAlexander V. Chernikov {
200968394ec8SAlexander V. Chernikov int min, max, mid, shift, res;
201068394ec8SAlexander V. Chernikov caddr_t paddr;
201168394ec8SAlexander V. Chernikov
201268394ec8SAlexander V. Chernikov if (nmemb == 0) {
201368394ec8SAlexander V. Chernikov memcpy(base, item, size);
201468394ec8SAlexander V. Chernikov return (1);
201568394ec8SAlexander V. Chernikov }
201668394ec8SAlexander V. Chernikov
201768394ec8SAlexander V. Chernikov /* Binary search */
201868394ec8SAlexander V. Chernikov min = 0;
201968394ec8SAlexander V. Chernikov max = nmemb - 1;
202068394ec8SAlexander V. Chernikov mid = 0;
202168394ec8SAlexander V. Chernikov while (min <= max) {
202268394ec8SAlexander V. Chernikov mid = (min + max) / 2;
202368394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size));
202468394ec8SAlexander V. Chernikov if (res == 0)
202568394ec8SAlexander V. Chernikov return (0);
202668394ec8SAlexander V. Chernikov
202768394ec8SAlexander V. Chernikov if (res > 0)
202868394ec8SAlexander V. Chernikov min = mid + 1;
202968394ec8SAlexander V. Chernikov else
203068394ec8SAlexander V. Chernikov max = mid - 1;
203168394ec8SAlexander V. Chernikov }
203268394ec8SAlexander V. Chernikov
203368394ec8SAlexander V. Chernikov /* Item not found. */
203468394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size));
203568394ec8SAlexander V. Chernikov if (res > 0)
203668394ec8SAlexander V. Chernikov shift = mid + 1;
203768394ec8SAlexander V. Chernikov else
203868394ec8SAlexander V. Chernikov shift = mid;
203968394ec8SAlexander V. Chernikov
204068394ec8SAlexander V. Chernikov paddr = (caddr_t)base + shift * size;
204168394ec8SAlexander V. Chernikov if (nmemb > shift)
204268394ec8SAlexander V. Chernikov memmove(paddr + size, paddr, (nmemb - shift) * size);
204368394ec8SAlexander V. Chernikov
204468394ec8SAlexander V. Chernikov memcpy(paddr, item, size);
204568394ec8SAlexander V. Chernikov
204668394ec8SAlexander V. Chernikov return (1);
204768394ec8SAlexander V. Chernikov }
204868394ec8SAlexander V. Chernikov
204968394ec8SAlexander V. Chernikov /*
205068394ec8SAlexander V. Chernikov * Deletes item with key @key from ascending-sorted array @base.
205168394ec8SAlexander V. Chernikov *
205268394ec8SAlexander V. Chernikov * Returns 1 on success, 0 for non-existent key.
205368394ec8SAlexander V. Chernikov */
205468394ec8SAlexander V. Chernikov static int
bdel(const void * key,void * base,size_t nmemb,size_t size,int (* compar)(const void *,const void *))205568394ec8SAlexander V. Chernikov bdel(const void *key, void *base, size_t nmemb, size_t size,
205668394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *))
205768394ec8SAlexander V. Chernikov {
205868394ec8SAlexander V. Chernikov caddr_t item;
205968394ec8SAlexander V. Chernikov size_t sz;
206068394ec8SAlexander V. Chernikov
206168394ec8SAlexander V. Chernikov item = (caddr_t)bsearch(key, base, nmemb, size, compar);
206268394ec8SAlexander V. Chernikov
206368394ec8SAlexander V. Chernikov if (item == NULL)
206468394ec8SAlexander V. Chernikov return (0);
206568394ec8SAlexander V. Chernikov
206668394ec8SAlexander V. Chernikov sz = (caddr_t)base + nmemb * size - item;
206768394ec8SAlexander V. Chernikov
206868394ec8SAlexander V. Chernikov if (sz > 0)
206968394ec8SAlexander V. Chernikov memmove(item, item + size, sz);
207068394ec8SAlexander V. Chernikov
207168394ec8SAlexander V. Chernikov return (1);
207268394ec8SAlexander V. Chernikov }
207368394ec8SAlexander V. Chernikov
207468394ec8SAlexander V. Chernikov static struct ifidx *
ifidx_find(struct table_info * ti,void * key)207568394ec8SAlexander V. Chernikov ifidx_find(struct table_info *ti, void *key)
207668394ec8SAlexander V. Chernikov {
207768394ec8SAlexander V. Chernikov struct ifidx *ifi;
207868394ec8SAlexander V. Chernikov
207968394ec8SAlexander V. Chernikov ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx),
208068394ec8SAlexander V. Chernikov compare_ifidx);
208168394ec8SAlexander V. Chernikov
208268394ec8SAlexander V. Chernikov return (ifi);
208368394ec8SAlexander V. Chernikov }
208468394ec8SAlexander V. Chernikov
208568394ec8SAlexander V. Chernikov static int
ta_lookup_ifidx(struct table_info * ti,void * key,uint32_t keylen,uint32_t * val)208668394ec8SAlexander V. Chernikov ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
20879f7d47b0SAlexander V. Chernikov uint32_t *val)
20889f7d47b0SAlexander V. Chernikov {
208968394ec8SAlexander V. Chernikov struct ifidx *ifi;
20909f7d47b0SAlexander V. Chernikov
209168394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, key);
20929f7d47b0SAlexander V. Chernikov
209368394ec8SAlexander V. Chernikov if (ifi != NULL) {
209468394ec8SAlexander V. Chernikov *val = ifi->value;
20959f7d47b0SAlexander V. Chernikov return (1);
20969f7d47b0SAlexander V. Chernikov }
20979f7d47b0SAlexander V. Chernikov
20989f7d47b0SAlexander V. Chernikov return (0);
20999f7d47b0SAlexander V. Chernikov }
21009f7d47b0SAlexander V. Chernikov
21019f7d47b0SAlexander V. Chernikov static int
ta_init_ifidx(struct ip_fw_chain * ch,void ** ta_state,struct table_info * ti,char * data,uint8_t tflags)210268394ec8SAlexander V. Chernikov ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
2103914bffb6SAlexander V. Chernikov char *data, uint8_t tflags)
21049f7d47b0SAlexander V. Chernikov {
210568394ec8SAlexander V. Chernikov struct iftable_cfg *icfg;
21069f7d47b0SAlexander V. Chernikov
210768394ec8SAlexander V. Chernikov icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO);
21089f7d47b0SAlexander V. Chernikov
2109*4a77657cSAndrey V. Elsukov icfg->ii = ipfw_objhash_create(DEFAULT_IFIDX_SIZE, DEFAULT_OBJHASH_SIZE);
21100cba2b28SAlexander V. Chernikov icfg->size = DEFAULT_IFIDX_SIZE;
21110bce0c23SAlexander V. Chernikov icfg->main_ptr = malloc(sizeof(struct ifidx) * icfg->size, M_IPFW,
211268394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO);
211368394ec8SAlexander V. Chernikov icfg->ch = ch;
21149f7d47b0SAlexander V. Chernikov
211568394ec8SAlexander V. Chernikov *ta_state = icfg;
211668394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr;
211768394ec8SAlexander V. Chernikov ti->lookup = ta_lookup_ifidx;
21189f7d47b0SAlexander V. Chernikov
21199f7d47b0SAlexander V. Chernikov return (0);
21209f7d47b0SAlexander V. Chernikov }
21219f7d47b0SAlexander V. Chernikov
212268394ec8SAlexander V. Chernikov /*
212368394ec8SAlexander V. Chernikov * Handle tableinfo @ti pointer change (on table array resize).
212468394ec8SAlexander V. Chernikov */
212568394ec8SAlexander V. Chernikov static void
ta_change_ti_ifidx(void * ta_state,struct table_info * ti)212668394ec8SAlexander V. Chernikov ta_change_ti_ifidx(void *ta_state, struct table_info *ti)
212768394ec8SAlexander V. Chernikov {
212868394ec8SAlexander V. Chernikov struct iftable_cfg *icfg;
212968394ec8SAlexander V. Chernikov
213068394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state;
213168394ec8SAlexander V. Chernikov icfg->ti = ti;
213268394ec8SAlexander V. Chernikov }
21339f7d47b0SAlexander V. Chernikov
2134b309f085SAndrey V. Elsukov static int
destroy_ifidx_locked(struct namedobj_instance * ii,struct named_object * no,void * arg)213568394ec8SAlexander V. Chernikov destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no,
213668394ec8SAlexander V. Chernikov void *arg)
21379f7d47b0SAlexander V. Chernikov {
213868394ec8SAlexander V. Chernikov struct ifentry *ife;
213968394ec8SAlexander V. Chernikov struct ip_fw_chain *ch;
21409f7d47b0SAlexander V. Chernikov
214168394ec8SAlexander V. Chernikov ch = (struct ip_fw_chain *)arg;
214268394ec8SAlexander V. Chernikov ife = (struct ifentry *)no;
214368394ec8SAlexander V. Chernikov
214468394ec8SAlexander V. Chernikov ipfw_iface_del_notify(ch, &ife->ic);
21450caab009SAlexander V. Chernikov ipfw_iface_unref(ch, &ife->ic);
214668394ec8SAlexander V. Chernikov free(ife, M_IPFW_TBL);
2147b309f085SAndrey V. Elsukov return (0);
21489f7d47b0SAlexander V. Chernikov }
21499f7d47b0SAlexander V. Chernikov
215068394ec8SAlexander V. Chernikov /*
215168394ec8SAlexander V. Chernikov * Destroys table @ti
215268394ec8SAlexander V. Chernikov */
215368394ec8SAlexander V. Chernikov static void
ta_destroy_ifidx(void * ta_state,struct table_info * ti)215468394ec8SAlexander V. Chernikov ta_destroy_ifidx(void *ta_state, struct table_info *ti)
21559f7d47b0SAlexander V. Chernikov {
215668394ec8SAlexander V. Chernikov struct iftable_cfg *icfg;
215768394ec8SAlexander V. Chernikov struct ip_fw_chain *ch;
215868394ec8SAlexander V. Chernikov
215968394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state;
216068394ec8SAlexander V. Chernikov ch = icfg->ch;
216168394ec8SAlexander V. Chernikov
216268394ec8SAlexander V. Chernikov if (icfg->main_ptr != NULL)
216368394ec8SAlexander V. Chernikov free(icfg->main_ptr, M_IPFW);
216468394ec8SAlexander V. Chernikov
21650caab009SAlexander V. Chernikov IPFW_UH_WLOCK(ch);
216668394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch);
21670caab009SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch);
216868394ec8SAlexander V. Chernikov
216968394ec8SAlexander V. Chernikov ipfw_objhash_destroy(icfg->ii);
217068394ec8SAlexander V. Chernikov
217168394ec8SAlexander V. Chernikov free(icfg, M_IPFW);
217268394ec8SAlexander V. Chernikov }
217368394ec8SAlexander V. Chernikov
217468394ec8SAlexander V. Chernikov /*
21755f379342SAlexander V. Chernikov * Provide algo-specific table info
21765f379342SAlexander V. Chernikov */
21775f379342SAlexander V. Chernikov static void
ta_dump_ifidx_tinfo(void * ta_state,struct table_info * ti,ipfw_ta_tinfo * tinfo)21785f379342SAlexander V. Chernikov ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
21795f379342SAlexander V. Chernikov {
21805f379342SAlexander V. Chernikov struct iftable_cfg *cfg;
21815f379342SAlexander V. Chernikov
21825f379342SAlexander V. Chernikov cfg = (struct iftable_cfg *)ta_state;
21835f379342SAlexander V. Chernikov
21845f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_ARRAY;
21855f379342SAlexander V. Chernikov tinfo->size4 = cfg->size;
21865f379342SAlexander V. Chernikov tinfo->count4 = cfg->used;
21875f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct ifidx);
21885f379342SAlexander V. Chernikov }
21895f379342SAlexander V. Chernikov
21905f379342SAlexander V. Chernikov /*
219168394ec8SAlexander V. Chernikov * Prepare state to add to the table:
219268394ec8SAlexander V. Chernikov * allocate ifentry and reference needed interface.
219368394ec8SAlexander V. Chernikov */
21949f7d47b0SAlexander V. Chernikov static int
ta_prepare_add_ifidx(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)219568394ec8SAlexander V. Chernikov ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
219668394ec8SAlexander V. Chernikov void *ta_buf)
219768394ec8SAlexander V. Chernikov {
219868394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb;
219968394ec8SAlexander V. Chernikov char *ifname;
220068394ec8SAlexander V. Chernikov struct ifentry *ife;
220168394ec8SAlexander V. Chernikov
220268394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf;
220368394ec8SAlexander V. Chernikov
220468394ec8SAlexander V. Chernikov /* Check if string is terminated */
220568394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr;
220668394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
220768394ec8SAlexander V. Chernikov return (EINVAL);
220868394ec8SAlexander V. Chernikov
220968394ec8SAlexander V. Chernikov ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO);
221068394ec8SAlexander V. Chernikov ife->ic.cb = if_notifier;
221168394ec8SAlexander V. Chernikov ife->ic.cbdata = ife;
221268394ec8SAlexander V. Chernikov
22138ebca97fSAlexander V. Chernikov if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0) {
22148ebca97fSAlexander V. Chernikov free(ife, M_IPFW_TBL);
221568394ec8SAlexander V. Chernikov return (EINVAL);
22168ebca97fSAlexander V. Chernikov }
221768394ec8SAlexander V. Chernikov
221868394ec8SAlexander V. Chernikov /* Use ipfw_iface 'ifname' field as stable storage */
221968394ec8SAlexander V. Chernikov ife->no.name = ife->ic.iface->ifname;
222068394ec8SAlexander V. Chernikov
222168394ec8SAlexander V. Chernikov tb->ife = ife;
222268394ec8SAlexander V. Chernikov
222368394ec8SAlexander V. Chernikov return (0);
222468394ec8SAlexander V. Chernikov }
222568394ec8SAlexander V. Chernikov
222668394ec8SAlexander V. Chernikov static int
ta_add_ifidx(void * ta_state,struct table_info * ti,struct tentry_info * tei,void * ta_buf,uint32_t * pnum)2227adea6201SAlexander V. Chernikov ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2228b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum)
222968394ec8SAlexander V. Chernikov {
223068394ec8SAlexander V. Chernikov struct iftable_cfg *icfg;
223168394ec8SAlexander V. Chernikov struct ifentry *ife, *tmp;
223268394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb;
223368394ec8SAlexander V. Chernikov struct ipfw_iface *iif;
223468394ec8SAlexander V. Chernikov struct ifidx *ifi;
223568394ec8SAlexander V. Chernikov char *ifname;
2236648e8380SAlexander V. Chernikov uint32_t value;
223768394ec8SAlexander V. Chernikov
223868394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf;
223968394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr;
224068394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state;
224168394ec8SAlexander V. Chernikov ife = tb->ife;
224268394ec8SAlexander V. Chernikov
224368394ec8SAlexander V. Chernikov ife->icfg = icfg;
224413263632SAlexander V. Chernikov ife->value = tei->value;
224568394ec8SAlexander V. Chernikov
224668394ec8SAlexander V. Chernikov tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
224768394ec8SAlexander V. Chernikov
224868394ec8SAlexander V. Chernikov if (tmp != NULL) {
224968394ec8SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
225068394ec8SAlexander V. Chernikov return (EEXIST);
225168394ec8SAlexander V. Chernikov
2252648e8380SAlexander V. Chernikov /* Exchange values in @tmp and @tei */
2253648e8380SAlexander V. Chernikov value = tmp->value;
2254648e8380SAlexander V. Chernikov tmp->value = tei->value;
2255648e8380SAlexander V. Chernikov tei->value = value;
225668394ec8SAlexander V. Chernikov
2257648e8380SAlexander V. Chernikov iif = tmp->ic.iface;
225868394ec8SAlexander V. Chernikov if (iif->resolved != 0) {
2259648e8380SAlexander V. Chernikov /* We have to update runtime value, too */
226068394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, &iif->ifindex);
226168394ec8SAlexander V. Chernikov ifi->value = ife->value;
226268394ec8SAlexander V. Chernikov }
226368394ec8SAlexander V. Chernikov
226468394ec8SAlexander V. Chernikov /* Indicate that update has happened instead of addition */
226568394ec8SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED;
2266adea6201SAlexander V. Chernikov *pnum = 0;
226768394ec8SAlexander V. Chernikov return (0);
226868394ec8SAlexander V. Chernikov }
226968394ec8SAlexander V. Chernikov
22704c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
22714c0c07a5SAlexander V. Chernikov return (EFBIG);
22724c0c07a5SAlexander V. Chernikov
227368394ec8SAlexander V. Chernikov /* Link to internal list */
227468394ec8SAlexander V. Chernikov ipfw_objhash_add(icfg->ii, &ife->no);
227568394ec8SAlexander V. Chernikov
227668394ec8SAlexander V. Chernikov /* Link notifier (possible running its callback) */
227768394ec8SAlexander V. Chernikov ipfw_iface_add_notify(icfg->ch, &ife->ic);
227868394ec8SAlexander V. Chernikov icfg->count++;
227968394ec8SAlexander V. Chernikov
228068394ec8SAlexander V. Chernikov tb->ife = NULL;
2281adea6201SAlexander V. Chernikov *pnum = 1;
228268394ec8SAlexander V. Chernikov
228368394ec8SAlexander V. Chernikov return (0);
228468394ec8SAlexander V. Chernikov }
228568394ec8SAlexander V. Chernikov
228668394ec8SAlexander V. Chernikov /*
228768394ec8SAlexander V. Chernikov * Prepare to delete key from table.
228868394ec8SAlexander V. Chernikov * Do basic interface name checks.
228968394ec8SAlexander V. Chernikov */
229068394ec8SAlexander V. Chernikov static int
ta_prepare_del_ifidx(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)229168394ec8SAlexander V. Chernikov ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
229268394ec8SAlexander V. Chernikov void *ta_buf)
22939f7d47b0SAlexander V. Chernikov {
2294e0a8b9eeSAlexander V. Chernikov char *ifname;
22959f7d47b0SAlexander V. Chernikov
22969f7d47b0SAlexander V. Chernikov /* Check if string is terminated */
2297e0a8b9eeSAlexander V. Chernikov ifname = (char *)tei->paddr;
2298e0a8b9eeSAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
22999f7d47b0SAlexander V. Chernikov return (EINVAL);
23009f7d47b0SAlexander V. Chernikov
23019f7d47b0SAlexander V. Chernikov return (0);
23029f7d47b0SAlexander V. Chernikov }
23039f7d47b0SAlexander V. Chernikov
230468394ec8SAlexander V. Chernikov /*
230568394ec8SAlexander V. Chernikov * Remove key from both configuration list and
230668394ec8SAlexander V. Chernikov * runtime array. Removed interface notification.
230768394ec8SAlexander V. Chernikov */
23089f7d47b0SAlexander V. Chernikov static int
ta_del_ifidx(void * ta_state,struct table_info * ti,struct tentry_info * tei,void * ta_buf,uint32_t * pnum)2309adea6201SAlexander V. Chernikov ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2310b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum)
23119f7d47b0SAlexander V. Chernikov {
231268394ec8SAlexander V. Chernikov struct iftable_cfg *icfg;
231368394ec8SAlexander V. Chernikov struct ifentry *ife;
231468394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb;
231568394ec8SAlexander V. Chernikov char *ifname;
231668394ec8SAlexander V. Chernikov uint16_t ifindex;
231760a28b09SMateusz Guzik int res __diagused;
23189f7d47b0SAlexander V. Chernikov
231968394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf;
232068394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr;
232168394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state;
23229f7d47b0SAlexander V. Chernikov
232368394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
23249f7d47b0SAlexander V. Chernikov
232568394ec8SAlexander V. Chernikov if (ife == NULL)
232681d3153dSAlexander V. Chernikov return (ENOENT);
23279f7d47b0SAlexander V. Chernikov
232868394ec8SAlexander V. Chernikov if (ife->linked != 0) {
232968394ec8SAlexander V. Chernikov /* We have to remove item from runtime */
233068394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex;
233168394ec8SAlexander V. Chernikov
233268394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used,
233368394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx);
233468394ec8SAlexander V. Chernikov
233568394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex));
233668394ec8SAlexander V. Chernikov icfg->used--;
233768394ec8SAlexander V. Chernikov ti->data = icfg->used;
233868394ec8SAlexander V. Chernikov ife->linked = 0;
233968394ec8SAlexander V. Chernikov }
234068394ec8SAlexander V. Chernikov
234168394ec8SAlexander V. Chernikov /* Unlink from local list */
234268394ec8SAlexander V. Chernikov ipfw_objhash_del(icfg->ii, &ife->no);
23430caab009SAlexander V. Chernikov /* Unlink notifier and deref */
234468394ec8SAlexander V. Chernikov ipfw_iface_del_notify(icfg->ch, &ife->ic);
23450caab009SAlexander V. Chernikov ipfw_iface_unref(icfg->ch, &ife->ic);
234668394ec8SAlexander V. Chernikov
234768394ec8SAlexander V. Chernikov icfg->count--;
2348648e8380SAlexander V. Chernikov tei->value = ife->value;
234968394ec8SAlexander V. Chernikov
235068394ec8SAlexander V. Chernikov tb->ife = ife;
2351adea6201SAlexander V. Chernikov *pnum = 1;
235268394ec8SAlexander V. Chernikov
23539f7d47b0SAlexander V. Chernikov return (0);
23549f7d47b0SAlexander V. Chernikov }
23559f7d47b0SAlexander V. Chernikov
235668394ec8SAlexander V. Chernikov /*
235768394ec8SAlexander V. Chernikov * Flush deleted entry.
235868394ec8SAlexander V. Chernikov * Drops interface reference and frees entry.
235968394ec8SAlexander V. Chernikov */
23609f7d47b0SAlexander V. Chernikov static void
ta_flush_ifidx_entry(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)236168394ec8SAlexander V. Chernikov ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
236268394ec8SAlexander V. Chernikov void *ta_buf)
23639f7d47b0SAlexander V. Chernikov {
236468394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb;
23659f7d47b0SAlexander V. Chernikov
236668394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf;
23679f7d47b0SAlexander V. Chernikov
23680caab009SAlexander V. Chernikov if (tb->ife != NULL)
236968394ec8SAlexander V. Chernikov free(tb->ife, M_IPFW_TBL);
237068394ec8SAlexander V. Chernikov }
237168394ec8SAlexander V. Chernikov
237268394ec8SAlexander V. Chernikov /*
237368394ec8SAlexander V. Chernikov * Handle interface announce/withdrawal for particular table.
237468394ec8SAlexander V. Chernikov * Every real runtime array modification happens here.
237568394ec8SAlexander V. Chernikov */
237668394ec8SAlexander V. Chernikov static void
if_notifier(struct ip_fw_chain * ch,void * cbdata,uint16_t ifindex)237768394ec8SAlexander V. Chernikov if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex)
237868394ec8SAlexander V. Chernikov {
237968394ec8SAlexander V. Chernikov struct ifentry *ife;
238068394ec8SAlexander V. Chernikov struct ifidx ifi;
238168394ec8SAlexander V. Chernikov struct iftable_cfg *icfg;
238268394ec8SAlexander V. Chernikov struct table_info *ti;
238360a28b09SMateusz Guzik int res __diagused;
238468394ec8SAlexander V. Chernikov
238568394ec8SAlexander V. Chernikov ife = (struct ifentry *)cbdata;
238668394ec8SAlexander V. Chernikov icfg = ife->icfg;
238768394ec8SAlexander V. Chernikov ti = icfg->ti;
238868394ec8SAlexander V. Chernikov
238968394ec8SAlexander V. Chernikov KASSERT(ti != NULL, ("ti=NULL, check change_ti handler"));
239068394ec8SAlexander V. Chernikov
239168394ec8SAlexander V. Chernikov if (ife->linked == 0 && ifindex != 0) {
239268394ec8SAlexander V. Chernikov /* Interface announce */
239368394ec8SAlexander V. Chernikov ifi.kidx = ifindex;
239468394ec8SAlexander V. Chernikov ifi.spare = 0;
239568394ec8SAlexander V. Chernikov ifi.value = ife->value;
239668394ec8SAlexander V. Chernikov res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used,
239768394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx);
239868394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d already exists", ifindex));
239968394ec8SAlexander V. Chernikov icfg->used++;
240068394ec8SAlexander V. Chernikov ti->data = icfg->used;
240168394ec8SAlexander V. Chernikov ife->linked = 1;
240268394ec8SAlexander V. Chernikov } else if (ife->linked != 0 && ifindex == 0) {
240368394ec8SAlexander V. Chernikov /* Interface withdrawal */
240468394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex;
240568394ec8SAlexander V. Chernikov
240668394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used,
240768394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx);
240868394ec8SAlexander V. Chernikov
240968394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex));
241068394ec8SAlexander V. Chernikov icfg->used--;
241168394ec8SAlexander V. Chernikov ti->data = icfg->used;
241268394ec8SAlexander V. Chernikov ife->linked = 0;
241368394ec8SAlexander V. Chernikov }
241468394ec8SAlexander V. Chernikov }
241568394ec8SAlexander V. Chernikov
241668394ec8SAlexander V. Chernikov /*
241768394ec8SAlexander V. Chernikov * Table growing callbacks.
241868394ec8SAlexander V. Chernikov */
241968394ec8SAlexander V. Chernikov
2420b6ee846eSAlexander V. Chernikov static int
ta_need_modify_ifidx(void * ta_state,struct table_info * ti,uint32_t count,uint64_t * pflags)2421301290bcSAlexander V. Chernikov ta_need_modify_ifidx(void *ta_state, struct table_info *ti, uint32_t count,
2422b6ee846eSAlexander V. Chernikov uint64_t *pflags)
2423b6ee846eSAlexander V. Chernikov {
2424b6ee846eSAlexander V. Chernikov struct iftable_cfg *cfg;
24250bce0c23SAlexander V. Chernikov uint32_t size;
2426b6ee846eSAlexander V. Chernikov
2427b6ee846eSAlexander V. Chernikov cfg = (struct iftable_cfg *)ta_state;
2428b6ee846eSAlexander V. Chernikov
24290bce0c23SAlexander V. Chernikov size = cfg->size;
24300bce0c23SAlexander V. Chernikov while (size < cfg->count + count)
24310bce0c23SAlexander V. Chernikov size *= 2;
24320bce0c23SAlexander V. Chernikov
24330bce0c23SAlexander V. Chernikov if (size != cfg->size) {
24340bce0c23SAlexander V. Chernikov *pflags = size;
2435301290bcSAlexander V. Chernikov return (1);
2436b6ee846eSAlexander V. Chernikov }
2437b6ee846eSAlexander V. Chernikov
2438301290bcSAlexander V. Chernikov return (0);
2439b6ee846eSAlexander V. Chernikov }
2440b6ee846eSAlexander V. Chernikov
244168394ec8SAlexander V. Chernikov /*
244268394ec8SAlexander V. Chernikov * Allocate ned, larger runtime ifidx array.
244368394ec8SAlexander V. Chernikov */
244468394ec8SAlexander V. Chernikov static int
ta_prepare_mod_ifidx(void * ta_buf,uint64_t * pflags)244568394ec8SAlexander V. Chernikov ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags)
244668394ec8SAlexander V. Chernikov {
24470bce0c23SAlexander V. Chernikov struct mod_item *mi;
244868394ec8SAlexander V. Chernikov
24490bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf;
245068394ec8SAlexander V. Chernikov
24510bce0c23SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item));
245268394ec8SAlexander V. Chernikov mi->size = *pflags;
245368394ec8SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW,
245468394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO);
245568394ec8SAlexander V. Chernikov
245668394ec8SAlexander V. Chernikov return (0);
245768394ec8SAlexander V. Chernikov }
245868394ec8SAlexander V. Chernikov
245968394ec8SAlexander V. Chernikov /*
246068394ec8SAlexander V. Chernikov * Copy data from old runtime array to new one.
246168394ec8SAlexander V. Chernikov */
246268394ec8SAlexander V. Chernikov static int
ta_fill_mod_ifidx(void * ta_state,struct table_info * ti,void * ta_buf,uint64_t * pflags)246368394ec8SAlexander V. Chernikov ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
246468394ec8SAlexander V. Chernikov uint64_t *pflags)
246568394ec8SAlexander V. Chernikov {
24660bce0c23SAlexander V. Chernikov struct mod_item *mi;
246768394ec8SAlexander V. Chernikov struct iftable_cfg *icfg;
246868394ec8SAlexander V. Chernikov
24690bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf;
247068394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state;
247168394ec8SAlexander V. Chernikov
247268394ec8SAlexander V. Chernikov /* Check if we still need to grow array */
247368394ec8SAlexander V. Chernikov if (icfg->size >= mi->size) {
247468394ec8SAlexander V. Chernikov *pflags = 0;
247568394ec8SAlexander V. Chernikov return (0);
247668394ec8SAlexander V. Chernikov }
247768394ec8SAlexander V. Chernikov
247868394ec8SAlexander V. Chernikov memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx));
247968394ec8SAlexander V. Chernikov
248068394ec8SAlexander V. Chernikov return (0);
248168394ec8SAlexander V. Chernikov }
248268394ec8SAlexander V. Chernikov
248368394ec8SAlexander V. Chernikov /*
248468394ec8SAlexander V. Chernikov * Switch old & new arrays.
248568394ec8SAlexander V. Chernikov */
2486301290bcSAlexander V. Chernikov static void
ta_modify_ifidx(void * ta_state,struct table_info * ti,void * ta_buf,uint64_t pflags)248768394ec8SAlexander V. Chernikov ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
248868394ec8SAlexander V. Chernikov uint64_t pflags)
248968394ec8SAlexander V. Chernikov {
24900bce0c23SAlexander V. Chernikov struct mod_item *mi;
249168394ec8SAlexander V. Chernikov struct iftable_cfg *icfg;
249268394ec8SAlexander V. Chernikov void *old_ptr;
249368394ec8SAlexander V. Chernikov
24940bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf;
249568394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state;
249668394ec8SAlexander V. Chernikov
249768394ec8SAlexander V. Chernikov old_ptr = icfg->main_ptr;
249868394ec8SAlexander V. Chernikov icfg->main_ptr = mi->main_ptr;
249968394ec8SAlexander V. Chernikov icfg->size = mi->size;
250068394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr;
250168394ec8SAlexander V. Chernikov
250268394ec8SAlexander V. Chernikov mi->main_ptr = old_ptr;
250368394ec8SAlexander V. Chernikov }
250468394ec8SAlexander V. Chernikov
250568394ec8SAlexander V. Chernikov /*
250668394ec8SAlexander V. Chernikov * Free unneded array.
250768394ec8SAlexander V. Chernikov */
250868394ec8SAlexander V. Chernikov static void
ta_flush_mod_ifidx(void * ta_buf)250968394ec8SAlexander V. Chernikov ta_flush_mod_ifidx(void *ta_buf)
251068394ec8SAlexander V. Chernikov {
25110bce0c23SAlexander V. Chernikov struct mod_item *mi;
251268394ec8SAlexander V. Chernikov
25130bce0c23SAlexander V. Chernikov mi = (struct mod_item *)ta_buf;
251468394ec8SAlexander V. Chernikov if (mi->main_ptr != NULL)
251568394ec8SAlexander V. Chernikov free(mi->main_ptr, M_IPFW);
25169f7d47b0SAlexander V. Chernikov }
25179f7d47b0SAlexander V. Chernikov
25189f7d47b0SAlexander V. Chernikov static int
ta_dump_ifidx_tentry(void * ta_state,struct table_info * ti,void * e,ipfw_obj_tentry * tent)251968394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
252081d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent)
25219f7d47b0SAlexander V. Chernikov {
252268394ec8SAlexander V. Chernikov struct ifentry *ife;
25239f7d47b0SAlexander V. Chernikov
252468394ec8SAlexander V. Chernikov ife = (struct ifentry *)e;
252568394ec8SAlexander V. Chernikov
252681d3153dSAlexander V. Chernikov tent->masklen = 8 * IF_NAMESIZE;
252768394ec8SAlexander V. Chernikov memcpy(&tent->k, ife->no.name, IF_NAMESIZE);
25280cba2b28SAlexander V. Chernikov tent->v.kidx = ife->value;
25299f7d47b0SAlexander V. Chernikov
25309f7d47b0SAlexander V. Chernikov return (0);
25319f7d47b0SAlexander V. Chernikov }
25329f7d47b0SAlexander V. Chernikov
253381d3153dSAlexander V. Chernikov static int
ta_find_ifidx_tentry(void * ta_state,struct table_info * ti,ipfw_obj_tentry * tent)2534914bffb6SAlexander V. Chernikov ta_find_ifidx_tentry(void *ta_state, struct table_info *ti,
2535914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent)
253681d3153dSAlexander V. Chernikov {
253768394ec8SAlexander V. Chernikov struct iftable_cfg *icfg;
253868394ec8SAlexander V. Chernikov struct ifentry *ife;
253968394ec8SAlexander V. Chernikov char *ifname;
254081d3153dSAlexander V. Chernikov
254168394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state;
2542914bffb6SAlexander V. Chernikov ifname = tent->k.iface;
254381d3153dSAlexander V. Chernikov
254468394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
254568394ec8SAlexander V. Chernikov return (EINVAL);
254681d3153dSAlexander V. Chernikov
254768394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
254868394ec8SAlexander V. Chernikov
254968394ec8SAlexander V. Chernikov if (ife != NULL) {
255068394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(ta_state, ti, ife, tent);
255181d3153dSAlexander V. Chernikov return (0);
255281d3153dSAlexander V. Chernikov }
255381d3153dSAlexander V. Chernikov
255481d3153dSAlexander V. Chernikov return (ENOENT);
255581d3153dSAlexander V. Chernikov }
255681d3153dSAlexander V. Chernikov
255768394ec8SAlexander V. Chernikov struct wa_ifidx {
255868394ec8SAlexander V. Chernikov ta_foreach_f *f;
255968394ec8SAlexander V. Chernikov void *arg;
256068394ec8SAlexander V. Chernikov };
256168394ec8SAlexander V. Chernikov
2562b309f085SAndrey V. Elsukov static int
foreach_ifidx(struct namedobj_instance * ii,struct named_object * no,void * arg)256368394ec8SAlexander V. Chernikov foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
25649f7d47b0SAlexander V. Chernikov void *arg)
25659f7d47b0SAlexander V. Chernikov {
256668394ec8SAlexander V. Chernikov struct ifentry *ife;
256768394ec8SAlexander V. Chernikov struct wa_ifidx *wa;
25689f7d47b0SAlexander V. Chernikov
256968394ec8SAlexander V. Chernikov ife = (struct ifentry *)no;
257068394ec8SAlexander V. Chernikov wa = (struct wa_ifidx *)arg;
257168394ec8SAlexander V. Chernikov
257268394ec8SAlexander V. Chernikov wa->f(ife, wa->arg);
2573b309f085SAndrey V. Elsukov return (0);
25749f7d47b0SAlexander V. Chernikov }
25759f7d47b0SAlexander V. Chernikov
257668394ec8SAlexander V. Chernikov static void
ta_foreach_ifidx(void * ta_state,struct table_info * ti,ta_foreach_f * f,void * arg)257768394ec8SAlexander V. Chernikov ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f,
257868394ec8SAlexander V. Chernikov void *arg)
257968394ec8SAlexander V. Chernikov {
258068394ec8SAlexander V. Chernikov struct iftable_cfg *icfg;
258168394ec8SAlexander V. Chernikov struct wa_ifidx wa;
258268394ec8SAlexander V. Chernikov
258368394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state;
258468394ec8SAlexander V. Chernikov
258568394ec8SAlexander V. Chernikov wa.f = f;
258668394ec8SAlexander V. Chernikov wa.arg = arg;
258768394ec8SAlexander V. Chernikov
258868394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa);
258968394ec8SAlexander V. Chernikov }
259068394ec8SAlexander V. Chernikov
259174b941f0SAlexander V. Chernikov struct table_algo iface_idx = {
2592adea6201SAlexander V. Chernikov .name = "iface:array",
25939d099b4fSAlexander V. Chernikov .type = IPFW_TABLE_INTERFACE,
259457a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT,
259557a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_ifidx),
259668394ec8SAlexander V. Chernikov .init = ta_init_ifidx,
259768394ec8SAlexander V. Chernikov .destroy = ta_destroy_ifidx,
259868394ec8SAlexander V. Chernikov .prepare_add = ta_prepare_add_ifidx,
259968394ec8SAlexander V. Chernikov .prepare_del = ta_prepare_del_ifidx,
260068394ec8SAlexander V. Chernikov .add = ta_add_ifidx,
260168394ec8SAlexander V. Chernikov .del = ta_del_ifidx,
260268394ec8SAlexander V. Chernikov .flush_entry = ta_flush_ifidx_entry,
260368394ec8SAlexander V. Chernikov .foreach = ta_foreach_ifidx,
260468394ec8SAlexander V. Chernikov .dump_tentry = ta_dump_ifidx_tentry,
260568394ec8SAlexander V. Chernikov .find_tentry = ta_find_ifidx_tentry,
26065f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_ifidx_tinfo,
2607301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_ifidx,
260868394ec8SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_ifidx,
260968394ec8SAlexander V. Chernikov .fill_mod = ta_fill_mod_ifidx,
261068394ec8SAlexander V. Chernikov .modify = ta_modify_ifidx,
261168394ec8SAlexander V. Chernikov .flush_mod = ta_flush_mod_ifidx,
261268394ec8SAlexander V. Chernikov .change_ti = ta_change_ti_ifidx,
26139f7d47b0SAlexander V. Chernikov };
26149f7d47b0SAlexander V. Chernikov
2615b23d5de9SAlexander V. Chernikov /*
2616b23d5de9SAlexander V. Chernikov * Number array cmds.
2617b23d5de9SAlexander V. Chernikov *
2618b23d5de9SAlexander V. Chernikov * Implementation:
2619b23d5de9SAlexander V. Chernikov *
2620b23d5de9SAlexander V. Chernikov * Runtime part:
2621b23d5de9SAlexander V. Chernikov * - sorted array of "struct numarray" pointed by ti->state.
2622b23d5de9SAlexander V. Chernikov * Array is allocated with rounding up to NUMARRAY_CHUNK.
2623b23d5de9SAlexander V. Chernikov * - current array size is stored in ti->data
2624b23d5de9SAlexander V. Chernikov *
2625b23d5de9SAlexander V. Chernikov */
2626b23d5de9SAlexander V. Chernikov
2627b23d5de9SAlexander V. Chernikov struct numarray {
2628b23d5de9SAlexander V. Chernikov uint32_t number;
2629b23d5de9SAlexander V. Chernikov uint32_t value;
2630b23d5de9SAlexander V. Chernikov };
2631b23d5de9SAlexander V. Chernikov
2632b23d5de9SAlexander V. Chernikov struct numarray_cfg {
2633b23d5de9SAlexander V. Chernikov void *main_ptr;
2634b23d5de9SAlexander V. Chernikov size_t size; /* Number of items allocated in array */
2635b23d5de9SAlexander V. Chernikov size_t used; /* Number of items _active_ now */
2636b23d5de9SAlexander V. Chernikov };
2637b23d5de9SAlexander V. Chernikov
26380bce0c23SAlexander V. Chernikov struct ta_buf_numarray
26390bce0c23SAlexander V. Chernikov {
26400bce0c23SAlexander V. Chernikov struct numarray na;
26410bce0c23SAlexander V. Chernikov };
2642b23d5de9SAlexander V. Chernikov
2643b23d5de9SAlexander V. Chernikov int compare_numarray(const void *k, const void *v);
26449fe15d06SAlexander V. Chernikov static struct numarray *numarray_find(struct table_info *ti, void *key);
26459fe15d06SAlexander V. Chernikov static int ta_lookup_numarray(struct table_info *ti, void *key,
26469fe15d06SAlexander V. Chernikov uint32_t keylen, uint32_t *val);
26479fe15d06SAlexander V. Chernikov static int ta_init_numarray(struct ip_fw_chain *ch, void **ta_state,
26489fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags);
26499fe15d06SAlexander V. Chernikov static void ta_destroy_numarray(void *ta_state, struct table_info *ti);
26509fe15d06SAlexander V. Chernikov static void ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti,
26519fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo);
26529fe15d06SAlexander V. Chernikov static int ta_prepare_add_numarray(struct ip_fw_chain *ch,
26539fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf);
26549fe15d06SAlexander V. Chernikov static int ta_add_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 int ta_del_numarray(void *ta_state, struct table_info *ti,
26579fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
26589fe15d06SAlexander V. Chernikov static void ta_flush_numarray_entry(struct ip_fw_chain *ch,
26599fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf);
26609fe15d06SAlexander V. Chernikov static int ta_need_modify_numarray(void *ta_state, struct table_info *ti,
26619fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags);
26629fe15d06SAlexander V. Chernikov static int ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags);
26639fe15d06SAlexander V. Chernikov static int ta_fill_mod_numarray(void *ta_state, struct table_info *ti,
26649fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t *pflags);
26659fe15d06SAlexander V. Chernikov static void ta_modify_numarray(void *ta_state, struct table_info *ti,
26669fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t pflags);
26679fe15d06SAlexander V. Chernikov static void ta_flush_mod_numarray(void *ta_buf);
26689fe15d06SAlexander V. Chernikov static int ta_dump_numarray_tentry(void *ta_state, struct table_info *ti,
26699fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent);
26709fe15d06SAlexander V. Chernikov static int ta_find_numarray_tentry(void *ta_state, struct table_info *ti,
26719fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent);
26729fe15d06SAlexander V. Chernikov static void ta_foreach_numarray(void *ta_state, struct table_info *ti,
26739fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg);
2674b23d5de9SAlexander V. Chernikov
2675b23d5de9SAlexander V. Chernikov int
compare_numarray(const void * k,const void * v)2676b23d5de9SAlexander V. Chernikov compare_numarray(const void *k, const void *v)
2677b23d5de9SAlexander V. Chernikov {
2678d4e1b515SAlexander V. Chernikov const struct numarray *na;
2679b23d5de9SAlexander V. Chernikov uint32_t key;
2680b23d5de9SAlexander V. Chernikov
2681d4e1b515SAlexander V. Chernikov key = *((const uint32_t *)k);
2682d4e1b515SAlexander V. Chernikov na = (const struct numarray *)v;
2683b23d5de9SAlexander V. Chernikov
2684b23d5de9SAlexander V. Chernikov if (key < na->number)
2685b23d5de9SAlexander V. Chernikov return (-1);
2686b23d5de9SAlexander V. Chernikov else if (key > na->number)
2687b23d5de9SAlexander V. Chernikov return (1);
2688b23d5de9SAlexander V. Chernikov
2689b23d5de9SAlexander V. Chernikov return (0);
2690b23d5de9SAlexander V. Chernikov }
2691b23d5de9SAlexander V. Chernikov
2692b23d5de9SAlexander V. Chernikov static struct numarray *
numarray_find(struct table_info * ti,void * key)2693b23d5de9SAlexander V. Chernikov numarray_find(struct table_info *ti, void *key)
2694b23d5de9SAlexander V. Chernikov {
2695b23d5de9SAlexander V. Chernikov struct numarray *ri;
2696b23d5de9SAlexander V. Chernikov
2697b23d5de9SAlexander V. Chernikov ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray),
2698194df014SAndrey V. Elsukov compare_numarray);
2699b23d5de9SAlexander V. Chernikov
2700b23d5de9SAlexander V. Chernikov return (ri);
2701b23d5de9SAlexander V. Chernikov }
2702b23d5de9SAlexander V. Chernikov
2703b23d5de9SAlexander V. Chernikov static int
ta_lookup_numarray(struct table_info * ti,void * key,uint32_t keylen,uint32_t * val)2704b23d5de9SAlexander V. Chernikov ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen,
2705b23d5de9SAlexander V. Chernikov uint32_t *val)
2706b23d5de9SAlexander V. Chernikov {
2707b23d5de9SAlexander V. Chernikov struct numarray *ri;
2708b23d5de9SAlexander V. Chernikov
2709b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, key);
2710b23d5de9SAlexander V. Chernikov
2711b23d5de9SAlexander V. Chernikov if (ri != NULL) {
2712b23d5de9SAlexander V. Chernikov *val = ri->value;
2713b23d5de9SAlexander V. Chernikov return (1);
2714b23d5de9SAlexander V. Chernikov }
2715b23d5de9SAlexander V. Chernikov
2716b23d5de9SAlexander V. Chernikov return (0);
2717b23d5de9SAlexander V. Chernikov }
2718b23d5de9SAlexander V. Chernikov
2719b23d5de9SAlexander V. Chernikov static int
ta_init_numarray(struct ip_fw_chain * ch,void ** ta_state,struct table_info * ti,char * data,uint8_t tflags)2720b23d5de9SAlexander V. Chernikov ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
2721914bffb6SAlexander V. Chernikov char *data, uint8_t tflags)
2722b23d5de9SAlexander V. Chernikov {
2723b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg;
2724b23d5de9SAlexander V. Chernikov
2725b23d5de9SAlexander V. Chernikov cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO);
2726b23d5de9SAlexander V. Chernikov
27270bce0c23SAlexander V. Chernikov cfg->size = 16;
2728b23d5de9SAlexander V. Chernikov cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW,
2729b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO);
2730b23d5de9SAlexander V. Chernikov
2731b23d5de9SAlexander V. Chernikov *ta_state = cfg;
2732b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr;
2733b23d5de9SAlexander V. Chernikov ti->lookup = ta_lookup_numarray;
2734b23d5de9SAlexander V. Chernikov
2735b23d5de9SAlexander V. Chernikov return (0);
2736b23d5de9SAlexander V. Chernikov }
2737b23d5de9SAlexander V. Chernikov
2738b23d5de9SAlexander V. Chernikov /*
2739b23d5de9SAlexander V. Chernikov * Destroys table @ti
2740b23d5de9SAlexander V. Chernikov */
2741b23d5de9SAlexander V. Chernikov static void
ta_destroy_numarray(void * ta_state,struct table_info * ti)2742b23d5de9SAlexander V. Chernikov ta_destroy_numarray(void *ta_state, struct table_info *ti)
2743b23d5de9SAlexander V. Chernikov {
2744b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg;
2745b23d5de9SAlexander V. Chernikov
2746b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state;
2747b23d5de9SAlexander V. Chernikov
2748b23d5de9SAlexander V. Chernikov if (cfg->main_ptr != NULL)
2749b23d5de9SAlexander V. Chernikov free(cfg->main_ptr, M_IPFW);
2750b23d5de9SAlexander V. Chernikov
2751b23d5de9SAlexander V. Chernikov free(cfg, M_IPFW);
2752b23d5de9SAlexander V. Chernikov }
2753b23d5de9SAlexander V. Chernikov
2754b23d5de9SAlexander V. Chernikov /*
27555f379342SAlexander V. Chernikov * Provide algo-specific table info
27565f379342SAlexander V. Chernikov */
27575f379342SAlexander V. Chernikov static void
ta_dump_numarray_tinfo(void * ta_state,struct table_info * ti,ipfw_ta_tinfo * tinfo)27585f379342SAlexander V. Chernikov ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
27595f379342SAlexander V. Chernikov {
27605f379342SAlexander V. Chernikov struct numarray_cfg *cfg;
27615f379342SAlexander V. Chernikov
27625f379342SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state;
27635f379342SAlexander V. Chernikov
27645f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_ARRAY;
27655f379342SAlexander V. Chernikov tinfo->size4 = cfg->size;
27665f379342SAlexander V. Chernikov tinfo->count4 = cfg->used;
27675f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct numarray);
27685f379342SAlexander V. Chernikov }
27695f379342SAlexander V. Chernikov
27705f379342SAlexander V. Chernikov /*
2771b23d5de9SAlexander V. Chernikov * Prepare for addition/deletion to an array.
2772b23d5de9SAlexander V. Chernikov */
2773b23d5de9SAlexander V. Chernikov static int
ta_prepare_add_numarray(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)2774b23d5de9SAlexander V. Chernikov ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei,
2775b23d5de9SAlexander V. Chernikov void *ta_buf)
2776b23d5de9SAlexander V. Chernikov {
2777b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb;
2778b23d5de9SAlexander V. Chernikov
2779b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf;
2780b23d5de9SAlexander V. Chernikov
2781b23d5de9SAlexander V. Chernikov tb->na.number = *((uint32_t *)tei->paddr);
2782b23d5de9SAlexander V. Chernikov
2783b23d5de9SAlexander V. Chernikov return (0);
2784b23d5de9SAlexander V. Chernikov }
2785b23d5de9SAlexander V. Chernikov
2786b23d5de9SAlexander V. Chernikov static int
ta_add_numarray(void * ta_state,struct table_info * ti,struct tentry_info * tei,void * ta_buf,uint32_t * pnum)2787b23d5de9SAlexander V. Chernikov ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2788b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum)
2789b23d5de9SAlexander V. Chernikov {
2790b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg;
2791b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb;
2792b23d5de9SAlexander V. Chernikov struct numarray *ri;
279360a28b09SMateusz Guzik int res __diagused;
2794648e8380SAlexander V. Chernikov uint32_t value;
2795b23d5de9SAlexander V. Chernikov
2796b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf;
2797b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state;
2798b23d5de9SAlexander V. Chernikov
279913263632SAlexander V. Chernikov /* Read current value from @tei */
280013263632SAlexander V. Chernikov tb->na.value = tei->value;
280113263632SAlexander V. Chernikov
2802b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number);
2803b23d5de9SAlexander V. Chernikov
2804b23d5de9SAlexander V. Chernikov if (ri != NULL) {
2805b23d5de9SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
2806b23d5de9SAlexander V. Chernikov return (EEXIST);
2807b23d5de9SAlexander V. Chernikov
2808648e8380SAlexander V. Chernikov /* Exchange values between ri and @tei */
2809648e8380SAlexander V. Chernikov value = ri->value;
2810648e8380SAlexander V. Chernikov ri->value = tei->value;
2811648e8380SAlexander V. Chernikov tei->value = value;
2812b23d5de9SAlexander V. Chernikov /* Indicate that update has happened instead of addition */
2813b23d5de9SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED;
2814b23d5de9SAlexander V. Chernikov *pnum = 0;
2815b23d5de9SAlexander V. Chernikov return (0);
2816b23d5de9SAlexander V. Chernikov }
2817b23d5de9SAlexander V. Chernikov
28184c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
28194c0c07a5SAlexander V. Chernikov return (EFBIG);
28204c0c07a5SAlexander V. Chernikov
2821b23d5de9SAlexander V. Chernikov res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used,
2822b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray);
2823b23d5de9SAlexander V. Chernikov
2824b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %d already exists", tb->na.number));
2825b23d5de9SAlexander V. Chernikov cfg->used++;
2826b23d5de9SAlexander V. Chernikov ti->data = cfg->used;
2827b23d5de9SAlexander V. Chernikov *pnum = 1;
2828b23d5de9SAlexander V. Chernikov
2829b23d5de9SAlexander V. Chernikov return (0);
2830b23d5de9SAlexander V. Chernikov }
2831b23d5de9SAlexander V. Chernikov
2832b23d5de9SAlexander V. Chernikov /*
2833b23d5de9SAlexander V. Chernikov * Remove key from both configuration list and
2834b23d5de9SAlexander V. Chernikov * runtime array. Removed interface notification.
2835b23d5de9SAlexander V. Chernikov */
2836b23d5de9SAlexander V. Chernikov static int
ta_del_numarray(void * ta_state,struct table_info * ti,struct tentry_info * tei,void * ta_buf,uint32_t * pnum)2837b23d5de9SAlexander V. Chernikov ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2838b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum)
2839b23d5de9SAlexander V. Chernikov {
2840b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg;
2841b23d5de9SAlexander V. Chernikov struct ta_buf_numarray *tb;
2842b23d5de9SAlexander V. Chernikov struct numarray *ri;
284360a28b09SMateusz Guzik int res __diagused;
2844b23d5de9SAlexander V. Chernikov
2845b23d5de9SAlexander V. Chernikov tb = (struct ta_buf_numarray *)ta_buf;
2846b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state;
2847b23d5de9SAlexander V. Chernikov
2848b23d5de9SAlexander V. Chernikov ri = numarray_find(ti, &tb->na.number);
2849b23d5de9SAlexander V. Chernikov if (ri == NULL)
2850b23d5de9SAlexander V. Chernikov return (ENOENT);
2851b23d5de9SAlexander V. Chernikov
2852648e8380SAlexander V. Chernikov tei->value = ri->value;
2853648e8380SAlexander V. Chernikov
2854b23d5de9SAlexander V. Chernikov res = bdel(&tb->na.number, cfg->main_ptr, cfg->used,
2855b23d5de9SAlexander V. Chernikov sizeof(struct numarray), compare_numarray);
2856b23d5de9SAlexander V. Chernikov
2857b23d5de9SAlexander V. Chernikov KASSERT(res == 1, ("number %u does not exist", tb->na.number));
2858b23d5de9SAlexander V. Chernikov cfg->used--;
2859b23d5de9SAlexander V. Chernikov ti->data = cfg->used;
2860b23d5de9SAlexander V. Chernikov *pnum = 1;
2861b23d5de9SAlexander V. Chernikov
2862b23d5de9SAlexander V. Chernikov return (0);
2863b23d5de9SAlexander V. Chernikov }
2864b23d5de9SAlexander V. Chernikov
2865b23d5de9SAlexander V. Chernikov static void
ta_flush_numarray_entry(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)2866b23d5de9SAlexander V. Chernikov ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
2867b23d5de9SAlexander V. Chernikov void *ta_buf)
2868b23d5de9SAlexander V. Chernikov {
2869b23d5de9SAlexander V. Chernikov
28700bce0c23SAlexander V. Chernikov /* We don't have any state, do nothing */
2871b23d5de9SAlexander V. Chernikov }
2872b23d5de9SAlexander V. Chernikov
2873b23d5de9SAlexander V. Chernikov /*
2874b23d5de9SAlexander V. Chernikov * Table growing callbacks.
2875b23d5de9SAlexander V. Chernikov */
2876b23d5de9SAlexander V. Chernikov
2877b6ee846eSAlexander V. Chernikov static int
ta_need_modify_numarray(void * ta_state,struct table_info * ti,uint32_t count,uint64_t * pflags)2878301290bcSAlexander V. Chernikov ta_need_modify_numarray(void *ta_state, struct table_info *ti, uint32_t count,
2879b6ee846eSAlexander V. Chernikov uint64_t *pflags)
2880b6ee846eSAlexander V. Chernikov {
2881b6ee846eSAlexander V. Chernikov struct numarray_cfg *cfg;
28820bce0c23SAlexander V. Chernikov size_t size;
2883b6ee846eSAlexander V. Chernikov
2884b6ee846eSAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state;
2885b6ee846eSAlexander V. Chernikov
28860bce0c23SAlexander V. Chernikov size = cfg->size;
28870bce0c23SAlexander V. Chernikov while (size < cfg->used + count)
28880bce0c23SAlexander V. Chernikov size *= 2;
28890bce0c23SAlexander V. Chernikov
28900bce0c23SAlexander V. Chernikov if (size != cfg->size) {
28910bce0c23SAlexander V. Chernikov *pflags = size;
2892301290bcSAlexander V. Chernikov return (1);
2893b6ee846eSAlexander V. Chernikov }
2894b6ee846eSAlexander V. Chernikov
2895301290bcSAlexander V. Chernikov return (0);
2896b6ee846eSAlexander V. Chernikov }
2897b6ee846eSAlexander V. Chernikov
2898b23d5de9SAlexander V. Chernikov /*
2899b6ee846eSAlexander V. Chernikov * Allocate new, larger runtime array.
2900b23d5de9SAlexander V. Chernikov */
2901b23d5de9SAlexander V. Chernikov static int
ta_prepare_mod_numarray(void * ta_buf,uint64_t * pflags)2902b23d5de9SAlexander V. Chernikov ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags)
2903b23d5de9SAlexander V. Chernikov {
2904b23d5de9SAlexander V. Chernikov struct mod_item *mi;
2905b23d5de9SAlexander V. Chernikov
2906b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf;
2907b23d5de9SAlexander V. Chernikov
2908b23d5de9SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item));
2909b23d5de9SAlexander V. Chernikov mi->size = *pflags;
2910b23d5de9SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW,
2911b23d5de9SAlexander V. Chernikov M_WAITOK | M_ZERO);
2912b23d5de9SAlexander V. Chernikov
2913b23d5de9SAlexander V. Chernikov return (0);
2914b23d5de9SAlexander V. Chernikov }
2915b23d5de9SAlexander V. Chernikov
2916b23d5de9SAlexander V. Chernikov /*
2917b23d5de9SAlexander V. Chernikov * Copy data from old runtime array to new one.
2918b23d5de9SAlexander V. Chernikov */
2919b23d5de9SAlexander V. Chernikov static int
ta_fill_mod_numarray(void * ta_state,struct table_info * ti,void * ta_buf,uint64_t * pflags)2920b23d5de9SAlexander V. Chernikov ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
2921b23d5de9SAlexander V. Chernikov uint64_t *pflags)
2922b23d5de9SAlexander V. Chernikov {
2923b23d5de9SAlexander V. Chernikov struct mod_item *mi;
2924b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg;
2925b23d5de9SAlexander V. Chernikov
2926b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf;
2927b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state;
2928b23d5de9SAlexander V. Chernikov
2929b23d5de9SAlexander V. Chernikov /* Check if we still need to grow array */
2930b23d5de9SAlexander V. Chernikov if (cfg->size >= mi->size) {
2931b23d5de9SAlexander V. Chernikov *pflags = 0;
2932b23d5de9SAlexander V. Chernikov return (0);
2933b23d5de9SAlexander V. Chernikov }
2934b23d5de9SAlexander V. Chernikov
2935b23d5de9SAlexander V. Chernikov memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray));
2936b23d5de9SAlexander V. Chernikov
2937b23d5de9SAlexander V. Chernikov return (0);
2938b23d5de9SAlexander V. Chernikov }
2939b23d5de9SAlexander V. Chernikov
2940b23d5de9SAlexander V. Chernikov /*
2941b23d5de9SAlexander V. Chernikov * Switch old & new arrays.
2942b23d5de9SAlexander V. Chernikov */
2943301290bcSAlexander V. Chernikov static void
ta_modify_numarray(void * ta_state,struct table_info * ti,void * ta_buf,uint64_t pflags)2944b23d5de9SAlexander V. Chernikov ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
2945b23d5de9SAlexander V. Chernikov uint64_t pflags)
2946b23d5de9SAlexander V. Chernikov {
2947b23d5de9SAlexander V. Chernikov struct mod_item *mi;
2948b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg;
2949b23d5de9SAlexander V. Chernikov void *old_ptr;
2950b23d5de9SAlexander V. Chernikov
2951b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf;
2952b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state;
2953b23d5de9SAlexander V. Chernikov
2954b23d5de9SAlexander V. Chernikov old_ptr = cfg->main_ptr;
2955b23d5de9SAlexander V. Chernikov cfg->main_ptr = mi->main_ptr;
2956b23d5de9SAlexander V. Chernikov cfg->size = mi->size;
2957b23d5de9SAlexander V. Chernikov ti->state = cfg->main_ptr;
2958b23d5de9SAlexander V. Chernikov
2959b23d5de9SAlexander V. Chernikov mi->main_ptr = old_ptr;
2960b23d5de9SAlexander V. Chernikov }
2961b23d5de9SAlexander V. Chernikov
2962b23d5de9SAlexander V. Chernikov /*
2963b23d5de9SAlexander V. Chernikov * Free unneded array.
2964b23d5de9SAlexander V. Chernikov */
2965b23d5de9SAlexander V. Chernikov static void
ta_flush_mod_numarray(void * ta_buf)2966b23d5de9SAlexander V. Chernikov ta_flush_mod_numarray(void *ta_buf)
2967b23d5de9SAlexander V. Chernikov {
2968b23d5de9SAlexander V. Chernikov struct mod_item *mi;
2969b23d5de9SAlexander V. Chernikov
2970b23d5de9SAlexander V. Chernikov mi = (struct mod_item *)ta_buf;
2971b23d5de9SAlexander V. Chernikov if (mi->main_ptr != NULL)
2972b23d5de9SAlexander V. Chernikov free(mi->main_ptr, M_IPFW);
2973b23d5de9SAlexander V. Chernikov }
2974b23d5de9SAlexander V. Chernikov
2975b23d5de9SAlexander V. Chernikov static int
ta_dump_numarray_tentry(void * ta_state,struct table_info * ti,void * e,ipfw_obj_tentry * tent)2976b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e,
2977b23d5de9SAlexander V. Chernikov ipfw_obj_tentry *tent)
2978b23d5de9SAlexander V. Chernikov {
2979b23d5de9SAlexander V. Chernikov struct numarray *na;
2980b23d5de9SAlexander V. Chernikov
2981b23d5de9SAlexander V. Chernikov na = (struct numarray *)e;
2982b23d5de9SAlexander V. Chernikov
2983b23d5de9SAlexander V. Chernikov tent->k.key = na->number;
29840cba2b28SAlexander V. Chernikov tent->v.kidx = na->value;
2985b23d5de9SAlexander V. Chernikov
2986b23d5de9SAlexander V. Chernikov return (0);
2987b23d5de9SAlexander V. Chernikov }
2988b23d5de9SAlexander V. Chernikov
2989b23d5de9SAlexander V. Chernikov static int
ta_find_numarray_tentry(void * ta_state,struct table_info * ti,ipfw_obj_tentry * tent)2990914bffb6SAlexander V. Chernikov ta_find_numarray_tentry(void *ta_state, struct table_info *ti,
2991914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent)
2992b23d5de9SAlexander V. Chernikov {
2993b23d5de9SAlexander V. Chernikov struct numarray *ri;
2994b23d5de9SAlexander V. Chernikov
2995914bffb6SAlexander V. Chernikov ri = numarray_find(ti, &tent->k.key);
2996b23d5de9SAlexander V. Chernikov
2997b23d5de9SAlexander V. Chernikov if (ri != NULL) {
2998b23d5de9SAlexander V. Chernikov ta_dump_numarray_tentry(ta_state, ti, ri, tent);
2999b23d5de9SAlexander V. Chernikov return (0);
3000b23d5de9SAlexander V. Chernikov }
3001b23d5de9SAlexander V. Chernikov
3002b23d5de9SAlexander V. Chernikov return (ENOENT);
3003b23d5de9SAlexander V. Chernikov }
3004b23d5de9SAlexander V. Chernikov
3005b23d5de9SAlexander V. Chernikov static void
ta_foreach_numarray(void * ta_state,struct table_info * ti,ta_foreach_f * f,void * arg)3006b23d5de9SAlexander V. Chernikov ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f,
3007b23d5de9SAlexander V. Chernikov void *arg)
3008b23d5de9SAlexander V. Chernikov {
3009b23d5de9SAlexander V. Chernikov struct numarray_cfg *cfg;
3010b23d5de9SAlexander V. Chernikov struct numarray *array;
3011b23d5de9SAlexander V. Chernikov int i;
3012b23d5de9SAlexander V. Chernikov
3013b23d5de9SAlexander V. Chernikov cfg = (struct numarray_cfg *)ta_state;
3014b23d5de9SAlexander V. Chernikov array = cfg->main_ptr;
3015b23d5de9SAlexander V. Chernikov
3016b23d5de9SAlexander V. Chernikov for (i = 0; i < cfg->used; i++)
3017b23d5de9SAlexander V. Chernikov f(&array[i], arg);
3018b23d5de9SAlexander V. Chernikov }
3019b23d5de9SAlexander V. Chernikov
3020b23d5de9SAlexander V. Chernikov struct table_algo number_array = {
3021b23d5de9SAlexander V. Chernikov .name = "number:array",
3022b23d5de9SAlexander V. Chernikov .type = IPFW_TABLE_NUMBER,
302357a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_numarray),
3024b23d5de9SAlexander V. Chernikov .init = ta_init_numarray,
3025b23d5de9SAlexander V. Chernikov .destroy = ta_destroy_numarray,
3026b23d5de9SAlexander V. Chernikov .prepare_add = ta_prepare_add_numarray,
3027b23d5de9SAlexander V. Chernikov .prepare_del = ta_prepare_add_numarray,
3028b23d5de9SAlexander V. Chernikov .add = ta_add_numarray,
3029b23d5de9SAlexander V. Chernikov .del = ta_del_numarray,
3030b23d5de9SAlexander V. Chernikov .flush_entry = ta_flush_numarray_entry,
3031b23d5de9SAlexander V. Chernikov .foreach = ta_foreach_numarray,
3032b23d5de9SAlexander V. Chernikov .dump_tentry = ta_dump_numarray_tentry,
3033b23d5de9SAlexander V. Chernikov .find_tentry = ta_find_numarray_tentry,
30345f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_numarray_tinfo,
3035301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_numarray,
3036b23d5de9SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_numarray,
3037b23d5de9SAlexander V. Chernikov .fill_mod = ta_fill_mod_numarray,
3038b23d5de9SAlexander V. Chernikov .modify = ta_modify_numarray,
3039b23d5de9SAlexander V. Chernikov .flush_mod = ta_flush_mod_numarray,
3040b23d5de9SAlexander V. Chernikov };
3041b23d5de9SAlexander V. Chernikov
3042914bffb6SAlexander V. Chernikov /*
3043914bffb6SAlexander V. Chernikov * flow:hash cmds
3044914bffb6SAlexander V. Chernikov *
3045914bffb6SAlexander V. Chernikov *
3046914bffb6SAlexander V. Chernikov * ti->data:
3047914bffb6SAlexander V. Chernikov * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
3048914bffb6SAlexander V. Chernikov * [ 8][ 8[ 8][ 8]
3049914bffb6SAlexander V. Chernikov *
3050914bffb6SAlexander V. Chernikov * inv.mask4: 32 - mask
3051914bffb6SAlexander V. Chernikov * inv.mask6:
3052914bffb6SAlexander V. Chernikov * 1) _slow lookup: mask
3053914bffb6SAlexander V. Chernikov * 2) _aligned: (128 - mask) / 8
3054914bffb6SAlexander V. Chernikov * 3) _64: 8
3055914bffb6SAlexander V. Chernikov *
3056914bffb6SAlexander V. Chernikov *
3057914bffb6SAlexander V. Chernikov * pflags:
3058b6ee846eSAlexander V. Chernikov * [hsize4][hsize6]
3059b6ee846eSAlexander V. Chernikov * [ 16][ 16]
3060914bffb6SAlexander V. Chernikov */
3061914bffb6SAlexander V. Chernikov
3062914bffb6SAlexander V. Chernikov struct fhashentry;
3063914bffb6SAlexander V. Chernikov
3064914bffb6SAlexander V. Chernikov SLIST_HEAD(fhashbhead, fhashentry);
3065914bffb6SAlexander V. Chernikov
3066914bffb6SAlexander V. Chernikov struct fhashentry {
3067914bffb6SAlexander V. Chernikov SLIST_ENTRY(fhashentry) next;
3068914bffb6SAlexander V. Chernikov uint8_t af;
3069914bffb6SAlexander V. Chernikov uint8_t proto;
3070914bffb6SAlexander V. Chernikov uint16_t spare0;
3071914bffb6SAlexander V. Chernikov uint16_t dport;
3072914bffb6SAlexander V. Chernikov uint16_t sport;
3073914bffb6SAlexander V. Chernikov uint32_t value;
3074914bffb6SAlexander V. Chernikov uint32_t spare1;
3075914bffb6SAlexander V. Chernikov };
3076914bffb6SAlexander V. Chernikov
3077914bffb6SAlexander V. Chernikov struct fhashentry4 {
3078914bffb6SAlexander V. Chernikov struct fhashentry e;
3079914bffb6SAlexander V. Chernikov struct in_addr dip;
3080914bffb6SAlexander V. Chernikov struct in_addr sip;
3081914bffb6SAlexander V. Chernikov };
3082914bffb6SAlexander V. Chernikov
3083914bffb6SAlexander V. Chernikov struct fhashentry6 {
3084914bffb6SAlexander V. Chernikov struct fhashentry e;
3085914bffb6SAlexander V. Chernikov struct in6_addr dip6;
3086914bffb6SAlexander V. Chernikov struct in6_addr sip6;
3087914bffb6SAlexander V. Chernikov };
3088914bffb6SAlexander V. Chernikov
3089914bffb6SAlexander V. Chernikov struct fhash_cfg {
3090914bffb6SAlexander V. Chernikov struct fhashbhead *head;
3091914bffb6SAlexander V. Chernikov size_t size;
3092914bffb6SAlexander V. Chernikov size_t items;
3093914bffb6SAlexander V. Chernikov struct fhashentry4 fe4;
3094914bffb6SAlexander V. Chernikov struct fhashentry6 fe6;
3095914bffb6SAlexander V. Chernikov };
3096914bffb6SAlexander V. Chernikov
30973fe2ef91SAlexander V. Chernikov struct ta_buf_fhash {
30980bce0c23SAlexander V. Chernikov void *ent_ptr;
30990bce0c23SAlexander V. Chernikov struct fhashentry6 fe6;
31000bce0c23SAlexander V. Chernikov };
31010bce0c23SAlexander V. Chernikov
31029fe15d06SAlexander V. Chernikov static __inline int cmp_flow_ent(struct fhashentry *a,
31039fe15d06SAlexander V. Chernikov struct fhashentry *b, size_t sz);
31049fe15d06SAlexander V. Chernikov static __inline uint32_t hash_flow4(struct fhashentry4 *f, int hsize);
31059fe15d06SAlexander V. Chernikov static __inline uint32_t hash_flow6(struct fhashentry6 *f, int hsize);
31069fe15d06SAlexander V. Chernikov static uint32_t hash_flow_ent(struct fhashentry *ent, uint32_t size);
31079fe15d06SAlexander V. Chernikov static int ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
31089fe15d06SAlexander V. Chernikov uint32_t *val);
31099fe15d06SAlexander V. Chernikov static int ta_init_fhash(struct ip_fw_chain *ch, void **ta_state,
31109fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags);
31119fe15d06SAlexander V. Chernikov static void ta_destroy_fhash(void *ta_state, struct table_info *ti);
31129fe15d06SAlexander V. Chernikov static void ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti,
31139fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo);
31149fe15d06SAlexander V. Chernikov static int ta_dump_fhash_tentry(void *ta_state, struct table_info *ti,
31159fe15d06SAlexander V. Chernikov void *e, ipfw_obj_tentry *tent);
31169fe15d06SAlexander V. Chernikov static int tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent);
31179fe15d06SAlexander V. Chernikov static int ta_find_fhash_tentry(void *ta_state, struct table_info *ti,
31189fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent);
31199fe15d06SAlexander V. Chernikov static void ta_foreach_fhash(void *ta_state, struct table_info *ti,
31209fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg);
31219fe15d06SAlexander V. Chernikov static int ta_prepare_add_fhash(struct ip_fw_chain *ch,
31229fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf);
31239fe15d06SAlexander V. Chernikov static int ta_add_fhash(void *ta_state, struct table_info *ti,
31249fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
31259fe15d06SAlexander V. Chernikov static int ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
31269fe15d06SAlexander V. Chernikov void *ta_buf);
31279fe15d06SAlexander V. Chernikov static int ta_del_fhash(void *ta_state, struct table_info *ti,
31289fe15d06SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
31299fe15d06SAlexander V. Chernikov static void ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
31309fe15d06SAlexander V. Chernikov void *ta_buf);
31319fe15d06SAlexander V. Chernikov static int ta_need_modify_fhash(void *ta_state, struct table_info *ti,
31329fe15d06SAlexander V. Chernikov uint32_t count, uint64_t *pflags);
31339fe15d06SAlexander V. Chernikov static int ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags);
31349fe15d06SAlexander V. Chernikov static int ta_fill_mod_fhash(void *ta_state, struct table_info *ti,
31359fe15d06SAlexander V. Chernikov void *ta_buf, uint64_t *pflags);
31369fe15d06SAlexander V. Chernikov static void ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
31379fe15d06SAlexander V. Chernikov uint64_t pflags);
31389fe15d06SAlexander V. Chernikov static void ta_flush_mod_fhash(void *ta_buf);
31399fe15d06SAlexander V. Chernikov
3140914bffb6SAlexander V. Chernikov static __inline int
cmp_flow_ent(struct fhashentry * a,struct fhashentry * b,size_t sz)3141914bffb6SAlexander V. Chernikov cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz)
3142914bffb6SAlexander V. Chernikov {
3143914bffb6SAlexander V. Chernikov uint64_t *ka, *kb;
3144914bffb6SAlexander V. Chernikov
3145914bffb6SAlexander V. Chernikov ka = (uint64_t *)(&a->next + 1);
3146914bffb6SAlexander V. Chernikov kb = (uint64_t *)(&b->next + 1);
3147914bffb6SAlexander V. Chernikov
3148914bffb6SAlexander V. Chernikov if (*ka == *kb && (memcmp(a + 1, b + 1, sz) == 0))
3149914bffb6SAlexander V. Chernikov return (1);
3150914bffb6SAlexander V. Chernikov
3151914bffb6SAlexander V. Chernikov return (0);
3152914bffb6SAlexander V. Chernikov }
3153914bffb6SAlexander V. Chernikov
3154914bffb6SAlexander V. Chernikov static __inline uint32_t
hash_flow4(struct fhashentry4 * f,int hsize)3155914bffb6SAlexander V. Chernikov hash_flow4(struct fhashentry4 *f, int hsize)
3156914bffb6SAlexander V. Chernikov {
3157914bffb6SAlexander V. Chernikov uint32_t i;
3158914bffb6SAlexander V. Chernikov
3159914bffb6SAlexander V. Chernikov i = (f->dip.s_addr) ^ (f->sip.s_addr) ^ (f->e.dport) ^ (f->e.sport);
3160914bffb6SAlexander V. Chernikov
3161914bffb6SAlexander V. Chernikov return (i % (hsize - 1));
3162914bffb6SAlexander V. Chernikov }
3163914bffb6SAlexander V. Chernikov
3164914bffb6SAlexander V. Chernikov static __inline uint32_t
hash_flow6(struct fhashentry6 * f,int hsize)3165914bffb6SAlexander V. Chernikov hash_flow6(struct fhashentry6 *f, int hsize)
3166914bffb6SAlexander V. Chernikov {
3167914bffb6SAlexander V. Chernikov uint32_t i;
3168914bffb6SAlexander V. Chernikov
3169914bffb6SAlexander V. Chernikov i = (f->dip6.__u6_addr.__u6_addr32[2]) ^
3170914bffb6SAlexander V. Chernikov (f->dip6.__u6_addr.__u6_addr32[3]) ^
3171914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[2]) ^
3172914bffb6SAlexander V. Chernikov (f->sip6.__u6_addr.__u6_addr32[3]) ^
3173914bffb6SAlexander V. Chernikov (f->e.dport) ^ (f->e.sport);
3174914bffb6SAlexander V. Chernikov
3175914bffb6SAlexander V. Chernikov return (i % (hsize - 1));
3176914bffb6SAlexander V. Chernikov }
3177914bffb6SAlexander V. Chernikov
3178914bffb6SAlexander V. Chernikov static uint32_t
hash_flow_ent(struct fhashentry * ent,uint32_t size)3179914bffb6SAlexander V. Chernikov hash_flow_ent(struct fhashentry *ent, uint32_t size)
3180914bffb6SAlexander V. Chernikov {
3181914bffb6SAlexander V. Chernikov uint32_t hash;
3182914bffb6SAlexander V. Chernikov
3183914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) {
3184914bffb6SAlexander V. Chernikov hash = hash_flow4((struct fhashentry4 *)ent, size);
3185914bffb6SAlexander V. Chernikov } else {
3186914bffb6SAlexander V. Chernikov hash = hash_flow6((struct fhashentry6 *)ent, size);
3187914bffb6SAlexander V. Chernikov }
3188914bffb6SAlexander V. Chernikov
3189914bffb6SAlexander V. Chernikov return (hash);
3190914bffb6SAlexander V. Chernikov }
3191914bffb6SAlexander V. Chernikov
3192914bffb6SAlexander V. Chernikov static int
ta_lookup_fhash(struct table_info * ti,void * key,uint32_t keylen,uint32_t * val)3193914bffb6SAlexander V. Chernikov ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
3194914bffb6SAlexander V. Chernikov uint32_t *val)
3195914bffb6SAlexander V. Chernikov {
3196914bffb6SAlexander V. Chernikov struct fhashbhead *head;
3197914bffb6SAlexander V. Chernikov struct fhashentry *ent;
3198914bffb6SAlexander V. Chernikov struct fhashentry4 *m4;
3199914bffb6SAlexander V. Chernikov struct ipfw_flow_id *id;
3200*4a77657cSAndrey V. Elsukov uint32_t hash, hsize;
3201914bffb6SAlexander V. Chernikov
3202914bffb6SAlexander V. Chernikov id = (struct ipfw_flow_id *)key;
3203914bffb6SAlexander V. Chernikov head = (struct fhashbhead *)ti->state;
3204914bffb6SAlexander V. Chernikov hsize = ti->data;
3205914bffb6SAlexander V. Chernikov m4 = (struct fhashentry4 *)ti->xstate;
3206914bffb6SAlexander V. Chernikov
3207914bffb6SAlexander V. Chernikov if (id->addr_type == 4) {
3208914bffb6SAlexander V. Chernikov struct fhashentry4 f;
3209914bffb6SAlexander V. Chernikov
3210914bffb6SAlexander V. Chernikov /* Copy hash mask */
3211914bffb6SAlexander V. Chernikov f = *m4;
3212914bffb6SAlexander V. Chernikov
3213914bffb6SAlexander V. Chernikov f.dip.s_addr &= id->dst_ip;
3214914bffb6SAlexander V. Chernikov f.sip.s_addr &= id->src_ip;
3215914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port;
3216914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port;
3217914bffb6SAlexander V. Chernikov f.e.proto &= id->proto;
3218914bffb6SAlexander V. Chernikov hash = hash_flow4(&f, hsize);
3219914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) {
3220914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) {
3221914bffb6SAlexander V. Chernikov *val = ent->value;
3222914bffb6SAlexander V. Chernikov return (1);
3223914bffb6SAlexander V. Chernikov }
3224914bffb6SAlexander V. Chernikov }
3225914bffb6SAlexander V. Chernikov } else if (id->addr_type == 6) {
3226914bffb6SAlexander V. Chernikov struct fhashentry6 f;
3227914bffb6SAlexander V. Chernikov uint64_t *fp, *idp;
3228914bffb6SAlexander V. Chernikov
3229914bffb6SAlexander V. Chernikov /* Copy hash mask */
3230914bffb6SAlexander V. Chernikov f = *((struct fhashentry6 *)(m4 + 1));
3231914bffb6SAlexander V. Chernikov
3232914bffb6SAlexander V. Chernikov /* Handle lack of __u6_addr.__u6_addr64 */
3233914bffb6SAlexander V. Chernikov fp = (uint64_t *)&f.dip6;
3234914bffb6SAlexander V. Chernikov idp = (uint64_t *)&id->dst_ip6;
3235914bffb6SAlexander V. Chernikov /* src IPv6 is stored after dst IPv6 */
3236914bffb6SAlexander V. Chernikov *fp++ &= *idp++;
3237914bffb6SAlexander V. Chernikov *fp++ &= *idp++;
3238914bffb6SAlexander V. Chernikov *fp++ &= *idp++;
3239914bffb6SAlexander V. Chernikov *fp &= *idp;
3240914bffb6SAlexander V. Chernikov f.e.dport &= id->dst_port;
3241914bffb6SAlexander V. Chernikov f.e.sport &= id->src_port;
3242914bffb6SAlexander V. Chernikov f.e.proto &= id->proto;
3243914bffb6SAlexander V. Chernikov hash = hash_flow6(&f, hsize);
3244914bffb6SAlexander V. Chernikov SLIST_FOREACH(ent, &head[hash], next) {
3245914bffb6SAlexander V. Chernikov if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) {
3246914bffb6SAlexander V. Chernikov *val = ent->value;
3247914bffb6SAlexander V. Chernikov return (1);
3248914bffb6SAlexander V. Chernikov }
3249914bffb6SAlexander V. Chernikov }
3250914bffb6SAlexander V. Chernikov }
3251914bffb6SAlexander V. Chernikov
3252914bffb6SAlexander V. Chernikov return (0);
3253914bffb6SAlexander V. Chernikov }
3254914bffb6SAlexander V. Chernikov
3255914bffb6SAlexander V. Chernikov /*
3256914bffb6SAlexander V. Chernikov * New table.
3257914bffb6SAlexander V. Chernikov */
3258914bffb6SAlexander V. Chernikov static int
ta_init_fhash(struct ip_fw_chain * ch,void ** ta_state,struct table_info * ti,char * data,uint8_t tflags)3259914bffb6SAlexander V. Chernikov ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
3260914bffb6SAlexander V. Chernikov char *data, uint8_t tflags)
3261914bffb6SAlexander V. Chernikov {
3262914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg;
3263914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4;
3264914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6;
3265d821d364SPedro F. Giffuni u_int i;
3266914bffb6SAlexander V. Chernikov
3267914bffb6SAlexander V. Chernikov cfg = malloc(sizeof(struct fhash_cfg), M_IPFW, M_WAITOK | M_ZERO);
3268914bffb6SAlexander V. Chernikov
3269914bffb6SAlexander V. Chernikov cfg->size = 512;
3270914bffb6SAlexander V. Chernikov
3271914bffb6SAlexander V. Chernikov cfg->head = malloc(sizeof(struct fhashbhead) * cfg->size, M_IPFW,
3272914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO);
3273914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++)
3274914bffb6SAlexander V. Chernikov SLIST_INIT(&cfg->head[i]);
3275914bffb6SAlexander V. Chernikov
3276914bffb6SAlexander V. Chernikov /* Fill in fe masks based on @tflags */
3277914bffb6SAlexander V. Chernikov fe4 = &cfg->fe4;
3278914bffb6SAlexander V. Chernikov fe6 = &cfg->fe6;
3279914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCIP) {
3280914bffb6SAlexander V. Chernikov memset(&fe4->sip, 0xFF, sizeof(fe4->sip));
3281914bffb6SAlexander V. Chernikov memset(&fe6->sip6, 0xFF, sizeof(fe6->sip6));
3282914bffb6SAlexander V. Chernikov }
3283914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTIP) {
3284914bffb6SAlexander V. Chernikov memset(&fe4->dip, 0xFF, sizeof(fe4->dip));
3285914bffb6SAlexander V. Chernikov memset(&fe6->dip6, 0xFF, sizeof(fe6->dip6));
3286914bffb6SAlexander V. Chernikov }
3287914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_SRCPORT) {
3288914bffb6SAlexander V. Chernikov memset(&fe4->e.sport, 0xFF, sizeof(fe4->e.sport));
3289914bffb6SAlexander V. Chernikov memset(&fe6->e.sport, 0xFF, sizeof(fe6->e.sport));
3290914bffb6SAlexander V. Chernikov }
3291914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_DSTPORT) {
3292914bffb6SAlexander V. Chernikov memset(&fe4->e.dport, 0xFF, sizeof(fe4->e.dport));
3293914bffb6SAlexander V. Chernikov memset(&fe6->e.dport, 0xFF, sizeof(fe6->e.dport));
3294914bffb6SAlexander V. Chernikov }
3295914bffb6SAlexander V. Chernikov if (tflags & IPFW_TFFLAG_PROTO) {
3296914bffb6SAlexander V. Chernikov memset(&fe4->e.proto, 0xFF, sizeof(fe4->e.proto));
3297914bffb6SAlexander V. Chernikov memset(&fe6->e.proto, 0xFF, sizeof(fe6->e.proto));
3298914bffb6SAlexander V. Chernikov }
3299914bffb6SAlexander V. Chernikov
3300914bffb6SAlexander V. Chernikov fe4->e.af = AF_INET;
3301914bffb6SAlexander V. Chernikov fe6->e.af = AF_INET6;
3302914bffb6SAlexander V. Chernikov
3303914bffb6SAlexander V. Chernikov *ta_state = cfg;
3304914bffb6SAlexander V. Chernikov ti->state = cfg->head;
3305914bffb6SAlexander V. Chernikov ti->xstate = &cfg->fe4;
3306914bffb6SAlexander V. Chernikov ti->data = cfg->size;
3307914bffb6SAlexander V. Chernikov ti->lookup = ta_lookup_fhash;
3308914bffb6SAlexander V. Chernikov
3309914bffb6SAlexander V. Chernikov return (0);
3310914bffb6SAlexander V. Chernikov }
3311914bffb6SAlexander V. Chernikov
3312914bffb6SAlexander V. Chernikov static void
ta_destroy_fhash(void * ta_state,struct table_info * ti)3313914bffb6SAlexander V. Chernikov ta_destroy_fhash(void *ta_state, struct table_info *ti)
3314914bffb6SAlexander V. Chernikov {
3315914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg;
3316914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next;
3317914bffb6SAlexander V. Chernikov int i;
3318914bffb6SAlexander V. Chernikov
3319914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state;
3320914bffb6SAlexander V. Chernikov
3321914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++)
3322914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
3323914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL);
3324914bffb6SAlexander V. Chernikov
3325914bffb6SAlexander V. Chernikov free(cfg->head, M_IPFW);
3326914bffb6SAlexander V. Chernikov free(cfg, M_IPFW);
3327914bffb6SAlexander V. Chernikov }
3328914bffb6SAlexander V. Chernikov
33295f379342SAlexander V. Chernikov /*
33305f379342SAlexander V. Chernikov * Provide algo-specific table info
33315f379342SAlexander V. Chernikov */
33325f379342SAlexander V. Chernikov static void
ta_dump_fhash_tinfo(void * ta_state,struct table_info * ti,ipfw_ta_tinfo * tinfo)33335f379342SAlexander V. Chernikov ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
33345f379342SAlexander V. Chernikov {
33355f379342SAlexander V. Chernikov struct fhash_cfg *cfg;
33365f379342SAlexander V. Chernikov
33375f379342SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state;
33385f379342SAlexander V. Chernikov
33395f379342SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFITEM;
33405f379342SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_HASH;
33415f379342SAlexander V. Chernikov tinfo->size4 = cfg->size;
33425f379342SAlexander V. Chernikov tinfo->count4 = cfg->items;
33435f379342SAlexander V. Chernikov tinfo->itemsize4 = sizeof(struct fhashentry4);
33445f379342SAlexander V. Chernikov tinfo->itemsize6 = sizeof(struct fhashentry6);
33455f379342SAlexander V. Chernikov }
33465f379342SAlexander V. Chernikov
3347914bffb6SAlexander V. Chernikov static int
ta_dump_fhash_tentry(void * ta_state,struct table_info * ti,void * e,ipfw_obj_tentry * tent)3348914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e,
3349914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent)
3350914bffb6SAlexander V. Chernikov {
3351914bffb6SAlexander V. Chernikov struct fhashentry *ent;
3352914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4;
33539fe15d06SAlexander V. Chernikov #ifdef INET6
3354914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6;
33559fe15d06SAlexander V. Chernikov #endif
3356914bffb6SAlexander V. Chernikov struct tflow_entry *tfe;
3357914bffb6SAlexander V. Chernikov
3358914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)e;
3359914bffb6SAlexander V. Chernikov tfe = &tent->k.flow;
3360914bffb6SAlexander V. Chernikov
3361914bffb6SAlexander V. Chernikov tfe->af = ent->af;
3362914bffb6SAlexander V. Chernikov tfe->proto = ent->proto;
3363914bffb6SAlexander V. Chernikov tfe->dport = htons(ent->dport);
3364914bffb6SAlexander V. Chernikov tfe->sport = htons(ent->sport);
33650cba2b28SAlexander V. Chernikov tent->v.kidx = ent->value;
3366914bffb6SAlexander V. Chernikov tent->subtype = ent->af;
3367914bffb6SAlexander V. Chernikov
3368914bffb6SAlexander V. Chernikov if (ent->af == AF_INET) {
3369914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent;
3370914bffb6SAlexander V. Chernikov tfe->a.a4.sip.s_addr = htonl(fe4->sip.s_addr);
3371914bffb6SAlexander V. Chernikov tfe->a.a4.dip.s_addr = htonl(fe4->dip.s_addr);
3372914bffb6SAlexander V. Chernikov tent->masklen = 32;
3373914bffb6SAlexander V. Chernikov #ifdef INET6
3374914bffb6SAlexander V. Chernikov } else {
3375914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent;
3376914bffb6SAlexander V. Chernikov tfe->a.a6.sip6 = fe6->sip6;
3377914bffb6SAlexander V. Chernikov tfe->a.a6.dip6 = fe6->dip6;
3378914bffb6SAlexander V. Chernikov tent->masklen = 128;
3379914bffb6SAlexander V. Chernikov #endif
3380914bffb6SAlexander V. Chernikov }
3381914bffb6SAlexander V. Chernikov
3382914bffb6SAlexander V. Chernikov return (0);
3383914bffb6SAlexander V. Chernikov }
3384914bffb6SAlexander V. Chernikov
3385914bffb6SAlexander V. Chernikov static int
tei_to_fhash_ent(struct tentry_info * tei,struct fhashentry * ent)3386914bffb6SAlexander V. Chernikov tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent)
3387914bffb6SAlexander V. Chernikov {
3388d699ee2dSAlexander V. Chernikov #ifdef INET
3389914bffb6SAlexander V. Chernikov struct fhashentry4 *fe4;
3390d699ee2dSAlexander V. Chernikov #endif
3391d699ee2dSAlexander V. Chernikov #ifdef INET6
3392914bffb6SAlexander V. Chernikov struct fhashentry6 *fe6;
3393d699ee2dSAlexander V. Chernikov #endif
3394914bffb6SAlexander V. Chernikov struct tflow_entry *tfe;
3395914bffb6SAlexander V. Chernikov
3396914bffb6SAlexander V. Chernikov tfe = (struct tflow_entry *)tei->paddr;
3397914bffb6SAlexander V. Chernikov
3398914bffb6SAlexander V. Chernikov ent->af = tei->subtype;
3399914bffb6SAlexander V. Chernikov ent->proto = tfe->proto;
3400914bffb6SAlexander V. Chernikov ent->dport = ntohs(tfe->dport);
3401914bffb6SAlexander V. Chernikov ent->sport = ntohs(tfe->sport);
3402914bffb6SAlexander V. Chernikov
3403914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET) {
3404914bffb6SAlexander V. Chernikov #ifdef INET
3405914bffb6SAlexander V. Chernikov fe4 = (struct fhashentry4 *)ent;
3406914bffb6SAlexander V. Chernikov fe4->sip.s_addr = ntohl(tfe->a.a4.sip.s_addr);
3407914bffb6SAlexander V. Chernikov fe4->dip.s_addr = ntohl(tfe->a.a4.dip.s_addr);
3408914bffb6SAlexander V. Chernikov #endif
3409914bffb6SAlexander V. Chernikov #ifdef INET6
3410914bffb6SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) {
3411914bffb6SAlexander V. Chernikov fe6 = (struct fhashentry6 *)ent;
3412914bffb6SAlexander V. Chernikov fe6->sip6 = tfe->a.a6.sip6;
3413914bffb6SAlexander V. Chernikov fe6->dip6 = tfe->a.a6.dip6;
3414914bffb6SAlexander V. Chernikov #endif
3415914bffb6SAlexander V. Chernikov } else {
3416914bffb6SAlexander V. Chernikov /* Unknown CIDR type */
3417914bffb6SAlexander V. Chernikov return (EINVAL);
3418914bffb6SAlexander V. Chernikov }
3419914bffb6SAlexander V. Chernikov
3420914bffb6SAlexander V. Chernikov return (0);
3421914bffb6SAlexander V. Chernikov }
3422914bffb6SAlexander V. Chernikov
3423914bffb6SAlexander V. Chernikov static int
ta_find_fhash_tentry(void * ta_state,struct table_info * ti,ipfw_obj_tentry * tent)3424914bffb6SAlexander V. Chernikov ta_find_fhash_tentry(void *ta_state, struct table_info *ti,
3425914bffb6SAlexander V. Chernikov ipfw_obj_tentry *tent)
3426914bffb6SAlexander V. Chernikov {
3427914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg;
3428914bffb6SAlexander V. Chernikov struct fhashbhead *head;
3429914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp;
3430914bffb6SAlexander V. Chernikov struct fhashentry6 fe6;
3431914bffb6SAlexander V. Chernikov struct tentry_info tei;
3432914bffb6SAlexander V. Chernikov int error;
3433914bffb6SAlexander V. Chernikov uint32_t hash;
3434914bffb6SAlexander V. Chernikov size_t sz;
3435914bffb6SAlexander V. Chernikov
3436914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state;
3437914bffb6SAlexander V. Chernikov
3438914bffb6SAlexander V. Chernikov ent = &fe6.e;
3439914bffb6SAlexander V. Chernikov
3440914bffb6SAlexander V. Chernikov memset(&fe6, 0, sizeof(fe6));
3441914bffb6SAlexander V. Chernikov memset(&tei, 0, sizeof(tei));
3442914bffb6SAlexander V. Chernikov
3443914bffb6SAlexander V. Chernikov tei.paddr = &tent->k.flow;
3444914bffb6SAlexander V. Chernikov tei.subtype = tent->subtype;
3445914bffb6SAlexander V. Chernikov
3446914bffb6SAlexander V. Chernikov if ((error = tei_to_fhash_ent(&tei, ent)) != 0)
3447914bffb6SAlexander V. Chernikov return (error);
3448914bffb6SAlexander V. Chernikov
3449914bffb6SAlexander V. Chernikov head = cfg->head;
3450914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size);
3451914bffb6SAlexander V. Chernikov
3452914bffb6SAlexander V. Chernikov if (tei.subtype == AF_INET)
3453914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr);
3454914bffb6SAlexander V. Chernikov else
3455914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr);
3456914bffb6SAlexander V. Chernikov
3457914bffb6SAlexander V. Chernikov /* Check for existence */
3458914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) {
3459914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) {
3460914bffb6SAlexander V. Chernikov ta_dump_fhash_tentry(ta_state, ti, tmp, tent);
3461914bffb6SAlexander V. Chernikov return (0);
3462914bffb6SAlexander V. Chernikov }
3463914bffb6SAlexander V. Chernikov }
3464914bffb6SAlexander V. Chernikov
3465914bffb6SAlexander V. Chernikov return (ENOENT);
3466914bffb6SAlexander V. Chernikov }
3467914bffb6SAlexander V. Chernikov
3468914bffb6SAlexander V. Chernikov static void
ta_foreach_fhash(void * ta_state,struct table_info * ti,ta_foreach_f * f,void * arg)3469914bffb6SAlexander V. Chernikov ta_foreach_fhash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
3470914bffb6SAlexander V. Chernikov void *arg)
3471914bffb6SAlexander V. Chernikov {
3472914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg;
3473914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next;
3474914bffb6SAlexander V. Chernikov int i;
3475914bffb6SAlexander V. Chernikov
3476914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state;
3477914bffb6SAlexander V. Chernikov
3478914bffb6SAlexander V. Chernikov for (i = 0; i < cfg->size; i++)
3479914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
3480914bffb6SAlexander V. Chernikov f(ent, arg);
3481914bffb6SAlexander V. Chernikov }
3482914bffb6SAlexander V. Chernikov
3483914bffb6SAlexander V. Chernikov static int
ta_prepare_add_fhash(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)3484914bffb6SAlexander V. Chernikov ta_prepare_add_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
3485914bffb6SAlexander V. Chernikov void *ta_buf)
3486914bffb6SAlexander V. Chernikov {
3487914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb;
3488914bffb6SAlexander V. Chernikov struct fhashentry *ent;
3489914bffb6SAlexander V. Chernikov size_t sz;
3490914bffb6SAlexander V. Chernikov int error;
3491914bffb6SAlexander V. Chernikov
3492914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf;
3493914bffb6SAlexander V. Chernikov
3494914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET)
3495914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry4);
3496914bffb6SAlexander V. Chernikov else if (tei->subtype == AF_INET6)
3497914bffb6SAlexander V. Chernikov sz = sizeof(struct fhashentry6);
3498914bffb6SAlexander V. Chernikov else
3499914bffb6SAlexander V. Chernikov return (EINVAL);
3500914bffb6SAlexander V. Chernikov
3501914bffb6SAlexander V. Chernikov ent = malloc(sz, M_IPFW_TBL, M_WAITOK | M_ZERO);
3502914bffb6SAlexander V. Chernikov
3503914bffb6SAlexander V. Chernikov error = tei_to_fhash_ent(tei, ent);
3504914bffb6SAlexander V. Chernikov if (error != 0) {
3505914bffb6SAlexander V. Chernikov free(ent, M_IPFW_TBL);
3506914bffb6SAlexander V. Chernikov return (error);
3507914bffb6SAlexander V. Chernikov }
3508914bffb6SAlexander V. Chernikov tb->ent_ptr = ent;
3509914bffb6SAlexander V. Chernikov
3510914bffb6SAlexander V. Chernikov return (0);
3511914bffb6SAlexander V. Chernikov }
3512914bffb6SAlexander V. Chernikov
3513914bffb6SAlexander V. Chernikov static int
ta_add_fhash(void * ta_state,struct table_info * ti,struct tentry_info * tei,void * ta_buf,uint32_t * pnum)3514914bffb6SAlexander V. Chernikov ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
3515b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum)
3516914bffb6SAlexander V. Chernikov {
3517914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg;
3518914bffb6SAlexander V. Chernikov struct fhashbhead *head;
3519914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp;
3520914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb;
3521914bffb6SAlexander V. Chernikov int exists;
3522648e8380SAlexander V. Chernikov uint32_t hash, value;
3523914bffb6SAlexander V. Chernikov size_t sz;
3524914bffb6SAlexander V. Chernikov
3525914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state;
3526914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf;
3527914bffb6SAlexander V. Chernikov ent = (struct fhashentry *)tb->ent_ptr;
3528914bffb6SAlexander V. Chernikov exists = 0;
3529914bffb6SAlexander V. Chernikov
353013263632SAlexander V. Chernikov /* Read current value from @tei */
353113263632SAlexander V. Chernikov ent->value = tei->value;
353213263632SAlexander V. Chernikov
3533914bffb6SAlexander V. Chernikov head = cfg->head;
3534914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size);
3535914bffb6SAlexander V. Chernikov
3536914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET)
3537914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr);
3538914bffb6SAlexander V. Chernikov else
3539914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr);
3540914bffb6SAlexander V. Chernikov
3541914bffb6SAlexander V. Chernikov /* Check for existence */
3542914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) {
3543914bffb6SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) != 0) {
3544914bffb6SAlexander V. Chernikov exists = 1;
3545914bffb6SAlexander V. Chernikov break;
3546914bffb6SAlexander V. Chernikov }
3547914bffb6SAlexander V. Chernikov }
3548914bffb6SAlexander V. Chernikov
3549914bffb6SAlexander V. Chernikov if (exists == 1) {
3550914bffb6SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
3551914bffb6SAlexander V. Chernikov return (EEXIST);
3552914bffb6SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */
3553648e8380SAlexander V. Chernikov /* Exchange values between tmp and @tei */
3554648e8380SAlexander V. Chernikov value = tmp->value;
3555914bffb6SAlexander V. Chernikov tmp->value = tei->value;
3556648e8380SAlexander V. Chernikov tei->value = value;
3557914bffb6SAlexander V. Chernikov /* Indicate that update has happened instead of addition */
3558914bffb6SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED;
3559914bffb6SAlexander V. Chernikov *pnum = 0;
3560914bffb6SAlexander V. Chernikov } else {
35614c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
35624c0c07a5SAlexander V. Chernikov return (EFBIG);
35634c0c07a5SAlexander V. Chernikov
3564914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&head[hash], ent, next);
3565914bffb6SAlexander V. Chernikov tb->ent_ptr = NULL;
3566914bffb6SAlexander V. Chernikov *pnum = 1;
3567914bffb6SAlexander V. Chernikov
3568914bffb6SAlexander V. Chernikov /* Update counters and check if we need to grow hash */
3569914bffb6SAlexander V. Chernikov cfg->items++;
3570914bffb6SAlexander V. Chernikov }
3571914bffb6SAlexander V. Chernikov
3572914bffb6SAlexander V. Chernikov return (0);
3573914bffb6SAlexander V. Chernikov }
3574914bffb6SAlexander V. Chernikov
3575914bffb6SAlexander V. Chernikov static int
ta_prepare_del_fhash(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)3576914bffb6SAlexander V. Chernikov ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
3577914bffb6SAlexander V. Chernikov void *ta_buf)
3578914bffb6SAlexander V. Chernikov {
3579914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb;
3580914bffb6SAlexander V. Chernikov
3581914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf;
3582914bffb6SAlexander V. Chernikov
3583914bffb6SAlexander V. Chernikov return (tei_to_fhash_ent(tei, &tb->fe6.e));
3584914bffb6SAlexander V. Chernikov }
3585914bffb6SAlexander V. Chernikov
3586914bffb6SAlexander V. Chernikov static int
ta_del_fhash(void * ta_state,struct table_info * ti,struct tentry_info * tei,void * ta_buf,uint32_t * pnum)3587914bffb6SAlexander V. Chernikov ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
3588b6ee846eSAlexander V. Chernikov void *ta_buf, uint32_t *pnum)
3589914bffb6SAlexander V. Chernikov {
3590914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg;
3591914bffb6SAlexander V. Chernikov struct fhashbhead *head;
3592914bffb6SAlexander V. Chernikov struct fhashentry *ent, *tmp;
3593914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb;
3594914bffb6SAlexander V. Chernikov uint32_t hash;
3595914bffb6SAlexander V. Chernikov size_t sz;
3596914bffb6SAlexander V. Chernikov
3597914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state;
3598914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf;
3599914bffb6SAlexander V. Chernikov ent = &tb->fe6.e;
3600914bffb6SAlexander V. Chernikov
3601914bffb6SAlexander V. Chernikov head = cfg->head;
3602914bffb6SAlexander V. Chernikov hash = hash_flow_ent(ent, cfg->size);
3603914bffb6SAlexander V. Chernikov
3604914bffb6SAlexander V. Chernikov if (tei->subtype == AF_INET)
3605914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in_addr);
3606914bffb6SAlexander V. Chernikov else
3607914bffb6SAlexander V. Chernikov sz = 2 * sizeof(struct in6_addr);
3608914bffb6SAlexander V. Chernikov
3609914bffb6SAlexander V. Chernikov /* Check for existence */
3610914bffb6SAlexander V. Chernikov SLIST_FOREACH(tmp, &head[hash], next) {
3611648e8380SAlexander V. Chernikov if (cmp_flow_ent(tmp, ent, sz) == 0)
3612648e8380SAlexander V. Chernikov continue;
3613648e8380SAlexander V. Chernikov
3614914bffb6SAlexander V. Chernikov SLIST_REMOVE(&head[hash], tmp, fhashentry, next);
3615648e8380SAlexander V. Chernikov tei->value = tmp->value;
3616914bffb6SAlexander V. Chernikov *pnum = 1;
3617914bffb6SAlexander V. Chernikov cfg->items--;
3618648e8380SAlexander V. Chernikov tb->ent_ptr = tmp;
3619914bffb6SAlexander V. Chernikov return (0);
3620914bffb6SAlexander V. Chernikov }
3621914bffb6SAlexander V. Chernikov
3622914bffb6SAlexander V. Chernikov return (ENOENT);
3623914bffb6SAlexander V. Chernikov }
3624914bffb6SAlexander V. Chernikov
3625914bffb6SAlexander V. Chernikov static void
ta_flush_fhash_entry(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)3626914bffb6SAlexander V. Chernikov ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
3627914bffb6SAlexander V. Chernikov void *ta_buf)
3628914bffb6SAlexander V. Chernikov {
3629914bffb6SAlexander V. Chernikov struct ta_buf_fhash *tb;
3630914bffb6SAlexander V. Chernikov
3631914bffb6SAlexander V. Chernikov tb = (struct ta_buf_fhash *)ta_buf;
3632914bffb6SAlexander V. Chernikov
3633914bffb6SAlexander V. Chernikov if (tb->ent_ptr != NULL)
3634914bffb6SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL);
3635914bffb6SAlexander V. Chernikov }
3636914bffb6SAlexander V. Chernikov
3637914bffb6SAlexander V. Chernikov /*
3638914bffb6SAlexander V. Chernikov * Hash growing callbacks.
3639914bffb6SAlexander V. Chernikov */
3640914bffb6SAlexander V. Chernikov
3641b6ee846eSAlexander V. Chernikov static int
ta_need_modify_fhash(void * ta_state,struct table_info * ti,uint32_t count,uint64_t * pflags)3642301290bcSAlexander V. Chernikov ta_need_modify_fhash(void *ta_state, struct table_info *ti, uint32_t count,
3643b6ee846eSAlexander V. Chernikov uint64_t *pflags)
3644b6ee846eSAlexander V. Chernikov {
3645b6ee846eSAlexander V. Chernikov struct fhash_cfg *cfg;
3646b6ee846eSAlexander V. Chernikov
3647b6ee846eSAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state;
3648b6ee846eSAlexander V. Chernikov
3649b6ee846eSAlexander V. Chernikov if (cfg->items > cfg->size && cfg->size < 65536) {
3650b6ee846eSAlexander V. Chernikov *pflags = cfg->size * 2;
3651301290bcSAlexander V. Chernikov return (1);
3652b6ee846eSAlexander V. Chernikov }
3653b6ee846eSAlexander V. Chernikov
3654301290bcSAlexander V. Chernikov return (0);
3655b6ee846eSAlexander V. Chernikov }
3656b6ee846eSAlexander V. Chernikov
3657914bffb6SAlexander V. Chernikov /*
3658914bffb6SAlexander V. Chernikov * Allocate new, larger fhash.
3659914bffb6SAlexander V. Chernikov */
3660914bffb6SAlexander V. Chernikov static int
ta_prepare_mod_fhash(void * ta_buf,uint64_t * pflags)3661914bffb6SAlexander V. Chernikov ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags)
3662914bffb6SAlexander V. Chernikov {
3663914bffb6SAlexander V. Chernikov struct mod_item *mi;
3664914bffb6SAlexander V. Chernikov struct fhashbhead *head;
3665d821d364SPedro F. Giffuni u_int i;
3666914bffb6SAlexander V. Chernikov
3667914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf;
3668914bffb6SAlexander V. Chernikov
3669914bffb6SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_item));
3670914bffb6SAlexander V. Chernikov mi->size = *pflags;
3671914bffb6SAlexander V. Chernikov head = malloc(sizeof(struct fhashbhead) * mi->size, M_IPFW,
3672914bffb6SAlexander V. Chernikov M_WAITOK | M_ZERO);
3673914bffb6SAlexander V. Chernikov for (i = 0; i < mi->size; i++)
3674914bffb6SAlexander V. Chernikov SLIST_INIT(&head[i]);
3675914bffb6SAlexander V. Chernikov
3676914bffb6SAlexander V. Chernikov mi->main_ptr = head;
3677914bffb6SAlexander V. Chernikov
3678914bffb6SAlexander V. Chernikov return (0);
3679914bffb6SAlexander V. Chernikov }
3680914bffb6SAlexander V. Chernikov
3681914bffb6SAlexander V. Chernikov /*
3682914bffb6SAlexander V. Chernikov * Copy data from old runtime array to new one.
3683914bffb6SAlexander V. Chernikov */
3684914bffb6SAlexander V. Chernikov static int
ta_fill_mod_fhash(void * ta_state,struct table_info * ti,void * ta_buf,uint64_t * pflags)3685914bffb6SAlexander V. Chernikov ta_fill_mod_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3686914bffb6SAlexander V. Chernikov uint64_t *pflags)
3687914bffb6SAlexander V. Chernikov {
3688914bffb6SAlexander V. Chernikov
3689914bffb6SAlexander V. Chernikov /* In is not possible to do rehash if we're not holidng WLOCK. */
3690914bffb6SAlexander V. Chernikov return (0);
3691914bffb6SAlexander V. Chernikov }
3692914bffb6SAlexander V. Chernikov
3693914bffb6SAlexander V. Chernikov /*
3694914bffb6SAlexander V. Chernikov * Switch old & new arrays.
3695914bffb6SAlexander V. Chernikov */
3696301290bcSAlexander V. Chernikov static void
ta_modify_fhash(void * ta_state,struct table_info * ti,void * ta_buf,uint64_t pflags)3697914bffb6SAlexander V. Chernikov ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3698914bffb6SAlexander V. Chernikov uint64_t pflags)
3699914bffb6SAlexander V. Chernikov {
3700914bffb6SAlexander V. Chernikov struct mod_item *mi;
3701914bffb6SAlexander V. Chernikov struct fhash_cfg *cfg;
3702914bffb6SAlexander V. Chernikov struct fhashbhead *old_head, *new_head;
3703914bffb6SAlexander V. Chernikov struct fhashentry *ent, *ent_next;
3704914bffb6SAlexander V. Chernikov int i;
3705914bffb6SAlexander V. Chernikov uint32_t nhash;
3706914bffb6SAlexander V. Chernikov size_t old_size;
3707914bffb6SAlexander V. Chernikov
3708914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf;
3709914bffb6SAlexander V. Chernikov cfg = (struct fhash_cfg *)ta_state;
3710914bffb6SAlexander V. Chernikov
3711914bffb6SAlexander V. Chernikov old_size = cfg->size;
3712914bffb6SAlexander V. Chernikov old_head = ti->state;
3713914bffb6SAlexander V. Chernikov
3714914bffb6SAlexander V. Chernikov new_head = (struct fhashbhead *)mi->main_ptr;
3715914bffb6SAlexander V. Chernikov for (i = 0; i < old_size; i++) {
3716914bffb6SAlexander V. Chernikov SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
3717914bffb6SAlexander V. Chernikov nhash = hash_flow_ent(ent, mi->size);
3718914bffb6SAlexander V. Chernikov SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
3719914bffb6SAlexander V. Chernikov }
3720914bffb6SAlexander V. Chernikov }
3721914bffb6SAlexander V. Chernikov
3722914bffb6SAlexander V. Chernikov ti->state = new_head;
3723914bffb6SAlexander V. Chernikov ti->data = mi->size;
3724914bffb6SAlexander V. Chernikov cfg->head = new_head;
3725914bffb6SAlexander V. Chernikov cfg->size = mi->size;
3726914bffb6SAlexander V. Chernikov
3727914bffb6SAlexander V. Chernikov mi->main_ptr = old_head;
3728914bffb6SAlexander V. Chernikov }
3729914bffb6SAlexander V. Chernikov
3730914bffb6SAlexander V. Chernikov /*
3731914bffb6SAlexander V. Chernikov * Free unneded array.
3732914bffb6SAlexander V. Chernikov */
3733914bffb6SAlexander V. Chernikov static void
ta_flush_mod_fhash(void * ta_buf)3734914bffb6SAlexander V. Chernikov ta_flush_mod_fhash(void *ta_buf)
3735914bffb6SAlexander V. Chernikov {
3736914bffb6SAlexander V. Chernikov struct mod_item *mi;
3737914bffb6SAlexander V. Chernikov
3738914bffb6SAlexander V. Chernikov mi = (struct mod_item *)ta_buf;
3739914bffb6SAlexander V. Chernikov if (mi->main_ptr != NULL)
3740914bffb6SAlexander V. Chernikov free(mi->main_ptr, M_IPFW);
3741914bffb6SAlexander V. Chernikov }
3742914bffb6SAlexander V. Chernikov
3743914bffb6SAlexander V. Chernikov struct table_algo flow_hash = {
3744914bffb6SAlexander V. Chernikov .name = "flow:hash",
3745914bffb6SAlexander V. Chernikov .type = IPFW_TABLE_FLOW,
374657a1cf95SAlexander V. Chernikov .flags = TA_FLAG_DEFAULT,
374757a1cf95SAlexander V. Chernikov .ta_buf_size = sizeof(struct ta_buf_fhash),
3748914bffb6SAlexander V. Chernikov .init = ta_init_fhash,
3749914bffb6SAlexander V. Chernikov .destroy = ta_destroy_fhash,
3750914bffb6SAlexander V. Chernikov .prepare_add = ta_prepare_add_fhash,
3751914bffb6SAlexander V. Chernikov .prepare_del = ta_prepare_del_fhash,
3752914bffb6SAlexander V. Chernikov .add = ta_add_fhash,
3753914bffb6SAlexander V. Chernikov .del = ta_del_fhash,
3754914bffb6SAlexander V. Chernikov .flush_entry = ta_flush_fhash_entry,
3755914bffb6SAlexander V. Chernikov .foreach = ta_foreach_fhash,
3756914bffb6SAlexander V. Chernikov .dump_tentry = ta_dump_fhash_tentry,
3757914bffb6SAlexander V. Chernikov .find_tentry = ta_find_fhash_tentry,
37585f379342SAlexander V. Chernikov .dump_tinfo = ta_dump_fhash_tinfo,
3759301290bcSAlexander V. Chernikov .need_modify = ta_need_modify_fhash,
3760914bffb6SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_fhash,
3761914bffb6SAlexander V. Chernikov .fill_mod = ta_fill_mod_fhash,
3762914bffb6SAlexander V. Chernikov .modify = ta_modify_fhash,
3763914bffb6SAlexander V. Chernikov .flush_mod = ta_flush_mod_fhash,
3764914bffb6SAlexander V. Chernikov };
37653fe2ef91SAlexander V. Chernikov
3766d3b00c08SAlexander V. Chernikov /*
3767d3b00c08SAlexander V. Chernikov * Kernel fibs bindings.
3768d3b00c08SAlexander V. Chernikov *
3769d3b00c08SAlexander V. Chernikov * Implementation:
3770d3b00c08SAlexander V. Chernikov *
3771d3b00c08SAlexander V. Chernikov * Runtime part:
3772d3b00c08SAlexander V. Chernikov * - fully relies on route API
3773d3b00c08SAlexander V. Chernikov * - fib number is stored in ti->data
3774d3b00c08SAlexander V. Chernikov *
3775d3b00c08SAlexander V. Chernikov */
3776d3b00c08SAlexander V. Chernikov
37779fe15d06SAlexander V. Chernikov static int ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
37789fe15d06SAlexander V. Chernikov uint32_t *val);
37799fe15d06SAlexander V. Chernikov static int kfib_parse_opts(int *pfib, char *data);
37809fe15d06SAlexander V. Chernikov static void ta_print_kfib_config(void *ta_state, struct table_info *ti,
37819fe15d06SAlexander V. Chernikov char *buf, size_t bufsize);
37829fe15d06SAlexander V. Chernikov static int ta_init_kfib(struct ip_fw_chain *ch, void **ta_state,
37839fe15d06SAlexander V. Chernikov struct table_info *ti, char *data, uint8_t tflags);
37849fe15d06SAlexander V. Chernikov static void ta_destroy_kfib(void *ta_state, struct table_info *ti);
37859fe15d06SAlexander V. Chernikov static void ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti,
37869fe15d06SAlexander V. Chernikov ipfw_ta_tinfo *tinfo);
37879fe15d06SAlexander V. Chernikov static int ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e,
37889fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent);
37894451d893SAlexander V. Chernikov static int ta_dump_kfib_tentry_int(int familt, const struct rtentry *rt,
37904451d893SAlexander V. Chernikov ipfw_obj_tentry *tent);
37919fe15d06SAlexander V. Chernikov static int ta_find_kfib_tentry(void *ta_state, struct table_info *ti,
37929fe15d06SAlexander V. Chernikov ipfw_obj_tentry *tent);
37939fe15d06SAlexander V. Chernikov static void ta_foreach_kfib(void *ta_state, struct table_info *ti,
37949fe15d06SAlexander V. Chernikov ta_foreach_f *f, void *arg);
37959fe15d06SAlexander V. Chernikov
3796d3b00c08SAlexander V. Chernikov static int
ta_lookup_kfib(struct table_info * ti,void * key,uint32_t keylen,uint32_t * val)3797d3b00c08SAlexander V. Chernikov ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
3798d3b00c08SAlexander V. Chernikov uint32_t *val)
3799d3b00c08SAlexander V. Chernikov {
3800004d3e30SAlexander V. Chernikov #ifdef INET
3801004d3e30SAlexander V. Chernikov struct in_addr in;
3802004d3e30SAlexander V. Chernikov #endif
3803004d3e30SAlexander V. Chernikov int error;
3804d3b00c08SAlexander V. Chernikov
380589fc126aSAlexander V. Chernikov error = ENOENT;
3806004d3e30SAlexander V. Chernikov #ifdef INET
3807004d3e30SAlexander V. Chernikov if (keylen == 4) {
3808004d3e30SAlexander V. Chernikov in.s_addr = *(in_addr_t *)key;
38096ad7446cSAlexander V. Chernikov NET_EPOCH_ASSERT();
38106ad7446cSAlexander V. Chernikov error = fib4_lookup(ti->data, in, 0, NHR_NONE, 0) != NULL;
3811004d3e30SAlexander V. Chernikov }
3812004d3e30SAlexander V. Chernikov #endif
3813004d3e30SAlexander V. Chernikov #ifdef INET6
3814004d3e30SAlexander V. Chernikov if (keylen == 6)
38156ad7446cSAlexander V. Chernikov error = fib6_lookup(ti->data, (struct in6_addr *)key,
38166ad7446cSAlexander V. Chernikov 0, NHR_NONE, 0) != NULL;
3817004d3e30SAlexander V. Chernikov #endif
3818004d3e30SAlexander V. Chernikov
3819004d3e30SAlexander V. Chernikov if (error != 0)
3820d3b00c08SAlexander V. Chernikov return (0);
3821d3b00c08SAlexander V. Chernikov
3822d3b00c08SAlexander V. Chernikov *val = 0;
3823d3b00c08SAlexander V. Chernikov
3824d3b00c08SAlexander V. Chernikov return (1);
3825d3b00c08SAlexander V. Chernikov }
3826d3b00c08SAlexander V. Chernikov
3827d3b00c08SAlexander V. Chernikov /* Parse 'fib=%d' */
3828d3b00c08SAlexander V. Chernikov static int
kfib_parse_opts(int * pfib,char * data)3829d3b00c08SAlexander V. Chernikov kfib_parse_opts(int *pfib, char *data)
3830d3b00c08SAlexander V. Chernikov {
3831d3b00c08SAlexander V. Chernikov char *pdel, *pend, *s;
3832d3b00c08SAlexander V. Chernikov int fibnum;
3833d3b00c08SAlexander V. Chernikov
3834d3b00c08SAlexander V. Chernikov if (data == NULL)
3835d3b00c08SAlexander V. Chernikov return (0);
3836d3b00c08SAlexander V. Chernikov if ((pdel = strchr(data, ' ')) == NULL)
3837d3b00c08SAlexander V. Chernikov return (0);
3838d3b00c08SAlexander V. Chernikov while (*pdel == ' ')
3839d3b00c08SAlexander V. Chernikov pdel++;
3840d3b00c08SAlexander V. Chernikov if (strncmp(pdel, "fib=", 4) != 0)
3841d3b00c08SAlexander V. Chernikov return (EINVAL);
3842d3b00c08SAlexander V. Chernikov if ((s = strchr(pdel, ' ')) != NULL)
3843d3b00c08SAlexander V. Chernikov *s++ = '\0';
3844d3b00c08SAlexander V. Chernikov
3845d3b00c08SAlexander V. Chernikov pdel += 4;
3846d3b00c08SAlexander V. Chernikov /* Need \d+ */
3847d3b00c08SAlexander V. Chernikov fibnum = strtol(pdel, &pend, 10);
3848d3b00c08SAlexander V. Chernikov if (*pend != '\0')
3849d3b00c08SAlexander V. Chernikov return (EINVAL);
3850d3b00c08SAlexander V. Chernikov
3851d3b00c08SAlexander V. Chernikov *pfib = fibnum;
3852d3b00c08SAlexander V. Chernikov
3853d3b00c08SAlexander V. Chernikov return (0);
3854d3b00c08SAlexander V. Chernikov }
3855d3b00c08SAlexander V. Chernikov
3856d3b00c08SAlexander V. Chernikov static void
ta_print_kfib_config(void * ta_state,struct table_info * ti,char * buf,size_t bufsize)3857d3b00c08SAlexander V. Chernikov ta_print_kfib_config(void *ta_state, struct table_info *ti, char *buf,
3858d3b00c08SAlexander V. Chernikov size_t bufsize)
3859d3b00c08SAlexander V. Chernikov {
3860d3b00c08SAlexander V. Chernikov
3861d3b00c08SAlexander V. Chernikov if (ti->data != 0)
3862c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s fib=%lu", "addr:kfib", ti->data);
3863d3b00c08SAlexander V. Chernikov else
3864c21034b7SAlexander V. Chernikov snprintf(buf, bufsize, "%s", "addr:kfib");
3865d3b00c08SAlexander V. Chernikov }
3866d3b00c08SAlexander V. Chernikov
3867d3b00c08SAlexander V. Chernikov static int
ta_init_kfib(struct ip_fw_chain * ch,void ** ta_state,struct table_info * ti,char * data,uint8_t tflags)3868d3b00c08SAlexander V. Chernikov ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
3869d3b00c08SAlexander V. Chernikov char *data, uint8_t tflags)
3870d3b00c08SAlexander V. Chernikov {
3871d3b00c08SAlexander V. Chernikov int error, fibnum;
3872d3b00c08SAlexander V. Chernikov
3873d3b00c08SAlexander V. Chernikov fibnum = 0;
3874d3b00c08SAlexander V. Chernikov if ((error = kfib_parse_opts(&fibnum, data)) != 0)
3875d3b00c08SAlexander V. Chernikov return (error);
3876d3b00c08SAlexander V. Chernikov
3877d3b00c08SAlexander V. Chernikov if (fibnum >= rt_numfibs)
3878d3b00c08SAlexander V. Chernikov return (E2BIG);
3879d3b00c08SAlexander V. Chernikov
3880d3b00c08SAlexander V. Chernikov ti->data = fibnum;
3881d3b00c08SAlexander V. Chernikov ti->lookup = ta_lookup_kfib;
3882d3b00c08SAlexander V. Chernikov
3883d3b00c08SAlexander V. Chernikov return (0);
3884d3b00c08SAlexander V. Chernikov }
3885d3b00c08SAlexander V. Chernikov
3886d3b00c08SAlexander V. Chernikov /*
3887d3b00c08SAlexander V. Chernikov * Destroys table @ti
3888d3b00c08SAlexander V. Chernikov */
3889d3b00c08SAlexander V. Chernikov static void
ta_destroy_kfib(void * ta_state,struct table_info * ti)3890d3b00c08SAlexander V. Chernikov ta_destroy_kfib(void *ta_state, struct table_info *ti)
3891d3b00c08SAlexander V. Chernikov {
3892d3b00c08SAlexander V. Chernikov
3893d3b00c08SAlexander V. Chernikov }
3894d3b00c08SAlexander V. Chernikov
3895d3b00c08SAlexander V. Chernikov /*
3896d3b00c08SAlexander V. Chernikov * Provide algo-specific table info
3897d3b00c08SAlexander V. Chernikov */
3898d3b00c08SAlexander V. Chernikov static void
ta_dump_kfib_tinfo(void * ta_state,struct table_info * ti,ipfw_ta_tinfo * tinfo)3899d3b00c08SAlexander V. Chernikov ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
3900d3b00c08SAlexander V. Chernikov {
3901d3b00c08SAlexander V. Chernikov
3902d3b00c08SAlexander V. Chernikov tinfo->flags = IPFW_TATFLAGS_AFDATA;
3903d3b00c08SAlexander V. Chernikov tinfo->taclass4 = IPFW_TACLASS_RADIX;
3904d3b00c08SAlexander V. Chernikov tinfo->count4 = 0;
39054451d893SAlexander V. Chernikov tinfo->itemsize4 = 128; /* table is readonly, value does not matter */
3906d3b00c08SAlexander V. Chernikov tinfo->taclass6 = IPFW_TACLASS_RADIX;
3907d3b00c08SAlexander V. Chernikov tinfo->count6 = 0;
39084451d893SAlexander V. Chernikov tinfo->itemsize6 = 128;
3909d3b00c08SAlexander V. Chernikov }
3910d3b00c08SAlexander V. Chernikov
3911d3b00c08SAlexander V. Chernikov static int
ta_dump_kfib_tentry_int(int family,const struct rtentry * rt,ipfw_obj_tentry * tent)39124451d893SAlexander V. Chernikov ta_dump_kfib_tentry_int(int family, const struct rtentry *rt,
3913d3b00c08SAlexander V. Chernikov ipfw_obj_tentry *tent)
3914d3b00c08SAlexander V. Chernikov {
39154451d893SAlexander V. Chernikov uint32_t scopeid;
39164451d893SAlexander V. Chernikov int plen;
3917004d3e30SAlexander V. Chernikov
3918d699ee2dSAlexander V. Chernikov #ifdef INET
39194451d893SAlexander V. Chernikov if (family == AF_INET) {
39204451d893SAlexander V. Chernikov rt_get_inet_prefix_plen(rt, &tent->k.addr, &plen, &scopeid);
39214451d893SAlexander V. Chernikov tent->masklen = plen;
3922d3b00c08SAlexander V. Chernikov tent->subtype = AF_INET;
39234451d893SAlexander V. Chernikov tent->v.kidx = 0;
3924d699ee2dSAlexander V. Chernikov }
3925d699ee2dSAlexander V. Chernikov #endif
39262616eaa3SAlexander V. Chernikov #ifdef INET6
39274451d893SAlexander V. Chernikov if (family == AF_INET6) {
39284451d893SAlexander V. Chernikov rt_get_inet6_prefix_plen(rt, &tent->k.addr6, &plen, &scopeid);
39294451d893SAlexander V. Chernikov tent->masklen = plen;
3930d3b00c08SAlexander V. Chernikov tent->subtype = AF_INET6;
39310cba2b28SAlexander V. Chernikov tent->v.kidx = 0;
3932d3b00c08SAlexander V. Chernikov }
3933d699ee2dSAlexander V. Chernikov #endif
3934d3b00c08SAlexander V. Chernikov return (0);
3935d3b00c08SAlexander V. Chernikov }
3936d3b00c08SAlexander V. Chernikov
3937d3b00c08SAlexander V. Chernikov static int
ta_find_kfib_tentry(void * ta_state,struct table_info * ti,ipfw_obj_tentry * tent)3938d3b00c08SAlexander V. Chernikov ta_find_kfib_tentry(void *ta_state, struct table_info *ti,
3939d3b00c08SAlexander V. Chernikov ipfw_obj_tentry *tent)
3940d3b00c08SAlexander V. Chernikov {
39413ad80c65SAlexander V. Chernikov struct rtentry *rt = NULL;
39424451d893SAlexander V. Chernikov struct route_nhop_data rnd;
39434451d893SAlexander V. Chernikov struct epoch_tracker et;
39444451d893SAlexander V. Chernikov int error;
3945004d3e30SAlexander V. Chernikov
39464451d893SAlexander V. Chernikov NET_EPOCH_ENTER(et);
39473ad80c65SAlexander V. Chernikov
39483ad80c65SAlexander V. Chernikov switch (tent->subtype) {
39493ad80c65SAlexander V. Chernikov #ifdef INET
39503ad80c65SAlexander V. Chernikov case AF_INET:
39514451d893SAlexander V. Chernikov rt = fib4_lookup_rt(ti->data, tent->k.addr, 0, 0, &rnd);
39523ad80c65SAlexander V. Chernikov break;
39533ad80c65SAlexander V. Chernikov #endif
39543ad80c65SAlexander V. Chernikov #ifdef INET6
39553ad80c65SAlexander V. Chernikov case AF_INET6:
39564451d893SAlexander V. Chernikov rt = fib6_lookup_rt(ti->data, &tent->k.addr6, 0, 0, &rnd);
39573ad80c65SAlexander V. Chernikov break;
39583ad80c65SAlexander V. Chernikov #endif
39594451d893SAlexander V. Chernikov }
39604451d893SAlexander V. Chernikov if (rt != NULL)
39614451d893SAlexander V. Chernikov error = ta_dump_kfib_tentry_int(tent->subtype, rt, tent);
39624451d893SAlexander V. Chernikov else
39634451d893SAlexander V. Chernikov error = ENOENT;
39644451d893SAlexander V. Chernikov NET_EPOCH_EXIT(et);
39654451d893SAlexander V. Chernikov
39664451d893SAlexander V. Chernikov return (error);
3967d3b00c08SAlexander V. Chernikov }
3968d3b00c08SAlexander V. Chernikov
39694451d893SAlexander V. Chernikov struct kfib_dump_arg {
39704451d893SAlexander V. Chernikov struct rtentry *rt;
39714451d893SAlexander V. Chernikov int family;
39724451d893SAlexander V. Chernikov ta_foreach_f *f;
39734451d893SAlexander V. Chernikov void *arg;
39744451d893SAlexander V. Chernikov };
3975004d3e30SAlexander V. Chernikov
39764451d893SAlexander V. Chernikov static int
ta_dump_kfib_tentry(void * ta_state,struct table_info * ti,void * e,ipfw_obj_tentry * tent)39774451d893SAlexander V. Chernikov ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e,
39784451d893SAlexander V. Chernikov ipfw_obj_tentry *tent)
39794451d893SAlexander V. Chernikov {
39804451d893SAlexander V. Chernikov struct kfib_dump_arg *karg = (struct kfib_dump_arg *)e;
3981004d3e30SAlexander V. Chernikov
39824451d893SAlexander V. Chernikov return (ta_dump_kfib_tentry_int(karg->family, karg->rt, tent));
39834451d893SAlexander V. Chernikov }
39844451d893SAlexander V. Chernikov
39854451d893SAlexander V. Chernikov static int
walk_wrapper_f(struct rtentry * rt,void * arg)39864451d893SAlexander V. Chernikov walk_wrapper_f(struct rtentry *rt, void *arg)
39874451d893SAlexander V. Chernikov {
39884451d893SAlexander V. Chernikov struct kfib_dump_arg *karg = (struct kfib_dump_arg *)arg;
39894451d893SAlexander V. Chernikov
39904451d893SAlexander V. Chernikov karg->rt = rt;
39914451d893SAlexander V. Chernikov return (karg->f(karg, karg->arg));
3992d3b00c08SAlexander V. Chernikov }
3993d3b00c08SAlexander V. Chernikov
3994d3b00c08SAlexander V. Chernikov static void
ta_foreach_kfib(void * ta_state,struct table_info * ti,ta_foreach_f * f,void * arg)3995d3b00c08SAlexander V. Chernikov ta_foreach_kfib(void *ta_state, struct table_info *ti, ta_foreach_f *f,
3996d3b00c08SAlexander V. Chernikov void *arg)
3997d3b00c08SAlexander V. Chernikov {
39984451d893SAlexander V. Chernikov struct kfib_dump_arg karg = { .f = f, .arg = arg };
3999d3b00c08SAlexander V. Chernikov
40004451d893SAlexander V. Chernikov karg.family = AF_INET;
40014451d893SAlexander V. Chernikov rib_walk(ti->data, AF_INET, false, walk_wrapper_f, &karg);
40024451d893SAlexander V. Chernikov karg.family = AF_INET6;
40034451d893SAlexander V. Chernikov rib_walk(ti->data, AF_INET6, false, walk_wrapper_f, &karg);
4004d3b00c08SAlexander V. Chernikov }
4005d3b00c08SAlexander V. Chernikov
4006c21034b7SAlexander V. Chernikov struct table_algo addr_kfib = {
4007c21034b7SAlexander V. Chernikov .name = "addr:kfib",
4008c21034b7SAlexander V. Chernikov .type = IPFW_TABLE_ADDR,
4009d3b00c08SAlexander V. Chernikov .flags = TA_FLAG_READONLY,
4010d3b00c08SAlexander V. Chernikov .ta_buf_size = 0,
4011d3b00c08SAlexander V. Chernikov .init = ta_init_kfib,
4012d3b00c08SAlexander V. Chernikov .destroy = ta_destroy_kfib,
4013d3b00c08SAlexander V. Chernikov .foreach = ta_foreach_kfib,
4014d3b00c08SAlexander V. Chernikov .dump_tentry = ta_dump_kfib_tentry,
4015d3b00c08SAlexander V. Chernikov .find_tentry = ta_find_kfib_tentry,
4016d3b00c08SAlexander V. Chernikov .dump_tinfo = ta_dump_kfib_tinfo,
4017d3b00c08SAlexander V. Chernikov .print_config = ta_print_kfib_config,
4018d3b00c08SAlexander V. Chernikov };
4019d3b00c08SAlexander V. Chernikov
402081cac390SArseny Smalyuk struct mac_radix_entry {
402181cac390SArseny Smalyuk struct radix_node rn[2];
4022*4a77657cSAndrey V. Elsukov struct sa_mac sa;
402381cac390SArseny Smalyuk uint32_t value;
402481cac390SArseny Smalyuk uint8_t masklen;
402581cac390SArseny Smalyuk };
402681cac390SArseny Smalyuk
402781cac390SArseny Smalyuk struct mac_radix_cfg {
402881cac390SArseny Smalyuk struct radix_node_head *head;
402981cac390SArseny Smalyuk size_t count;
403081cac390SArseny Smalyuk };
403181cac390SArseny Smalyuk
403281cac390SArseny Smalyuk static int
ta_lookup_mac_radix(struct table_info * ti,void * key,uint32_t keylen,uint32_t * val)403381cac390SArseny Smalyuk ta_lookup_mac_radix(struct table_info *ti, void *key, uint32_t keylen,
403481cac390SArseny Smalyuk uint32_t *val)
403581cac390SArseny Smalyuk {
403681cac390SArseny Smalyuk struct radix_node_head *rnh;
403781cac390SArseny Smalyuk
403881cac390SArseny Smalyuk if (keylen == ETHER_ADDR_LEN) {
403981cac390SArseny Smalyuk struct mac_radix_entry *ent;
404081cac390SArseny Smalyuk struct sa_mac sa;
404181cac390SArseny Smalyuk KEY_LEN(sa) = KEY_LEN_MAC;
404281cac390SArseny Smalyuk memcpy(sa.mac_addr.octet, key, ETHER_ADDR_LEN);
404381cac390SArseny Smalyuk rnh = (struct radix_node_head *)ti->state;
404481cac390SArseny Smalyuk ent = (struct mac_radix_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh));
404581cac390SArseny Smalyuk if (ent != NULL) {
404681cac390SArseny Smalyuk *val = ent->value;
404781cac390SArseny Smalyuk return (1);
404881cac390SArseny Smalyuk }
404981cac390SArseny Smalyuk }
405081cac390SArseny Smalyuk return (0);
405181cac390SArseny Smalyuk }
405281cac390SArseny Smalyuk
405381cac390SArseny Smalyuk static int
ta_init_mac_radix(struct ip_fw_chain * ch,void ** ta_state,struct table_info * ti,char * data,uint8_t tflags)405481cac390SArseny Smalyuk ta_init_mac_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
405581cac390SArseny Smalyuk char *data, uint8_t tflags)
405681cac390SArseny Smalyuk {
405781cac390SArseny Smalyuk struct mac_radix_cfg *cfg;
405881cac390SArseny Smalyuk
405981cac390SArseny Smalyuk if (!rn_inithead(&ti->state, OFF_LEN_MAC))
406081cac390SArseny Smalyuk return (ENOMEM);
406181cac390SArseny Smalyuk
406281cac390SArseny Smalyuk cfg = malloc(sizeof(struct mac_radix_cfg), M_IPFW, M_WAITOK | M_ZERO);
406381cac390SArseny Smalyuk
406481cac390SArseny Smalyuk *ta_state = cfg;
406581cac390SArseny Smalyuk ti->lookup = ta_lookup_mac_radix;
406681cac390SArseny Smalyuk
406781cac390SArseny Smalyuk return (0);
406881cac390SArseny Smalyuk }
406981cac390SArseny Smalyuk
407081cac390SArseny Smalyuk static void
ta_destroy_mac_radix(void * ta_state,struct table_info * ti)407181cac390SArseny Smalyuk ta_destroy_mac_radix(void *ta_state, struct table_info *ti)
407281cac390SArseny Smalyuk {
407381cac390SArseny Smalyuk struct mac_radix_cfg *cfg;
407481cac390SArseny Smalyuk struct radix_node_head *rnh;
407581cac390SArseny Smalyuk
407681cac390SArseny Smalyuk cfg = (struct mac_radix_cfg *)ta_state;
407781cac390SArseny Smalyuk
407881cac390SArseny Smalyuk rnh = (struct radix_node_head *)(ti->state);
407981cac390SArseny Smalyuk rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
408081cac390SArseny Smalyuk rn_detachhead(&ti->state);
408181cac390SArseny Smalyuk
408281cac390SArseny Smalyuk free(cfg, M_IPFW);
408381cac390SArseny Smalyuk }
408481cac390SArseny Smalyuk
408581cac390SArseny Smalyuk static void
tei_to_sockaddr_ent_mac(struct tentry_info * tei,struct sockaddr * sa,struct sockaddr * ma,int * set_mask)408681cac390SArseny Smalyuk tei_to_sockaddr_ent_mac(struct tentry_info *tei, struct sockaddr *sa,
408781cac390SArseny Smalyuk struct sockaddr *ma, int *set_mask)
408881cac390SArseny Smalyuk {
408981cac390SArseny Smalyuk int mlen, i;
409081cac390SArseny Smalyuk struct sa_mac *addr, *mask;
409181cac390SArseny Smalyuk u_char *cp;
409281cac390SArseny Smalyuk
409381cac390SArseny Smalyuk mlen = tei->masklen;
409481cac390SArseny Smalyuk addr = (struct sa_mac *)sa;
409581cac390SArseny Smalyuk mask = (struct sa_mac *)ma;
409681cac390SArseny Smalyuk /* Set 'total' structure length */
409781cac390SArseny Smalyuk KEY_LEN(*addr) = KEY_LEN_MAC;
409881cac390SArseny Smalyuk KEY_LEN(*mask) = KEY_LEN_MAC;
409981cac390SArseny Smalyuk
410081cac390SArseny Smalyuk for (i = mlen, cp = mask->mac_addr.octet; i >= 8; i -= 8)
410181cac390SArseny Smalyuk *cp++ = 0xFF;
410281cac390SArseny Smalyuk if (i > 0)
410381cac390SArseny Smalyuk *cp = ~((1 << (8 - i)) - 1);
410481cac390SArseny Smalyuk
410581cac390SArseny Smalyuk addr->mac_addr = *((struct ether_addr *)tei->paddr);
410681cac390SArseny Smalyuk for (i = 0; i < ETHER_ADDR_LEN; ++i)
410781cac390SArseny Smalyuk addr->mac_addr.octet[i] &= mask->mac_addr.octet[i];
410881cac390SArseny Smalyuk
410981cac390SArseny Smalyuk if (mlen != 8 * ETHER_ADDR_LEN)
411081cac390SArseny Smalyuk *set_mask = 1;
411181cac390SArseny Smalyuk else
411281cac390SArseny Smalyuk *set_mask = 0;
411381cac390SArseny Smalyuk }
411481cac390SArseny Smalyuk
411581cac390SArseny Smalyuk static int
ta_prepare_add_mac_radix(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)411681cac390SArseny Smalyuk ta_prepare_add_mac_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
411781cac390SArseny Smalyuk void *ta_buf)
411881cac390SArseny Smalyuk {
411981cac390SArseny Smalyuk struct ta_buf_radix *tb;
412081cac390SArseny Smalyuk struct mac_radix_entry *ent;
412181cac390SArseny Smalyuk struct sockaddr *addr, *mask;
412281cac390SArseny Smalyuk int mlen, set_mask;
412381cac390SArseny Smalyuk
412481cac390SArseny Smalyuk tb = (struct ta_buf_radix *)ta_buf;
412581cac390SArseny Smalyuk
412681cac390SArseny Smalyuk mlen = tei->masklen;
412781cac390SArseny Smalyuk set_mask = 0;
412881cac390SArseny Smalyuk
412981cac390SArseny Smalyuk if (tei->subtype == AF_LINK) {
413081cac390SArseny Smalyuk if (mlen > 8 * ETHER_ADDR_LEN)
413181cac390SArseny Smalyuk return (EINVAL);
413281cac390SArseny Smalyuk ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
413381cac390SArseny Smalyuk ent->masklen = mlen;
413481cac390SArseny Smalyuk
413581cac390SArseny Smalyuk addr = (struct sockaddr *)&ent->sa;
413681cac390SArseny Smalyuk mask = (struct sockaddr *)&tb->addr.mac.ma;
413781cac390SArseny Smalyuk tb->ent_ptr = ent;
413881cac390SArseny Smalyuk } else {
413981cac390SArseny Smalyuk /* Unknown CIDR type */
414081cac390SArseny Smalyuk return (EINVAL);
414181cac390SArseny Smalyuk }
414281cac390SArseny Smalyuk
414381cac390SArseny Smalyuk tei_to_sockaddr_ent_mac(tei, addr, mask, &set_mask);
414481cac390SArseny Smalyuk /* Set pointers */
414581cac390SArseny Smalyuk tb->addr_ptr = addr;
414681cac390SArseny Smalyuk if (set_mask != 0)
414781cac390SArseny Smalyuk tb->mask_ptr = mask;
414881cac390SArseny Smalyuk
414981cac390SArseny Smalyuk return (0);
415081cac390SArseny Smalyuk }
415181cac390SArseny Smalyuk
415281cac390SArseny Smalyuk static int
ta_add_mac_radix(void * ta_state,struct table_info * ti,struct tentry_info * tei,void * ta_buf,uint32_t * pnum)415381cac390SArseny Smalyuk ta_add_mac_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
415481cac390SArseny Smalyuk void *ta_buf, uint32_t *pnum)
415581cac390SArseny Smalyuk {
415681cac390SArseny Smalyuk struct mac_radix_cfg *cfg;
415781cac390SArseny Smalyuk struct radix_node_head *rnh;
415881cac390SArseny Smalyuk struct radix_node *rn;
415981cac390SArseny Smalyuk struct ta_buf_radix *tb;
416081cac390SArseny Smalyuk uint32_t *old_value, value;
416181cac390SArseny Smalyuk
416281cac390SArseny Smalyuk cfg = (struct mac_radix_cfg *)ta_state;
416381cac390SArseny Smalyuk tb = (struct ta_buf_radix *)ta_buf;
416481cac390SArseny Smalyuk
416581cac390SArseny Smalyuk /* Save current entry value from @tei */
416681cac390SArseny Smalyuk rnh = ti->state;
416781cac390SArseny Smalyuk ((struct mac_radix_entry *)tb->ent_ptr)->value = tei->value;
416881cac390SArseny Smalyuk
416981cac390SArseny Smalyuk /* Search for an entry first */
417081cac390SArseny Smalyuk rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
417181cac390SArseny Smalyuk if (rn != NULL) {
417281cac390SArseny Smalyuk if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
417381cac390SArseny Smalyuk return (EEXIST);
417481cac390SArseny Smalyuk /* Record already exists. Update value if we're asked to */
417581cac390SArseny Smalyuk old_value = &((struct mac_radix_entry *)rn)->value;
417681cac390SArseny Smalyuk
417781cac390SArseny Smalyuk value = *old_value;
417881cac390SArseny Smalyuk *old_value = tei->value;
417981cac390SArseny Smalyuk tei->value = value;
418081cac390SArseny Smalyuk
418181cac390SArseny Smalyuk /* Indicate that update has happened instead of addition */
418281cac390SArseny Smalyuk tei->flags |= TEI_FLAGS_UPDATED;
418381cac390SArseny Smalyuk *pnum = 0;
418481cac390SArseny Smalyuk
418581cac390SArseny Smalyuk return (0);
418681cac390SArseny Smalyuk }
418781cac390SArseny Smalyuk
418881cac390SArseny Smalyuk if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
418981cac390SArseny Smalyuk return (EFBIG);
419081cac390SArseny Smalyuk
419181cac390SArseny Smalyuk rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, &rnh->rh, tb->ent_ptr);
419281cac390SArseny Smalyuk if (rn == NULL) {
419381cac390SArseny Smalyuk /* Unknown error */
419481cac390SArseny Smalyuk return (EINVAL);
419581cac390SArseny Smalyuk }
419681cac390SArseny Smalyuk
419781cac390SArseny Smalyuk cfg->count++;
419881cac390SArseny Smalyuk tb->ent_ptr = NULL;
419981cac390SArseny Smalyuk *pnum = 1;
420081cac390SArseny Smalyuk
420181cac390SArseny Smalyuk return (0);
420281cac390SArseny Smalyuk }
420381cac390SArseny Smalyuk
420481cac390SArseny Smalyuk static int
ta_prepare_del_mac_radix(struct ip_fw_chain * ch,struct tentry_info * tei,void * ta_buf)420581cac390SArseny Smalyuk ta_prepare_del_mac_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
420681cac390SArseny Smalyuk void *ta_buf)
420781cac390SArseny Smalyuk {
420881cac390SArseny Smalyuk struct ta_buf_radix *tb;
420981cac390SArseny Smalyuk struct sockaddr *addr, *mask;
421081cac390SArseny Smalyuk int mlen, set_mask;
421181cac390SArseny Smalyuk
421281cac390SArseny Smalyuk tb = (struct ta_buf_radix *)ta_buf;
421381cac390SArseny Smalyuk
421481cac390SArseny Smalyuk mlen = tei->masklen;
421581cac390SArseny Smalyuk set_mask = 0;
421681cac390SArseny Smalyuk
421781cac390SArseny Smalyuk if (tei->subtype == AF_LINK) {
421881cac390SArseny Smalyuk if (mlen > 8 * ETHER_ADDR_LEN)
421981cac390SArseny Smalyuk return (EINVAL);
422081cac390SArseny Smalyuk
422181cac390SArseny Smalyuk addr = (struct sockaddr *)&tb->addr.mac.sa;
422281cac390SArseny Smalyuk mask = (struct sockaddr *)&tb->addr.mac.ma;
422381cac390SArseny Smalyuk } else
422481cac390SArseny Smalyuk return (EINVAL);
422581cac390SArseny Smalyuk
422681cac390SArseny Smalyuk tei_to_sockaddr_ent_mac(tei, addr, mask, &set_mask);
422781cac390SArseny Smalyuk tb->addr_ptr = addr;
422881cac390SArseny Smalyuk if (set_mask != 0)
422981cac390SArseny Smalyuk tb->mask_ptr = mask;
423081cac390SArseny Smalyuk
423181cac390SArseny Smalyuk return (0);
423281cac390SArseny Smalyuk }
423381cac390SArseny Smalyuk
423481cac390SArseny Smalyuk static int
ta_del_mac_radix(void * ta_state,struct table_info * ti,struct tentry_info * tei,void * ta_buf,uint32_t * pnum)423581cac390SArseny Smalyuk ta_del_mac_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
423681cac390SArseny Smalyuk void *ta_buf, uint32_t *pnum)
423781cac390SArseny Smalyuk {
423881cac390SArseny Smalyuk struct mac_radix_cfg *cfg;
423981cac390SArseny Smalyuk struct radix_node_head *rnh;
424081cac390SArseny Smalyuk struct radix_node *rn;
424181cac390SArseny Smalyuk struct ta_buf_radix *tb;
424281cac390SArseny Smalyuk
424381cac390SArseny Smalyuk cfg = (struct mac_radix_cfg *)ta_state;
424481cac390SArseny Smalyuk tb = (struct ta_buf_radix *)ta_buf;
424581cac390SArseny Smalyuk rnh = ti->state;
424681cac390SArseny Smalyuk
424781cac390SArseny Smalyuk rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
424881cac390SArseny Smalyuk
424981cac390SArseny Smalyuk if (rn == NULL)
425081cac390SArseny Smalyuk return (ENOENT);
425181cac390SArseny Smalyuk
425281cac390SArseny Smalyuk /* Save entry value to @tei */
425381cac390SArseny Smalyuk tei->value = ((struct mac_radix_entry *)rn)->value;
425481cac390SArseny Smalyuk
425581cac390SArseny Smalyuk tb->ent_ptr = rn;
425681cac390SArseny Smalyuk cfg->count--;
425781cac390SArseny Smalyuk *pnum = 1;
425881cac390SArseny Smalyuk
425981cac390SArseny Smalyuk return (0);
426081cac390SArseny Smalyuk }
426181cac390SArseny Smalyuk
426281cac390SArseny Smalyuk static void
ta_foreach_mac_radix(void * ta_state,struct table_info * ti,ta_foreach_f * f,void * arg)426381cac390SArseny Smalyuk ta_foreach_mac_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
426481cac390SArseny Smalyuk void *arg)
426581cac390SArseny Smalyuk {
426681cac390SArseny Smalyuk struct radix_node_head *rnh;
426781cac390SArseny Smalyuk
426881cac390SArseny Smalyuk rnh = (struct radix_node_head *)(ti->state);
426981cac390SArseny Smalyuk rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg);
427081cac390SArseny Smalyuk }
427181cac390SArseny Smalyuk
427281cac390SArseny Smalyuk static void
ta_dump_mac_radix_tinfo(void * ta_state,struct table_info * ti,ipfw_ta_tinfo * tinfo)427381cac390SArseny Smalyuk ta_dump_mac_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
427481cac390SArseny Smalyuk {
427581cac390SArseny Smalyuk struct mac_radix_cfg *cfg;
427681cac390SArseny Smalyuk
427781cac390SArseny Smalyuk cfg = (struct mac_radix_cfg *)ta_state;
427881cac390SArseny Smalyuk
427981cac390SArseny Smalyuk tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
428081cac390SArseny Smalyuk tinfo->taclass4 = IPFW_TACLASS_RADIX;
428181cac390SArseny Smalyuk tinfo->count4 = cfg->count;
428281cac390SArseny Smalyuk tinfo->itemsize4 = sizeof(struct mac_radix_entry);
428381cac390SArseny Smalyuk }
428481cac390SArseny Smalyuk
428581cac390SArseny Smalyuk static int
ta_dump_mac_radix_tentry(void * ta_state,struct table_info * ti,void * e,ipfw_obj_tentry * tent)428681cac390SArseny Smalyuk ta_dump_mac_radix_tentry(void *ta_state, struct table_info *ti, void *e,
428781cac390SArseny Smalyuk ipfw_obj_tentry *tent)
428881cac390SArseny Smalyuk {
428981cac390SArseny Smalyuk struct mac_radix_entry *n = (struct mac_radix_entry *)e;
429081cac390SArseny Smalyuk
429181cac390SArseny Smalyuk memcpy(tent->k.mac, n->sa.mac_addr.octet, ETHER_ADDR_LEN);
429281cac390SArseny Smalyuk tent->masklen = n->masklen;
429381cac390SArseny Smalyuk tent->subtype = AF_LINK;
429481cac390SArseny Smalyuk tent->v.kidx = n->value;
429581cac390SArseny Smalyuk
429681cac390SArseny Smalyuk return (0);
429781cac390SArseny Smalyuk }
429881cac390SArseny Smalyuk
429981cac390SArseny Smalyuk static int
ta_find_mac_radix_tentry(void * ta_state,struct table_info * ti,ipfw_obj_tentry * tent)430081cac390SArseny Smalyuk ta_find_mac_radix_tentry(void *ta_state, struct table_info *ti,
430181cac390SArseny Smalyuk ipfw_obj_tentry *tent)
430281cac390SArseny Smalyuk {
430381cac390SArseny Smalyuk struct radix_node_head *rnh;
430481cac390SArseny Smalyuk void *e;
430581cac390SArseny Smalyuk
430681cac390SArseny Smalyuk e = NULL;
430781cac390SArseny Smalyuk if (tent->subtype == AF_LINK) {
430881cac390SArseny Smalyuk struct sa_mac sa;
430981cac390SArseny Smalyuk KEY_LEN(sa) = KEY_LEN_MAC;
4310e012d79cSAndrey V. Elsukov memcpy(sa.mac_addr.octet, tent->k.mac, ETHER_ADDR_LEN);
431181cac390SArseny Smalyuk rnh = (struct radix_node_head *)ti->state;
431281cac390SArseny Smalyuk e = rnh->rnh_matchaddr(&sa, &rnh->rh);
431381cac390SArseny Smalyuk }
431481cac390SArseny Smalyuk
431581cac390SArseny Smalyuk if (e != NULL) {
431681cac390SArseny Smalyuk ta_dump_mac_radix_tentry(ta_state, ti, e, tent);
431781cac390SArseny Smalyuk return (0);
431881cac390SArseny Smalyuk }
431981cac390SArseny Smalyuk
432081cac390SArseny Smalyuk return (ENOENT);
432181cac390SArseny Smalyuk }
432281cac390SArseny Smalyuk
432381cac390SArseny Smalyuk struct table_algo mac_radix = {
432481cac390SArseny Smalyuk .name = "mac:radix",
432581cac390SArseny Smalyuk .type = IPFW_TABLE_MAC,
432681cac390SArseny Smalyuk .flags = TA_FLAG_DEFAULT,
432781cac390SArseny Smalyuk .ta_buf_size = sizeof(struct ta_buf_radix),
432881cac390SArseny Smalyuk .init = ta_init_mac_radix,
432981cac390SArseny Smalyuk .destroy = ta_destroy_mac_radix,
433081cac390SArseny Smalyuk .prepare_add = ta_prepare_add_mac_radix,
433181cac390SArseny Smalyuk .prepare_del = ta_prepare_del_mac_radix,
433281cac390SArseny Smalyuk .add = ta_add_mac_radix,
433381cac390SArseny Smalyuk .del = ta_del_mac_radix,
433481cac390SArseny Smalyuk .flush_entry = ta_flush_radix_entry,
433581cac390SArseny Smalyuk .foreach = ta_foreach_mac_radix,
433681cac390SArseny Smalyuk .dump_tentry = ta_dump_mac_radix_tentry,
433781cac390SArseny Smalyuk .find_tentry = ta_find_mac_radix_tentry,
433881cac390SArseny Smalyuk .dump_tinfo = ta_dump_mac_radix_tinfo,
433981cac390SArseny Smalyuk .need_modify = ta_need_modify_radix,
434081cac390SArseny Smalyuk };
434181cac390SArseny Smalyuk
43429f7d47b0SAlexander V. Chernikov void
ipfw_table_algo_init(struct ip_fw_chain * ch)43430b565ac0SAlexander V. Chernikov ipfw_table_algo_init(struct ip_fw_chain *ch)
43449f7d47b0SAlexander V. Chernikov {
43450b565ac0SAlexander V. Chernikov size_t sz;
43460b565ac0SAlexander V. Chernikov
43479f7d47b0SAlexander V. Chernikov /*
43489f7d47b0SAlexander V. Chernikov * Register all algorithms presented here.
43499f7d47b0SAlexander V. Chernikov */
43500b565ac0SAlexander V. Chernikov sz = sizeof(struct table_algo);
4351c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_radix, sz, &addr_radix.idx);
4352c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_hash, sz, &addr_hash.idx);
43530b565ac0SAlexander V. Chernikov ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx);
4354b23d5de9SAlexander V. Chernikov ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx);
4355914bffb6SAlexander V. Chernikov ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx);
4356c21034b7SAlexander V. Chernikov ipfw_add_table_algo(ch, &addr_kfib, sz, &addr_kfib.idx);
435781cac390SArseny Smalyuk ipfw_add_table_algo(ch, &mac_radix, sz, &mac_radix.idx);
43589f7d47b0SAlexander V. Chernikov }
43599f7d47b0SAlexander V. Chernikov
43609f7d47b0SAlexander V. Chernikov void
ipfw_table_algo_destroy(struct ip_fw_chain * ch)43610b565ac0SAlexander V. Chernikov ipfw_table_algo_destroy(struct ip_fw_chain *ch)
43629f7d47b0SAlexander V. Chernikov {
43630b565ac0SAlexander V. Chernikov
4364c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_radix.idx);
4365c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_hash.idx);
43660b565ac0SAlexander V. Chernikov ipfw_del_table_algo(ch, iface_idx.idx);
4367b23d5de9SAlexander V. Chernikov ipfw_del_table_algo(ch, number_array.idx);
4368914bffb6SAlexander V. Chernikov ipfw_del_table_algo(ch, flow_hash.idx);
4369c21034b7SAlexander V. Chernikov ipfw_del_table_algo(ch, addr_kfib.idx);
437081cac390SArseny Smalyuk ipfw_del_table_algo(ch, mac_radix.idx);
43719f7d47b0SAlexander V. Chernikov }
4372