2 * Copyright (c) 2014 Yandex LLC
3 * Copyright (c) 2014 Alexander V. Chernikov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
31 * Lookup table algorithms.
38 #error IPFIREWALL requires INET.
40 #include "opt_inet6.h"
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/malloc.h>
45 #include <sys/kernel.h>
47 #include <sys/rwlock.h>
48 #include <sys/rmlock.h>
49 #include <sys/socket.h>
50 #include <sys/queue.h>
51 #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */
52 #include <net/radix.h>
53 #include <net/route.h>
54 #include <net/route/nhop.h>
55 #include <net/route/route_var.h>
57 #include <netinet/in.h>
58 #include <netinet/in_fib.h>
59 #include <netinet/ip_var.h> /* struct ipfw_rule_ref */
60 #include <netinet/ip_fw.h>
61 #include <netinet6/in6_fib.h>
63 #include <netpfil/ipfw/ip_fw_private.h>
64 #include <netpfil/ipfw/ip_fw_table.h>
67 * IPFW table lookup algorithms.
69 * What is needed to add another table algo?
72 * * struct table_algo has to be filled with:
73 * name: "type:algoname" format, e.g. "addr:radix". Currently
74 * there are the following types: "addr", "iface", "number" and "flow".
75 * type: one of IPFW_TABLE_* types
76 * flags: one or more TA_FLAGS_*
77 * ta_buf_size: size of structure used to store add/del item state.
78 * Needs to be less than TA_BUF_SZ.
79 * callbacks: see below for description.
80 * * ipfw_add_table_algo / ipfw_del_table_algo has to be called
82 * Callbacks description:
84 * -init: request to initialize new table instance.
85 * typedef int (ta_init)(struct ip_fw_chain *ch, void **ta_state,
86 * struct table_info *ti, char *data, uint8_t tflags);
87 * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success.
89 * Allocate all structures needed for normal operations.
90 * * Caller may want to parse @data for some algo-specific
91 * options provided by userland.
92 * * Caller may want to save configuration state pointer to @ta_state
93 * * Caller needs to save desired runtime structure pointer(s)
94 * inside @ti fields. Note that it is not correct to save
95 * @ti pointer at this moment. Use -change_ti hook for that.
96 * * Caller has to fill in ti->lookup to appropriate function
101 * -destroy: request to destroy table instance.
102 * typedef void (ta_destroy)(void *ta_state, struct table_info *ti);
103 * MANDATORY, unlocked. (M_WAITOK).
105 * Frees all table entries and all tables structures allocated by -init.
109 * -prepare_add: request to allocate state for adding new entry.
110 * typedef int (ta_prepare_add)(struct ip_fw_chain *ch, struct tentry_info *tei,
112 * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success.
114 * Allocates state and fills it in with all necessary data (EXCEPT value)
115 * from @tei to minimize operations needed to be done under WLOCK.
116 * "value" field has to be copied to new entry in @add callback.
117 * Buffer ta_buf of size ta->ta_buf_sz may be used to store
122 * -prepare_del: request to set state for deleting existing entry.
123 * typedef int (ta_prepare_del)(struct ip_fw_chain *ch, struct tentry_info *tei,
125 * MANDATORY, locked, UH. (M_NOWAIT). Returns 0 on success.
127 * Buffer ta_buf of size ta->ta_buf_sz may be used to store
128 * allocated state. Caller should use on-stack ta_buf allocation
129 * instead of doing malloc().
133 * -add: request to insert new entry into runtime/config structures.
134 * typedef int (ta_add)(void *ta_state, struct table_info *ti,
135 * struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
136 * MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success.
138 * Insert new entry using previously-allocated state in @ta_buf.
139 * * @tei may have the following flags:
140 * TEI_FLAGS_UPDATE: request to add or update entry.
141 * TEI_FLAGS_DONTADD: request to update (but not add) entry.
142 * * Caller is required to do the following:
143 * copy real entry value from @tei
144 * entry added: return 0, set 1 to @pnum
145 * entry updated: return 0, store 0 to @pnum, store old value in @tei,
146 * add TEI_FLAGS_UPDATED flag to @tei.
147 * entry exists: return EEXIST
148 * entry not found: return ENOENT
149 * other error: return non-zero error code.
153 * -del: request to delete existing entry from runtime/config structures.
154 * typedef int (ta_del)(void *ta_state, struct table_info *ti,
155 * struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
156 * MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success.
158 * Delete entry using previously set up in @ta_buf.
159 * * Caller is required to do the following:
160 * entry deleted: return 0, set 1 to @pnum, store old value in @tei.
161 * entry not found: return ENOENT
162 * other error: return non-zero error code.
166 * -flush_entry: flush entry state created by -prepare_add / -del / others
167 * typedef void (ta_flush_entry)(struct ip_fw_chain *ch,
168 * struct tentry_info *tei, void *ta_buf);
169 * MANDATORY, may be locked. (M_NOWAIT).
171 * Delete state allocated by:
172 * -prepare_add (-add returned EEXIST|UPDATED)
173 * -prepare_del (if any)
175 * * Caller is required to handle empty @ta_buf correctly.
178 * -find_tentry: finds entry specified by key @tei
179 * typedef int ta_find_tentry(void *ta_state, struct table_info *ti,
180 * ipfw_obj_tentry *tent);
181 * OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 on success.
183 * Finds entry specified by given key.
184 * * Caller is required to do the following:
185 * entry found: returns 0, export entry to @tent
186 * entry not found: returns ENOENT
189 * -need_modify: checks if @ti has enough space to hold another @count items.
190 * typedef int (ta_need_modify)(void *ta_state, struct table_info *ti,
191 * uint32_t count, uint64_t *pflags);
192 * OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 if has.
194 * Checks if given table has enough space to add @count items without
195 * resize. Caller may use @pflags to store desired modification data.
199 * -prepare_mod: allocate structures for table modification.
200 * typedef int (ta_prepare_mod)(void *ta_buf, uint64_t *pflags);
201 * OPTIONAL(need_modify), unlocked. (M_WAITOK). Returns 0 on success.
203 * Allocate all needed state for table modification. Caller
204 * should use `struct mod_item` to store new state in @ta_buf.
205 * Up to TA_BUF_SZ (128 bytes) can be stored in @ta_buf.
209 * -fill_mod: copy some data to new state/
210 * typedef int (ta_fill_mod)(void *ta_state, struct table_info *ti,
211 * void *ta_buf, uint64_t *pflags);
212 * OPTIONAL(need_modify), locked (UH). (M_NOWAIT). Returns 0 on success.
214 * Copy as much data as we can to minimize changes under WLOCK.
215 * For example, array can be merged inside this callback.
219 * -modify: perform final modification.
220 * typedef void (ta_modify)(void *ta_state, struct table_info *ti,
221 * void *ta_buf, uint64_t pflags);
222 * OPTIONAL(need_modify), locked (UH+WLOCK). (M_NOWAIT).
224 * Performs all changes necessary to switch to new structures.
225 * * Caller should save old pointers to @ta_buf storage.
229 * -flush_mod: flush table modification state.
230 * typedef void (ta_flush_mod)(void *ta_buf);
231 * OPTIONAL(need_modify), unlocked. (M_WAITOK).
233 * Performs flush for the following:
234 * - prepare_mod (modification was not necessary)
235 * - modify (for the old state)
239 * -change_gi: monitor table info pointer changes
240 * typedef void (ta_change_ti)(void *ta_state, struct table_info *ti);
241 * OPTIONAL, locked (UH). (M_NOWAIT).
243 * Called on @ti pointer changed. Called immediately after -init
244 * to set initial state.
248 * -foreach: calls @f for each table entry
249 * typedef void ta_foreach(void *ta_state, struct table_info *ti,
250 * ta_foreach_f *f, void *arg);
251 * MANDATORY, locked(UH). (M_NOWAIT).
253 * Runs callback with specified argument for each table entry,
254 * Typically used for dumping table entries.
258 * -dump_tentry: dump table entry in current @tentry format.
259 * typedef int ta_dump_tentry(void *ta_state, struct table_info *ti, void *e,
260 * ipfw_obj_tentry *tent);
261 * MANDATORY, locked(UH). (M_NOWAIT). Returns 0 on success.
263 * Dumps entry @e to @tent.
266 * -print_config: prints custom algorithm options into buffer.
267 * typedef void (ta_print_config)(void *ta_state, struct table_info *ti,
268 * char *buf, size_t bufsize);
269 * OPTIONAL. locked(UH). (M_NOWAIT).
271 * Prints custom algorithm options in the format suitable to pass
272 * back to -init callback.
276 * -dump_tinfo: dumps algo-specific info.
277 * typedef void ta_dump_tinfo(void *ta_state, struct table_info *ti,
278 * ipfw_ta_tinfo *tinfo);
279 * OPTIONAL. locked(UH). (M_NOWAIT).
281 * Dumps options like items size/hash size, etc.
284 MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
287 * Utility structures/functions common to more than one algo
297 static int badd(const void *key, void *item, void *base, size_t nmemb,
298 size_t size, int (*compar) (const void *, const void *));
299 static int bdel(const void *key, void *base, size_t nmemb, size_t size,
300 int (*compar) (const void *, const void *));
303 * ADDR implementation using radix
308 * The radix code expects addr and mask to be array of bytes,
309 * with the first byte being the length of the array. rn_inithead
310 * is called with the offset in bits of the lookup key within the
311 * array. If we use a sockaddr_in as the underlying type,
312 * sin_len is conveniently located at offset 0, sin_addr is at
313 * offset 4 and normally aligned.
314 * But for portability, let's avoid assumption and make the code explicit
316 #define KEY_LEN(v) *((uint8_t *)&(v))
318 * Do not require radix to compare more than actual IPv4/IPv6 address
320 #define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t))
321 #define KEY_LEN_INET6 (offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr))
323 #define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr))
324 #define OFF_LEN_INET6 (8 * offsetof(struct sa_in6, sin6_addr))
326 struct radix_addr_entry {
327 struct radix_node rn[2];
328 struct sockaddr_in addr;
337 struct in6_addr sin6_addr;
340 struct radix_addr_xentry {
341 struct radix_node rn[2];
348 struct radix_node_head *head4;
349 struct radix_node_head *head6;
357 struct sockaddr *addr_ptr;
358 struct sockaddr *mask_ptr;
361 struct sockaddr_in sa;
362 struct sockaddr_in ma;
371 static int ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
373 static int ta_init_radix(struct ip_fw_chain *ch, void **ta_state,
374 struct table_info *ti, char *data, uint8_t tflags);
375 static int flush_radix_entry(struct radix_node *rn, void *arg);
376 static void ta_destroy_radix(void *ta_state, struct table_info *ti);
377 static void ta_dump_radix_tinfo(void *ta_state, struct table_info *ti,
378 ipfw_ta_tinfo *tinfo);
379 static int ta_dump_radix_tentry(void *ta_state, struct table_info *ti,
380 void *e, ipfw_obj_tentry *tent);
381 static int ta_find_radix_tentry(void *ta_state, struct table_info *ti,
382 ipfw_obj_tentry *tent);
383 static void ta_foreach_radix(void *ta_state, struct table_info *ti,
384 ta_foreach_f *f, void *arg);
385 static void tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa,
386 struct sockaddr *ma, int *set_mask);
387 static int ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
389 static int ta_add_radix(void *ta_state, struct table_info *ti,
390 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
391 static int ta_prepare_del_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
393 static int ta_del_radix(void *ta_state, struct table_info *ti,
394 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
395 static void ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
397 static int ta_need_modify_radix(void *ta_state, struct table_info *ti,
398 uint32_t count, uint64_t *pflags);
401 ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen,
404 struct radix_node_head *rnh;
406 if (keylen == sizeof(in_addr_t)) {
407 struct radix_addr_entry *ent;
408 struct sockaddr_in sa;
409 KEY_LEN(sa) = KEY_LEN_INET;
410 sa.sin_addr.s_addr = *((in_addr_t *)key);
411 rnh = (struct radix_node_head *)ti->state;
412 ent = (struct radix_addr_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh));
418 struct radix_addr_xentry *xent;
420 KEY_LEN(sa6) = KEY_LEN_INET6;
421 memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
422 rnh = (struct radix_node_head *)ti->xstate;
423 xent = (struct radix_addr_xentry *)(rnh->rnh_matchaddr(&sa6, &rnh->rh));
437 ta_init_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
438 char *data, uint8_t tflags)
440 struct radix_cfg *cfg;
442 if (!rn_inithead(&ti->state, OFF_LEN_INET))
444 if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) {
445 rn_detachhead(&ti->state);
449 cfg = malloc(sizeof(struct radix_cfg), M_IPFW, M_WAITOK | M_ZERO);
452 ti->lookup = ta_lookup_radix;
458 flush_radix_entry(struct radix_node *rn, void *arg)
460 struct radix_node_head * const rnh = arg;
461 struct radix_addr_entry *ent;
463 ent = (struct radix_addr_entry *)
464 rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, &rnh->rh);
466 free(ent, M_IPFW_TBL);
471 ta_destroy_radix(void *ta_state, struct table_info *ti)
473 struct radix_cfg *cfg;
474 struct radix_node_head *rnh;
476 cfg = (struct radix_cfg *)ta_state;
478 rnh = (struct radix_node_head *)(ti->state);
479 rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
480 rn_detachhead(&ti->state);
482 rnh = (struct radix_node_head *)(ti->xstate);
483 rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
484 rn_detachhead(&ti->xstate);
490 * Provide algo-specific table info
493 ta_dump_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
495 struct radix_cfg *cfg;
497 cfg = (struct radix_cfg *)ta_state;
499 tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
500 tinfo->taclass4 = IPFW_TACLASS_RADIX;
501 tinfo->count4 = cfg->count4;
502 tinfo->itemsize4 = sizeof(struct radix_addr_entry);
503 tinfo->taclass6 = IPFW_TACLASS_RADIX;
504 tinfo->count6 = cfg->count6;
505 tinfo->itemsize6 = sizeof(struct radix_addr_xentry);
509 ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e,
510 ipfw_obj_tentry *tent)
512 struct radix_addr_entry *n;
514 struct radix_addr_xentry *xn;
517 n = (struct radix_addr_entry *)e;
519 /* Guess IPv4/IPv6 radix by sockaddr family */
520 if (n->addr.sin_family == AF_INET) {
521 tent->k.addr.s_addr = n->addr.sin_addr.s_addr;
522 tent->masklen = n->masklen;
523 tent->subtype = AF_INET;
524 tent->v.kidx = n->value;
527 xn = (struct radix_addr_xentry *)e;
528 memcpy(&tent->k.addr6, &xn->addr6.sin6_addr,
529 sizeof(struct in6_addr));
530 tent->masklen = xn->masklen;
531 tent->subtype = AF_INET6;
532 tent->v.kidx = xn->value;
540 ta_find_radix_tentry(void *ta_state, struct table_info *ti,
541 ipfw_obj_tentry *tent)
543 struct radix_node_head *rnh;
547 if (tent->subtype == AF_INET) {
548 struct sockaddr_in sa;
549 KEY_LEN(sa) = KEY_LEN_INET;
550 sa.sin_addr.s_addr = tent->k.addr.s_addr;
551 rnh = (struct radix_node_head *)ti->state;
552 e = rnh->rnh_matchaddr(&sa, &rnh->rh);
555 KEY_LEN(sa6) = KEY_LEN_INET6;
556 memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr));
557 rnh = (struct radix_node_head *)ti->xstate;
558 e = rnh->rnh_matchaddr(&sa6, &rnh->rh);
562 ta_dump_radix_tentry(ta_state, ti, e, tent);
570 ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
573 struct radix_node_head *rnh;
575 rnh = (struct radix_node_head *)(ti->state);
576 rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg);
578 rnh = (struct radix_node_head *)(ti->xstate);
579 rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg);
583 static inline void ipv6_writemask(struct in6_addr *addr6, uint8_t mask);
586 ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
590 for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32)
593 *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
598 tei_to_sockaddr_ent(struct tentry_info *tei, struct sockaddr *sa,
599 struct sockaddr *ma, int *set_mask)
603 struct sockaddr_in *addr, *mask;
606 struct sa_in6 *addr6, *mask6;
612 if (tei->subtype == AF_INET) {
614 addr = (struct sockaddr_in *)sa;
615 mask = (struct sockaddr_in *)ma;
616 /* Set 'total' structure length */
617 KEY_LEN(*addr) = KEY_LEN_INET;
618 KEY_LEN(*mask) = KEY_LEN_INET;
619 addr->sin_family = AF_INET;
620 mask->sin_addr.s_addr =
621 htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
622 a4 = *((in_addr_t *)tei->paddr);
623 addr->sin_addr.s_addr = a4 & mask->sin_addr.s_addr;
630 } else if (tei->subtype == AF_INET6) {
632 addr6 = (struct sa_in6 *)sa;
633 mask6 = (struct sa_in6 *)ma;
634 /* Set 'total' structure length */
635 KEY_LEN(*addr6) = KEY_LEN_INET6;
636 KEY_LEN(*mask6) = KEY_LEN_INET6;
637 addr6->sin6_family = AF_INET6;
638 ipv6_writemask(&mask6->sin6_addr, mlen);
639 memcpy(&addr6->sin6_addr, tei->paddr, sizeof(struct in6_addr));
640 APPLY_MASK(&addr6->sin6_addr, &mask6->sin6_addr);
650 ta_prepare_add_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
653 struct ta_buf_radix *tb;
654 struct radix_addr_entry *ent;
656 struct radix_addr_xentry *xent;
658 struct sockaddr *addr, *mask;
661 tb = (struct ta_buf_radix *)ta_buf;
666 if (tei->subtype == AF_INET) {
670 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
673 addr = (struct sockaddr *)&ent->addr;
674 mask = (struct sockaddr *)&tb->addr.a4.ma;
678 } else if (tei->subtype == AF_INET6) {
682 xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
683 xent->masklen = mlen;
685 addr = (struct sockaddr *)&xent->addr6;
686 mask = (struct sockaddr *)&tb->addr.a6.ma;
690 /* Unknown CIDR type */
694 tei_to_sockaddr_ent(tei, addr, mask, &set_mask);
704 ta_add_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
705 void *ta_buf, uint32_t *pnum)
707 struct radix_cfg *cfg;
708 struct radix_node_head *rnh;
709 struct radix_node *rn;
710 struct ta_buf_radix *tb;
711 uint32_t *old_value, value;
713 cfg = (struct radix_cfg *)ta_state;
714 tb = (struct ta_buf_radix *)ta_buf;
716 /* Save current entry value from @tei */
717 if (tei->subtype == AF_INET) {
719 ((struct radix_addr_entry *)tb->ent_ptr)->value = tei->value;
722 ((struct radix_addr_xentry *)tb->ent_ptr)->value = tei->value;
725 /* Search for an entry first */
726 rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
728 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
730 /* Record already exists. Update value if we're asked to */
731 if (tei->subtype == AF_INET)
732 old_value = &((struct radix_addr_entry *)rn)->value;
734 old_value = &((struct radix_addr_xentry *)rn)->value;
737 *old_value = tei->value;
740 /* Indicate that update has happened instead of addition */
741 tei->flags |= TEI_FLAGS_UPDATED;
747 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
750 rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, &rnh->rh,tb->ent_ptr);
756 if (tei->subtype == AF_INET)
767 ta_prepare_del_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
770 struct ta_buf_radix *tb;
771 struct sockaddr *addr, *mask;
774 tb = (struct ta_buf_radix *)ta_buf;
779 if (tei->subtype == AF_INET) {
783 addr = (struct sockaddr *)&tb->addr.a4.sa;
784 mask = (struct sockaddr *)&tb->addr.a4.ma;
786 } else if (tei->subtype == AF_INET6) {
790 addr = (struct sockaddr *)&tb->addr.a6.sa;
791 mask = (struct sockaddr *)&tb->addr.a6.ma;
796 tei_to_sockaddr_ent(tei, addr, mask, &set_mask);
805 ta_del_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
806 void *ta_buf, uint32_t *pnum)
808 struct radix_cfg *cfg;
809 struct radix_node_head *rnh;
810 struct radix_node *rn;
811 struct ta_buf_radix *tb;
813 cfg = (struct radix_cfg *)ta_state;
814 tb = (struct ta_buf_radix *)ta_buf;
816 if (tei->subtype == AF_INET)
821 rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
826 /* Save entry value to @tei */
827 if (tei->subtype == AF_INET)
828 tei->value = ((struct radix_addr_entry *)rn)->value;
830 tei->value = ((struct radix_addr_xentry *)rn)->value;
834 if (tei->subtype == AF_INET)
844 ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
847 struct ta_buf_radix *tb;
849 tb = (struct ta_buf_radix *)ta_buf;
851 if (tb->ent_ptr != NULL)
852 free(tb->ent_ptr, M_IPFW_TBL);
856 ta_need_modify_radix(void *ta_state, struct table_info *ti, uint32_t count,
861 * radix does not require additional memory allocations
862 * other than nodes itself. Adding new masks to the tree do
863 * but we don't have any API to call (and we don't known which
869 struct table_algo addr_radix = {
870 .name = "addr:radix",
871 .type = IPFW_TABLE_ADDR,
872 .flags = TA_FLAG_DEFAULT,
873 .ta_buf_size = sizeof(struct ta_buf_radix),
874 .init = ta_init_radix,
875 .destroy = ta_destroy_radix,
876 .prepare_add = ta_prepare_add_radix,
877 .prepare_del = ta_prepare_del_radix,
880 .flush_entry = ta_flush_radix_entry,
881 .foreach = ta_foreach_radix,
882 .dump_tentry = ta_dump_radix_tentry,
883 .find_tentry = ta_find_radix_tentry,
884 .dump_tinfo = ta_dump_radix_tinfo,
885 .need_modify = ta_need_modify_radix,
893 * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
896 * inv.mask4: 32 - mask
898 * 1) _slow lookup: mask
899 * 2) _aligned: (128 - mask) / 8
910 SLIST_HEAD(chashbhead, chashentry);
913 struct chashbhead *head4;
914 struct chashbhead *head6;
924 SLIST_ENTRY(chashentry) next;
928 uint32_t a4; /* Host format */
929 struct in6_addr a6; /* Network format */
936 struct chashentry ent;
940 static __inline uint32_t hash_ip(uint32_t addr, int hsize);
943 static __inline uint32_t hash_ip6(struct in6_addr *addr6, int hsize);
944 static __inline uint16_t hash_ip64(struct in6_addr *addr6, int hsize);
945 static __inline uint32_t hash_ip6_slow(struct in6_addr *addr6, void *key,
946 int mask, int hsize);
947 static __inline uint32_t hash_ip6_al(struct in6_addr *addr6, void *key, int mask,
950 static int ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
952 static int ta_lookup_chash_aligned(struct table_info *ti, void *key,
953 uint32_t keylen, uint32_t *val);
954 static int ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
956 static int chash_parse_opts(struct chash_cfg *cfg, char *data);
957 static void ta_print_chash_config(void *ta_state, struct table_info *ti,
958 char *buf, size_t bufsize);
959 static int ta_log2(uint32_t v);
960 static int ta_init_chash(struct ip_fw_chain *ch, void **ta_state,
961 struct table_info *ti, char *data, uint8_t tflags);
962 static void ta_destroy_chash(void *ta_state, struct table_info *ti);
963 static void ta_dump_chash_tinfo(void *ta_state, struct table_info *ti,
964 ipfw_ta_tinfo *tinfo);
965 static int ta_dump_chash_tentry(void *ta_state, struct table_info *ti,
966 void *e, ipfw_obj_tentry *tent);
967 static uint32_t hash_ent(struct chashentry *ent, int af, int mlen,
969 static int tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent);
970 static int ta_find_chash_tentry(void *ta_state, struct table_info *ti,
971 ipfw_obj_tentry *tent);
972 static void ta_foreach_chash(void *ta_state, struct table_info *ti,
973 ta_foreach_f *f, void *arg);
974 static int ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
976 static int ta_add_chash(void *ta_state, struct table_info *ti,
977 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
978 static int ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
980 static int ta_del_chash(void *ta_state, struct table_info *ti,
981 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
982 static void ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
984 static int ta_need_modify_chash(void *ta_state, struct table_info *ti,
985 uint32_t count, uint64_t *pflags);
986 static int ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags);
987 static int ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf,
989 static void ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf,
991 static void ta_flush_mod_chash(void *ta_buf);
994 static __inline uint32_t
995 hash_ip(uint32_t addr, int hsize)
998 return (addr % (hsize - 1));
1003 static __inline uint32_t
1004 hash_ip6(struct in6_addr *addr6, int hsize)
1008 i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^
1009 addr6->s6_addr32[2] ^ addr6->s6_addr32[3];
1011 return (i % (hsize - 1));
1014 static __inline uint16_t
1015 hash_ip64(struct in6_addr *addr6, int hsize)
1019 i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1];
1021 return (i % (hsize - 1));
1024 static __inline uint32_t
1025 hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize)
1027 struct in6_addr mask6;
1029 ipv6_writemask(&mask6, mask);
1030 memcpy(addr6, key, sizeof(struct in6_addr));
1031 APPLY_MASK(addr6, &mask6);
1032 return (hash_ip6(addr6, hsize));
1035 static __inline uint32_t
1036 hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize)
1040 paddr = (uint64_t *)addr6;
1043 memcpy(addr6, key, mask);
1044 return (hash_ip6(addr6, hsize));
1049 ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
1052 struct chashbhead *head;
1053 struct chashentry *ent;
1054 uint16_t hash, hsize;
1057 if (keylen == sizeof(in_addr_t)) {
1059 head = (struct chashbhead *)ti->state;
1060 imask = ti->data >> 24;
1061 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
1063 a = ntohl(*((in_addr_t *)key));
1065 hash = hash_ip(a, hsize);
1066 SLIST_FOREACH(ent, &head[hash], next) {
1067 if (ent->a.a4 == a) {
1075 /* IPv6: worst scenario: non-round mask */
1076 struct in6_addr addr6;
1077 head = (struct chashbhead *)ti->xstate;
1078 imask = (ti->data & 0xFF0000) >> 16;
1079 hsize = 1 << (ti->data & 0xFF);
1080 hash = hash_ip6_slow(&addr6, key, imask, hsize);
1081 SLIST_FOREACH(ent, &head[hash], next) {
1082 if (memcmp(&ent->a.a6, &addr6, 16) == 0) {
1094 ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
1097 struct chashbhead *head;
1098 struct chashentry *ent;
1099 uint16_t hash, hsize;
1102 if (keylen == sizeof(in_addr_t)) {
1104 head = (struct chashbhead *)ti->state;
1105 imask = ti->data >> 24;
1106 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
1108 a = ntohl(*((in_addr_t *)key));
1110 hash = hash_ip(a, hsize);
1111 SLIST_FOREACH(ent, &head[hash], next) {
1112 if (ent->a.a4 == a) {
1120 /* IPv6: aligned to 8bit mask */
1121 struct in6_addr addr6;
1122 uint64_t *paddr, *ptmp;
1123 head = (struct chashbhead *)ti->xstate;
1124 imask = (ti->data & 0xFF0000) >> 16;
1125 hsize = 1 << (ti->data & 0xFF);
1127 hash = hash_ip6_al(&addr6, key, imask, hsize);
1128 paddr = (uint64_t *)&addr6;
1129 SLIST_FOREACH(ent, &head[hash], next) {
1130 ptmp = (uint64_t *)&ent->a.a6;
1131 if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) {
1143 ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
1146 struct chashbhead *head;
1147 struct chashentry *ent;
1148 uint16_t hash, hsize;
1151 if (keylen == sizeof(in_addr_t)) {
1153 head = (struct chashbhead *)ti->state;
1154 imask = ti->data >> 24;
1155 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
1157 a = ntohl(*((in_addr_t *)key));
1159 hash = hash_ip(a, hsize);
1160 SLIST_FOREACH(ent, &head[hash], next) {
1161 if (ent->a.a4 == a) {
1170 uint64_t a6, *paddr;
1171 head = (struct chashbhead *)ti->xstate;
1172 paddr = (uint64_t *)key;
1173 hsize = 1 << (ti->data & 0xFF);
1175 hash = hash_ip64((struct in6_addr *)key, hsize);
1176 SLIST_FOREACH(ent, &head[hash], next) {
1177 paddr = (uint64_t *)&ent->a.a6;
1190 chash_parse_opts(struct chash_cfg *cfg, char *data)
1192 char *pdel, *pend, *s;
1200 if ((pdel = strchr(data, ' ')) == NULL)
1202 while (*pdel == ' ')
1204 if (strncmp(pdel, "masks=", 6) != 0)
1206 if ((s = strchr(pdel, ' ')) != NULL)
1210 /* Need /XX[,/YY] */
1213 mask4 = strtol(pdel, &pend, 10);
1219 mask6 = strtol(pdel, &pend, 10);
1222 } else if (*pend != '\0')
1225 if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128)
1235 ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf,
1238 struct chash_cfg *cfg;
1240 cfg = (struct chash_cfg *)ta_state;
1242 if (cfg->mask4 != 32 || cfg->mask6 != 128)
1243 snprintf(buf, bufsize, "%s masks=/%d,/%d", "addr:hash",
1244 cfg->mask4, cfg->mask6);
1246 snprintf(buf, bufsize, "%s", "addr:hash");
1263 * We assume 'data' to be either NULL or the following format:
1264 * 'addr:hash [masks=/32[,/128]]'
1267 ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
1268 char *data, uint8_t tflags)
1272 struct chash_cfg *cfg;
1274 cfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO);
1279 if ((error = chash_parse_opts(cfg, data)) != 0) {
1287 cfg->head4 = malloc(sizeof(struct chashbhead) * cfg->size4, M_IPFW,
1289 cfg->head6 = malloc(sizeof(struct chashbhead) * cfg->size6, M_IPFW,
1291 for (i = 0; i < cfg->size4; i++)
1292 SLIST_INIT(&cfg->head4[i]);
1293 for (i = 0; i < cfg->size6; i++)
1294 SLIST_INIT(&cfg->head6[i]);
1297 ti->state = cfg->head4;
1298 ti->xstate = cfg->head6;
1300 /* Store data depending on v6 mask length */
1301 hsize = ta_log2(cfg->size4) << 8 | ta_log2(cfg->size6);
1302 if (cfg->mask6 == 64) {
1303 ti->data = (32 - cfg->mask4) << 24 | (128 - cfg->mask6) << 16|
1305 ti->lookup = ta_lookup_chash_64;
1306 } else if ((cfg->mask6 % 8) == 0) {
1307 ti->data = (32 - cfg->mask4) << 24 |
1308 cfg->mask6 << 13 | hsize;
1309 ti->lookup = ta_lookup_chash_aligned;
1311 /* don't do that! */
1312 ti->data = (32 - cfg->mask4) << 24 |
1313 cfg->mask6 << 16 | hsize;
1314 ti->lookup = ta_lookup_chash_slow;
1321 ta_destroy_chash(void *ta_state, struct table_info *ti)
1323 struct chash_cfg *cfg;
1324 struct chashentry *ent, *ent_next;
1327 cfg = (struct chash_cfg *)ta_state;
1329 for (i = 0; i < cfg->size4; i++)
1330 SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next)
1331 free(ent, M_IPFW_TBL);
1333 for (i = 0; i < cfg->size6; i++)
1334 SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next)
1335 free(ent, M_IPFW_TBL);
1337 free(cfg->head4, M_IPFW);
1338 free(cfg->head6, M_IPFW);
1344 ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
1346 struct chash_cfg *cfg;
1348 cfg = (struct chash_cfg *)ta_state;
1350 tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
1351 tinfo->taclass4 = IPFW_TACLASS_HASH;
1352 tinfo->size4 = cfg->size4;
1353 tinfo->count4 = cfg->items4;
1354 tinfo->itemsize4 = sizeof(struct chashentry);
1355 tinfo->taclass6 = IPFW_TACLASS_HASH;
1356 tinfo->size6 = cfg->size6;
1357 tinfo->count6 = cfg->items6;
1358 tinfo->itemsize6 = sizeof(struct chashentry);
1362 ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e,
1363 ipfw_obj_tentry *tent)
1365 struct chash_cfg *cfg;
1366 struct chashentry *ent;
1368 cfg = (struct chash_cfg *)ta_state;
1369 ent = (struct chashentry *)e;
1371 if (ent->type == AF_INET) {
1372 tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - cfg->mask4));
1373 tent->masklen = cfg->mask4;
1374 tent->subtype = AF_INET;
1375 tent->v.kidx = ent->value;
1378 memcpy(&tent->k.addr6, &ent->a.a6, sizeof(struct in6_addr));
1379 tent->masklen = cfg->mask6;
1380 tent->subtype = AF_INET6;
1381 tent->v.kidx = ent->value;
1389 hash_ent(struct chashentry *ent, int af, int mlen, uint32_t size)
1395 if (af == AF_INET) {
1397 hash = hash_ip(ent->a.a4, size);
1402 hash = hash_ip64(&ent->a.a6, size);
1404 hash = hash_ip6(&ent->a.a6, size);
1412 tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent)
1416 struct in6_addr mask6;
1419 mlen = tei->masklen;
1421 if (tei->subtype == AF_INET) {
1425 ent->type = AF_INET;
1427 /* Calculate masked address */
1428 ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
1431 } else if (tei->subtype == AF_INET6) {
1435 ent->type = AF_INET6;
1437 ipv6_writemask(&mask6, mlen);
1438 memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr));
1439 APPLY_MASK(&ent->a.a6, &mask6);
1442 /* Unknown CIDR type */
1450 ta_find_chash_tentry(void *ta_state, struct table_info *ti,
1451 ipfw_obj_tentry *tent)
1453 struct chash_cfg *cfg;
1454 struct chashbhead *head;
1455 struct chashentry ent, *tmp;
1456 struct tentry_info tei;
1460 cfg = (struct chash_cfg *)ta_state;
1462 memset(&ent, 0, sizeof(ent));
1463 memset(&tei, 0, sizeof(tei));
1465 if (tent->subtype == AF_INET) {
1466 tei.paddr = &tent->k.addr;
1467 tei.masklen = cfg->mask4;
1468 tei.subtype = AF_INET;
1470 if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
1474 hash = hash_ent(&ent, AF_INET, cfg->mask4, cfg->size4);
1475 /* Check for existence */
1476 SLIST_FOREACH(tmp, &head[hash], next) {
1477 if (tmp->a.a4 != ent.a.a4)
1480 ta_dump_chash_tentry(ta_state, ti, tmp, tent);
1484 tei.paddr = &tent->k.addr6;
1485 tei.masklen = cfg->mask6;
1486 tei.subtype = AF_INET6;
1488 if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
1492 hash = hash_ent(&ent, AF_INET6, cfg->mask6, cfg->size6);
1493 /* Check for existence */
1494 SLIST_FOREACH(tmp, &head[hash], next) {
1495 if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0)
1497 ta_dump_chash_tentry(ta_state, ti, tmp, tent);
1506 ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
1509 struct chash_cfg *cfg;
1510 struct chashentry *ent, *ent_next;
1513 cfg = (struct chash_cfg *)ta_state;
1515 for (i = 0; i < cfg->size4; i++)
1516 SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next)
1519 for (i = 0; i < cfg->size6; i++)
1520 SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next)
1525 ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
1528 struct ta_buf_chash *tb;
1529 struct chashentry *ent;
1532 tb = (struct ta_buf_chash *)ta_buf;
1534 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
1536 error = tei_to_chash_ent(tei, ent);
1538 free(ent, M_IPFW_TBL);
1547 ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1548 void *ta_buf, uint32_t *pnum)
1550 struct chash_cfg *cfg;
1551 struct chashbhead *head;
1552 struct chashentry *ent, *tmp;
1553 struct ta_buf_chash *tb;
1555 uint32_t hash, value;
1557 cfg = (struct chash_cfg *)ta_state;
1558 tb = (struct ta_buf_chash *)ta_buf;
1559 ent = (struct chashentry *)tb->ent_ptr;
1563 /* Read current value from @tei */
1564 ent->value = tei->value;
1566 /* Read cuurrent value */
1567 if (tei->subtype == AF_INET) {
1568 if (tei->masklen != cfg->mask4)
1571 hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4);
1573 /* Check for existence */
1574 SLIST_FOREACH(tmp, &head[hash], next) {
1575 if (tmp->a.a4 == ent->a.a4) {
1581 if (tei->masklen != cfg->mask6)
1584 hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6);
1585 /* Check for existence */
1586 SLIST_FOREACH(tmp, &head[hash], next) {
1587 if (memcmp(&tmp->a.a6, &ent->a.a6, 16) == 0) {
1595 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
1597 /* Record already exists. Update value if we're asked to */
1599 tmp->value = tei->value;
1601 /* Indicate that update has happened instead of addition */
1602 tei->flags |= TEI_FLAGS_UPDATED;
1605 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
1607 SLIST_INSERT_HEAD(&head[hash], ent, next);
1611 /* Update counters */
1612 if (tei->subtype == AF_INET)
1622 ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
1625 struct ta_buf_chash *tb;
1627 tb = (struct ta_buf_chash *)ta_buf;
1629 return (tei_to_chash_ent(tei, &tb->ent));
1633 ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1634 void *ta_buf, uint32_t *pnum)
1636 struct chash_cfg *cfg;
1637 struct chashbhead *head;
1638 struct chashentry *tmp, *tmp_next, *ent;
1639 struct ta_buf_chash *tb;
1642 cfg = (struct chash_cfg *)ta_state;
1643 tb = (struct ta_buf_chash *)ta_buf;
1646 if (tei->subtype == AF_INET) {
1647 if (tei->masklen != cfg->mask4)
1650 hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4);
1652 SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) {
1653 if (tmp->a.a4 != ent->a.a4)
1656 SLIST_REMOVE(&head[hash], tmp, chashentry, next);
1659 tei->value = tmp->value;
1664 if (tei->masklen != cfg->mask6)
1667 hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6);
1668 SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) {
1669 if (memcmp(&tmp->a.a6, &ent->a.a6, 16) != 0)
1672 SLIST_REMOVE(&head[hash], tmp, chashentry, next);
1675 tei->value = tmp->value;
1685 ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
1688 struct ta_buf_chash *tb;
1690 tb = (struct ta_buf_chash *)ta_buf;
1692 if (tb->ent_ptr != NULL)
1693 free(tb->ent_ptr, M_IPFW_TBL);
1697 * Hash growing callbacks.
1701 ta_need_modify_chash(void *ta_state, struct table_info *ti, uint32_t count,
1704 struct chash_cfg *cfg;
1708 * Since we don't know exact number of IPv4/IPv6 records in @count,
1709 * ignore non-zero @count value at all. Check current hash sizes
1710 * and return appropriate data.
1713 cfg = (struct chash_cfg *)ta_state;
1716 if (cfg->items4 > cfg->size4 && cfg->size4 < 65536)
1717 data |= (cfg->size4 * 2) << 16;
1718 if (cfg->items6 > cfg->size6 && cfg->size6 < 65536)
1719 data |= cfg->size6 * 2;
1730 * Allocate new, larger chash.
1733 ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags)
1735 struct mod_item *mi;
1736 struct chashbhead *head;
1739 mi = (struct mod_item *)ta_buf;
1741 memset(mi, 0, sizeof(struct mod_item));
1742 mi->size = (*pflags >> 16) & 0xFFFF;
1743 mi->size6 = *pflags & 0xFFFF;
1745 head = malloc(sizeof(struct chashbhead) * mi->size,
1746 M_IPFW, M_WAITOK | M_ZERO);
1747 for (i = 0; i < mi->size; i++)
1748 SLIST_INIT(&head[i]);
1749 mi->main_ptr = head;
1752 if (mi->size6 > 0) {
1753 head = malloc(sizeof(struct chashbhead) * mi->size6,
1754 M_IPFW, M_WAITOK | M_ZERO);
1755 for (i = 0; i < mi->size6; i++)
1756 SLIST_INIT(&head[i]);
1757 mi->main_ptr6 = head;
1764 * Copy data from old runtime array to new one.
1767 ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1771 /* In is not possible to do rehash if we're not holidng WLOCK. */
1776 * Switch old & new arrays.
1779 ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1782 struct mod_item *mi;
1783 struct chash_cfg *cfg;
1784 struct chashbhead *old_head, *new_head;
1785 struct chashentry *ent, *ent_next;
1788 size_t old_size, new_size;
1790 mi = (struct mod_item *)ta_buf;
1791 cfg = (struct chash_cfg *)ta_state;
1793 /* Check which hash we need to grow and do we still need that */
1794 if (mi->size > 0 && cfg->size4 < mi->size) {
1795 new_head = (struct chashbhead *)mi->main_ptr;
1796 new_size = mi->size;
1797 old_size = cfg->size4;
1798 old_head = ti->state;
1802 for (i = 0; i < old_size; i++) {
1803 SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
1804 nhash = hash_ent(ent, af, mlen, new_size);
1805 SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
1809 ti->state = new_head;
1810 cfg->head4 = new_head;
1811 cfg->size4 = mi->size;
1812 mi->main_ptr = old_head;
1815 if (mi->size6 > 0 && cfg->size6 < mi->size6) {
1816 new_head = (struct chashbhead *)mi->main_ptr6;
1817 new_size = mi->size6;
1818 old_size = cfg->size6;
1819 old_head = ti->xstate;
1823 for (i = 0; i < old_size; i++) {
1824 SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
1825 nhash = hash_ent(ent, af, mlen, new_size);
1826 SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
1830 ti->xstate = new_head;
1831 cfg->head6 = new_head;
1832 cfg->size6 = mi->size6;
1833 mi->main_ptr6 = old_head;
1836 /* Update lower 32 bits with new values */
1837 ti->data &= 0xFFFFFFFF00000000;
1838 ti->data |= ta_log2(cfg->size4) << 8 | ta_log2(cfg->size6);
1842 * Free unneded array.
1845 ta_flush_mod_chash(void *ta_buf)
1847 struct mod_item *mi;
1849 mi = (struct mod_item *)ta_buf;
1850 if (mi->main_ptr != NULL)
1851 free(mi->main_ptr, M_IPFW);
1852 if (mi->main_ptr6 != NULL)
1853 free(mi->main_ptr6, M_IPFW);
1856 struct table_algo addr_hash = {
1857 .name = "addr:hash",
1858 .type = IPFW_TABLE_ADDR,
1859 .ta_buf_size = sizeof(struct ta_buf_chash),
1860 .init = ta_init_chash,
1861 .destroy = ta_destroy_chash,
1862 .prepare_add = ta_prepare_add_chash,
1863 .prepare_del = ta_prepare_del_chash,
1864 .add = ta_add_chash,
1865 .del = ta_del_chash,
1866 .flush_entry = ta_flush_chash_entry,
1867 .foreach = ta_foreach_chash,
1868 .dump_tentry = ta_dump_chash_tentry,
1869 .find_tentry = ta_find_chash_tentry,
1870 .print_config = ta_print_chash_config,
1871 .dump_tinfo = ta_dump_chash_tinfo,
1872 .need_modify = ta_need_modify_chash,
1873 .prepare_mod = ta_prepare_mod_chash,
1874 .fill_mod = ta_fill_mod_chash,
1875 .modify = ta_modify_chash,
1876 .flush_mod = ta_flush_mod_chash,
1885 * - sorted array of "struct ifidx" pointed by ti->state.
1886 * Array is allocated with rounding up to IFIDX_CHUNK. Only existing
1887 * interfaces are stored in array, however its allocated size is
1888 * sufficient to hold all table records if needed.
1889 * - current array size is stored in ti->data
1892 * - "struct iftable_cfg" is allocated to store table state (ta_state).
1893 * - All table records are stored inside namedobj instance.
1902 #define DEFAULT_IFIDX_SIZE 64
1907 struct named_object no;
1909 struct iftable_cfg *icfg;
1914 struct iftable_cfg {
1915 struct namedobj_instance *ii;
1916 struct ip_fw_chain *ch;
1917 struct table_info *ti;
1919 size_t size; /* Number of items allocated in array */
1920 size_t count; /* Number of all items */
1921 size_t used; /* Number of items _active_ now */
1926 struct ifentry *ife;
1930 int compare_ifidx(const void *k, const void *v);
1931 static struct ifidx * ifidx_find(struct table_info *ti, void *key);
1932 static int ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
1934 static int ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state,
1935 struct table_info *ti, char *data, uint8_t tflags);
1936 static void ta_change_ti_ifidx(void *ta_state, struct table_info *ti);
1937 static int destroy_ifidx_locked(struct namedobj_instance *ii,
1938 struct named_object *no, void *arg);
1939 static void ta_destroy_ifidx(void *ta_state, struct table_info *ti);
1940 static void ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti,
1941 ipfw_ta_tinfo *tinfo);
1942 static int ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
1944 static int ta_add_ifidx(void *ta_state, struct table_info *ti,
1945 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
1946 static int ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
1948 static int ta_del_ifidx(void *ta_state, struct table_info *ti,
1949 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
1950 static void ta_flush_ifidx_entry(struct ip_fw_chain *ch,
1951 struct tentry_info *tei, void *ta_buf);
1952 static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex);
1953 static int ta_need_modify_ifidx(void *ta_state, struct table_info *ti,
1954 uint32_t count, uint64_t *pflags);
1955 static int ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags);
1956 static int ta_fill_mod_ifidx(void *ta_state, struct table_info *ti,
1957 void *ta_buf, uint64_t *pflags);
1958 static void ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
1960 static void ta_flush_mod_ifidx(void *ta_buf);
1961 static int ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
1962 ipfw_obj_tentry *tent);
1963 static int ta_find_ifidx_tentry(void *ta_state, struct table_info *ti,
1964 ipfw_obj_tentry *tent);
1965 static int foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
1967 static void ta_foreach_ifidx(void *ta_state, struct table_info *ti,
1968 ta_foreach_f *f, void *arg);
1971 compare_ifidx(const void *k, const void *v)
1973 const struct ifidx *ifidx;
1976 key = *((const uint16_t *)k);
1977 ifidx = (const struct ifidx *)v;
1979 if (key < ifidx->kidx)
1981 else if (key > ifidx->kidx)
1988 * Adds item @item with key @key into ascending-sorted array @base.
1989 * Assumes @base has enough additional storage.
1991 * Returns 1 on success, 0 on duplicate key.
1994 badd(const void *key, void *item, void *base, size_t nmemb,
1995 size_t size, int (*compar) (const void *, const void *))
1997 int min, max, mid, shift, res;
2001 memcpy(base, item, size);
2009 while (min <= max) {
2010 mid = (min + max) / 2;
2011 res = compar(key, (const void *)((caddr_t)base + mid * size));
2021 /* Item not found. */
2022 res = compar(key, (const void *)((caddr_t)base + mid * size));
2028 paddr = (caddr_t)base + shift * size;
2030 memmove(paddr + size, paddr, (nmemb - shift) * size);
2032 memcpy(paddr, item, size);
2038 * Deletes item with key @key from ascending-sorted array @base.
2040 * Returns 1 on success, 0 for non-existent key.
2043 bdel(const void *key, void *base, size_t nmemb, size_t size,
2044 int (*compar) (const void *, const void *))
2049 item = (caddr_t)bsearch(key, base, nmemb, size, compar);
2054 sz = (caddr_t)base + nmemb * size - item;
2057 memmove(item, item + size, sz);
2062 static struct ifidx *
2063 ifidx_find(struct table_info *ti, void *key)
2067 ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx),
2074 ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
2079 ifi = ifidx_find(ti, key);
2090 ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
2091 char *data, uint8_t tflags)
2093 struct iftable_cfg *icfg;
2095 icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO);
2097 icfg->ii = ipfw_objhash_create(DEFAULT_IFIDX_SIZE);
2098 icfg->size = DEFAULT_IFIDX_SIZE;
2099 icfg->main_ptr = malloc(sizeof(struct ifidx) * icfg->size, M_IPFW,
2104 ti->state = icfg->main_ptr;
2105 ti->lookup = ta_lookup_ifidx;
2111 * Handle tableinfo @ti pointer change (on table array resize).
2114 ta_change_ti_ifidx(void *ta_state, struct table_info *ti)
2116 struct iftable_cfg *icfg;
2118 icfg = (struct iftable_cfg *)ta_state;
2123 destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no,
2126 struct ifentry *ife;
2127 struct ip_fw_chain *ch;
2129 ch = (struct ip_fw_chain *)arg;
2130 ife = (struct ifentry *)no;
2132 ipfw_iface_del_notify(ch, &ife->ic);
2133 ipfw_iface_unref(ch, &ife->ic);
2134 free(ife, M_IPFW_TBL);
2139 * Destroys table @ti
2142 ta_destroy_ifidx(void *ta_state, struct table_info *ti)
2144 struct iftable_cfg *icfg;
2145 struct ip_fw_chain *ch;
2147 icfg = (struct iftable_cfg *)ta_state;
2150 if (icfg->main_ptr != NULL)
2151 free(icfg->main_ptr, M_IPFW);
2154 ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch);
2155 IPFW_UH_WUNLOCK(ch);
2157 ipfw_objhash_destroy(icfg->ii);
2163 * Provide algo-specific table info
2166 ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
2168 struct iftable_cfg *cfg;
2170 cfg = (struct iftable_cfg *)ta_state;
2172 tinfo->taclass4 = IPFW_TACLASS_ARRAY;
2173 tinfo->size4 = cfg->size;
2174 tinfo->count4 = cfg->used;
2175 tinfo->itemsize4 = sizeof(struct ifidx);
2179 * Prepare state to add to the table:
2180 * allocate ifentry and reference needed interface.
2183 ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
2186 struct ta_buf_ifidx *tb;
2188 struct ifentry *ife;
2190 tb = (struct ta_buf_ifidx *)ta_buf;
2192 /* Check if string is terminated */
2193 ifname = (char *)tei->paddr;
2194 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
2197 ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO);
2198 ife->ic.cb = if_notifier;
2199 ife->ic.cbdata = ife;
2201 if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0) {
2202 free(ife, M_IPFW_TBL);
2206 /* Use ipfw_iface 'ifname' field as stable storage */
2207 ife->no.name = ife->ic.iface->ifname;
2215 ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2216 void *ta_buf, uint32_t *pnum)
2218 struct iftable_cfg *icfg;
2219 struct ifentry *ife, *tmp;
2220 struct ta_buf_ifidx *tb;
2221 struct ipfw_iface *iif;
2226 tb = (struct ta_buf_ifidx *)ta_buf;
2227 ifname = (char *)tei->paddr;
2228 icfg = (struct iftable_cfg *)ta_state;
2232 ife->value = tei->value;
2234 tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
2237 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
2240 /* Exchange values in @tmp and @tei */
2242 tmp->value = tei->value;
2245 iif = tmp->ic.iface;
2246 if (iif->resolved != 0) {
2247 /* We have to update runtime value, too */
2248 ifi = ifidx_find(ti, &iif->ifindex);
2249 ifi->value = ife->value;
2252 /* Indicate that update has happened instead of addition */
2253 tei->flags |= TEI_FLAGS_UPDATED;
2258 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
2261 /* Link to internal list */
2262 ipfw_objhash_add(icfg->ii, &ife->no);
2264 /* Link notifier (possible running its callback) */
2265 ipfw_iface_add_notify(icfg->ch, &ife->ic);
2275 * Prepare to delete key from table.
2276 * Do basic interface name checks.
2279 ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
2282 struct ta_buf_ifidx *tb;
2285 tb = (struct ta_buf_ifidx *)ta_buf;
2287 /* Check if string is terminated */
2288 ifname = (char *)tei->paddr;
2289 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
2296 * Remove key from both configuration list and
2297 * runtime array. Removed interface notification.
2300 ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2301 void *ta_buf, uint32_t *pnum)
2303 struct iftable_cfg *icfg;
2304 struct ifentry *ife;
2305 struct ta_buf_ifidx *tb;
2310 tb = (struct ta_buf_ifidx *)ta_buf;
2311 ifname = (char *)tei->paddr;
2312 icfg = (struct iftable_cfg *)ta_state;
2314 ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
2319 if (ife->linked != 0) {
2320 /* We have to remove item from runtime */
2321 ifindex = ife->ic.iface->ifindex;
2323 res = bdel(&ifindex, icfg->main_ptr, icfg->used,
2324 sizeof(struct ifidx), compare_ifidx);
2326 KASSERT(res == 1, ("index %d does not exist", ifindex));
2328 ti->data = icfg->used;
2332 /* Unlink from local list */
2333 ipfw_objhash_del(icfg->ii, &ife->no);
2334 /* Unlink notifier and deref */
2335 ipfw_iface_del_notify(icfg->ch, &ife->ic);
2336 ipfw_iface_unref(icfg->ch, &ife->ic);
2339 tei->value = ife->value;
2348 * Flush deleted entry.
2349 * Drops interface reference and frees entry.
2352 ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
2355 struct ta_buf_ifidx *tb;
2357 tb = (struct ta_buf_ifidx *)ta_buf;
2359 if (tb->ife != NULL)
2360 free(tb->ife, M_IPFW_TBL);
2364 * Handle interface announce/withdrawal for particular table.
2365 * Every real runtime array modification happens here.
2368 if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex)
2370 struct ifentry *ife;
2372 struct iftable_cfg *icfg;
2373 struct table_info *ti;
2376 ife = (struct ifentry *)cbdata;
2380 KASSERT(ti != NULL, ("ti=NULL, check change_ti handler"));
2382 if (ife->linked == 0 && ifindex != 0) {
2383 /* Interface announce */
2386 ifi.value = ife->value;
2387 res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used,
2388 sizeof(struct ifidx), compare_ifidx);
2389 KASSERT(res == 1, ("index %d already exists", ifindex));
2391 ti->data = icfg->used;
2393 } else if (ife->linked != 0 && ifindex == 0) {
2394 /* Interface withdrawal */
2395 ifindex = ife->ic.iface->ifindex;
2397 res = bdel(&ifindex, icfg->main_ptr, icfg->used,
2398 sizeof(struct ifidx), compare_ifidx);
2400 KASSERT(res == 1, ("index %d does not exist", ifindex));
2402 ti->data = icfg->used;
2408 * Table growing callbacks.
2412 ta_need_modify_ifidx(void *ta_state, struct table_info *ti, uint32_t count,
2415 struct iftable_cfg *cfg;
2418 cfg = (struct iftable_cfg *)ta_state;
2421 while (size < cfg->count + count)
2424 if (size != cfg->size) {
2433 * Allocate ned, larger runtime ifidx array.
2436 ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags)
2438 struct mod_item *mi;
2440 mi = (struct mod_item *)ta_buf;
2442 memset(mi, 0, sizeof(struct mod_item));
2444 mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW,
2451 * Copy data from old runtime array to new one.
2454 ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
2457 struct mod_item *mi;
2458 struct iftable_cfg *icfg;
2460 mi = (struct mod_item *)ta_buf;
2461 icfg = (struct iftable_cfg *)ta_state;
2463 /* Check if we still need to grow array */
2464 if (icfg->size >= mi->size) {
2469 memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx));
2475 * Switch old & new arrays.
2478 ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
2481 struct mod_item *mi;
2482 struct iftable_cfg *icfg;
2485 mi = (struct mod_item *)ta_buf;
2486 icfg = (struct iftable_cfg *)ta_state;
2488 old_ptr = icfg->main_ptr;
2489 icfg->main_ptr = mi->main_ptr;
2490 icfg->size = mi->size;
2491 ti->state = icfg->main_ptr;
2493 mi->main_ptr = old_ptr;
2497 * Free unneded array.
2500 ta_flush_mod_ifidx(void *ta_buf)
2502 struct mod_item *mi;
2504 mi = (struct mod_item *)ta_buf;
2505 if (mi->main_ptr != NULL)
2506 free(mi->main_ptr, M_IPFW);
2510 ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
2511 ipfw_obj_tentry *tent)
2513 struct ifentry *ife;
2515 ife = (struct ifentry *)e;
2517 tent->masklen = 8 * IF_NAMESIZE;
2518 memcpy(&tent->k, ife->no.name, IF_NAMESIZE);
2519 tent->v.kidx = ife->value;
2525 ta_find_ifidx_tentry(void *ta_state, struct table_info *ti,
2526 ipfw_obj_tentry *tent)
2528 struct iftable_cfg *icfg;
2529 struct ifentry *ife;
2532 icfg = (struct iftable_cfg *)ta_state;
2533 ifname = tent->k.iface;
2535 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
2538 ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
2541 ta_dump_ifidx_tentry(ta_state, ti, ife, tent);
2554 foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
2557 struct ifentry *ife;
2558 struct wa_ifidx *wa;
2560 ife = (struct ifentry *)no;
2561 wa = (struct wa_ifidx *)arg;
2563 wa->f(ife, wa->arg);
2568 ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f,
2571 struct iftable_cfg *icfg;
2574 icfg = (struct iftable_cfg *)ta_state;
2579 ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa);
2582 struct table_algo iface_idx = {
2583 .name = "iface:array",
2584 .type = IPFW_TABLE_INTERFACE,
2585 .flags = TA_FLAG_DEFAULT,
2586 .ta_buf_size = sizeof(struct ta_buf_ifidx),
2587 .init = ta_init_ifidx,
2588 .destroy = ta_destroy_ifidx,
2589 .prepare_add = ta_prepare_add_ifidx,
2590 .prepare_del = ta_prepare_del_ifidx,
2591 .add = ta_add_ifidx,
2592 .del = ta_del_ifidx,
2593 .flush_entry = ta_flush_ifidx_entry,
2594 .foreach = ta_foreach_ifidx,
2595 .dump_tentry = ta_dump_ifidx_tentry,
2596 .find_tentry = ta_find_ifidx_tentry,
2597 .dump_tinfo = ta_dump_ifidx_tinfo,
2598 .need_modify = ta_need_modify_ifidx,
2599 .prepare_mod = ta_prepare_mod_ifidx,
2600 .fill_mod = ta_fill_mod_ifidx,
2601 .modify = ta_modify_ifidx,
2602 .flush_mod = ta_flush_mod_ifidx,
2603 .change_ti = ta_change_ti_ifidx,
2607 * Number array cmds.
2612 * - sorted array of "struct numarray" pointed by ti->state.
2613 * Array is allocated with rounding up to NUMARRAY_CHUNK.
2614 * - current array size is stored in ti->data
2623 struct numarray_cfg {
2625 size_t size; /* Number of items allocated in array */
2626 size_t used; /* Number of items _active_ now */
2629 struct ta_buf_numarray
2634 int compare_numarray(const void *k, const void *v);
2635 static struct numarray *numarray_find(struct table_info *ti, void *key);
2636 static int ta_lookup_numarray(struct table_info *ti, void *key,
2637 uint32_t keylen, uint32_t *val);
2638 static int ta_init_numarray(struct ip_fw_chain *ch, void **ta_state,
2639 struct table_info *ti, char *data, uint8_t tflags);
2640 static void ta_destroy_numarray(void *ta_state, struct table_info *ti);
2641 static void ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti,
2642 ipfw_ta_tinfo *tinfo);
2643 static int ta_prepare_add_numarray(struct ip_fw_chain *ch,
2644 struct tentry_info *tei, void *ta_buf);
2645 static int ta_add_numarray(void *ta_state, struct table_info *ti,
2646 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
2647 static int ta_del_numarray(void *ta_state, struct table_info *ti,
2648 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
2649 static void ta_flush_numarray_entry(struct ip_fw_chain *ch,
2650 struct tentry_info *tei, void *ta_buf);
2651 static int ta_need_modify_numarray(void *ta_state, struct table_info *ti,
2652 uint32_t count, uint64_t *pflags);
2653 static int ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags);
2654 static int ta_fill_mod_numarray(void *ta_state, struct table_info *ti,
2655 void *ta_buf, uint64_t *pflags);
2656 static void ta_modify_numarray(void *ta_state, struct table_info *ti,
2657 void *ta_buf, uint64_t pflags);
2658 static void ta_flush_mod_numarray(void *ta_buf);
2659 static int ta_dump_numarray_tentry(void *ta_state, struct table_info *ti,
2660 void *e, ipfw_obj_tentry *tent);
2661 static int ta_find_numarray_tentry(void *ta_state, struct table_info *ti,
2662 ipfw_obj_tentry *tent);
2663 static void ta_foreach_numarray(void *ta_state, struct table_info *ti,
2664 ta_foreach_f *f, void *arg);
2667 compare_numarray(const void *k, const void *v)
2669 const struct numarray *na;
2672 key = *((const uint32_t *)k);
2673 na = (const struct numarray *)v;
2675 if (key < na->number)
2677 else if (key > na->number)
2683 static struct numarray *
2684 numarray_find(struct table_info *ti, void *key)
2686 struct numarray *ri;
2688 ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray),
2695 ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen,
2698 struct numarray *ri;
2700 ri = numarray_find(ti, key);
2711 ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
2712 char *data, uint8_t tflags)
2714 struct numarray_cfg *cfg;
2716 cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO);
2719 cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW,
2723 ti->state = cfg->main_ptr;
2724 ti->lookup = ta_lookup_numarray;
2730 * Destroys table @ti
2733 ta_destroy_numarray(void *ta_state, struct table_info *ti)
2735 struct numarray_cfg *cfg;
2737 cfg = (struct numarray_cfg *)ta_state;
2739 if (cfg->main_ptr != NULL)
2740 free(cfg->main_ptr, M_IPFW);
2746 * Provide algo-specific table info
2749 ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
2751 struct numarray_cfg *cfg;
2753 cfg = (struct numarray_cfg *)ta_state;
2755 tinfo->taclass4 = IPFW_TACLASS_ARRAY;
2756 tinfo->size4 = cfg->size;
2757 tinfo->count4 = cfg->used;
2758 tinfo->itemsize4 = sizeof(struct numarray);
2762 * Prepare for addition/deletion to an array.
2765 ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei,
2768 struct ta_buf_numarray *tb;
2770 tb = (struct ta_buf_numarray *)ta_buf;
2772 tb->na.number = *((uint32_t *)tei->paddr);
2778 ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2779 void *ta_buf, uint32_t *pnum)
2781 struct numarray_cfg *cfg;
2782 struct ta_buf_numarray *tb;
2783 struct numarray *ri;
2787 tb = (struct ta_buf_numarray *)ta_buf;
2788 cfg = (struct numarray_cfg *)ta_state;
2790 /* Read current value from @tei */
2791 tb->na.value = tei->value;
2793 ri = numarray_find(ti, &tb->na.number);
2796 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
2799 /* Exchange values between ri and @tei */
2801 ri->value = tei->value;
2803 /* Indicate that update has happened instead of addition */
2804 tei->flags |= TEI_FLAGS_UPDATED;
2809 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
2812 res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used,
2813 sizeof(struct numarray), compare_numarray);
2815 KASSERT(res == 1, ("number %d already exists", tb->na.number));
2817 ti->data = cfg->used;
2824 * Remove key from both configuration list and
2825 * runtime array. Removed interface notification.
2828 ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2829 void *ta_buf, uint32_t *pnum)
2831 struct numarray_cfg *cfg;
2832 struct ta_buf_numarray *tb;
2833 struct numarray *ri;
2836 tb = (struct ta_buf_numarray *)ta_buf;
2837 cfg = (struct numarray_cfg *)ta_state;
2839 ri = numarray_find(ti, &tb->na.number);
2843 tei->value = ri->value;
2845 res = bdel(&tb->na.number, cfg->main_ptr, cfg->used,
2846 sizeof(struct numarray), compare_numarray);
2848 KASSERT(res == 1, ("number %u does not exist", tb->na.number));
2850 ti->data = cfg->used;
2857 ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
2861 /* We don't have any state, do nothing */
2865 * Table growing callbacks.
2869 ta_need_modify_numarray(void *ta_state, struct table_info *ti, uint32_t count,
2872 struct numarray_cfg *cfg;
2875 cfg = (struct numarray_cfg *)ta_state;
2878 while (size < cfg->used + count)
2881 if (size != cfg->size) {
2890 * Allocate new, larger runtime array.
2893 ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags)
2895 struct mod_item *mi;
2897 mi = (struct mod_item *)ta_buf;
2899 memset(mi, 0, sizeof(struct mod_item));
2901 mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW,
2908 * Copy data from old runtime array to new one.
2911 ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
2914 struct mod_item *mi;
2915 struct numarray_cfg *cfg;
2917 mi = (struct mod_item *)ta_buf;
2918 cfg = (struct numarray_cfg *)ta_state;
2920 /* Check if we still need to grow array */
2921 if (cfg->size >= mi->size) {
2926 memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray));
2932 * Switch old & new arrays.
2935 ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
2938 struct mod_item *mi;
2939 struct numarray_cfg *cfg;
2942 mi = (struct mod_item *)ta_buf;
2943 cfg = (struct numarray_cfg *)ta_state;
2945 old_ptr = cfg->main_ptr;
2946 cfg->main_ptr = mi->main_ptr;
2947 cfg->size = mi->size;
2948 ti->state = cfg->main_ptr;
2950 mi->main_ptr = old_ptr;
2954 * Free unneded array.
2957 ta_flush_mod_numarray(void *ta_buf)
2959 struct mod_item *mi;
2961 mi = (struct mod_item *)ta_buf;
2962 if (mi->main_ptr != NULL)
2963 free(mi->main_ptr, M_IPFW);
2967 ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e,
2968 ipfw_obj_tentry *tent)
2970 struct numarray *na;
2972 na = (struct numarray *)e;
2974 tent->k.key = na->number;
2975 tent->v.kidx = na->value;
2981 ta_find_numarray_tentry(void *ta_state, struct table_info *ti,
2982 ipfw_obj_tentry *tent)
2984 struct numarray_cfg *cfg;
2985 struct numarray *ri;
2987 cfg = (struct numarray_cfg *)ta_state;
2989 ri = numarray_find(ti, &tent->k.key);
2992 ta_dump_numarray_tentry(ta_state, ti, ri, tent);
3000 ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f,
3003 struct numarray_cfg *cfg;
3004 struct numarray *array;
3007 cfg = (struct numarray_cfg *)ta_state;
3008 array = cfg->main_ptr;
3010 for (i = 0; i < cfg->used; i++)
3014 struct table_algo number_array = {
3015 .name = "number:array",
3016 .type = IPFW_TABLE_NUMBER,
3017 .ta_buf_size = sizeof(struct ta_buf_numarray),
3018 .init = ta_init_numarray,
3019 .destroy = ta_destroy_numarray,
3020 .prepare_add = ta_prepare_add_numarray,
3021 .prepare_del = ta_prepare_add_numarray,
3022 .add = ta_add_numarray,
3023 .del = ta_del_numarray,
3024 .flush_entry = ta_flush_numarray_entry,
3025 .foreach = ta_foreach_numarray,
3026 .dump_tentry = ta_dump_numarray_tentry,
3027 .find_tentry = ta_find_numarray_tentry,
3028 .dump_tinfo = ta_dump_numarray_tinfo,
3029 .need_modify = ta_need_modify_numarray,
3030 .prepare_mod = ta_prepare_mod_numarray,
3031 .fill_mod = ta_fill_mod_numarray,
3032 .modify = ta_modify_numarray,
3033 .flush_mod = ta_flush_mod_numarray,
3041 * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
3044 * inv.mask4: 32 - mask
3046 * 1) _slow lookup: mask
3047 * 2) _aligned: (128 - mask) / 8
3058 SLIST_HEAD(fhashbhead, fhashentry);
3061 SLIST_ENTRY(fhashentry) next;
3071 struct fhashentry4 {
3072 struct fhashentry e;
3077 struct fhashentry6 {
3078 struct fhashentry e;
3079 struct in6_addr dip6;
3080 struct in6_addr sip6;
3084 struct fhashbhead *head;
3087 struct fhashentry4 fe4;
3088 struct fhashentry6 fe6;
3091 struct ta_buf_fhash {
3093 struct fhashentry6 fe6;
3096 static __inline int cmp_flow_ent(struct fhashentry *a,
3097 struct fhashentry *b, size_t sz);
3098 static __inline uint32_t hash_flow4(struct fhashentry4 *f, int hsize);
3099 static __inline uint32_t hash_flow6(struct fhashentry6 *f, int hsize);
3100 static uint32_t hash_flow_ent(struct fhashentry *ent, uint32_t size);
3101 static int ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
3103 static int ta_init_fhash(struct ip_fw_chain *ch, void **ta_state,
3104 struct table_info *ti, char *data, uint8_t tflags);
3105 static void ta_destroy_fhash(void *ta_state, struct table_info *ti);
3106 static void ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti,
3107 ipfw_ta_tinfo *tinfo);
3108 static int ta_dump_fhash_tentry(void *ta_state, struct table_info *ti,
3109 void *e, ipfw_obj_tentry *tent);
3110 static int tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent);
3111 static int ta_find_fhash_tentry(void *ta_state, struct table_info *ti,
3112 ipfw_obj_tentry *tent);
3113 static void ta_foreach_fhash(void *ta_state, struct table_info *ti,
3114 ta_foreach_f *f, void *arg);
3115 static int ta_prepare_add_fhash(struct ip_fw_chain *ch,
3116 struct tentry_info *tei, void *ta_buf);
3117 static int ta_add_fhash(void *ta_state, struct table_info *ti,
3118 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
3119 static int ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
3121 static int ta_del_fhash(void *ta_state, struct table_info *ti,
3122 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
3123 static void ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
3125 static int ta_need_modify_fhash(void *ta_state, struct table_info *ti,
3126 uint32_t count, uint64_t *pflags);
3127 static int ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags);
3128 static int ta_fill_mod_fhash(void *ta_state, struct table_info *ti,
3129 void *ta_buf, uint64_t *pflags);
3130 static void ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3132 static void ta_flush_mod_fhash(void *ta_buf);
3135 cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz)
3139 ka = (uint64_t *)(&a->next + 1);
3140 kb = (uint64_t *)(&b->next + 1);
3142 if (*ka == *kb && (memcmp(a + 1, b + 1, sz) == 0))
3148 static __inline uint32_t
3149 hash_flow4(struct fhashentry4 *f, int hsize)
3153 i = (f->dip.s_addr) ^ (f->sip.s_addr) ^ (f->e.dport) ^ (f->e.sport);
3155 return (i % (hsize - 1));
3158 static __inline uint32_t
3159 hash_flow6(struct fhashentry6 *f, int hsize)
3163 i = (f->dip6.__u6_addr.__u6_addr32[2]) ^
3164 (f->dip6.__u6_addr.__u6_addr32[3]) ^
3165 (f->sip6.__u6_addr.__u6_addr32[2]) ^
3166 (f->sip6.__u6_addr.__u6_addr32[3]) ^
3167 (f->e.dport) ^ (f->e.sport);
3169 return (i % (hsize - 1));
3173 hash_flow_ent(struct fhashentry *ent, uint32_t size)
3177 if (ent->af == AF_INET) {
3178 hash = hash_flow4((struct fhashentry4 *)ent, size);
3180 hash = hash_flow6((struct fhashentry6 *)ent, size);
3187 ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
3190 struct fhashbhead *head;
3191 struct fhashentry *ent;
3192 struct fhashentry4 *m4;
3193 struct ipfw_flow_id *id;
3197 id = (struct ipfw_flow_id *)key;
3198 head = (struct fhashbhead *)ti->state;
3200 m4 = (struct fhashentry4 *)ti->xstate;
3202 if (id->addr_type == 4) {
3203 struct fhashentry4 f;
3205 /* Copy hash mask */
3208 f.dip.s_addr &= id->dst_ip;
3209 f.sip.s_addr &= id->src_ip;
3210 f.e.dport &= id->dst_port;
3211 f.e.sport &= id->src_port;
3212 f.e.proto &= id->proto;
3213 hash = hash_flow4(&f, hsize);
3214 SLIST_FOREACH(ent, &head[hash], next) {
3215 if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) {
3220 } else if (id->addr_type == 6) {
3221 struct fhashentry6 f;
3224 /* Copy hash mask */
3225 f = *((struct fhashentry6 *)(m4 + 1));
3227 /* Handle lack of __u6_addr.__u6_addr64 */
3228 fp = (uint64_t *)&f.dip6;
3229 idp = (uint64_t *)&id->dst_ip6;
3230 /* src IPv6 is stored after dst IPv6 */
3235 f.e.dport &= id->dst_port;
3236 f.e.sport &= id->src_port;
3237 f.e.proto &= id->proto;
3238 hash = hash_flow6(&f, hsize);
3239 SLIST_FOREACH(ent, &head[hash], next) {
3240 if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) {
3254 ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
3255 char *data, uint8_t tflags)
3257 struct fhash_cfg *cfg;
3258 struct fhashentry4 *fe4;
3259 struct fhashentry6 *fe6;
3262 cfg = malloc(sizeof(struct fhash_cfg), M_IPFW, M_WAITOK | M_ZERO);
3266 cfg->head = malloc(sizeof(struct fhashbhead) * cfg->size, M_IPFW,
3268 for (i = 0; i < cfg->size; i++)
3269 SLIST_INIT(&cfg->head[i]);
3271 /* Fill in fe masks based on @tflags */
3274 if (tflags & IPFW_TFFLAG_SRCIP) {
3275 memset(&fe4->sip, 0xFF, sizeof(fe4->sip));
3276 memset(&fe6->sip6, 0xFF, sizeof(fe6->sip6));
3278 if (tflags & IPFW_TFFLAG_DSTIP) {
3279 memset(&fe4->dip, 0xFF, sizeof(fe4->dip));
3280 memset(&fe6->dip6, 0xFF, sizeof(fe6->dip6));
3282 if (tflags & IPFW_TFFLAG_SRCPORT) {
3283 memset(&fe4->e.sport, 0xFF, sizeof(fe4->e.sport));
3284 memset(&fe6->e.sport, 0xFF, sizeof(fe6->e.sport));
3286 if (tflags & IPFW_TFFLAG_DSTPORT) {
3287 memset(&fe4->e.dport, 0xFF, sizeof(fe4->e.dport));
3288 memset(&fe6->e.dport, 0xFF, sizeof(fe6->e.dport));
3290 if (tflags & IPFW_TFFLAG_PROTO) {
3291 memset(&fe4->e.proto, 0xFF, sizeof(fe4->e.proto));
3292 memset(&fe6->e.proto, 0xFF, sizeof(fe6->e.proto));
3295 fe4->e.af = AF_INET;
3296 fe6->e.af = AF_INET6;
3299 ti->state = cfg->head;
3300 ti->xstate = &cfg->fe4;
3301 ti->data = cfg->size;
3302 ti->lookup = ta_lookup_fhash;
3308 ta_destroy_fhash(void *ta_state, struct table_info *ti)
3310 struct fhash_cfg *cfg;
3311 struct fhashentry *ent, *ent_next;
3314 cfg = (struct fhash_cfg *)ta_state;
3316 for (i = 0; i < cfg->size; i++)
3317 SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
3318 free(ent, M_IPFW_TBL);
3320 free(cfg->head, M_IPFW);
3325 * Provide algo-specific table info
3328 ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
3330 struct fhash_cfg *cfg;
3332 cfg = (struct fhash_cfg *)ta_state;
3334 tinfo->flags = IPFW_TATFLAGS_AFITEM;
3335 tinfo->taclass4 = IPFW_TACLASS_HASH;
3336 tinfo->size4 = cfg->size;
3337 tinfo->count4 = cfg->items;
3338 tinfo->itemsize4 = sizeof(struct fhashentry4);
3339 tinfo->itemsize6 = sizeof(struct fhashentry6);
3343 ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e,
3344 ipfw_obj_tentry *tent)
3346 struct fhash_cfg *cfg;
3347 struct fhashentry *ent;
3348 struct fhashentry4 *fe4;
3350 struct fhashentry6 *fe6;
3352 struct tflow_entry *tfe;
3354 cfg = (struct fhash_cfg *)ta_state;
3355 ent = (struct fhashentry *)e;
3356 tfe = &tent->k.flow;
3359 tfe->proto = ent->proto;
3360 tfe->dport = htons(ent->dport);
3361 tfe->sport = htons(ent->sport);
3362 tent->v.kidx = ent->value;
3363 tent->subtype = ent->af;
3365 if (ent->af == AF_INET) {
3366 fe4 = (struct fhashentry4 *)ent;
3367 tfe->a.a4.sip.s_addr = htonl(fe4->sip.s_addr);
3368 tfe->a.a4.dip.s_addr = htonl(fe4->dip.s_addr);
3372 fe6 = (struct fhashentry6 *)ent;
3373 tfe->a.a6.sip6 = fe6->sip6;
3374 tfe->a.a6.dip6 = fe6->dip6;
3375 tent->masklen = 128;
3383 tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent)
3386 struct fhashentry4 *fe4;
3389 struct fhashentry6 *fe6;
3391 struct tflow_entry *tfe;
3393 tfe = (struct tflow_entry *)tei->paddr;
3395 ent->af = tei->subtype;
3396 ent->proto = tfe->proto;
3397 ent->dport = ntohs(tfe->dport);
3398 ent->sport = ntohs(tfe->sport);
3400 if (tei->subtype == AF_INET) {
3402 fe4 = (struct fhashentry4 *)ent;
3403 fe4->sip.s_addr = ntohl(tfe->a.a4.sip.s_addr);
3404 fe4->dip.s_addr = ntohl(tfe->a.a4.dip.s_addr);
3407 } else if (tei->subtype == AF_INET6) {
3408 fe6 = (struct fhashentry6 *)ent;
3409 fe6->sip6 = tfe->a.a6.sip6;
3410 fe6->dip6 = tfe->a.a6.dip6;
3413 /* Unknown CIDR type */
3421 ta_find_fhash_tentry(void *ta_state, struct table_info *ti,
3422 ipfw_obj_tentry *tent)
3424 struct fhash_cfg *cfg;
3425 struct fhashbhead *head;
3426 struct fhashentry *ent, *tmp;
3427 struct fhashentry6 fe6;
3428 struct tentry_info tei;
3433 cfg = (struct fhash_cfg *)ta_state;
3437 memset(&fe6, 0, sizeof(fe6));
3438 memset(&tei, 0, sizeof(tei));
3440 tei.paddr = &tent->k.flow;
3441 tei.subtype = tent->subtype;
3443 if ((error = tei_to_fhash_ent(&tei, ent)) != 0)
3447 hash = hash_flow_ent(ent, cfg->size);
3449 if (tei.subtype == AF_INET)
3450 sz = 2 * sizeof(struct in_addr);
3452 sz = 2 * sizeof(struct in6_addr);
3454 /* Check for existence */
3455 SLIST_FOREACH(tmp, &head[hash], next) {
3456 if (cmp_flow_ent(tmp, ent, sz) != 0) {
3457 ta_dump_fhash_tentry(ta_state, ti, tmp, tent);
3466 ta_foreach_fhash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
3469 struct fhash_cfg *cfg;
3470 struct fhashentry *ent, *ent_next;
3473 cfg = (struct fhash_cfg *)ta_state;
3475 for (i = 0; i < cfg->size; i++)
3476 SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
3481 ta_prepare_add_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
3484 struct ta_buf_fhash *tb;
3485 struct fhashentry *ent;
3489 tb = (struct ta_buf_fhash *)ta_buf;
3491 if (tei->subtype == AF_INET)
3492 sz = sizeof(struct fhashentry4);
3493 else if (tei->subtype == AF_INET6)
3494 sz = sizeof(struct fhashentry6);
3498 ent = malloc(sz, M_IPFW_TBL, M_WAITOK | M_ZERO);
3500 error = tei_to_fhash_ent(tei, ent);
3502 free(ent, M_IPFW_TBL);
3511 ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
3512 void *ta_buf, uint32_t *pnum)
3514 struct fhash_cfg *cfg;
3515 struct fhashbhead *head;
3516 struct fhashentry *ent, *tmp;
3517 struct ta_buf_fhash *tb;
3519 uint32_t hash, value;
3522 cfg = (struct fhash_cfg *)ta_state;
3523 tb = (struct ta_buf_fhash *)ta_buf;
3524 ent = (struct fhashentry *)tb->ent_ptr;
3527 /* Read current value from @tei */
3528 ent->value = tei->value;
3531 hash = hash_flow_ent(ent, cfg->size);
3533 if (tei->subtype == AF_INET)
3534 sz = 2 * sizeof(struct in_addr);
3536 sz = 2 * sizeof(struct in6_addr);
3538 /* Check for existence */
3539 SLIST_FOREACH(tmp, &head[hash], next) {
3540 if (cmp_flow_ent(tmp, ent, sz) != 0) {
3547 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
3549 /* Record already exists. Update value if we're asked to */
3550 /* Exchange values between tmp and @tei */
3552 tmp->value = tei->value;
3554 /* Indicate that update has happened instead of addition */
3555 tei->flags |= TEI_FLAGS_UPDATED;
3558 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
3561 SLIST_INSERT_HEAD(&head[hash], ent, next);
3565 /* Update counters and check if we need to grow hash */
3573 ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
3576 struct ta_buf_fhash *tb;
3578 tb = (struct ta_buf_fhash *)ta_buf;
3580 return (tei_to_fhash_ent(tei, &tb->fe6.e));
3584 ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
3585 void *ta_buf, uint32_t *pnum)
3587 struct fhash_cfg *cfg;
3588 struct fhashbhead *head;
3589 struct fhashentry *ent, *tmp;
3590 struct ta_buf_fhash *tb;
3594 cfg = (struct fhash_cfg *)ta_state;
3595 tb = (struct ta_buf_fhash *)ta_buf;
3599 hash = hash_flow_ent(ent, cfg->size);
3601 if (tei->subtype == AF_INET)
3602 sz = 2 * sizeof(struct in_addr);
3604 sz = 2 * sizeof(struct in6_addr);
3606 /* Check for existence */
3607 SLIST_FOREACH(tmp, &head[hash], next) {
3608 if (cmp_flow_ent(tmp, ent, sz) == 0)
3611 SLIST_REMOVE(&head[hash], tmp, fhashentry, next);
3612 tei->value = tmp->value;
3623 ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
3626 struct ta_buf_fhash *tb;
3628 tb = (struct ta_buf_fhash *)ta_buf;
3630 if (tb->ent_ptr != NULL)
3631 free(tb->ent_ptr, M_IPFW_TBL);
3635 * Hash growing callbacks.
3639 ta_need_modify_fhash(void *ta_state, struct table_info *ti, uint32_t count,
3642 struct fhash_cfg *cfg;
3644 cfg = (struct fhash_cfg *)ta_state;
3646 if (cfg->items > cfg->size && cfg->size < 65536) {
3647 *pflags = cfg->size * 2;
3655 * Allocate new, larger fhash.
3658 ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags)
3660 struct mod_item *mi;
3661 struct fhashbhead *head;
3664 mi = (struct mod_item *)ta_buf;
3666 memset(mi, 0, sizeof(struct mod_item));
3668 head = malloc(sizeof(struct fhashbhead) * mi->size, M_IPFW,
3670 for (i = 0; i < mi->size; i++)
3671 SLIST_INIT(&head[i]);
3673 mi->main_ptr = head;
3679 * Copy data from old runtime array to new one.
3682 ta_fill_mod_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3686 /* In is not possible to do rehash if we're not holidng WLOCK. */
3691 * Switch old & new arrays.
3694 ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3697 struct mod_item *mi;
3698 struct fhash_cfg *cfg;
3699 struct fhashbhead *old_head, *new_head;
3700 struct fhashentry *ent, *ent_next;
3705 mi = (struct mod_item *)ta_buf;
3706 cfg = (struct fhash_cfg *)ta_state;
3708 old_size = cfg->size;
3709 old_head = ti->state;
3711 new_head = (struct fhashbhead *)mi->main_ptr;
3712 for (i = 0; i < old_size; i++) {
3713 SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
3714 nhash = hash_flow_ent(ent, mi->size);
3715 SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
3719 ti->state = new_head;
3720 ti->data = mi->size;
3721 cfg->head = new_head;
3722 cfg->size = mi->size;
3724 mi->main_ptr = old_head;
3728 * Free unneded array.
3731 ta_flush_mod_fhash(void *ta_buf)
3733 struct mod_item *mi;
3735 mi = (struct mod_item *)ta_buf;
3736 if (mi->main_ptr != NULL)
3737 free(mi->main_ptr, M_IPFW);
3740 struct table_algo flow_hash = {
3741 .name = "flow:hash",
3742 .type = IPFW_TABLE_FLOW,
3743 .flags = TA_FLAG_DEFAULT,
3744 .ta_buf_size = sizeof(struct ta_buf_fhash),
3745 .init = ta_init_fhash,
3746 .destroy = ta_destroy_fhash,
3747 .prepare_add = ta_prepare_add_fhash,
3748 .prepare_del = ta_prepare_del_fhash,
3749 .add = ta_add_fhash,
3750 .del = ta_del_fhash,
3751 .flush_entry = ta_flush_fhash_entry,
3752 .foreach = ta_foreach_fhash,
3753 .dump_tentry = ta_dump_fhash_tentry,
3754 .find_tentry = ta_find_fhash_tentry,
3755 .dump_tinfo = ta_dump_fhash_tinfo,
3756 .need_modify = ta_need_modify_fhash,
3757 .prepare_mod = ta_prepare_mod_fhash,
3758 .fill_mod = ta_fill_mod_fhash,
3759 .modify = ta_modify_fhash,
3760 .flush_mod = ta_flush_mod_fhash,
3764 * Kernel fibs bindings.
3769 * - fully relies on route API
3770 * - fib number is stored in ti->data
3774 static int ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
3776 static int kfib_parse_opts(int *pfib, char *data);
3777 static void ta_print_kfib_config(void *ta_state, struct table_info *ti,
3778 char *buf, size_t bufsize);
3779 static int ta_init_kfib(struct ip_fw_chain *ch, void **ta_state,
3780 struct table_info *ti, char *data, uint8_t tflags);
3781 static void ta_destroy_kfib(void *ta_state, struct table_info *ti);
3782 static void ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti,
3783 ipfw_ta_tinfo *tinfo);
3784 static int contigmask(uint8_t *p, int len);
3785 static int ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e,
3786 ipfw_obj_tentry *tent);
3787 static int ta_dump_kfib_tentry_int(struct sockaddr *paddr,
3788 struct sockaddr *pmask, ipfw_obj_tentry *tent);
3789 static int ta_find_kfib_tentry(void *ta_state, struct table_info *ti,
3790 ipfw_obj_tentry *tent);
3791 static void ta_foreach_kfib(void *ta_state, struct table_info *ti,
3792 ta_foreach_f *f, void *arg);
3795 ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
3806 in.s_addr = *(in_addr_t *)key;
3808 error = fib4_lookup(ti->data, in, 0, NHR_NONE, 0) != NULL;
3813 error = fib6_lookup(ti->data, (struct in6_addr *)key,
3814 0, NHR_NONE, 0) != NULL;
3825 /* Parse 'fib=%d' */
3827 kfib_parse_opts(int *pfib, char *data)
3829 char *pdel, *pend, *s;
3834 if ((pdel = strchr(data, ' ')) == NULL)
3836 while (*pdel == ' ')
3838 if (strncmp(pdel, "fib=", 4) != 0)
3840 if ((s = strchr(pdel, ' ')) != NULL)
3845 fibnum = strtol(pdel, &pend, 10);
3855 ta_print_kfib_config(void *ta_state, struct table_info *ti, char *buf,
3860 snprintf(buf, bufsize, "%s fib=%lu", "addr:kfib", ti->data);
3862 snprintf(buf, bufsize, "%s", "addr:kfib");
3866 ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
3867 char *data, uint8_t tflags)
3872 if ((error = kfib_parse_opts(&fibnum, data)) != 0)
3875 if (fibnum >= rt_numfibs)
3879 ti->lookup = ta_lookup_kfib;
3885 * Destroys table @ti
3888 ta_destroy_kfib(void *ta_state, struct table_info *ti)
3894 * Provide algo-specific table info
3897 ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
3900 tinfo->flags = IPFW_TATFLAGS_AFDATA;
3901 tinfo->taclass4 = IPFW_TACLASS_RADIX;
3903 tinfo->itemsize4 = sizeof(struct rtentry);
3904 tinfo->taclass6 = IPFW_TACLASS_RADIX;
3906 tinfo->itemsize6 = sizeof(struct rtentry);
3910 contigmask(uint8_t *p, int len)
3914 for (i = 0; i < len ; i++)
3915 if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */
3917 for (n= i + 1; n < len; n++)
3918 if ( (p[n/8] & (1 << (7 - (n % 8)))) != 0)
3919 return (-1); /* mask not contiguous */
3924 ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e,
3925 ipfw_obj_tentry *tent)
3927 struct rtentry *rte;
3929 rte = (struct rtentry *)e;
3931 return ta_dump_kfib_tentry_int(rt_key(rte), rt_mask(rte), tent);
3935 ta_dump_kfib_tentry_int(struct sockaddr *paddr, struct sockaddr *pmask,
3936 ipfw_obj_tentry *tent)
3939 struct sockaddr_in *addr, *mask;
3942 struct sockaddr_in6 *addr6, *mask6;
3948 /* Guess IPv4/IPv6 radix by sockaddr family */
3950 if (paddr->sa_family == AF_INET) {
3951 addr = (struct sockaddr_in *)paddr;
3952 mask = (struct sockaddr_in *)pmask;
3953 tent->k.addr.s_addr = addr->sin_addr.s_addr;
3956 len = contigmask((uint8_t *)&mask->sin_addr, 32);
3959 tent->masklen = len;
3960 tent->subtype = AF_INET;
3961 tent->v.kidx = 0; /* Do we need to put GW here? */
3965 if (paddr->sa_family == AF_INET6) {
3966 addr6 = (struct sockaddr_in6 *)paddr;
3967 mask6 = (struct sockaddr_in6 *)pmask;
3968 memcpy(&tent->k.addr6, &addr6->sin6_addr,
3969 sizeof(struct in6_addr));
3972 len = contigmask((uint8_t *)&mask6->sin6_addr, 128);
3975 tent->masklen = len;
3976 tent->subtype = AF_INET6;
3985 ta_find_kfib_tentry(void *ta_state, struct table_info *ti,
3986 ipfw_obj_tentry *tent)
3988 struct rt_addrinfo info;
3989 struct sockaddr_in6 key6, dst6, mask6;
3990 struct sockaddr *dst, *key, *mask;
3992 /* Prepare sockaddr for prefix/mask and info */
3993 bzero(&dst6, sizeof(dst6));
3994 dst6.sin6_len = sizeof(dst6);
3995 dst = (struct sockaddr *)&dst6;
3996 bzero(&mask6, sizeof(mask6));
3997 mask6.sin6_len = sizeof(mask6);
3998 mask = (struct sockaddr *)&mask6;
4000 bzero(&info, sizeof(info));
4001 info.rti_info[RTAX_DST] = dst;
4002 info.rti_info[RTAX_NETMASK] = mask;
4004 /* Prepare the lookup key */
4005 bzero(&key6, sizeof(key6));
4006 key6.sin6_family = tent->subtype;
4007 key = (struct sockaddr *)&key6;
4009 if (tent->subtype == AF_INET) {
4010 ((struct sockaddr_in *)&key6)->sin_addr = tent->k.addr;
4011 key6.sin6_len = sizeof(struct sockaddr_in);
4013 key6.sin6_addr = tent->k.addr6;
4014 key6.sin6_len = sizeof(struct sockaddr_in6);
4017 if (rib_lookup_info(ti->data, key, 0, 0, &info) != 0)
4019 if ((info.rti_addrs & RTA_NETMASK) == 0)
4022 ta_dump_kfib_tentry_int(dst, mask, tent);
4028 ta_foreach_kfib(void *ta_state, struct table_info *ti, ta_foreach_f *f,
4032 struct rib_head *rh;
4035 rh = rt_tables_get_rnh(ti->data, AF_INET);
4038 error = rh->rnh_walktree(&rh->head, (walktree_f_t *)f, arg);
4042 rh = rt_tables_get_rnh(ti->data, AF_INET6);
4045 error = rh->rnh_walktree(&rh->head, (walktree_f_t *)f, arg);
4050 struct table_algo addr_kfib = {
4051 .name = "addr:kfib",
4052 .type = IPFW_TABLE_ADDR,
4053 .flags = TA_FLAG_READONLY,
4055 .init = ta_init_kfib,
4056 .destroy = ta_destroy_kfib,
4057 .foreach = ta_foreach_kfib,
4058 .dump_tentry = ta_dump_kfib_tentry,
4059 .find_tentry = ta_find_kfib_tentry,
4060 .dump_tinfo = ta_dump_kfib_tinfo,
4061 .print_config = ta_print_kfib_config,
4065 ipfw_table_algo_init(struct ip_fw_chain *ch)
4070 * Register all algorithms presented here.
4072 sz = sizeof(struct table_algo);
4073 ipfw_add_table_algo(ch, &addr_radix, sz, &addr_radix.idx);
4074 ipfw_add_table_algo(ch, &addr_hash, sz, &addr_hash.idx);
4075 ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx);
4076 ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx);
4077 ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx);
4078 ipfw_add_table_algo(ch, &addr_kfib, sz, &addr_kfib.idx);
4082 ipfw_table_algo_destroy(struct ip_fw_chain *ch)
4085 ipfw_del_table_algo(ch, addr_radix.idx);
4086 ipfw_del_table_algo(ch, addr_hash.idx);
4087 ipfw_del_table_algo(ch, iface_idx.idx);
4088 ipfw_del_table_algo(ch, number_array.idx);
4089 ipfw_del_table_algo(ch, flow_hash.idx);
4090 ipfw_del_table_algo(ch, addr_kfib.idx);