1 /*-
2 * Copyright (c) 2014 Yandex LLC
3 * Copyright (c) 2014 Alexander V. Chernikov
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
13 *
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
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 /*
31 * Lookup table algorithms.
32 *
33 */
34
35 #include "opt_ipfw.h"
36 #include "opt_inet.h"
37 #ifndef INET
38 #error IPFIREWALL requires INET.
39 #endif /* INET */
40 #include "opt_inet6.h"
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/malloc.h>
45 #include <sys/kernel.h>
46 #include <sys/lock.h>
47 #include <sys/rwlock.h>
48 #include <sys/rmlock.h>
49 #include <sys/socket.h>
50 #include <sys/queue.h>
51 #include <net/ethernet.h>
52 #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */
53 #include <net/radix.h>
54 #include <net/route.h>
55 #include <net/route/nhop.h>
56 #include <net/route/route_ctl.h>
57
58 #include <netinet/in.h>
59 #include <netinet/in_fib.h>
60 #include <netinet/ip_var.h> /* struct ipfw_rule_ref */
61 #include <netinet/ip_fw.h>
62 #include <netinet6/in6_fib.h>
63
64 #include <netpfil/ipfw/ip_fw_private.h>
65 #include <netpfil/ipfw/ip_fw_table.h>
66
67 /*
68 * IPFW table lookup algorithms.
69 *
70 * What is needed to add another table algo?
71 *
72 * Algo init:
73 * * struct table_algo has to be filled with:
74 * name: "type:algoname" format, e.g. "addr:radix". Currently
75 * there are the following types: "addr", "iface", "number" and "flow".
76 * type: one of IPFW_TABLE_* types
77 * flags: one or more TA_FLAGS_*
78 * ta_buf_size: size of structure used to store add/del item state.
79 * Needs to be less than TA_BUF_SZ.
80 * callbacks: see below for description.
81 * * ipfw_add_table_algo / ipfw_del_table_algo has to be called
82 *
83 * Callbacks description:
84 *
85 * -init: request to initialize new table instance.
86 * typedef int (ta_init)(struct ip_fw_chain *ch, void **ta_state,
87 * struct table_info *ti, char *data, uint8_t tflags);
88 * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success.
89 *
90 * Allocate all structures needed for normal operations.
91 * * Caller may want to parse @data for some algo-specific
92 * options provided by userland.
93 * * Caller may want to save configuration state pointer to @ta_state
94 * * Caller needs to save desired runtime structure pointer(s)
95 * inside @ti fields. Note that it is not correct to save
96 * @ti pointer at this moment. Use -change_ti hook for that.
97 * * Caller has to fill in ti->lookup to appropriate function
98 * pointer.
99 *
100 *
101 *
102 * -destroy: request to destroy table instance.
103 * typedef void (ta_destroy)(void *ta_state, struct table_info *ti);
104 * MANDATORY, unlocked. (M_WAITOK).
105 *
106 * Frees all table entries and all tables structures allocated by -init.
107 *
108 *
109 *
110 * -prepare_add: request to allocate state for adding new entry.
111 * typedef int (ta_prepare_add)(struct ip_fw_chain *ch, struct tentry_info *tei,
112 * void *ta_buf);
113 * MANDATORY, unlocked. (M_WAITOK). Returns 0 on success.
114 *
115 * Allocates state and fills it in with all necessary data (EXCEPT value)
116 * from @tei to minimize operations needed to be done under WLOCK.
117 * "value" field has to be copied to new entry in @add callback.
118 * Buffer ta_buf of size ta->ta_buf_sz may be used to store
119 * allocated state.
120 *
121 *
122 *
123 * -prepare_del: request to set state for deleting existing entry.
124 * typedef int (ta_prepare_del)(struct ip_fw_chain *ch, struct tentry_info *tei,
125 * void *ta_buf);
126 * MANDATORY, locked, UH. (M_NOWAIT). Returns 0 on success.
127 *
128 * Buffer ta_buf of size ta->ta_buf_sz may be used to store
129 * allocated state. Caller should use on-stack ta_buf allocation
130 * instead of doing malloc().
131 *
132 *
133 *
134 * -add: request to insert new entry into runtime/config structures.
135 * typedef int (ta_add)(void *ta_state, struct table_info *ti,
136 * struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
137 * MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success.
138 *
139 * Insert new entry using previously-allocated state in @ta_buf.
140 * * @tei may have the following flags:
141 * TEI_FLAGS_UPDATE: request to add or update entry.
142 * TEI_FLAGS_DONTADD: request to update (but not add) entry.
143 * * Caller is required to do the following:
144 * copy real entry value from @tei
145 * entry added: return 0, set 1 to @pnum
146 * entry updated: return 0, store 0 to @pnum, store old value in @tei,
147 * add TEI_FLAGS_UPDATED flag to @tei.
148 * entry exists: return EEXIST
149 * entry not found: return ENOENT
150 * other error: return non-zero error code.
151 *
152 *
153 *
154 * -del: request to delete existing entry from runtime/config structures.
155 * typedef int (ta_del)(void *ta_state, struct table_info *ti,
156 * struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
157 * MANDATORY, UH+WLOCK. (M_NOWAIT). Returns 0 on success.
158 *
159 * Delete entry using previously set up in @ta_buf.
160 * * Caller is required to do the following:
161 * entry deleted: return 0, set 1 to @pnum, store old value in @tei.
162 * entry not found: return ENOENT
163 * other error: return non-zero error code.
164 *
165 *
166 *
167 * -flush_entry: flush entry state created by -prepare_add / -del / others
168 * typedef void (ta_flush_entry)(struct ip_fw_chain *ch,
169 * struct tentry_info *tei, void *ta_buf);
170 * MANDATORY, may be locked. (M_NOWAIT).
171 *
172 * Delete state allocated by:
173 * -prepare_add (-add returned EEXIST|UPDATED)
174 * -prepare_del (if any)
175 * -del
176 * * Caller is required to handle empty @ta_buf correctly.
177 *
178 *
179 * -find_tentry: finds entry specified by key @tei
180 * typedef int ta_find_tentry(void *ta_state, struct table_info *ti,
181 * ipfw_obj_tentry *tent);
182 * OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 on success.
183 *
184 * Finds entry specified by given key.
185 * * Caller is required to do the following:
186 * entry found: returns 0, export entry to @tent
187 * entry not found: returns ENOENT
188 *
189 *
190 * -need_modify: checks if @ti has enough space to hold another @count items.
191 * typedef int (ta_need_modify)(void *ta_state, struct table_info *ti,
192 * uint32_t count, uint64_t *pflags);
193 * OPTIONAL, locked (UH). (M_NOWAIT). Returns 0 if has.
194 *
195 * Checks if given table has enough space to add @count items without
196 * resize. Caller may use @pflags to store desired modification data.
197 *
198 *
199 *
200 * -prepare_mod: allocate structures for table modification.
201 * typedef int (ta_prepare_mod)(void *ta_buf, uint64_t *pflags);
202 * OPTIONAL(need_modify), unlocked. (M_WAITOK). Returns 0 on success.
203 *
204 * Allocate all needed state for table modification. Caller
205 * should use `struct mod_item` to store new state in @ta_buf.
206 * Up to TA_BUF_SZ (128 bytes) can be stored in @ta_buf.
207 *
208 *
209 *
210 * -fill_mod: copy some data to new state/
211 * typedef int (ta_fill_mod)(void *ta_state, struct table_info *ti,
212 * void *ta_buf, uint64_t *pflags);
213 * OPTIONAL(need_modify), locked (UH). (M_NOWAIT). Returns 0 on success.
214 *
215 * Copy as much data as we can to minimize changes under WLOCK.
216 * For example, array can be merged inside this callback.
217 *
218 *
219 *
220 * -modify: perform final modification.
221 * typedef void (ta_modify)(void *ta_state, struct table_info *ti,
222 * void *ta_buf, uint64_t pflags);
223 * OPTIONAL(need_modify), locked (UH+WLOCK). (M_NOWAIT).
224 *
225 * Performs all changes necessary to switch to new structures.
226 * * Caller should save old pointers to @ta_buf storage.
227 *
228 *
229 *
230 * -flush_mod: flush table modification state.
231 * typedef void (ta_flush_mod)(void *ta_buf);
232 * OPTIONAL(need_modify), unlocked. (M_WAITOK).
233 *
234 * Performs flush for the following:
235 * - prepare_mod (modification was not necessary)
236 * - modify (for the old state)
237 *
238 *
239 *
240 * -change_gi: monitor table info pointer changes
241 * typedef void (ta_change_ti)(void *ta_state, struct table_info *ti);
242 * OPTIONAL, locked (UH). (M_NOWAIT).
243 *
244 * Called on @ti pointer changed. Called immediately after -init
245 * to set initial state.
246 *
247 *
248 *
249 * -foreach: calls @f for each table entry
250 * typedef void ta_foreach(void *ta_state, struct table_info *ti,
251 * ta_foreach_f *f, void *arg);
252 * MANDATORY, locked(UH). (M_NOWAIT).
253 *
254 * Runs callback with specified argument for each table entry,
255 * Typically used for dumping table entries.
256 *
257 *
258 *
259 * -dump_tentry: dump table entry in current @tentry format.
260 * typedef int ta_dump_tentry(void *ta_state, struct table_info *ti, void *e,
261 * ipfw_obj_tentry *tent);
262 * MANDATORY, locked(UH). (M_NOWAIT). Returns 0 on success.
263 *
264 * Dumps entry @e to @tent.
265 *
266 *
267 * -print_config: prints custom algorithm options into buffer.
268 * typedef void (ta_print_config)(void *ta_state, struct table_info *ti,
269 * char *buf, size_t bufsize);
270 * OPTIONAL. locked(UH). (M_NOWAIT).
271 *
272 * Prints custom algorithm options in the format suitable to pass
273 * back to -init callback.
274 *
275 *
276 *
277 * -dump_tinfo: dumps algo-specific info.
278 * typedef void ta_dump_tinfo(void *ta_state, struct table_info *ti,
279 * ipfw_ta_tinfo *tinfo);
280 * OPTIONAL. locked(UH). (M_NOWAIT).
281 *
282 * Dumps options like items size/hash size, etc.
283 */
284
285 MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
286
287 /*
288 * Utility structures/functions common to more than one algo
289 */
290
291 struct mod_item {
292 void *main_ptr;
293 size_t size;
294 void *main_ptr6;
295 size_t size6;
296 };
297
298 static int badd(const void *key, void *item, void *base, size_t nmemb,
299 size_t size, int (*compar) (const void *, const void *));
300 static int bdel(const void *key, void *base, size_t nmemb, size_t size,
301 int (*compar) (const void *, const void *));
302
303 /*
304 * ADDR implementation using radix
305 *
306 */
307
308 /*
309 * The radix code expects addr and mask to be array of bytes,
310 * with the first byte being the length of the array. rn_inithead
311 * is called with the offset in bits of the lookup key within the
312 * array. If we use a sockaddr_in as the underlying type,
313 * sin_len is conveniently located at offset 0, sin_addr is at
314 * offset 4 and normally aligned.
315 * But for portability, let's avoid assumption and make the code explicit
316 */
317 #define KEY_LEN(v) *((uint8_t *)&(v))
318 /*
319 * Do not require radix to compare more than actual IPv4/IPv6/MAC address
320 */
321 #define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t))
322 #define KEY_LEN_INET6 (offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr))
323 #define KEY_LEN_MAC (offsetof(struct sa_mac, mac_addr) + ETHER_ADDR_LEN)
324
325 #define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr))
326 #define OFF_LEN_INET6 (8 * offsetof(struct sa_in6, sin6_addr))
327 #define OFF_LEN_MAC (8 * offsetof(struct sa_mac, mac_addr))
328
329 struct addr_radix_entry {
330 struct radix_node rn[2];
331 struct sockaddr_in addr;
332 uint32_t value;
333 uint8_t masklen;
334 };
335
336 struct sa_in6 {
337 uint8_t sin6_len;
338 uint8_t sin6_family;
339 uint8_t pad[2];
340 struct in6_addr sin6_addr;
341 };
342
343 struct addr_radix_xentry {
344 struct radix_node rn[2];
345 struct sa_in6 addr6;
346 uint32_t value;
347 uint8_t masklen;
348 };
349
350 struct addr_radix_cfg {
351 struct radix_node_head *head4;
352 struct radix_node_head *head6;
353 size_t count4;
354 size_t count6;
355 };
356
357 struct sa_mac {
358 uint8_t mac_len;
359 struct ether_addr mac_addr;
360 };
361
362 struct ta_buf_radix
363 {
364 void *ent_ptr;
365 struct sockaddr *addr_ptr;
366 struct sockaddr *mask_ptr;
367 union {
368 struct {
369 struct sockaddr_in sa;
370 struct sockaddr_in ma;
371 } a4;
372 struct {
373 struct sa_in6 sa;
374 struct sa_in6 ma;
375 } a6;
376 struct {
377 struct sa_mac sa;
378 struct sa_mac ma;
379 } mac;
380 } addr;
381 };
382
383 static int ta_lookup_addr_radix(struct table_info *ti, void *key, uint32_t keylen,
384 uint32_t *val);
385 static int ta_init_addr_radix(struct ip_fw_chain *ch, void **ta_state,
386 struct table_info *ti, char *data, uint8_t tflags);
387 static int flush_radix_entry(struct radix_node *rn, void *arg);
388 static void ta_destroy_addr_radix(void *ta_state, struct table_info *ti);
389 static void ta_dump_addr_radix_tinfo(void *ta_state, struct table_info *ti,
390 ipfw_ta_tinfo *tinfo);
391 static int ta_dump_addr_radix_tentry(void *ta_state, struct table_info *ti,
392 void *e, ipfw_obj_tentry *tent);
393 static int ta_find_addr_radix_tentry(void *ta_state, struct table_info *ti,
394 ipfw_obj_tentry *tent);
395 static void ta_foreach_addr_radix(void *ta_state, struct table_info *ti,
396 ta_foreach_f *f, void *arg);
397 static void tei_to_sockaddr_ent_addr(struct tentry_info *tei, struct sockaddr *sa,
398 struct sockaddr *ma, int *set_mask);
399 static int ta_prepare_add_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
400 void *ta_buf);
401 static int ta_add_addr_radix(void *ta_state, struct table_info *ti,
402 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
403 static int ta_prepare_del_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
404 void *ta_buf);
405 static int ta_del_addr_radix(void *ta_state, struct table_info *ti,
406 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
407 static void ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
408 void *ta_buf);
409 static int ta_need_modify_radix(void *ta_state, struct table_info *ti,
410 uint32_t count, uint64_t *pflags);
411
412 static int
413 ta_lookup_addr_radix(struct table_info *ti, void *key, uint32_t keylen,
414 uint32_t *val)
415 {
416 struct radix_node_head *rnh;
417
418 if (keylen == sizeof(in_addr_t)) {
419 struct addr_radix_entry *ent;
420 struct sockaddr_in sa;
421 KEY_LEN(sa) = KEY_LEN_INET;
422 sa.sin_addr.s_addr = *((in_addr_t *)key);
423 rnh = (struct radix_node_head *)ti->state;
424 ent = (struct addr_radix_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh));
425 if (ent != NULL) {
426 *val = ent->value;
427 return (1);
428 }
429 } else if (keylen == sizeof(struct in6_addr)) {
430 struct addr_radix_xentry *xent;
431 struct sa_in6 sa6;
432 KEY_LEN(sa6) = KEY_LEN_INET6;
433 memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr));
434 rnh = (struct radix_node_head *)ti->xstate;
435 xent = (struct addr_radix_xentry *)(rnh->rnh_matchaddr(&sa6, &rnh->rh));
436 if (xent != NULL) {
437 *val = xent->value;
438 return (1);
439 }
440 }
441
442 return (0);
443 }
444
445 /*
446 * New table
447 */
448 static int
449 ta_init_addr_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
450 char *data, uint8_t tflags)
451 {
452 struct addr_radix_cfg *cfg;
453
454 if (!rn_inithead(&ti->state, OFF_LEN_INET))
455 return (ENOMEM);
456 if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) {
457 rn_detachhead(&ti->state);
458 return (ENOMEM);
459 }
460
461 cfg = malloc(sizeof(struct addr_radix_cfg), M_IPFW, M_WAITOK | M_ZERO);
462
463 *ta_state = cfg;
464 ti->lookup = ta_lookup_addr_radix;
465
466 return (0);
467 }
468
469 static int
470 flush_radix_entry(struct radix_node *rn, void *arg)
471 {
472 struct radix_node_head * const rnh = arg;
473 struct addr_radix_entry *ent;
474
475 ent = (struct addr_radix_entry *)
476 rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, &rnh->rh);
477 if (ent != NULL)
478 free(ent, M_IPFW_TBL);
479 return (0);
480 }
481
482 static void
483 ta_destroy_addr_radix(void *ta_state, struct table_info *ti)
484 {
485 struct addr_radix_cfg *cfg;
486 struct radix_node_head *rnh;
487
488 cfg = (struct addr_radix_cfg *)ta_state;
489
490 rnh = (struct radix_node_head *)(ti->state);
491 rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
492 rn_detachhead(&ti->state);
493
494 rnh = (struct radix_node_head *)(ti->xstate);
495 rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
496 rn_detachhead(&ti->xstate);
497
498 free(cfg, M_IPFW);
499 }
500
501 /*
502 * Provide algo-specific table info
503 */
504 static void
505 ta_dump_addr_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
506 {
507 struct addr_radix_cfg *cfg;
508
509 cfg = (struct addr_radix_cfg *)ta_state;
510
511 tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
512 tinfo->taclass4 = IPFW_TACLASS_RADIX;
513 tinfo->count4 = cfg->count4;
514 tinfo->itemsize4 = sizeof(struct addr_radix_entry);
515 tinfo->taclass6 = IPFW_TACLASS_RADIX;
516 tinfo->count6 = cfg->count6;
517 tinfo->itemsize6 = sizeof(struct addr_radix_xentry);
518 }
519
520 static int
521 ta_dump_addr_radix_tentry(void *ta_state, struct table_info *ti, void *e,
522 ipfw_obj_tentry *tent)
523 {
524 struct addr_radix_entry *n;
525 #ifdef INET6
526 struct addr_radix_xentry *xn;
527 #endif
528
529 n = (struct addr_radix_entry *)e;
530
531 /* Guess IPv4/IPv6 radix by sockaddr family */
532 if (n->addr.sin_family == AF_INET) {
533 tent->k.addr.s_addr = n->addr.sin_addr.s_addr;
534 tent->masklen = n->masklen;
535 tent->subtype = AF_INET;
536 tent->v.kidx = n->value;
537 #ifdef INET6
538 } else {
539 xn = (struct addr_radix_xentry *)e;
540 memcpy(&tent->k.addr6, &xn->addr6.sin6_addr,
541 sizeof(struct in6_addr));
542 tent->masklen = xn->masklen;
543 tent->subtype = AF_INET6;
544 tent->v.kidx = xn->value;
545 #endif
546 }
547
548 return (0);
549 }
550
551 static int
552 ta_find_addr_radix_tentry(void *ta_state, struct table_info *ti,
553 ipfw_obj_tentry *tent)
554 {
555 struct radix_node_head *rnh;
556 void *e;
557
558 e = NULL;
559 if (tent->subtype == AF_INET) {
560 struct sockaddr_in sa;
561 KEY_LEN(sa) = KEY_LEN_INET;
562 sa.sin_addr.s_addr = tent->k.addr.s_addr;
563 rnh = (struct radix_node_head *)ti->state;
564 e = rnh->rnh_matchaddr(&sa, &rnh->rh);
565 } else if (tent->subtype == AF_INET6) {
566 struct sa_in6 sa6;
567 KEY_LEN(sa6) = KEY_LEN_INET6;
568 memcpy(&sa6.sin6_addr, &tent->k.addr6, sizeof(struct in6_addr));
569 rnh = (struct radix_node_head *)ti->xstate;
570 e = rnh->rnh_matchaddr(&sa6, &rnh->rh);
571 }
572
573 if (e != NULL) {
574 ta_dump_addr_radix_tentry(ta_state, ti, e, tent);
575 return (0);
576 }
577
578 return (ENOENT);
579 }
580
581 static void
582 ta_foreach_addr_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
583 void *arg)
584 {
585 struct radix_node_head *rnh;
586
587 rnh = (struct radix_node_head *)(ti->state);
588 rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg);
589
590 rnh = (struct radix_node_head *)(ti->xstate);
591 rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg);
592 }
593
594 #ifdef INET6
595 static inline void ipv6_writemask(struct in6_addr *addr6, uint8_t mask);
596
597 static inline void
598 ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
599 {
600 uint32_t *cp;
601
602 for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32)
603 *cp++ = 0xFFFFFFFF;
604 if (mask > 0)
605 *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
606 }
607 #endif
608
609 static void
610 tei_to_sockaddr_ent_addr(struct tentry_info *tei, struct sockaddr *sa,
611 struct sockaddr *ma, int *set_mask)
612 {
613 int mlen;
614 #ifdef INET
615 struct sockaddr_in *addr, *mask;
616 #endif
617 #ifdef INET6
618 struct sa_in6 *addr6, *mask6;
619 #endif
620 in_addr_t a4;
621
622 mlen = tei->masklen;
623
624 if (tei->subtype == AF_INET) {
625 #ifdef INET
626 addr = (struct sockaddr_in *)sa;
627 mask = (struct sockaddr_in *)ma;
628 /* Set 'total' structure length */
629 KEY_LEN(*addr) = KEY_LEN_INET;
630 KEY_LEN(*mask) = KEY_LEN_INET;
631 addr->sin_family = AF_INET;
632 mask->sin_addr.s_addr =
633 htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
634 a4 = *((in_addr_t *)tei->paddr);
635 addr->sin_addr.s_addr = a4 & mask->sin_addr.s_addr;
636 if (mlen != 32)
637 *set_mask = 1;
638 else
639 *set_mask = 0;
640 #endif
641 #ifdef INET6
642 } else if (tei->subtype == AF_INET6) {
643 /* IPv6 case */
644 addr6 = (struct sa_in6 *)sa;
645 mask6 = (struct sa_in6 *)ma;
646 /* Set 'total' structure length */
647 KEY_LEN(*addr6) = KEY_LEN_INET6;
648 KEY_LEN(*mask6) = KEY_LEN_INET6;
649 addr6->sin6_family = AF_INET6;
650 ipv6_writemask(&mask6->sin6_addr, mlen);
651 memcpy(&addr6->sin6_addr, tei->paddr, sizeof(struct in6_addr));
652 APPLY_MASK(&addr6->sin6_addr, &mask6->sin6_addr);
653 if (mlen != 128)
654 *set_mask = 1;
655 else
656 *set_mask = 0;
657 #endif
658 }
659 }
660
661 static int
662 ta_prepare_add_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
663 void *ta_buf)
664 {
665 struct ta_buf_radix *tb;
666 struct addr_radix_entry *ent;
667 #ifdef INET6
668 struct addr_radix_xentry *xent;
669 #endif
670 struct sockaddr *addr, *mask;
671 int mlen, set_mask;
672
673 tb = (struct ta_buf_radix *)ta_buf;
674
675 mlen = tei->masklen;
676 set_mask = 0;
677
678 if (tei->subtype == AF_INET) {
679 #ifdef INET
680 if (mlen > 32)
681 return (EINVAL);
682 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
683 ent->masklen = mlen;
684
685 addr = (struct sockaddr *)&ent->addr;
686 mask = (struct sockaddr *)&tb->addr.a4.ma;
687 tb->ent_ptr = ent;
688 #endif
689 #ifdef INET6
690 } else if (tei->subtype == AF_INET6) {
691 /* IPv6 case */
692 if (mlen > 128)
693 return (EINVAL);
694 xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
695 xent->masklen = mlen;
696
697 addr = (struct sockaddr *)&xent->addr6;
698 mask = (struct sockaddr *)&tb->addr.a6.ma;
699 tb->ent_ptr = xent;
700 #endif
701 } else {
702 /* Unknown CIDR type */
703 return (EINVAL);
704 }
705
706 tei_to_sockaddr_ent_addr(tei, addr, mask, &set_mask);
707 /* Set pointers */
708 tb->addr_ptr = addr;
709 if (set_mask != 0)
710 tb->mask_ptr = mask;
711
712 return (0);
713 }
714
715 static int
716 ta_add_addr_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
717 void *ta_buf, uint32_t *pnum)
718 {
719 struct addr_radix_cfg *cfg;
720 struct radix_node_head *rnh;
721 struct radix_node *rn;
722 struct ta_buf_radix *tb;
723 uint32_t *old_value, value;
724
725 cfg = (struct addr_radix_cfg *)ta_state;
726 tb = (struct ta_buf_radix *)ta_buf;
727
728 /* Save current entry value from @tei */
729 if (tei->subtype == AF_INET) {
730 rnh = ti->state;
731 ((struct addr_radix_entry *)tb->ent_ptr)->value = tei->value;
732 } else {
733 rnh = ti->xstate;
734 ((struct addr_radix_xentry *)tb->ent_ptr)->value = tei->value;
735 }
736
737 /* Search for an entry first */
738 rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
739 if (rn != NULL) {
740 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
741 return (EEXIST);
742 /* Record already exists. Update value if we're asked to */
743 if (tei->subtype == AF_INET)
744 old_value = &((struct addr_radix_entry *)rn)->value;
745 else
746 old_value = &((struct addr_radix_xentry *)rn)->value;
747
748 value = *old_value;
749 *old_value = tei->value;
750 tei->value = value;
751
752 /* Indicate that update has happened instead of addition */
753 tei->flags |= TEI_FLAGS_UPDATED;
754 *pnum = 0;
755
756 return (0);
757 }
758
759 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
760 return (EFBIG);
761
762 rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, &rnh->rh,tb->ent_ptr);
763 if (rn == NULL) {
764 /* Unknown error */
765 return (EINVAL);
766 }
767
768 if (tei->subtype == AF_INET)
769 cfg->count4++;
770 else
771 cfg->count6++;
772 tb->ent_ptr = NULL;
773 *pnum = 1;
774
775 return (0);
776 }
777
778 static int
779 ta_prepare_del_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
780 void *ta_buf)
781 {
782 struct ta_buf_radix *tb;
783 struct sockaddr *addr, *mask;
784 int mlen, set_mask;
785
786 tb = (struct ta_buf_radix *)ta_buf;
787
788 mlen = tei->masklen;
789 set_mask = 0;
790
791 if (tei->subtype == AF_INET) {
792 if (mlen > 32)
793 return (EINVAL);
794
795 addr = (struct sockaddr *)&tb->addr.a4.sa;
796 mask = (struct sockaddr *)&tb->addr.a4.ma;
797 #ifdef INET6
798 } else if (tei->subtype == AF_INET6) {
799 if (mlen > 128)
800 return (EINVAL);
801
802 addr = (struct sockaddr *)&tb->addr.a6.sa;
803 mask = (struct sockaddr *)&tb->addr.a6.ma;
804 #endif
805 } else
806 return (EINVAL);
807
808 tei_to_sockaddr_ent_addr(tei, addr, mask, &set_mask);
809 tb->addr_ptr = addr;
810 if (set_mask != 0)
811 tb->mask_ptr = mask;
812
813 return (0);
814 }
815
816 static int
817 ta_del_addr_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
818 void *ta_buf, uint32_t *pnum)
819 {
820 struct addr_radix_cfg *cfg;
821 struct radix_node_head *rnh;
822 struct radix_node *rn;
823 struct ta_buf_radix *tb;
824
825 cfg = (struct addr_radix_cfg *)ta_state;
826 tb = (struct ta_buf_radix *)ta_buf;
827
828 if (tei->subtype == AF_INET)
829 rnh = ti->state;
830 else
831 rnh = ti->xstate;
832
833 rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
834
835 if (rn == NULL)
836 return (ENOENT);
837
838 /* Save entry value to @tei */
839 if (tei->subtype == AF_INET)
840 tei->value = ((struct addr_radix_entry *)rn)->value;
841 else
842 tei->value = ((struct addr_radix_xentry *)rn)->value;
843
844 tb->ent_ptr = rn;
845
846 if (tei->subtype == AF_INET)
847 cfg->count4--;
848 else
849 cfg->count6--;
850 *pnum = 1;
851
852 return (0);
853 }
854
855 static void
856 ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
857 void *ta_buf)
858 {
859 struct ta_buf_radix *tb;
860
861 tb = (struct ta_buf_radix *)ta_buf;
862
863 if (tb->ent_ptr != NULL)
864 free(tb->ent_ptr, M_IPFW_TBL);
865 }
866
867 static int
868 ta_need_modify_radix(void *ta_state, struct table_info *ti, uint32_t count,
869 uint64_t *pflags)
870 {
871
872 /*
873 * radix does not require additional memory allocations
874 * other than nodes itself. Adding new masks to the tree do
875 * but we don't have any API to call (and we don't known which
876 * sizes do we need).
877 */
878 return (0);
879 }
880
881 struct table_algo addr_radix = {
882 .name = "addr:radix",
883 .type = IPFW_TABLE_ADDR,
884 .flags = TA_FLAG_DEFAULT,
885 .ta_buf_size = sizeof(struct ta_buf_radix),
886 .init = ta_init_addr_radix,
887 .destroy = ta_destroy_addr_radix,
888 .prepare_add = ta_prepare_add_addr_radix,
889 .prepare_del = ta_prepare_del_addr_radix,
890 .add = ta_add_addr_radix,
891 .del = ta_del_addr_radix,
892 .flush_entry = ta_flush_radix_entry,
893 .foreach = ta_foreach_addr_radix,
894 .dump_tentry = ta_dump_addr_radix_tentry,
895 .find_tentry = ta_find_addr_radix_tentry,
896 .dump_tinfo = ta_dump_addr_radix_tinfo,
897 .need_modify = ta_need_modify_radix,
898 };
899
900 /*
901 * addr:hash cmds
902 *
903 *
904 * ti->data:
905 * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
906 * [ 8][ 8[ 8][ 8]
907 *
908 * inv.mask4: 32 - mask
909 * inv.mask6:
910 * 1) _slow lookup: mask
911 * 2) _aligned: (128 - mask) / 8
912 * 3) _64: 8
913 *
914 *
915 * pflags:
916 * [v4=1/v6=0][hsize]
917 * [ 32][ 32]
918 */
919
920 struct chashentry;
921
922 SLIST_HEAD(chashbhead, chashentry);
923
924 struct chash_cfg {
925 struct chashbhead *head4;
926 struct chashbhead *head6;
927 size_t size4;
928 size_t size6;
929 size_t items4;
930 size_t items6;
931 uint8_t mask4;
932 uint8_t mask6;
933 };
934
935 struct chashentry {
936 SLIST_ENTRY(chashentry) next;
937 uint32_t value;
938 uint32_t type;
939 union {
940 uint32_t a4; /* Host format */
941 struct in6_addr a6; /* Network format */
942 } a;
943 };
944
945 struct ta_buf_chash
946 {
947 void *ent_ptr;
948 struct chashentry ent;
949 };
950
951 #ifdef INET
952 static __inline uint32_t hash_ip(uint32_t addr, int hsize);
953 #endif
954 #ifdef INET6
955 static __inline uint32_t hash_ip6(struct in6_addr *addr6, int hsize);
956 static __inline uint16_t hash_ip64(struct in6_addr *addr6, int hsize);
957 static __inline uint32_t hash_ip6_slow(struct in6_addr *addr6, void *key,
958 int mask, int hsize);
959 static __inline uint32_t hash_ip6_al(struct in6_addr *addr6, void *key, int mask,
960 int hsize);
961 #endif
962 static int ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
963 uint32_t *val);
964 static int ta_lookup_chash_aligned(struct table_info *ti, void *key,
965 uint32_t keylen, uint32_t *val);
966 static int ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
967 uint32_t *val);
968 static int chash_parse_opts(struct chash_cfg *cfg, char *data);
969 static void ta_print_chash_config(void *ta_state, struct table_info *ti,
970 char *buf, size_t bufsize);
971 static int ta_log2(uint32_t v);
972 static int ta_init_chash(struct ip_fw_chain *ch, void **ta_state,
973 struct table_info *ti, char *data, uint8_t tflags);
974 static void ta_destroy_chash(void *ta_state, struct table_info *ti);
975 static void ta_dump_chash_tinfo(void *ta_state, struct table_info *ti,
976 ipfw_ta_tinfo *tinfo);
977 static int ta_dump_chash_tentry(void *ta_state, struct table_info *ti,
978 void *e, ipfw_obj_tentry *tent);
979 static uint32_t hash_ent(struct chashentry *ent, int af, int mlen,
980 uint32_t size);
981 static int tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent);
982 static int ta_find_chash_tentry(void *ta_state, struct table_info *ti,
983 ipfw_obj_tentry *tent);
984 static void ta_foreach_chash(void *ta_state, struct table_info *ti,
985 ta_foreach_f *f, void *arg);
986 static int ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
987 void *ta_buf);
988 static int ta_add_chash(void *ta_state, struct table_info *ti,
989 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
990 static int ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
991 void *ta_buf);
992 static int ta_del_chash(void *ta_state, struct table_info *ti,
993 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
994 static void ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
995 void *ta_buf);
996 static int ta_need_modify_chash(void *ta_state, struct table_info *ti,
997 uint32_t count, uint64_t *pflags);
998 static int ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags);
999 static int ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1000 uint64_t *pflags);
1001 static void ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1002 uint64_t pflags);
1003 static void ta_flush_mod_chash(void *ta_buf);
1004
1005 #ifdef INET
1006 static __inline uint32_t
1007 hash_ip(uint32_t addr, int hsize)
1008 {
1009
1010 return (addr % (hsize - 1));
1011 }
1012 #endif
1013
1014 #ifdef INET6
1015 static __inline uint32_t
1016 hash_ip6(struct in6_addr *addr6, int hsize)
1017 {
1018 uint32_t i;
1019
1020 i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1] ^
1021 addr6->s6_addr32[2] ^ addr6->s6_addr32[3];
1022
1023 return (i % (hsize - 1));
1024 }
1025
1026 static __inline uint16_t
1027 hash_ip64(struct in6_addr *addr6, int hsize)
1028 {
1029 uint32_t i;
1030
1031 i = addr6->s6_addr32[0] ^ addr6->s6_addr32[1];
1032
1033 return (i % (hsize - 1));
1034 }
1035
1036 static __inline uint32_t
1037 hash_ip6_slow(struct in6_addr *addr6, void *key, int mask, int hsize)
1038 {
1039 struct in6_addr mask6;
1040
1041 ipv6_writemask(&mask6, mask);
1042 memcpy(addr6, key, sizeof(struct in6_addr));
1043 APPLY_MASK(addr6, &mask6);
1044 return (hash_ip6(addr6, hsize));
1045 }
1046
1047 static __inline uint32_t
1048 hash_ip6_al(struct in6_addr *addr6, void *key, int mask, int hsize)
1049 {
1050 uint64_t *paddr;
1051
1052 paddr = (uint64_t *)addr6;
1053 *paddr = 0;
1054 *(paddr + 1) = 0;
1055 memcpy(addr6, key, mask);
1056 return (hash_ip6(addr6, hsize));
1057 }
1058 #endif
1059
1060 static int
1061 ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen,
1062 uint32_t *val)
1063 {
1064 struct chashbhead *head;
1065 struct chashentry *ent;
1066 uint16_t hash, hsize;
1067 uint8_t imask;
1068
1069 if (keylen == sizeof(in_addr_t)) {
1070 #ifdef INET
1071 head = (struct chashbhead *)ti->state;
1072 imask = ti->data >> 24;
1073 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
1074 uint32_t a;
1075 a = ntohl(*((in_addr_t *)key));
1076 a = a >> imask;
1077 hash = hash_ip(a, hsize);
1078 SLIST_FOREACH(ent, &head[hash], next) {
1079 if (ent->a.a4 == a) {
1080 *val = ent->value;
1081 return (1);
1082 }
1083 }
1084 #endif
1085 } else {
1086 #ifdef INET6
1087 /* IPv6: worst scenario: non-round mask */
1088 struct in6_addr addr6;
1089 head = (struct chashbhead *)ti->xstate;
1090 imask = (ti->data & 0xFF0000) >> 16;
1091 hsize = 1 << (ti->data & 0xFF);
1092 hash = hash_ip6_slow(&addr6, key, imask, hsize);
1093 SLIST_FOREACH(ent, &head[hash], next) {
1094 if (memcmp(&ent->a.a6, &addr6, 16) == 0) {
1095 *val = ent->value;
1096 return (1);
1097 }
1098 }
1099 #endif
1100 }
1101
1102 return (0);
1103 }
1104
1105 static int
1106 ta_lookup_chash_aligned(struct table_info *ti, void *key, uint32_t keylen,
1107 uint32_t *val)
1108 {
1109 struct chashbhead *head;
1110 struct chashentry *ent;
1111 uint16_t hash, hsize;
1112 uint8_t imask;
1113
1114 if (keylen == sizeof(in_addr_t)) {
1115 #ifdef INET
1116 head = (struct chashbhead *)ti->state;
1117 imask = ti->data >> 24;
1118 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
1119 uint32_t a;
1120 a = ntohl(*((in_addr_t *)key));
1121 a = a >> imask;
1122 hash = hash_ip(a, hsize);
1123 SLIST_FOREACH(ent, &head[hash], next) {
1124 if (ent->a.a4 == a) {
1125 *val = ent->value;
1126 return (1);
1127 }
1128 }
1129 #endif
1130 } else {
1131 #ifdef INET6
1132 /* IPv6: aligned to 8bit mask */
1133 struct in6_addr addr6;
1134 uint64_t *paddr, *ptmp;
1135 head = (struct chashbhead *)ti->xstate;
1136 imask = (ti->data & 0xFF0000) >> 16;
1137 hsize = 1 << (ti->data & 0xFF);
1138
1139 hash = hash_ip6_al(&addr6, key, imask, hsize);
1140 paddr = (uint64_t *)&addr6;
1141 SLIST_FOREACH(ent, &head[hash], next) {
1142 ptmp = (uint64_t *)&ent->a.a6;
1143 if (paddr[0] == ptmp[0] && paddr[1] == ptmp[1]) {
1144 *val = ent->value;
1145 return (1);
1146 }
1147 }
1148 #endif
1149 }
1150
1151 return (0);
1152 }
1153
1154 static int
1155 ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen,
1156 uint32_t *val)
1157 {
1158 struct chashbhead *head;
1159 struct chashentry *ent;
1160 uint16_t hash, hsize;
1161 uint8_t imask;
1162
1163 if (keylen == sizeof(in_addr_t)) {
1164 #ifdef INET
1165 head = (struct chashbhead *)ti->state;
1166 imask = ti->data >> 24;
1167 hsize = 1 << ((ti->data & 0xFFFF) >> 8);
1168 uint32_t a;
1169 a = ntohl(*((in_addr_t *)key));
1170 a = a >> imask;
1171 hash = hash_ip(a, hsize);
1172 SLIST_FOREACH(ent, &head[hash], next) {
1173 if (ent->a.a4 == a) {
1174 *val = ent->value;
1175 return (1);
1176 }
1177 }
1178 #endif
1179 } else {
1180 #ifdef INET6
1181 /* IPv6: /64 */
1182 uint64_t a6, *paddr;
1183 head = (struct chashbhead *)ti->xstate;
1184 paddr = (uint64_t *)key;
1185 hsize = 1 << (ti->data & 0xFF);
1186 a6 = *paddr;
1187 hash = hash_ip64((struct in6_addr *)key, hsize);
1188 SLIST_FOREACH(ent, &head[hash], next) {
1189 paddr = (uint64_t *)&ent->a.a6;
1190 if (a6 == *paddr) {
1191 *val = ent->value;
1192 return (1);
1193 }
1194 }
1195 #endif
1196 }
1197
1198 return (0);
1199 }
1200
1201 static int
1202 chash_parse_opts(struct chash_cfg *cfg, char *data)
1203 {
1204 char *pdel, *pend, *s;
1205 int mask4, mask6;
1206
1207 mask4 = cfg->mask4;
1208 mask6 = cfg->mask6;
1209
1210 if (data == NULL)
1211 return (0);
1212 if ((pdel = strchr(data, ' ')) == NULL)
1213 return (0);
1214 while (*pdel == ' ')
1215 pdel++;
1216 if (strncmp(pdel, "masks=", 6) != 0)
1217 return (EINVAL);
1218 if ((s = strchr(pdel, ' ')) != NULL)
1219 *s++ = '\0';
1220
1221 pdel += 6;
1222 /* Need /XX[,/YY] */
1223 if (*pdel++ != '/')
1224 return (EINVAL);
1225 mask4 = strtol(pdel, &pend, 10);
1226 if (*pend == ',') {
1227 /* ,/YY */
1228 pdel = pend + 1;
1229 if (*pdel++ != '/')
1230 return (EINVAL);
1231 mask6 = strtol(pdel, &pend, 10);
1232 if (*pend != '\0')
1233 return (EINVAL);
1234 } else if (*pend != '\0')
1235 return (EINVAL);
1236
1237 if (mask4 < 0 || mask4 > 32 || mask6 < 0 || mask6 > 128)
1238 return (EINVAL);
1239
1240 cfg->mask4 = mask4;
1241 cfg->mask6 = mask6;
1242
1243 return (0);
1244 }
1245
1246 static void
1247 ta_print_chash_config(void *ta_state, struct table_info *ti, char *buf,
1248 size_t bufsize)
1249 {
1250 struct chash_cfg *cfg;
1251
1252 cfg = (struct chash_cfg *)ta_state;
1253
1254 if (cfg->mask4 != 32 || cfg->mask6 != 128)
1255 snprintf(buf, bufsize, "%s masks=/%d,/%d", "addr:hash",
1256 cfg->mask4, cfg->mask6);
1257 else
1258 snprintf(buf, bufsize, "%s", "addr:hash");
1259 }
1260
1261 static int
1262 ta_log2(uint32_t v)
1263 {
1264 uint32_t r;
1265
1266 r = 0;
1267 while (v >>= 1)
1268 r++;
1269
1270 return (r);
1271 }
1272
1273 /*
1274 * New table.
1275 * We assume 'data' to be either NULL or the following format:
1276 * 'addr:hash [masks=/32[,/128]]'
1277 */
1278 static int
1279 ta_init_chash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
1280 char *data, uint8_t tflags)
1281 {
1282 int error, i;
1283 uint32_t hsize;
1284 struct chash_cfg *cfg;
1285
1286 cfg = malloc(sizeof(struct chash_cfg), M_IPFW, M_WAITOK | M_ZERO);
1287
1288 cfg->mask4 = 32;
1289 cfg->mask6 = 128;
1290
1291 if ((error = chash_parse_opts(cfg, data)) != 0) {
1292 free(cfg, M_IPFW);
1293 return (error);
1294 }
1295
1296 cfg->size4 = 128;
1297 cfg->size6 = 128;
1298
1299 cfg->head4 = malloc(sizeof(struct chashbhead) * cfg->size4, M_IPFW,
1300 M_WAITOK | M_ZERO);
1301 cfg->head6 = malloc(sizeof(struct chashbhead) * cfg->size6, M_IPFW,
1302 M_WAITOK | M_ZERO);
1303 for (i = 0; i < cfg->size4; i++)
1304 SLIST_INIT(&cfg->head4[i]);
1305 for (i = 0; i < cfg->size6; i++)
1306 SLIST_INIT(&cfg->head6[i]);
1307
1308 *ta_state = cfg;
1309 ti->state = cfg->head4;
1310 ti->xstate = cfg->head6;
1311
1312 /* Store data depending on v6 mask length */
1313 hsize = ta_log2(cfg->size4) << 8 | ta_log2(cfg->size6);
1314 if (cfg->mask6 == 64) {
1315 ti->data = (32 - cfg->mask4) << 24 | (128 - cfg->mask6) << 16|
1316 hsize;
1317 ti->lookup = ta_lookup_chash_64;
1318 } else if ((cfg->mask6 % 8) == 0) {
1319 ti->data = (32 - cfg->mask4) << 24 |
1320 cfg->mask6 << 13 | hsize;
1321 ti->lookup = ta_lookup_chash_aligned;
1322 } else {
1323 /* don't do that! */
1324 ti->data = (32 - cfg->mask4) << 24 |
1325 cfg->mask6 << 16 | hsize;
1326 ti->lookup = ta_lookup_chash_slow;
1327 }
1328
1329 return (0);
1330 }
1331
1332 static void
1333 ta_destroy_chash(void *ta_state, struct table_info *ti)
1334 {
1335 struct chash_cfg *cfg;
1336 struct chashentry *ent, *ent_next;
1337 int i;
1338
1339 cfg = (struct chash_cfg *)ta_state;
1340
1341 for (i = 0; i < cfg->size4; i++)
1342 SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next)
1343 free(ent, M_IPFW_TBL);
1344
1345 for (i = 0; i < cfg->size6; i++)
1346 SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next)
1347 free(ent, M_IPFW_TBL);
1348
1349 free(cfg->head4, M_IPFW);
1350 free(cfg->head6, M_IPFW);
1351
1352 free(cfg, M_IPFW);
1353 }
1354
1355 static void
1356 ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
1357 {
1358 struct chash_cfg *cfg;
1359
1360 cfg = (struct chash_cfg *)ta_state;
1361
1362 tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
1363 tinfo->taclass4 = IPFW_TACLASS_HASH;
1364 tinfo->size4 = cfg->size4;
1365 tinfo->count4 = cfg->items4;
1366 tinfo->itemsize4 = sizeof(struct chashentry);
1367 tinfo->taclass6 = IPFW_TACLASS_HASH;
1368 tinfo->size6 = cfg->size6;
1369 tinfo->count6 = cfg->items6;
1370 tinfo->itemsize6 = sizeof(struct chashentry);
1371 }
1372
1373 static int
1374 ta_dump_chash_tentry(void *ta_state, struct table_info *ti, void *e,
1375 ipfw_obj_tentry *tent)
1376 {
1377 struct chash_cfg *cfg;
1378 struct chashentry *ent;
1379
1380 cfg = (struct chash_cfg *)ta_state;
1381 ent = (struct chashentry *)e;
1382
1383 if (ent->type == AF_INET) {
1384 tent->k.addr.s_addr = htonl(ent->a.a4 << (32 - cfg->mask4));
1385 tent->masklen = cfg->mask4;
1386 tent->subtype = AF_INET;
1387 tent->v.kidx = ent->value;
1388 #ifdef INET6
1389 } else {
1390 memcpy(&tent->k.addr6, &ent->a.a6, sizeof(struct in6_addr));
1391 tent->masklen = cfg->mask6;
1392 tent->subtype = AF_INET6;
1393 tent->v.kidx = ent->value;
1394 #endif
1395 }
1396
1397 return (0);
1398 }
1399
1400 static uint32_t
1401 hash_ent(struct chashentry *ent, int af, int mlen, uint32_t size)
1402 {
1403 uint32_t hash;
1404
1405 hash = 0;
1406
1407 if (af == AF_INET) {
1408 #ifdef INET
1409 hash = hash_ip(ent->a.a4, size);
1410 #endif
1411 } else {
1412 #ifdef INET6
1413 if (mlen == 64)
1414 hash = hash_ip64(&ent->a.a6, size);
1415 else
1416 hash = hash_ip6(&ent->a.a6, size);
1417 #endif
1418 }
1419
1420 return (hash);
1421 }
1422
1423 static int
1424 tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent)
1425 {
1426 int mlen;
1427 #ifdef INET6
1428 struct in6_addr mask6;
1429 #endif
1430
1431 mlen = tei->masklen;
1432
1433 if (tei->subtype == AF_INET) {
1434 #ifdef INET
1435 if (mlen > 32)
1436 return (EINVAL);
1437 ent->type = AF_INET;
1438
1439 /* Calculate masked address */
1440 ent->a.a4 = ntohl(*((in_addr_t *)tei->paddr)) >> (32 - mlen);
1441 #endif
1442 #ifdef INET6
1443 } else if (tei->subtype == AF_INET6) {
1444 /* IPv6 case */
1445 if (mlen > 128)
1446 return (EINVAL);
1447 ent->type = AF_INET6;
1448
1449 ipv6_writemask(&mask6, mlen);
1450 memcpy(&ent->a.a6, tei->paddr, sizeof(struct in6_addr));
1451 APPLY_MASK(&ent->a.a6, &mask6);
1452 #endif
1453 } else {
1454 /* Unknown CIDR type */
1455 return (EINVAL);
1456 }
1457
1458 return (0);
1459 }
1460
1461 static int
1462 ta_find_chash_tentry(void *ta_state, struct table_info *ti,
1463 ipfw_obj_tentry *tent)
1464 {
1465 struct chash_cfg *cfg;
1466 struct chashbhead *head;
1467 struct chashentry ent, *tmp;
1468 struct tentry_info tei;
1469 int error;
1470 uint32_t hash;
1471
1472 cfg = (struct chash_cfg *)ta_state;
1473
1474 memset(&ent, 0, sizeof(ent));
1475 memset(&tei, 0, sizeof(tei));
1476
1477 if (tent->subtype == AF_INET) {
1478 tei.paddr = &tent->k.addr;
1479 tei.masklen = cfg->mask4;
1480 tei.subtype = AF_INET;
1481
1482 if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
1483 return (error);
1484
1485 head = cfg->head4;
1486 hash = hash_ent(&ent, AF_INET, cfg->mask4, cfg->size4);
1487 /* Check for existence */
1488 SLIST_FOREACH(tmp, &head[hash], next) {
1489 if (tmp->a.a4 != ent.a.a4)
1490 continue;
1491
1492 ta_dump_chash_tentry(ta_state, ti, tmp, tent);
1493 return (0);
1494 }
1495 } else {
1496 tei.paddr = &tent->k.addr6;
1497 tei.masklen = cfg->mask6;
1498 tei.subtype = AF_INET6;
1499
1500 if ((error = tei_to_chash_ent(&tei, &ent)) != 0)
1501 return (error);
1502
1503 head = cfg->head6;
1504 hash = hash_ent(&ent, AF_INET6, cfg->mask6, cfg->size6);
1505 /* Check for existence */
1506 SLIST_FOREACH(tmp, &head[hash], next) {
1507 if (memcmp(&tmp->a.a6, &ent.a.a6, 16) != 0)
1508 continue;
1509 ta_dump_chash_tentry(ta_state, ti, tmp, tent);
1510 return (0);
1511 }
1512 }
1513
1514 return (ENOENT);
1515 }
1516
1517 static void
1518 ta_foreach_chash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
1519 void *arg)
1520 {
1521 struct chash_cfg *cfg;
1522 struct chashentry *ent, *ent_next;
1523 int i;
1524
1525 cfg = (struct chash_cfg *)ta_state;
1526
1527 for (i = 0; i < cfg->size4; i++)
1528 SLIST_FOREACH_SAFE(ent, &cfg->head4[i], next, ent_next)
1529 f(ent, arg);
1530
1531 for (i = 0; i < cfg->size6; i++)
1532 SLIST_FOREACH_SAFE(ent, &cfg->head6[i], next, ent_next)
1533 f(ent, arg);
1534 }
1535
1536 static int
1537 ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
1538 void *ta_buf)
1539 {
1540 struct ta_buf_chash *tb;
1541 struct chashentry *ent;
1542 int error;
1543
1544 tb = (struct ta_buf_chash *)ta_buf;
1545
1546 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
1547
1548 error = tei_to_chash_ent(tei, ent);
1549 if (error != 0) {
1550 free(ent, M_IPFW_TBL);
1551 return (error);
1552 }
1553 tb->ent_ptr = ent;
1554
1555 return (0);
1556 }
1557
1558 static int
1559 ta_add_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1560 void *ta_buf, uint32_t *pnum)
1561 {
1562 struct chash_cfg *cfg;
1563 struct chashbhead *head;
1564 struct chashentry *ent, *tmp;
1565 struct ta_buf_chash *tb;
1566 int exists;
1567 uint32_t hash, value;
1568
1569 cfg = (struct chash_cfg *)ta_state;
1570 tb = (struct ta_buf_chash *)ta_buf;
1571 ent = (struct chashentry *)tb->ent_ptr;
1572 hash = 0;
1573 exists = 0;
1574
1575 /* Read current value from @tei */
1576 ent->value = tei->value;
1577
1578 /* Read cuurrent value */
1579 if (tei->subtype == AF_INET) {
1580 if (tei->masklen != cfg->mask4)
1581 return (EINVAL);
1582 head = cfg->head4;
1583 hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4);
1584
1585 /* Check for existence */
1586 SLIST_FOREACH(tmp, &head[hash], next) {
1587 if (tmp->a.a4 == ent->a.a4) {
1588 exists = 1;
1589 break;
1590 }
1591 }
1592 } else {
1593 if (tei->masklen != cfg->mask6)
1594 return (EINVAL);
1595 head = cfg->head6;
1596 hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6);
1597 /* Check for existence */
1598 SLIST_FOREACH(tmp, &head[hash], next) {
1599 if (memcmp(&tmp->a.a6, &ent->a.a6, 16) == 0) {
1600 exists = 1;
1601 break;
1602 }
1603 }
1604 }
1605
1606 if (exists == 1) {
1607 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
1608 return (EEXIST);
1609 /* Record already exists. Update value if we're asked to */
1610 value = tmp->value;
1611 tmp->value = tei->value;
1612 tei->value = value;
1613 /* Indicate that update has happened instead of addition */
1614 tei->flags |= TEI_FLAGS_UPDATED;
1615 *pnum = 0;
1616 } else {
1617 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
1618 return (EFBIG);
1619 SLIST_INSERT_HEAD(&head[hash], ent, next);
1620 tb->ent_ptr = NULL;
1621 *pnum = 1;
1622
1623 /* Update counters */
1624 if (tei->subtype == AF_INET)
1625 cfg->items4++;
1626 else
1627 cfg->items6++;
1628 }
1629
1630 return (0);
1631 }
1632
1633 static int
1634 ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei,
1635 void *ta_buf)
1636 {
1637 struct ta_buf_chash *tb;
1638
1639 tb = (struct ta_buf_chash *)ta_buf;
1640
1641 return (tei_to_chash_ent(tei, &tb->ent));
1642 }
1643
1644 static int
1645 ta_del_chash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
1646 void *ta_buf, uint32_t *pnum)
1647 {
1648 struct chash_cfg *cfg;
1649 struct chashbhead *head;
1650 struct chashentry *tmp, *tmp_next, *ent;
1651 struct ta_buf_chash *tb;
1652 uint32_t hash;
1653
1654 cfg = (struct chash_cfg *)ta_state;
1655 tb = (struct ta_buf_chash *)ta_buf;
1656 ent = &tb->ent;
1657
1658 if (tei->subtype == AF_INET) {
1659 if (tei->masklen != cfg->mask4)
1660 return (EINVAL);
1661 head = cfg->head4;
1662 hash = hash_ent(ent, AF_INET, cfg->mask4, cfg->size4);
1663
1664 SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) {
1665 if (tmp->a.a4 != ent->a.a4)
1666 continue;
1667
1668 SLIST_REMOVE(&head[hash], tmp, chashentry, next);
1669 cfg->items4--;
1670 tb->ent_ptr = tmp;
1671 tei->value = tmp->value;
1672 *pnum = 1;
1673 return (0);
1674 }
1675 } else {
1676 if (tei->masklen != cfg->mask6)
1677 return (EINVAL);
1678 head = cfg->head6;
1679 hash = hash_ent(ent, AF_INET6, cfg->mask6, cfg->size6);
1680 SLIST_FOREACH_SAFE(tmp, &head[hash], next, tmp_next) {
1681 if (memcmp(&tmp->a.a6, &ent->a.a6, 16) != 0)
1682 continue;
1683
1684 SLIST_REMOVE(&head[hash], tmp, chashentry, next);
1685 cfg->items6--;
1686 tb->ent_ptr = tmp;
1687 tei->value = tmp->value;
1688 *pnum = 1;
1689 return (0);
1690 }
1691 }
1692
1693 return (ENOENT);
1694 }
1695
1696 static void
1697 ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
1698 void *ta_buf)
1699 {
1700 struct ta_buf_chash *tb;
1701
1702 tb = (struct ta_buf_chash *)ta_buf;
1703
1704 if (tb->ent_ptr != NULL)
1705 free(tb->ent_ptr, M_IPFW_TBL);
1706 }
1707
1708 /*
1709 * Hash growing callbacks.
1710 */
1711
1712 static int
1713 ta_need_modify_chash(void *ta_state, struct table_info *ti, uint32_t count,
1714 uint64_t *pflags)
1715 {
1716 struct chash_cfg *cfg;
1717 uint64_t data;
1718
1719 /*
1720 * Since we don't know exact number of IPv4/IPv6 records in @count,
1721 * ignore non-zero @count value at all. Check current hash sizes
1722 * and return appropriate data.
1723 */
1724
1725 cfg = (struct chash_cfg *)ta_state;
1726
1727 data = 0;
1728 if (cfg->items4 > cfg->size4 && cfg->size4 < 65536)
1729 data |= (cfg->size4 * 2) << 16;
1730 if (cfg->items6 > cfg->size6 && cfg->size6 < 65536)
1731 data |= cfg->size6 * 2;
1732
1733 if (data != 0) {
1734 *pflags = data;
1735 return (1);
1736 }
1737
1738 return (0);
1739 }
1740
1741 /*
1742 * Allocate new, larger chash.
1743 */
1744 static int
1745 ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags)
1746 {
1747 struct mod_item *mi;
1748 struct chashbhead *head;
1749 int i;
1750
1751 mi = (struct mod_item *)ta_buf;
1752
1753 memset(mi, 0, sizeof(struct mod_item));
1754 mi->size = (*pflags >> 16) & 0xFFFF;
1755 mi->size6 = *pflags & 0xFFFF;
1756 if (mi->size > 0) {
1757 head = malloc(sizeof(struct chashbhead) * mi->size,
1758 M_IPFW, M_WAITOK | M_ZERO);
1759 for (i = 0; i < mi->size; i++)
1760 SLIST_INIT(&head[i]);
1761 mi->main_ptr = head;
1762 }
1763
1764 if (mi->size6 > 0) {
1765 head = malloc(sizeof(struct chashbhead) * mi->size6,
1766 M_IPFW, M_WAITOK | M_ZERO);
1767 for (i = 0; i < mi->size6; i++)
1768 SLIST_INIT(&head[i]);
1769 mi->main_ptr6 = head;
1770 }
1771
1772 return (0);
1773 }
1774
1775 /*
1776 * Copy data from old runtime array to new one.
1777 */
1778 static int
1779 ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1780 uint64_t *pflags)
1781 {
1782
1783 /* In is not possible to do rehash if we're not holidng WLOCK. */
1784 return (0);
1785 }
1786
1787 /*
1788 * Switch old & new arrays.
1789 */
1790 static void
1791 ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf,
1792 uint64_t pflags)
1793 {
1794 struct mod_item *mi;
1795 struct chash_cfg *cfg;
1796 struct chashbhead *old_head, *new_head;
1797 struct chashentry *ent, *ent_next;
1798 int af, i, mlen;
1799 uint32_t nhash;
1800 size_t old_size, new_size;
1801
1802 mi = (struct mod_item *)ta_buf;
1803 cfg = (struct chash_cfg *)ta_state;
1804
1805 /* Check which hash we need to grow and do we still need that */
1806 if (mi->size > 0 && cfg->size4 < mi->size) {
1807 new_head = (struct chashbhead *)mi->main_ptr;
1808 new_size = mi->size;
1809 old_size = cfg->size4;
1810 old_head = ti->state;
1811 mlen = cfg->mask4;
1812 af = AF_INET;
1813
1814 for (i = 0; i < old_size; i++) {
1815 SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
1816 nhash = hash_ent(ent, af, mlen, new_size);
1817 SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
1818 }
1819 }
1820
1821 ti->state = new_head;
1822 cfg->head4 = new_head;
1823 cfg->size4 = mi->size;
1824 mi->main_ptr = old_head;
1825 }
1826
1827 if (mi->size6 > 0 && cfg->size6 < mi->size6) {
1828 new_head = (struct chashbhead *)mi->main_ptr6;
1829 new_size = mi->size6;
1830 old_size = cfg->size6;
1831 old_head = ti->xstate;
1832 mlen = cfg->mask6;
1833 af = AF_INET6;
1834
1835 for (i = 0; i < old_size; i++) {
1836 SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
1837 nhash = hash_ent(ent, af, mlen, new_size);
1838 SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
1839 }
1840 }
1841
1842 ti->xstate = new_head;
1843 cfg->head6 = new_head;
1844 cfg->size6 = mi->size6;
1845 mi->main_ptr6 = old_head;
1846 }
1847
1848 /* Update lower 32 bits with new values */
1849 ti->data &= 0xFFFFFFFF00000000;
1850 ti->data |= ta_log2(cfg->size4) << 8 | ta_log2(cfg->size6);
1851 }
1852
1853 /*
1854 * Free unneded array.
1855 */
1856 static void
1857 ta_flush_mod_chash(void *ta_buf)
1858 {
1859 struct mod_item *mi;
1860
1861 mi = (struct mod_item *)ta_buf;
1862 if (mi->main_ptr != NULL)
1863 free(mi->main_ptr, M_IPFW);
1864 if (mi->main_ptr6 != NULL)
1865 free(mi->main_ptr6, M_IPFW);
1866 }
1867
1868 struct table_algo addr_hash = {
1869 .name = "addr:hash",
1870 .type = IPFW_TABLE_ADDR,
1871 .ta_buf_size = sizeof(struct ta_buf_chash),
1872 .init = ta_init_chash,
1873 .destroy = ta_destroy_chash,
1874 .prepare_add = ta_prepare_add_chash,
1875 .prepare_del = ta_prepare_del_chash,
1876 .add = ta_add_chash,
1877 .del = ta_del_chash,
1878 .flush_entry = ta_flush_chash_entry,
1879 .foreach = ta_foreach_chash,
1880 .dump_tentry = ta_dump_chash_tentry,
1881 .find_tentry = ta_find_chash_tentry,
1882 .print_config = ta_print_chash_config,
1883 .dump_tinfo = ta_dump_chash_tinfo,
1884 .need_modify = ta_need_modify_chash,
1885 .prepare_mod = ta_prepare_mod_chash,
1886 .fill_mod = ta_fill_mod_chash,
1887 .modify = ta_modify_chash,
1888 .flush_mod = ta_flush_mod_chash,
1889 };
1890
1891 /*
1892 * Iface table cmds.
1893 *
1894 * Implementation:
1895 *
1896 * Runtime part:
1897 * - sorted array of "struct ifidx" pointed by ti->state.
1898 * Array is allocated with rounding up to IFIDX_CHUNK. Only existing
1899 * interfaces are stored in array, however its allocated size is
1900 * sufficient to hold all table records if needed.
1901 * - current array size is stored in ti->data
1902 *
1903 * Table data:
1904 * - "struct iftable_cfg" is allocated to store table state (ta_state).
1905 * - All table records are stored inside namedobj instance.
1906 *
1907 */
1908
1909 struct ifidx {
1910 uint16_t kidx;
1911 uint16_t spare;
1912 uint32_t value;
1913 };
1914 #define DEFAULT_IFIDX_SIZE 64
1915
1916 struct iftable_cfg;
1917
1918 struct ifentry {
1919 struct named_object no;
1920 struct ipfw_ifc ic;
1921 struct iftable_cfg *icfg;
1922 uint32_t value;
1923 int linked;
1924 };
1925
1926 struct iftable_cfg {
1927 struct namedobj_instance *ii;
1928 struct ip_fw_chain *ch;
1929 struct table_info *ti;
1930 void *main_ptr;
1931 size_t size; /* Number of items allocated in array */
1932 size_t count; /* Number of all items */
1933 size_t used; /* Number of items _active_ now */
1934 };
1935
1936 struct ta_buf_ifidx
1937 {
1938 struct ifentry *ife;
1939 uint32_t value;
1940 };
1941
1942 int compare_ifidx(const void *k, const void *v);
1943 static struct ifidx * ifidx_find(struct table_info *ti, void *key);
1944 static int ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
1945 uint32_t *val);
1946 static int ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state,
1947 struct table_info *ti, char *data, uint8_t tflags);
1948 static void ta_change_ti_ifidx(void *ta_state, struct table_info *ti);
1949 static int destroy_ifidx_locked(struct namedobj_instance *ii,
1950 struct named_object *no, void *arg);
1951 static void ta_destroy_ifidx(void *ta_state, struct table_info *ti);
1952 static void ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti,
1953 ipfw_ta_tinfo *tinfo);
1954 static int ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
1955 void *ta_buf);
1956 static int ta_add_ifidx(void *ta_state, struct table_info *ti,
1957 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
1958 static int ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
1959 void *ta_buf);
1960 static int ta_del_ifidx(void *ta_state, struct table_info *ti,
1961 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
1962 static void ta_flush_ifidx_entry(struct ip_fw_chain *ch,
1963 struct tentry_info *tei, void *ta_buf);
1964 static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex);
1965 static int ta_need_modify_ifidx(void *ta_state, struct table_info *ti,
1966 uint32_t count, uint64_t *pflags);
1967 static int ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags);
1968 static int ta_fill_mod_ifidx(void *ta_state, struct table_info *ti,
1969 void *ta_buf, uint64_t *pflags);
1970 static void ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
1971 uint64_t pflags);
1972 static void ta_flush_mod_ifidx(void *ta_buf);
1973 static int ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
1974 ipfw_obj_tentry *tent);
1975 static int ta_find_ifidx_tentry(void *ta_state, struct table_info *ti,
1976 ipfw_obj_tentry *tent);
1977 static int foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
1978 void *arg);
1979 static void ta_foreach_ifidx(void *ta_state, struct table_info *ti,
1980 ta_foreach_f *f, void *arg);
1981
1982 int
1983 compare_ifidx(const void *k, const void *v)
1984 {
1985 const struct ifidx *ifidx;
1986 uint16_t key;
1987
1988 key = *((const uint16_t *)k);
1989 ifidx = (const struct ifidx *)v;
1990
1991 if (key < ifidx->kidx)
1992 return (-1);
1993 else if (key > ifidx->kidx)
1994 return (1);
1995
1996 return (0);
1997 }
1998
1999 /*
2000 * Adds item @item with key @key into ascending-sorted array @base.
2001 * Assumes @base has enough additional storage.
2002 *
2003 * Returns 1 on success, 0 on duplicate key.
2004 */
2005 static int
2006 badd(const void *key, void *item, void *base, size_t nmemb,
2007 size_t size, int (*compar) (const void *, const void *))
2008 {
2009 int min, max, mid, shift, res;
2010 caddr_t paddr;
2011
2012 if (nmemb == 0) {
2013 memcpy(base, item, size);
2014 return (1);
2015 }
2016
2017 /* Binary search */
2018 min = 0;
2019 max = nmemb - 1;
2020 mid = 0;
2021 while (min <= max) {
2022 mid = (min + max) / 2;
2023 res = compar(key, (const void *)((caddr_t)base + mid * size));
2024 if (res == 0)
2025 return (0);
2026
2027 if (res > 0)
2028 min = mid + 1;
2029 else
2030 max = mid - 1;
2031 }
2032
2033 /* Item not found. */
2034 res = compar(key, (const void *)((caddr_t)base + mid * size));
2035 if (res > 0)
2036 shift = mid + 1;
2037 else
2038 shift = mid;
2039
2040 paddr = (caddr_t)base + shift * size;
2041 if (nmemb > shift)
2042 memmove(paddr + size, paddr, (nmemb - shift) * size);
2043
2044 memcpy(paddr, item, size);
2045
2046 return (1);
2047 }
2048
2049 /*
2050 * Deletes item with key @key from ascending-sorted array @base.
2051 *
2052 * Returns 1 on success, 0 for non-existent key.
2053 */
2054 static int
2055 bdel(const void *key, void *base, size_t nmemb, size_t size,
2056 int (*compar) (const void *, const void *))
2057 {
2058 caddr_t item;
2059 size_t sz;
2060
2061 item = (caddr_t)bsearch(key, base, nmemb, size, compar);
2062
2063 if (item == NULL)
2064 return (0);
2065
2066 sz = (caddr_t)base + nmemb * size - item;
2067
2068 if (sz > 0)
2069 memmove(item, item + size, sz);
2070
2071 return (1);
2072 }
2073
2074 static struct ifidx *
2075 ifidx_find(struct table_info *ti, void *key)
2076 {
2077 struct ifidx *ifi;
2078
2079 ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx),
2080 compare_ifidx);
2081
2082 return (ifi);
2083 }
2084
2085 static int
2086 ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen,
2087 uint32_t *val)
2088 {
2089 struct ifidx *ifi;
2090
2091 ifi = ifidx_find(ti, key);
2092
2093 if (ifi != NULL) {
2094 *val = ifi->value;
2095 return (1);
2096 }
2097
2098 return (0);
2099 }
2100
2101 static int
2102 ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
2103 char *data, uint8_t tflags)
2104 {
2105 struct iftable_cfg *icfg;
2106
2107 icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO);
2108
2109 icfg->ii = ipfw_objhash_create(DEFAULT_IFIDX_SIZE);
2110 icfg->size = DEFAULT_IFIDX_SIZE;
2111 icfg->main_ptr = malloc(sizeof(struct ifidx) * icfg->size, M_IPFW,
2112 M_WAITOK | M_ZERO);
2113 icfg->ch = ch;
2114
2115 *ta_state = icfg;
2116 ti->state = icfg->main_ptr;
2117 ti->lookup = ta_lookup_ifidx;
2118
2119 return (0);
2120 }
2121
2122 /*
2123 * Handle tableinfo @ti pointer change (on table array resize).
2124 */
2125 static void
2126 ta_change_ti_ifidx(void *ta_state, struct table_info *ti)
2127 {
2128 struct iftable_cfg *icfg;
2129
2130 icfg = (struct iftable_cfg *)ta_state;
2131 icfg->ti = ti;
2132 }
2133
2134 static int
2135 destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no,
2136 void *arg)
2137 {
2138 struct ifentry *ife;
2139 struct ip_fw_chain *ch;
2140
2141 ch = (struct ip_fw_chain *)arg;
2142 ife = (struct ifentry *)no;
2143
2144 ipfw_iface_del_notify(ch, &ife->ic);
2145 ipfw_iface_unref(ch, &ife->ic);
2146 free(ife, M_IPFW_TBL);
2147 return (0);
2148 }
2149
2150 /*
2151 * Destroys table @ti
2152 */
2153 static void
2154 ta_destroy_ifidx(void *ta_state, struct table_info *ti)
2155 {
2156 struct iftable_cfg *icfg;
2157 struct ip_fw_chain *ch;
2158
2159 icfg = (struct iftable_cfg *)ta_state;
2160 ch = icfg->ch;
2161
2162 if (icfg->main_ptr != NULL)
2163 free(icfg->main_ptr, M_IPFW);
2164
2165 IPFW_UH_WLOCK(ch);
2166 ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch);
2167 IPFW_UH_WUNLOCK(ch);
2168
2169 ipfw_objhash_destroy(icfg->ii);
2170
2171 free(icfg, M_IPFW);
2172 }
2173
2174 /*
2175 * Provide algo-specific table info
2176 */
2177 static void
2178 ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
2179 {
2180 struct iftable_cfg *cfg;
2181
2182 cfg = (struct iftable_cfg *)ta_state;
2183
2184 tinfo->taclass4 = IPFW_TACLASS_ARRAY;
2185 tinfo->size4 = cfg->size;
2186 tinfo->count4 = cfg->used;
2187 tinfo->itemsize4 = sizeof(struct ifidx);
2188 }
2189
2190 /*
2191 * Prepare state to add to the table:
2192 * allocate ifentry and reference needed interface.
2193 */
2194 static int
2195 ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
2196 void *ta_buf)
2197 {
2198 struct ta_buf_ifidx *tb;
2199 char *ifname;
2200 struct ifentry *ife;
2201
2202 tb = (struct ta_buf_ifidx *)ta_buf;
2203
2204 /* Check if string is terminated */
2205 ifname = (char *)tei->paddr;
2206 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
2207 return (EINVAL);
2208
2209 ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO);
2210 ife->ic.cb = if_notifier;
2211 ife->ic.cbdata = ife;
2212
2213 if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0) {
2214 free(ife, M_IPFW_TBL);
2215 return (EINVAL);
2216 }
2217
2218 /* Use ipfw_iface 'ifname' field as stable storage */
2219 ife->no.name = ife->ic.iface->ifname;
2220
2221 tb->ife = ife;
2222
2223 return (0);
2224 }
2225
2226 static int
2227 ta_add_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2228 void *ta_buf, uint32_t *pnum)
2229 {
2230 struct iftable_cfg *icfg;
2231 struct ifentry *ife, *tmp;
2232 struct ta_buf_ifidx *tb;
2233 struct ipfw_iface *iif;
2234 struct ifidx *ifi;
2235 char *ifname;
2236 uint32_t value;
2237
2238 tb = (struct ta_buf_ifidx *)ta_buf;
2239 ifname = (char *)tei->paddr;
2240 icfg = (struct iftable_cfg *)ta_state;
2241 ife = tb->ife;
2242
2243 ife->icfg = icfg;
2244 ife->value = tei->value;
2245
2246 tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
2247
2248 if (tmp != NULL) {
2249 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
2250 return (EEXIST);
2251
2252 /* Exchange values in @tmp and @tei */
2253 value = tmp->value;
2254 tmp->value = tei->value;
2255 tei->value = value;
2256
2257 iif = tmp->ic.iface;
2258 if (iif->resolved != 0) {
2259 /* We have to update runtime value, too */
2260 ifi = ifidx_find(ti, &iif->ifindex);
2261 ifi->value = ife->value;
2262 }
2263
2264 /* Indicate that update has happened instead of addition */
2265 tei->flags |= TEI_FLAGS_UPDATED;
2266 *pnum = 0;
2267 return (0);
2268 }
2269
2270 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
2271 return (EFBIG);
2272
2273 /* Link to internal list */
2274 ipfw_objhash_add(icfg->ii, &ife->no);
2275
2276 /* Link notifier (possible running its callback) */
2277 ipfw_iface_add_notify(icfg->ch, &ife->ic);
2278 icfg->count++;
2279
2280 tb->ife = NULL;
2281 *pnum = 1;
2282
2283 return (0);
2284 }
2285
2286 /*
2287 * Prepare to delete key from table.
2288 * Do basic interface name checks.
2289 */
2290 static int
2291 ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei,
2292 void *ta_buf)
2293 {
2294 char *ifname;
2295
2296 /* Check if string is terminated */
2297 ifname = (char *)tei->paddr;
2298 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
2299 return (EINVAL);
2300
2301 return (0);
2302 }
2303
2304 /*
2305 * Remove key from both configuration list and
2306 * runtime array. Removed interface notification.
2307 */
2308 static int
2309 ta_del_ifidx(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2310 void *ta_buf, uint32_t *pnum)
2311 {
2312 struct iftable_cfg *icfg;
2313 struct ifentry *ife;
2314 struct ta_buf_ifidx *tb;
2315 char *ifname;
2316 uint16_t ifindex;
2317 int res __diagused;
2318
2319 tb = (struct ta_buf_ifidx *)ta_buf;
2320 ifname = (char *)tei->paddr;
2321 icfg = (struct iftable_cfg *)ta_state;
2322
2323 ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
2324
2325 if (ife == NULL)
2326 return (ENOENT);
2327
2328 if (ife->linked != 0) {
2329 /* We have to remove item from runtime */
2330 ifindex = ife->ic.iface->ifindex;
2331
2332 res = bdel(&ifindex, icfg->main_ptr, icfg->used,
2333 sizeof(struct ifidx), compare_ifidx);
2334
2335 KASSERT(res == 1, ("index %d does not exist", ifindex));
2336 icfg->used--;
2337 ti->data = icfg->used;
2338 ife->linked = 0;
2339 }
2340
2341 /* Unlink from local list */
2342 ipfw_objhash_del(icfg->ii, &ife->no);
2343 /* Unlink notifier and deref */
2344 ipfw_iface_del_notify(icfg->ch, &ife->ic);
2345 ipfw_iface_unref(icfg->ch, &ife->ic);
2346
2347 icfg->count--;
2348 tei->value = ife->value;
2349
2350 tb->ife = ife;
2351 *pnum = 1;
2352
2353 return (0);
2354 }
2355
2356 /*
2357 * Flush deleted entry.
2358 * Drops interface reference and frees entry.
2359 */
2360 static void
2361 ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
2362 void *ta_buf)
2363 {
2364 struct ta_buf_ifidx *tb;
2365
2366 tb = (struct ta_buf_ifidx *)ta_buf;
2367
2368 if (tb->ife != NULL)
2369 free(tb->ife, M_IPFW_TBL);
2370 }
2371
2372 /*
2373 * Handle interface announce/withdrawal for particular table.
2374 * Every real runtime array modification happens here.
2375 */
2376 static void
2377 if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex)
2378 {
2379 struct ifentry *ife;
2380 struct ifidx ifi;
2381 struct iftable_cfg *icfg;
2382 struct table_info *ti;
2383 int res __diagused;
2384
2385 ife = (struct ifentry *)cbdata;
2386 icfg = ife->icfg;
2387 ti = icfg->ti;
2388
2389 KASSERT(ti != NULL, ("ti=NULL, check change_ti handler"));
2390
2391 if (ife->linked == 0 && ifindex != 0) {
2392 /* Interface announce */
2393 ifi.kidx = ifindex;
2394 ifi.spare = 0;
2395 ifi.value = ife->value;
2396 res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used,
2397 sizeof(struct ifidx), compare_ifidx);
2398 KASSERT(res == 1, ("index %d already exists", ifindex));
2399 icfg->used++;
2400 ti->data = icfg->used;
2401 ife->linked = 1;
2402 } else if (ife->linked != 0 && ifindex == 0) {
2403 /* Interface withdrawal */
2404 ifindex = ife->ic.iface->ifindex;
2405
2406 res = bdel(&ifindex, icfg->main_ptr, icfg->used,
2407 sizeof(struct ifidx), compare_ifidx);
2408
2409 KASSERT(res == 1, ("index %d does not exist", ifindex));
2410 icfg->used--;
2411 ti->data = icfg->used;
2412 ife->linked = 0;
2413 }
2414 }
2415
2416 /*
2417 * Table growing callbacks.
2418 */
2419
2420 static int
2421 ta_need_modify_ifidx(void *ta_state, struct table_info *ti, uint32_t count,
2422 uint64_t *pflags)
2423 {
2424 struct iftable_cfg *cfg;
2425 uint32_t size;
2426
2427 cfg = (struct iftable_cfg *)ta_state;
2428
2429 size = cfg->size;
2430 while (size < cfg->count + count)
2431 size *= 2;
2432
2433 if (size != cfg->size) {
2434 *pflags = size;
2435 return (1);
2436 }
2437
2438 return (0);
2439 }
2440
2441 /*
2442 * Allocate ned, larger runtime ifidx array.
2443 */
2444 static int
2445 ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags)
2446 {
2447 struct mod_item *mi;
2448
2449 mi = (struct mod_item *)ta_buf;
2450
2451 memset(mi, 0, sizeof(struct mod_item));
2452 mi->size = *pflags;
2453 mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW,
2454 M_WAITOK | M_ZERO);
2455
2456 return (0);
2457 }
2458
2459 /*
2460 * Copy data from old runtime array to new one.
2461 */
2462 static int
2463 ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
2464 uint64_t *pflags)
2465 {
2466 struct mod_item *mi;
2467 struct iftable_cfg *icfg;
2468
2469 mi = (struct mod_item *)ta_buf;
2470 icfg = (struct iftable_cfg *)ta_state;
2471
2472 /* Check if we still need to grow array */
2473 if (icfg->size >= mi->size) {
2474 *pflags = 0;
2475 return (0);
2476 }
2477
2478 memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx));
2479
2480 return (0);
2481 }
2482
2483 /*
2484 * Switch old & new arrays.
2485 */
2486 static void
2487 ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf,
2488 uint64_t pflags)
2489 {
2490 struct mod_item *mi;
2491 struct iftable_cfg *icfg;
2492 void *old_ptr;
2493
2494 mi = (struct mod_item *)ta_buf;
2495 icfg = (struct iftable_cfg *)ta_state;
2496
2497 old_ptr = icfg->main_ptr;
2498 icfg->main_ptr = mi->main_ptr;
2499 icfg->size = mi->size;
2500 ti->state = icfg->main_ptr;
2501
2502 mi->main_ptr = old_ptr;
2503 }
2504
2505 /*
2506 * Free unneded array.
2507 */
2508 static void
2509 ta_flush_mod_ifidx(void *ta_buf)
2510 {
2511 struct mod_item *mi;
2512
2513 mi = (struct mod_item *)ta_buf;
2514 if (mi->main_ptr != NULL)
2515 free(mi->main_ptr, M_IPFW);
2516 }
2517
2518 static int
2519 ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e,
2520 ipfw_obj_tentry *tent)
2521 {
2522 struct ifentry *ife;
2523
2524 ife = (struct ifentry *)e;
2525
2526 tent->masklen = 8 * IF_NAMESIZE;
2527 memcpy(&tent->k, ife->no.name, IF_NAMESIZE);
2528 tent->v.kidx = ife->value;
2529
2530 return (0);
2531 }
2532
2533 static int
2534 ta_find_ifidx_tentry(void *ta_state, struct table_info *ti,
2535 ipfw_obj_tentry *tent)
2536 {
2537 struct iftable_cfg *icfg;
2538 struct ifentry *ife;
2539 char *ifname;
2540
2541 icfg = (struct iftable_cfg *)ta_state;
2542 ifname = tent->k.iface;
2543
2544 if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE)
2545 return (EINVAL);
2546
2547 ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname);
2548
2549 if (ife != NULL) {
2550 ta_dump_ifidx_tentry(ta_state, ti, ife, tent);
2551 return (0);
2552 }
2553
2554 return (ENOENT);
2555 }
2556
2557 struct wa_ifidx {
2558 ta_foreach_f *f;
2559 void *arg;
2560 };
2561
2562 static int
2563 foreach_ifidx(struct namedobj_instance *ii, struct named_object *no,
2564 void *arg)
2565 {
2566 struct ifentry *ife;
2567 struct wa_ifidx *wa;
2568
2569 ife = (struct ifentry *)no;
2570 wa = (struct wa_ifidx *)arg;
2571
2572 wa->f(ife, wa->arg);
2573 return (0);
2574 }
2575
2576 static void
2577 ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f,
2578 void *arg)
2579 {
2580 struct iftable_cfg *icfg;
2581 struct wa_ifidx wa;
2582
2583 icfg = (struct iftable_cfg *)ta_state;
2584
2585 wa.f = f;
2586 wa.arg = arg;
2587
2588 ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa);
2589 }
2590
2591 struct table_algo iface_idx = {
2592 .name = "iface:array",
2593 .type = IPFW_TABLE_INTERFACE,
2594 .flags = TA_FLAG_DEFAULT,
2595 .ta_buf_size = sizeof(struct ta_buf_ifidx),
2596 .init = ta_init_ifidx,
2597 .destroy = ta_destroy_ifidx,
2598 .prepare_add = ta_prepare_add_ifidx,
2599 .prepare_del = ta_prepare_del_ifidx,
2600 .add = ta_add_ifidx,
2601 .del = ta_del_ifidx,
2602 .flush_entry = ta_flush_ifidx_entry,
2603 .foreach = ta_foreach_ifidx,
2604 .dump_tentry = ta_dump_ifidx_tentry,
2605 .find_tentry = ta_find_ifidx_tentry,
2606 .dump_tinfo = ta_dump_ifidx_tinfo,
2607 .need_modify = ta_need_modify_ifidx,
2608 .prepare_mod = ta_prepare_mod_ifidx,
2609 .fill_mod = ta_fill_mod_ifidx,
2610 .modify = ta_modify_ifidx,
2611 .flush_mod = ta_flush_mod_ifidx,
2612 .change_ti = ta_change_ti_ifidx,
2613 };
2614
2615 /*
2616 * Number array cmds.
2617 *
2618 * Implementation:
2619 *
2620 * Runtime part:
2621 * - sorted array of "struct numarray" pointed by ti->state.
2622 * Array is allocated with rounding up to NUMARRAY_CHUNK.
2623 * - current array size is stored in ti->data
2624 *
2625 */
2626
2627 struct numarray {
2628 uint32_t number;
2629 uint32_t value;
2630 };
2631
2632 struct numarray_cfg {
2633 void *main_ptr;
2634 size_t size; /* Number of items allocated in array */
2635 size_t used; /* Number of items _active_ now */
2636 };
2637
2638 struct ta_buf_numarray
2639 {
2640 struct numarray na;
2641 };
2642
2643 int compare_numarray(const void *k, const void *v);
2644 static struct numarray *numarray_find(struct table_info *ti, void *key);
2645 static int ta_lookup_numarray(struct table_info *ti, void *key,
2646 uint32_t keylen, uint32_t *val);
2647 static int ta_init_numarray(struct ip_fw_chain *ch, void **ta_state,
2648 struct table_info *ti, char *data, uint8_t tflags);
2649 static void ta_destroy_numarray(void *ta_state, struct table_info *ti);
2650 static void ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti,
2651 ipfw_ta_tinfo *tinfo);
2652 static int ta_prepare_add_numarray(struct ip_fw_chain *ch,
2653 struct tentry_info *tei, void *ta_buf);
2654 static int ta_add_numarray(void *ta_state, struct table_info *ti,
2655 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
2656 static int ta_del_numarray(void *ta_state, struct table_info *ti,
2657 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
2658 static void ta_flush_numarray_entry(struct ip_fw_chain *ch,
2659 struct tentry_info *tei, void *ta_buf);
2660 static int ta_need_modify_numarray(void *ta_state, struct table_info *ti,
2661 uint32_t count, uint64_t *pflags);
2662 static int ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags);
2663 static int ta_fill_mod_numarray(void *ta_state, struct table_info *ti,
2664 void *ta_buf, uint64_t *pflags);
2665 static void ta_modify_numarray(void *ta_state, struct table_info *ti,
2666 void *ta_buf, uint64_t pflags);
2667 static void ta_flush_mod_numarray(void *ta_buf);
2668 static int ta_dump_numarray_tentry(void *ta_state, struct table_info *ti,
2669 void *e, ipfw_obj_tentry *tent);
2670 static int ta_find_numarray_tentry(void *ta_state, struct table_info *ti,
2671 ipfw_obj_tentry *tent);
2672 static void ta_foreach_numarray(void *ta_state, struct table_info *ti,
2673 ta_foreach_f *f, void *arg);
2674
2675 int
2676 compare_numarray(const void *k, const void *v)
2677 {
2678 const struct numarray *na;
2679 uint32_t key;
2680
2681 key = *((const uint32_t *)k);
2682 na = (const struct numarray *)v;
2683
2684 if (key < na->number)
2685 return (-1);
2686 else if (key > na->number)
2687 return (1);
2688
2689 return (0);
2690 }
2691
2692 static struct numarray *
2693 numarray_find(struct table_info *ti, void *key)
2694 {
2695 struct numarray *ri;
2696
2697 ri = bsearch(key, ti->state, ti->data, sizeof(struct numarray),
2698 compare_ifidx);
2699
2700 return (ri);
2701 }
2702
2703 static int
2704 ta_lookup_numarray(struct table_info *ti, void *key, uint32_t keylen,
2705 uint32_t *val)
2706 {
2707 struct numarray *ri;
2708
2709 ri = numarray_find(ti, key);
2710
2711 if (ri != NULL) {
2712 *val = ri->value;
2713 return (1);
2714 }
2715
2716 return (0);
2717 }
2718
2719 static int
2720 ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
2721 char *data, uint8_t tflags)
2722 {
2723 struct numarray_cfg *cfg;
2724
2725 cfg = malloc(sizeof(*cfg), M_IPFW, M_WAITOK | M_ZERO);
2726
2727 cfg->size = 16;
2728 cfg->main_ptr = malloc(sizeof(struct numarray) * cfg->size, M_IPFW,
2729 M_WAITOK | M_ZERO);
2730
2731 *ta_state = cfg;
2732 ti->state = cfg->main_ptr;
2733 ti->lookup = ta_lookup_numarray;
2734
2735 return (0);
2736 }
2737
2738 /*
2739 * Destroys table @ti
2740 */
2741 static void
2742 ta_destroy_numarray(void *ta_state, struct table_info *ti)
2743 {
2744 struct numarray_cfg *cfg;
2745
2746 cfg = (struct numarray_cfg *)ta_state;
2747
2748 if (cfg->main_ptr != NULL)
2749 free(cfg->main_ptr, M_IPFW);
2750
2751 free(cfg, M_IPFW);
2752 }
2753
2754 /*
2755 * Provide algo-specific table info
2756 */
2757 static void
2758 ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
2759 {
2760 struct numarray_cfg *cfg;
2761
2762 cfg = (struct numarray_cfg *)ta_state;
2763
2764 tinfo->taclass4 = IPFW_TACLASS_ARRAY;
2765 tinfo->size4 = cfg->size;
2766 tinfo->count4 = cfg->used;
2767 tinfo->itemsize4 = sizeof(struct numarray);
2768 }
2769
2770 /*
2771 * Prepare for addition/deletion to an array.
2772 */
2773 static int
2774 ta_prepare_add_numarray(struct ip_fw_chain *ch, struct tentry_info *tei,
2775 void *ta_buf)
2776 {
2777 struct ta_buf_numarray *tb;
2778
2779 tb = (struct ta_buf_numarray *)ta_buf;
2780
2781 tb->na.number = *((uint32_t *)tei->paddr);
2782
2783 return (0);
2784 }
2785
2786 static int
2787 ta_add_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2788 void *ta_buf, uint32_t *pnum)
2789 {
2790 struct numarray_cfg *cfg;
2791 struct ta_buf_numarray *tb;
2792 struct numarray *ri;
2793 int res __diagused;
2794 uint32_t value;
2795
2796 tb = (struct ta_buf_numarray *)ta_buf;
2797 cfg = (struct numarray_cfg *)ta_state;
2798
2799 /* Read current value from @tei */
2800 tb->na.value = tei->value;
2801
2802 ri = numarray_find(ti, &tb->na.number);
2803
2804 if (ri != NULL) {
2805 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
2806 return (EEXIST);
2807
2808 /* Exchange values between ri and @tei */
2809 value = ri->value;
2810 ri->value = tei->value;
2811 tei->value = value;
2812 /* Indicate that update has happened instead of addition */
2813 tei->flags |= TEI_FLAGS_UPDATED;
2814 *pnum = 0;
2815 return (0);
2816 }
2817
2818 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
2819 return (EFBIG);
2820
2821 res = badd(&tb->na.number, &tb->na, cfg->main_ptr, cfg->used,
2822 sizeof(struct numarray), compare_numarray);
2823
2824 KASSERT(res == 1, ("number %d already exists", tb->na.number));
2825 cfg->used++;
2826 ti->data = cfg->used;
2827 *pnum = 1;
2828
2829 return (0);
2830 }
2831
2832 /*
2833 * Remove key from both configuration list and
2834 * runtime array. Removed interface notification.
2835 */
2836 static int
2837 ta_del_numarray(void *ta_state, struct table_info *ti, struct tentry_info *tei,
2838 void *ta_buf, uint32_t *pnum)
2839 {
2840 struct numarray_cfg *cfg;
2841 struct ta_buf_numarray *tb;
2842 struct numarray *ri;
2843 int res __diagused;
2844
2845 tb = (struct ta_buf_numarray *)ta_buf;
2846 cfg = (struct numarray_cfg *)ta_state;
2847
2848 ri = numarray_find(ti, &tb->na.number);
2849 if (ri == NULL)
2850 return (ENOENT);
2851
2852 tei->value = ri->value;
2853
2854 res = bdel(&tb->na.number, cfg->main_ptr, cfg->used,
2855 sizeof(struct numarray), compare_numarray);
2856
2857 KASSERT(res == 1, ("number %u does not exist", tb->na.number));
2858 cfg->used--;
2859 ti->data = cfg->used;
2860 *pnum = 1;
2861
2862 return (0);
2863 }
2864
2865 static void
2866 ta_flush_numarray_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
2867 void *ta_buf)
2868 {
2869
2870 /* We don't have any state, do nothing */
2871 }
2872
2873 /*
2874 * Table growing callbacks.
2875 */
2876
2877 static int
2878 ta_need_modify_numarray(void *ta_state, struct table_info *ti, uint32_t count,
2879 uint64_t *pflags)
2880 {
2881 struct numarray_cfg *cfg;
2882 size_t size;
2883
2884 cfg = (struct numarray_cfg *)ta_state;
2885
2886 size = cfg->size;
2887 while (size < cfg->used + count)
2888 size *= 2;
2889
2890 if (size != cfg->size) {
2891 *pflags = size;
2892 return (1);
2893 }
2894
2895 return (0);
2896 }
2897
2898 /*
2899 * Allocate new, larger runtime array.
2900 */
2901 static int
2902 ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags)
2903 {
2904 struct mod_item *mi;
2905
2906 mi = (struct mod_item *)ta_buf;
2907
2908 memset(mi, 0, sizeof(struct mod_item));
2909 mi->size = *pflags;
2910 mi->main_ptr = malloc(sizeof(struct numarray) * mi->size, M_IPFW,
2911 M_WAITOK | M_ZERO);
2912
2913 return (0);
2914 }
2915
2916 /*
2917 * Copy data from old runtime array to new one.
2918 */
2919 static int
2920 ta_fill_mod_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
2921 uint64_t *pflags)
2922 {
2923 struct mod_item *mi;
2924 struct numarray_cfg *cfg;
2925
2926 mi = (struct mod_item *)ta_buf;
2927 cfg = (struct numarray_cfg *)ta_state;
2928
2929 /* Check if we still need to grow array */
2930 if (cfg->size >= mi->size) {
2931 *pflags = 0;
2932 return (0);
2933 }
2934
2935 memcpy(mi->main_ptr, cfg->main_ptr, cfg->used * sizeof(struct numarray));
2936
2937 return (0);
2938 }
2939
2940 /*
2941 * Switch old & new arrays.
2942 */
2943 static void
2944 ta_modify_numarray(void *ta_state, struct table_info *ti, void *ta_buf,
2945 uint64_t pflags)
2946 {
2947 struct mod_item *mi;
2948 struct numarray_cfg *cfg;
2949 void *old_ptr;
2950
2951 mi = (struct mod_item *)ta_buf;
2952 cfg = (struct numarray_cfg *)ta_state;
2953
2954 old_ptr = cfg->main_ptr;
2955 cfg->main_ptr = mi->main_ptr;
2956 cfg->size = mi->size;
2957 ti->state = cfg->main_ptr;
2958
2959 mi->main_ptr = old_ptr;
2960 }
2961
2962 /*
2963 * Free unneded array.
2964 */
2965 static void
2966 ta_flush_mod_numarray(void *ta_buf)
2967 {
2968 struct mod_item *mi;
2969
2970 mi = (struct mod_item *)ta_buf;
2971 if (mi->main_ptr != NULL)
2972 free(mi->main_ptr, M_IPFW);
2973 }
2974
2975 static int
2976 ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, void *e,
2977 ipfw_obj_tentry *tent)
2978 {
2979 struct numarray *na;
2980
2981 na = (struct numarray *)e;
2982
2983 tent->k.key = na->number;
2984 tent->v.kidx = na->value;
2985
2986 return (0);
2987 }
2988
2989 static int
2990 ta_find_numarray_tentry(void *ta_state, struct table_info *ti,
2991 ipfw_obj_tentry *tent)
2992 {
2993 struct numarray *ri;
2994
2995 ri = numarray_find(ti, &tent->k.key);
2996
2997 if (ri != NULL) {
2998 ta_dump_numarray_tentry(ta_state, ti, ri, tent);
2999 return (0);
3000 }
3001
3002 return (ENOENT);
3003 }
3004
3005 static void
3006 ta_foreach_numarray(void *ta_state, struct table_info *ti, ta_foreach_f *f,
3007 void *arg)
3008 {
3009 struct numarray_cfg *cfg;
3010 struct numarray *array;
3011 int i;
3012
3013 cfg = (struct numarray_cfg *)ta_state;
3014 array = cfg->main_ptr;
3015
3016 for (i = 0; i < cfg->used; i++)
3017 f(&array[i], arg);
3018 }
3019
3020 struct table_algo number_array = {
3021 .name = "number:array",
3022 .type = IPFW_TABLE_NUMBER,
3023 .ta_buf_size = sizeof(struct ta_buf_numarray),
3024 .init = ta_init_numarray,
3025 .destroy = ta_destroy_numarray,
3026 .prepare_add = ta_prepare_add_numarray,
3027 .prepare_del = ta_prepare_add_numarray,
3028 .add = ta_add_numarray,
3029 .del = ta_del_numarray,
3030 .flush_entry = ta_flush_numarray_entry,
3031 .foreach = ta_foreach_numarray,
3032 .dump_tentry = ta_dump_numarray_tentry,
3033 .find_tentry = ta_find_numarray_tentry,
3034 .dump_tinfo = ta_dump_numarray_tinfo,
3035 .need_modify = ta_need_modify_numarray,
3036 .prepare_mod = ta_prepare_mod_numarray,
3037 .fill_mod = ta_fill_mod_numarray,
3038 .modify = ta_modify_numarray,
3039 .flush_mod = ta_flush_mod_numarray,
3040 };
3041
3042 /*
3043 * flow:hash cmds
3044 *
3045 *
3046 * ti->data:
3047 * [inv.mask4][inv.mask6][log2hsize4][log2hsize6]
3048 * [ 8][ 8[ 8][ 8]
3049 *
3050 * inv.mask4: 32 - mask
3051 * inv.mask6:
3052 * 1) _slow lookup: mask
3053 * 2) _aligned: (128 - mask) / 8
3054 * 3) _64: 8
3055 *
3056 *
3057 * pflags:
3058 * [hsize4][hsize6]
3059 * [ 16][ 16]
3060 */
3061
3062 struct fhashentry;
3063
3064 SLIST_HEAD(fhashbhead, fhashentry);
3065
3066 struct fhashentry {
3067 SLIST_ENTRY(fhashentry) next;
3068 uint8_t af;
3069 uint8_t proto;
3070 uint16_t spare0;
3071 uint16_t dport;
3072 uint16_t sport;
3073 uint32_t value;
3074 uint32_t spare1;
3075 };
3076
3077 struct fhashentry4 {
3078 struct fhashentry e;
3079 struct in_addr dip;
3080 struct in_addr sip;
3081 };
3082
3083 struct fhashentry6 {
3084 struct fhashentry e;
3085 struct in6_addr dip6;
3086 struct in6_addr sip6;
3087 };
3088
3089 struct fhash_cfg {
3090 struct fhashbhead *head;
3091 size_t size;
3092 size_t items;
3093 struct fhashentry4 fe4;
3094 struct fhashentry6 fe6;
3095 };
3096
3097 struct ta_buf_fhash {
3098 void *ent_ptr;
3099 struct fhashentry6 fe6;
3100 };
3101
3102 static __inline int cmp_flow_ent(struct fhashentry *a,
3103 struct fhashentry *b, size_t sz);
3104 static __inline uint32_t hash_flow4(struct fhashentry4 *f, int hsize);
3105 static __inline uint32_t hash_flow6(struct fhashentry6 *f, int hsize);
3106 static uint32_t hash_flow_ent(struct fhashentry *ent, uint32_t size);
3107 static int ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
3108 uint32_t *val);
3109 static int ta_init_fhash(struct ip_fw_chain *ch, void **ta_state,
3110 struct table_info *ti, char *data, uint8_t tflags);
3111 static void ta_destroy_fhash(void *ta_state, struct table_info *ti);
3112 static void ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti,
3113 ipfw_ta_tinfo *tinfo);
3114 static int ta_dump_fhash_tentry(void *ta_state, struct table_info *ti,
3115 void *e, ipfw_obj_tentry *tent);
3116 static int tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent);
3117 static int ta_find_fhash_tentry(void *ta_state, struct table_info *ti,
3118 ipfw_obj_tentry *tent);
3119 static void ta_foreach_fhash(void *ta_state, struct table_info *ti,
3120 ta_foreach_f *f, void *arg);
3121 static int ta_prepare_add_fhash(struct ip_fw_chain *ch,
3122 struct tentry_info *tei, void *ta_buf);
3123 static int ta_add_fhash(void *ta_state, struct table_info *ti,
3124 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
3125 static int ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
3126 void *ta_buf);
3127 static int ta_del_fhash(void *ta_state, struct table_info *ti,
3128 struct tentry_info *tei, void *ta_buf, uint32_t *pnum);
3129 static void ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
3130 void *ta_buf);
3131 static int ta_need_modify_fhash(void *ta_state, struct table_info *ti,
3132 uint32_t count, uint64_t *pflags);
3133 static int ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags);
3134 static int ta_fill_mod_fhash(void *ta_state, struct table_info *ti,
3135 void *ta_buf, uint64_t *pflags);
3136 static void ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3137 uint64_t pflags);
3138 static void ta_flush_mod_fhash(void *ta_buf);
3139
3140 static __inline int
3141 cmp_flow_ent(struct fhashentry *a, struct fhashentry *b, size_t sz)
3142 {
3143 uint64_t *ka, *kb;
3144
3145 ka = (uint64_t *)(&a->next + 1);
3146 kb = (uint64_t *)(&b->next + 1);
3147
3148 if (*ka == *kb && (memcmp(a + 1, b + 1, sz) == 0))
3149 return (1);
3150
3151 return (0);
3152 }
3153
3154 static __inline uint32_t
3155 hash_flow4(struct fhashentry4 *f, int hsize)
3156 {
3157 uint32_t i;
3158
3159 i = (f->dip.s_addr) ^ (f->sip.s_addr) ^ (f->e.dport) ^ (f->e.sport);
3160
3161 return (i % (hsize - 1));
3162 }
3163
3164 static __inline uint32_t
3165 hash_flow6(struct fhashentry6 *f, int hsize)
3166 {
3167 uint32_t i;
3168
3169 i = (f->dip6.__u6_addr.__u6_addr32[2]) ^
3170 (f->dip6.__u6_addr.__u6_addr32[3]) ^
3171 (f->sip6.__u6_addr.__u6_addr32[2]) ^
3172 (f->sip6.__u6_addr.__u6_addr32[3]) ^
3173 (f->e.dport) ^ (f->e.sport);
3174
3175 return (i % (hsize - 1));
3176 }
3177
3178 static uint32_t
3179 hash_flow_ent(struct fhashentry *ent, uint32_t size)
3180 {
3181 uint32_t hash;
3182
3183 if (ent->af == AF_INET) {
3184 hash = hash_flow4((struct fhashentry4 *)ent, size);
3185 } else {
3186 hash = hash_flow6((struct fhashentry6 *)ent, size);
3187 }
3188
3189 return (hash);
3190 }
3191
3192 static int
3193 ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen,
3194 uint32_t *val)
3195 {
3196 struct fhashbhead *head;
3197 struct fhashentry *ent;
3198 struct fhashentry4 *m4;
3199 struct ipfw_flow_id *id;
3200 uint32_t hsize;
3201 uint16_t hash;
3202
3203 id = (struct ipfw_flow_id *)key;
3204 head = (struct fhashbhead *)ti->state;
3205 hsize = ti->data;
3206 m4 = (struct fhashentry4 *)ti->xstate;
3207
3208 if (id->addr_type == 4) {
3209 struct fhashentry4 f;
3210
3211 /* Copy hash mask */
3212 f = *m4;
3213
3214 f.dip.s_addr &= id->dst_ip;
3215 f.sip.s_addr &= id->src_ip;
3216 f.e.dport &= id->dst_port;
3217 f.e.sport &= id->src_port;
3218 f.e.proto &= id->proto;
3219 hash = hash_flow4(&f, hsize);
3220 SLIST_FOREACH(ent, &head[hash], next) {
3221 if (cmp_flow_ent(ent, &f.e, 2 * 4) != 0) {
3222 *val = ent->value;
3223 return (1);
3224 }
3225 }
3226 } else if (id->addr_type == 6) {
3227 struct fhashentry6 f;
3228 uint64_t *fp, *idp;
3229
3230 /* Copy hash mask */
3231 f = *((struct fhashentry6 *)(m4 + 1));
3232
3233 /* Handle lack of __u6_addr.__u6_addr64 */
3234 fp = (uint64_t *)&f.dip6;
3235 idp = (uint64_t *)&id->dst_ip6;
3236 /* src IPv6 is stored after dst IPv6 */
3237 *fp++ &= *idp++;
3238 *fp++ &= *idp++;
3239 *fp++ &= *idp++;
3240 *fp &= *idp;
3241 f.e.dport &= id->dst_port;
3242 f.e.sport &= id->src_port;
3243 f.e.proto &= id->proto;
3244 hash = hash_flow6(&f, hsize);
3245 SLIST_FOREACH(ent, &head[hash], next) {
3246 if (cmp_flow_ent(ent, &f.e, 2 * 16) != 0) {
3247 *val = ent->value;
3248 return (1);
3249 }
3250 }
3251 }
3252
3253 return (0);
3254 }
3255
3256 /*
3257 * New table.
3258 */
3259 static int
3260 ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
3261 char *data, uint8_t tflags)
3262 {
3263 struct fhash_cfg *cfg;
3264 struct fhashentry4 *fe4;
3265 struct fhashentry6 *fe6;
3266 u_int i;
3267
3268 cfg = malloc(sizeof(struct fhash_cfg), M_IPFW, M_WAITOK | M_ZERO);
3269
3270 cfg->size = 512;
3271
3272 cfg->head = malloc(sizeof(struct fhashbhead) * cfg->size, M_IPFW,
3273 M_WAITOK | M_ZERO);
3274 for (i = 0; i < cfg->size; i++)
3275 SLIST_INIT(&cfg->head[i]);
3276
3277 /* Fill in fe masks based on @tflags */
3278 fe4 = &cfg->fe4;
3279 fe6 = &cfg->fe6;
3280 if (tflags & IPFW_TFFLAG_SRCIP) {
3281 memset(&fe4->sip, 0xFF, sizeof(fe4->sip));
3282 memset(&fe6->sip6, 0xFF, sizeof(fe6->sip6));
3283 }
3284 if (tflags & IPFW_TFFLAG_DSTIP) {
3285 memset(&fe4->dip, 0xFF, sizeof(fe4->dip));
3286 memset(&fe6->dip6, 0xFF, sizeof(fe6->dip6));
3287 }
3288 if (tflags & IPFW_TFFLAG_SRCPORT) {
3289 memset(&fe4->e.sport, 0xFF, sizeof(fe4->e.sport));
3290 memset(&fe6->e.sport, 0xFF, sizeof(fe6->e.sport));
3291 }
3292 if (tflags & IPFW_TFFLAG_DSTPORT) {
3293 memset(&fe4->e.dport, 0xFF, sizeof(fe4->e.dport));
3294 memset(&fe6->e.dport, 0xFF, sizeof(fe6->e.dport));
3295 }
3296 if (tflags & IPFW_TFFLAG_PROTO) {
3297 memset(&fe4->e.proto, 0xFF, sizeof(fe4->e.proto));
3298 memset(&fe6->e.proto, 0xFF, sizeof(fe6->e.proto));
3299 }
3300
3301 fe4->e.af = AF_INET;
3302 fe6->e.af = AF_INET6;
3303
3304 *ta_state = cfg;
3305 ti->state = cfg->head;
3306 ti->xstate = &cfg->fe4;
3307 ti->data = cfg->size;
3308 ti->lookup = ta_lookup_fhash;
3309
3310 return (0);
3311 }
3312
3313 static void
3314 ta_destroy_fhash(void *ta_state, struct table_info *ti)
3315 {
3316 struct fhash_cfg *cfg;
3317 struct fhashentry *ent, *ent_next;
3318 int i;
3319
3320 cfg = (struct fhash_cfg *)ta_state;
3321
3322 for (i = 0; i < cfg->size; i++)
3323 SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
3324 free(ent, M_IPFW_TBL);
3325
3326 free(cfg->head, M_IPFW);
3327 free(cfg, M_IPFW);
3328 }
3329
3330 /*
3331 * Provide algo-specific table info
3332 */
3333 static void
3334 ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
3335 {
3336 struct fhash_cfg *cfg;
3337
3338 cfg = (struct fhash_cfg *)ta_state;
3339
3340 tinfo->flags = IPFW_TATFLAGS_AFITEM;
3341 tinfo->taclass4 = IPFW_TACLASS_HASH;
3342 tinfo->size4 = cfg->size;
3343 tinfo->count4 = cfg->items;
3344 tinfo->itemsize4 = sizeof(struct fhashentry4);
3345 tinfo->itemsize6 = sizeof(struct fhashentry6);
3346 }
3347
3348 static int
3349 ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, void *e,
3350 ipfw_obj_tentry *tent)
3351 {
3352 struct fhashentry *ent;
3353 struct fhashentry4 *fe4;
3354 #ifdef INET6
3355 struct fhashentry6 *fe6;
3356 #endif
3357 struct tflow_entry *tfe;
3358
3359 ent = (struct fhashentry *)e;
3360 tfe = &tent->k.flow;
3361
3362 tfe->af = ent->af;
3363 tfe->proto = ent->proto;
3364 tfe->dport = htons(ent->dport);
3365 tfe->sport = htons(ent->sport);
3366 tent->v.kidx = ent->value;
3367 tent->subtype = ent->af;
3368
3369 if (ent->af == AF_INET) {
3370 fe4 = (struct fhashentry4 *)ent;
3371 tfe->a.a4.sip.s_addr = htonl(fe4->sip.s_addr);
3372 tfe->a.a4.dip.s_addr = htonl(fe4->dip.s_addr);
3373 tent->masklen = 32;
3374 #ifdef INET6
3375 } else {
3376 fe6 = (struct fhashentry6 *)ent;
3377 tfe->a.a6.sip6 = fe6->sip6;
3378 tfe->a.a6.dip6 = fe6->dip6;
3379 tent->masklen = 128;
3380 #endif
3381 }
3382
3383 return (0);
3384 }
3385
3386 static int
3387 tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent)
3388 {
3389 #ifdef INET
3390 struct fhashentry4 *fe4;
3391 #endif
3392 #ifdef INET6
3393 struct fhashentry6 *fe6;
3394 #endif
3395 struct tflow_entry *tfe;
3396
3397 tfe = (struct tflow_entry *)tei->paddr;
3398
3399 ent->af = tei->subtype;
3400 ent->proto = tfe->proto;
3401 ent->dport = ntohs(tfe->dport);
3402 ent->sport = ntohs(tfe->sport);
3403
3404 if (tei->subtype == AF_INET) {
3405 #ifdef INET
3406 fe4 = (struct fhashentry4 *)ent;
3407 fe4->sip.s_addr = ntohl(tfe->a.a4.sip.s_addr);
3408 fe4->dip.s_addr = ntohl(tfe->a.a4.dip.s_addr);
3409 #endif
3410 #ifdef INET6
3411 } else if (tei->subtype == AF_INET6) {
3412 fe6 = (struct fhashentry6 *)ent;
3413 fe6->sip6 = tfe->a.a6.sip6;
3414 fe6->dip6 = tfe->a.a6.dip6;
3415 #endif
3416 } else {
3417 /* Unknown CIDR type */
3418 return (EINVAL);
3419 }
3420
3421 return (0);
3422 }
3423
3424 static int
3425 ta_find_fhash_tentry(void *ta_state, struct table_info *ti,
3426 ipfw_obj_tentry *tent)
3427 {
3428 struct fhash_cfg *cfg;
3429 struct fhashbhead *head;
3430 struct fhashentry *ent, *tmp;
3431 struct fhashentry6 fe6;
3432 struct tentry_info tei;
3433 int error;
3434 uint32_t hash;
3435 size_t sz;
3436
3437 cfg = (struct fhash_cfg *)ta_state;
3438
3439 ent = &fe6.e;
3440
3441 memset(&fe6, 0, sizeof(fe6));
3442 memset(&tei, 0, sizeof(tei));
3443
3444 tei.paddr = &tent->k.flow;
3445 tei.subtype = tent->subtype;
3446
3447 if ((error = tei_to_fhash_ent(&tei, ent)) != 0)
3448 return (error);
3449
3450 head = cfg->head;
3451 hash = hash_flow_ent(ent, cfg->size);
3452
3453 if (tei.subtype == AF_INET)
3454 sz = 2 * sizeof(struct in_addr);
3455 else
3456 sz = 2 * sizeof(struct in6_addr);
3457
3458 /* Check for existence */
3459 SLIST_FOREACH(tmp, &head[hash], next) {
3460 if (cmp_flow_ent(tmp, ent, sz) != 0) {
3461 ta_dump_fhash_tentry(ta_state, ti, tmp, tent);
3462 return (0);
3463 }
3464 }
3465
3466 return (ENOENT);
3467 }
3468
3469 static void
3470 ta_foreach_fhash(void *ta_state, struct table_info *ti, ta_foreach_f *f,
3471 void *arg)
3472 {
3473 struct fhash_cfg *cfg;
3474 struct fhashentry *ent, *ent_next;
3475 int i;
3476
3477 cfg = (struct fhash_cfg *)ta_state;
3478
3479 for (i = 0; i < cfg->size; i++)
3480 SLIST_FOREACH_SAFE(ent, &cfg->head[i], next, ent_next)
3481 f(ent, arg);
3482 }
3483
3484 static int
3485 ta_prepare_add_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
3486 void *ta_buf)
3487 {
3488 struct ta_buf_fhash *tb;
3489 struct fhashentry *ent;
3490 size_t sz;
3491 int error;
3492
3493 tb = (struct ta_buf_fhash *)ta_buf;
3494
3495 if (tei->subtype == AF_INET)
3496 sz = sizeof(struct fhashentry4);
3497 else if (tei->subtype == AF_INET6)
3498 sz = sizeof(struct fhashentry6);
3499 else
3500 return (EINVAL);
3501
3502 ent = malloc(sz, M_IPFW_TBL, M_WAITOK | M_ZERO);
3503
3504 error = tei_to_fhash_ent(tei, ent);
3505 if (error != 0) {
3506 free(ent, M_IPFW_TBL);
3507 return (error);
3508 }
3509 tb->ent_ptr = ent;
3510
3511 return (0);
3512 }
3513
3514 static int
3515 ta_add_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
3516 void *ta_buf, uint32_t *pnum)
3517 {
3518 struct fhash_cfg *cfg;
3519 struct fhashbhead *head;
3520 struct fhashentry *ent, *tmp;
3521 struct ta_buf_fhash *tb;
3522 int exists;
3523 uint32_t hash, value;
3524 size_t sz;
3525
3526 cfg = (struct fhash_cfg *)ta_state;
3527 tb = (struct ta_buf_fhash *)ta_buf;
3528 ent = (struct fhashentry *)tb->ent_ptr;
3529 exists = 0;
3530
3531 /* Read current value from @tei */
3532 ent->value = tei->value;
3533
3534 head = cfg->head;
3535 hash = hash_flow_ent(ent, cfg->size);
3536
3537 if (tei->subtype == AF_INET)
3538 sz = 2 * sizeof(struct in_addr);
3539 else
3540 sz = 2 * sizeof(struct in6_addr);
3541
3542 /* Check for existence */
3543 SLIST_FOREACH(tmp, &head[hash], next) {
3544 if (cmp_flow_ent(tmp, ent, sz) != 0) {
3545 exists = 1;
3546 break;
3547 }
3548 }
3549
3550 if (exists == 1) {
3551 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
3552 return (EEXIST);
3553 /* Record already exists. Update value if we're asked to */
3554 /* Exchange values between tmp and @tei */
3555 value = tmp->value;
3556 tmp->value = tei->value;
3557 tei->value = value;
3558 /* Indicate that update has happened instead of addition */
3559 tei->flags |= TEI_FLAGS_UPDATED;
3560 *pnum = 0;
3561 } else {
3562 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
3563 return (EFBIG);
3564
3565 SLIST_INSERT_HEAD(&head[hash], ent, next);
3566 tb->ent_ptr = NULL;
3567 *pnum = 1;
3568
3569 /* Update counters and check if we need to grow hash */
3570 cfg->items++;
3571 }
3572
3573 return (0);
3574 }
3575
3576 static int
3577 ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei,
3578 void *ta_buf)
3579 {
3580 struct ta_buf_fhash *tb;
3581
3582 tb = (struct ta_buf_fhash *)ta_buf;
3583
3584 return (tei_to_fhash_ent(tei, &tb->fe6.e));
3585 }
3586
3587 static int
3588 ta_del_fhash(void *ta_state, struct table_info *ti, struct tentry_info *tei,
3589 void *ta_buf, uint32_t *pnum)
3590 {
3591 struct fhash_cfg *cfg;
3592 struct fhashbhead *head;
3593 struct fhashentry *ent, *tmp;
3594 struct ta_buf_fhash *tb;
3595 uint32_t hash;
3596 size_t sz;
3597
3598 cfg = (struct fhash_cfg *)ta_state;
3599 tb = (struct ta_buf_fhash *)ta_buf;
3600 ent = &tb->fe6.e;
3601
3602 head = cfg->head;
3603 hash = hash_flow_ent(ent, cfg->size);
3604
3605 if (tei->subtype == AF_INET)
3606 sz = 2 * sizeof(struct in_addr);
3607 else
3608 sz = 2 * sizeof(struct in6_addr);
3609
3610 /* Check for existence */
3611 SLIST_FOREACH(tmp, &head[hash], next) {
3612 if (cmp_flow_ent(tmp, ent, sz) == 0)
3613 continue;
3614
3615 SLIST_REMOVE(&head[hash], tmp, fhashentry, next);
3616 tei->value = tmp->value;
3617 *pnum = 1;
3618 cfg->items--;
3619 tb->ent_ptr = tmp;
3620 return (0);
3621 }
3622
3623 return (ENOENT);
3624 }
3625
3626 static void
3627 ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei,
3628 void *ta_buf)
3629 {
3630 struct ta_buf_fhash *tb;
3631
3632 tb = (struct ta_buf_fhash *)ta_buf;
3633
3634 if (tb->ent_ptr != NULL)
3635 free(tb->ent_ptr, M_IPFW_TBL);
3636 }
3637
3638 /*
3639 * Hash growing callbacks.
3640 */
3641
3642 static int
3643 ta_need_modify_fhash(void *ta_state, struct table_info *ti, uint32_t count,
3644 uint64_t *pflags)
3645 {
3646 struct fhash_cfg *cfg;
3647
3648 cfg = (struct fhash_cfg *)ta_state;
3649
3650 if (cfg->items > cfg->size && cfg->size < 65536) {
3651 *pflags = cfg->size * 2;
3652 return (1);
3653 }
3654
3655 return (0);
3656 }
3657
3658 /*
3659 * Allocate new, larger fhash.
3660 */
3661 static int
3662 ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags)
3663 {
3664 struct mod_item *mi;
3665 struct fhashbhead *head;
3666 u_int i;
3667
3668 mi = (struct mod_item *)ta_buf;
3669
3670 memset(mi, 0, sizeof(struct mod_item));
3671 mi->size = *pflags;
3672 head = malloc(sizeof(struct fhashbhead) * mi->size, M_IPFW,
3673 M_WAITOK | M_ZERO);
3674 for (i = 0; i < mi->size; i++)
3675 SLIST_INIT(&head[i]);
3676
3677 mi->main_ptr = head;
3678
3679 return (0);
3680 }
3681
3682 /*
3683 * Copy data from old runtime array to new one.
3684 */
3685 static int
3686 ta_fill_mod_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3687 uint64_t *pflags)
3688 {
3689
3690 /* In is not possible to do rehash if we're not holidng WLOCK. */
3691 return (0);
3692 }
3693
3694 /*
3695 * Switch old & new arrays.
3696 */
3697 static void
3698 ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf,
3699 uint64_t pflags)
3700 {
3701 struct mod_item *mi;
3702 struct fhash_cfg *cfg;
3703 struct fhashbhead *old_head, *new_head;
3704 struct fhashentry *ent, *ent_next;
3705 int i;
3706 uint32_t nhash;
3707 size_t old_size;
3708
3709 mi = (struct mod_item *)ta_buf;
3710 cfg = (struct fhash_cfg *)ta_state;
3711
3712 old_size = cfg->size;
3713 old_head = ti->state;
3714
3715 new_head = (struct fhashbhead *)mi->main_ptr;
3716 for (i = 0; i < old_size; i++) {
3717 SLIST_FOREACH_SAFE(ent, &old_head[i], next, ent_next) {
3718 nhash = hash_flow_ent(ent, mi->size);
3719 SLIST_INSERT_HEAD(&new_head[nhash], ent, next);
3720 }
3721 }
3722
3723 ti->state = new_head;
3724 ti->data = mi->size;
3725 cfg->head = new_head;
3726 cfg->size = mi->size;
3727
3728 mi->main_ptr = old_head;
3729 }
3730
3731 /*
3732 * Free unneded array.
3733 */
3734 static void
3735 ta_flush_mod_fhash(void *ta_buf)
3736 {
3737 struct mod_item *mi;
3738
3739 mi = (struct mod_item *)ta_buf;
3740 if (mi->main_ptr != NULL)
3741 free(mi->main_ptr, M_IPFW);
3742 }
3743
3744 struct table_algo flow_hash = {
3745 .name = "flow:hash",
3746 .type = IPFW_TABLE_FLOW,
3747 .flags = TA_FLAG_DEFAULT,
3748 .ta_buf_size = sizeof(struct ta_buf_fhash),
3749 .init = ta_init_fhash,
3750 .destroy = ta_destroy_fhash,
3751 .prepare_add = ta_prepare_add_fhash,
3752 .prepare_del = ta_prepare_del_fhash,
3753 .add = ta_add_fhash,
3754 .del = ta_del_fhash,
3755 .flush_entry = ta_flush_fhash_entry,
3756 .foreach = ta_foreach_fhash,
3757 .dump_tentry = ta_dump_fhash_tentry,
3758 .find_tentry = ta_find_fhash_tentry,
3759 .dump_tinfo = ta_dump_fhash_tinfo,
3760 .need_modify = ta_need_modify_fhash,
3761 .prepare_mod = ta_prepare_mod_fhash,
3762 .fill_mod = ta_fill_mod_fhash,
3763 .modify = ta_modify_fhash,
3764 .flush_mod = ta_flush_mod_fhash,
3765 };
3766
3767 /*
3768 * Kernel fibs bindings.
3769 *
3770 * Implementation:
3771 *
3772 * Runtime part:
3773 * - fully relies on route API
3774 * - fib number is stored in ti->data
3775 *
3776 */
3777
3778 static int ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
3779 uint32_t *val);
3780 static int kfib_parse_opts(int *pfib, char *data);
3781 static void ta_print_kfib_config(void *ta_state, struct table_info *ti,
3782 char *buf, size_t bufsize);
3783 static int ta_init_kfib(struct ip_fw_chain *ch, void **ta_state,
3784 struct table_info *ti, char *data, uint8_t tflags);
3785 static void ta_destroy_kfib(void *ta_state, struct table_info *ti);
3786 static void ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti,
3787 ipfw_ta_tinfo *tinfo);
3788 static int ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e,
3789 ipfw_obj_tentry *tent);
3790 static int ta_dump_kfib_tentry_int(int familt, const struct rtentry *rt,
3791 ipfw_obj_tentry *tent);
3792 static int ta_find_kfib_tentry(void *ta_state, struct table_info *ti,
3793 ipfw_obj_tentry *tent);
3794 static void ta_foreach_kfib(void *ta_state, struct table_info *ti,
3795 ta_foreach_f *f, void *arg);
3796
3797 static int
3798 ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen,
3799 uint32_t *val)
3800 {
3801 #ifdef INET
3802 struct in_addr in;
3803 #endif
3804 int error;
3805
3806 error = ENOENT;
3807 #ifdef INET
3808 if (keylen == 4) {
3809 in.s_addr = *(in_addr_t *)key;
3810 NET_EPOCH_ASSERT();
3811 error = fib4_lookup(ti->data, in, 0, NHR_NONE, 0) != NULL;
3812 }
3813 #endif
3814 #ifdef INET6
3815 if (keylen == 6)
3816 error = fib6_lookup(ti->data, (struct in6_addr *)key,
3817 0, NHR_NONE, 0) != NULL;
3818 #endif
3819
3820 if (error != 0)
3821 return (0);
3822
3823 *val = 0;
3824
3825 return (1);
3826 }
3827
3828 /* Parse 'fib=%d' */
3829 static int
3830 kfib_parse_opts(int *pfib, char *data)
3831 {
3832 char *pdel, *pend, *s;
3833 int fibnum;
3834
3835 if (data == NULL)
3836 return (0);
3837 if ((pdel = strchr(data, ' ')) == NULL)
3838 return (0);
3839 while (*pdel == ' ')
3840 pdel++;
3841 if (strncmp(pdel, "fib=", 4) != 0)
3842 return (EINVAL);
3843 if ((s = strchr(pdel, ' ')) != NULL)
3844 *s++ = '\0';
3845
3846 pdel += 4;
3847 /* Need \d+ */
3848 fibnum = strtol(pdel, &pend, 10);
3849 if (*pend != '\0')
3850 return (EINVAL);
3851
3852 *pfib = fibnum;
3853
3854 return (0);
3855 }
3856
3857 static void
3858 ta_print_kfib_config(void *ta_state, struct table_info *ti, char *buf,
3859 size_t bufsize)
3860 {
3861
3862 if (ti->data != 0)
3863 snprintf(buf, bufsize, "%s fib=%lu", "addr:kfib", ti->data);
3864 else
3865 snprintf(buf, bufsize, "%s", "addr:kfib");
3866 }
3867
3868 static int
3869 ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
3870 char *data, uint8_t tflags)
3871 {
3872 int error, fibnum;
3873
3874 fibnum = 0;
3875 if ((error = kfib_parse_opts(&fibnum, data)) != 0)
3876 return (error);
3877
3878 if (fibnum >= rt_numfibs)
3879 return (E2BIG);
3880
3881 ti->data = fibnum;
3882 ti->lookup = ta_lookup_kfib;
3883
3884 return (0);
3885 }
3886
3887 /*
3888 * Destroys table @ti
3889 */
3890 static void
3891 ta_destroy_kfib(void *ta_state, struct table_info *ti)
3892 {
3893
3894 }
3895
3896 /*
3897 * Provide algo-specific table info
3898 */
3899 static void
3900 ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
3901 {
3902
3903 tinfo->flags = IPFW_TATFLAGS_AFDATA;
3904 tinfo->taclass4 = IPFW_TACLASS_RADIX;
3905 tinfo->count4 = 0;
3906 tinfo->itemsize4 = 128; /* table is readonly, value does not matter */
3907 tinfo->taclass6 = IPFW_TACLASS_RADIX;
3908 tinfo->count6 = 0;
3909 tinfo->itemsize6 = 128;
3910 }
3911
3912 static int
3913 ta_dump_kfib_tentry_int(int family, const struct rtentry *rt,
3914 ipfw_obj_tentry *tent)
3915 {
3916 uint32_t scopeid;
3917 int plen;
3918
3919 #ifdef INET
3920 if (family == AF_INET) {
3921 rt_get_inet_prefix_plen(rt, &tent->k.addr, &plen, &scopeid);
3922 tent->masklen = plen;
3923 tent->subtype = AF_INET;
3924 tent->v.kidx = 0;
3925 }
3926 #endif
3927 #ifdef INET6
3928 if (family == AF_INET6) {
3929 rt_get_inet6_prefix_plen(rt, &tent->k.addr6, &plen, &scopeid);
3930 tent->masklen = plen;
3931 tent->subtype = AF_INET6;
3932 tent->v.kidx = 0;
3933 }
3934 #endif
3935 return (0);
3936 }
3937
3938 static int
3939 ta_find_kfib_tentry(void *ta_state, struct table_info *ti,
3940 ipfw_obj_tentry *tent)
3941 {
3942 struct rtentry *rt = NULL;
3943 struct route_nhop_data rnd;
3944 struct epoch_tracker et;
3945 int error;
3946
3947 NET_EPOCH_ENTER(et);
3948
3949 switch (tent->subtype) {
3950 #ifdef INET
3951 case AF_INET:
3952 rt = fib4_lookup_rt(ti->data, tent->k.addr, 0, 0, &rnd);
3953 break;
3954 #endif
3955 #ifdef INET6
3956 case AF_INET6:
3957 rt = fib6_lookup_rt(ti->data, &tent->k.addr6, 0, 0, &rnd);
3958 break;
3959 #endif
3960 }
3961 if (rt != NULL)
3962 error = ta_dump_kfib_tentry_int(tent->subtype, rt, tent);
3963 else
3964 error = ENOENT;
3965 NET_EPOCH_EXIT(et);
3966
3967 return (error);
3968 }
3969
3970 struct kfib_dump_arg {
3971 struct rtentry *rt;
3972 int family;
3973 ta_foreach_f *f;
3974 void *arg;
3975 };
3976
3977 static int
3978 ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e,
3979 ipfw_obj_tentry *tent)
3980 {
3981 struct kfib_dump_arg *karg = (struct kfib_dump_arg *)e;
3982
3983 return (ta_dump_kfib_tentry_int(karg->family, karg->rt, tent));
3984 }
3985
3986 static int
3987 walk_wrapper_f(struct rtentry *rt, void *arg)
3988 {
3989 struct kfib_dump_arg *karg = (struct kfib_dump_arg *)arg;
3990
3991 karg->rt = rt;
3992 return (karg->f(karg, karg->arg));
3993 }
3994
3995 static void
3996 ta_foreach_kfib(void *ta_state, struct table_info *ti, ta_foreach_f *f,
3997 void *arg)
3998 {
3999 struct kfib_dump_arg karg = { .f = f, .arg = arg };
4000
4001 karg.family = AF_INET;
4002 rib_walk(ti->data, AF_INET, false, walk_wrapper_f, &karg);
4003 karg.family = AF_INET6;
4004 rib_walk(ti->data, AF_INET6, false, walk_wrapper_f, &karg);
4005 }
4006
4007 struct table_algo addr_kfib = {
4008 .name = "addr:kfib",
4009 .type = IPFW_TABLE_ADDR,
4010 .flags = TA_FLAG_READONLY,
4011 .ta_buf_size = 0,
4012 .init = ta_init_kfib,
4013 .destroy = ta_destroy_kfib,
4014 .foreach = ta_foreach_kfib,
4015 .dump_tentry = ta_dump_kfib_tentry,
4016 .find_tentry = ta_find_kfib_tentry,
4017 .dump_tinfo = ta_dump_kfib_tinfo,
4018 .print_config = ta_print_kfib_config,
4019 };
4020
4021 struct mac_radix_entry {
4022 struct radix_node rn[2];
4023 uint32_t value;
4024 uint8_t masklen;
4025 struct sa_mac sa;
4026 };
4027
4028 struct mac_radix_cfg {
4029 struct radix_node_head *head;
4030 size_t count;
4031 };
4032
4033 static int
4034 ta_lookup_mac_radix(struct table_info *ti, void *key, uint32_t keylen,
4035 uint32_t *val)
4036 {
4037 struct radix_node_head *rnh;
4038
4039 if (keylen == ETHER_ADDR_LEN) {
4040 struct mac_radix_entry *ent;
4041 struct sa_mac sa;
4042 KEY_LEN(sa) = KEY_LEN_MAC;
4043 memcpy(sa.mac_addr.octet, key, ETHER_ADDR_LEN);
4044 rnh = (struct radix_node_head *)ti->state;
4045 ent = (struct mac_radix_entry *)(rnh->rnh_matchaddr(&sa, &rnh->rh));
4046 if (ent != NULL) {
4047 *val = ent->value;
4048 return (1);
4049 }
4050 }
4051 return (0);
4052 }
4053
4054 static int
4055 ta_init_mac_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti,
4056 char *data, uint8_t tflags)
4057 {
4058 struct mac_radix_cfg *cfg;
4059
4060 if (!rn_inithead(&ti->state, OFF_LEN_MAC))
4061 return (ENOMEM);
4062
4063 cfg = malloc(sizeof(struct mac_radix_cfg), M_IPFW, M_WAITOK | M_ZERO);
4064
4065 *ta_state = cfg;
4066 ti->lookup = ta_lookup_mac_radix;
4067
4068 return (0);
4069 }
4070
4071 static void
4072 ta_destroy_mac_radix(void *ta_state, struct table_info *ti)
4073 {
4074 struct mac_radix_cfg *cfg;
4075 struct radix_node_head *rnh;
4076
4077 cfg = (struct mac_radix_cfg *)ta_state;
4078
4079 rnh = (struct radix_node_head *)(ti->state);
4080 rnh->rnh_walktree(&rnh->rh, flush_radix_entry, rnh);
4081 rn_detachhead(&ti->state);
4082
4083 free(cfg, M_IPFW);
4084 }
4085
4086 static void
4087 tei_to_sockaddr_ent_mac(struct tentry_info *tei, struct sockaddr *sa,
4088 struct sockaddr *ma, int *set_mask)
4089 {
4090 int mlen, i;
4091 struct sa_mac *addr, *mask;
4092 u_char *cp;
4093
4094 mlen = tei->masklen;
4095 addr = (struct sa_mac *)sa;
4096 mask = (struct sa_mac *)ma;
4097 /* Set 'total' structure length */
4098 KEY_LEN(*addr) = KEY_LEN_MAC;
4099 KEY_LEN(*mask) = KEY_LEN_MAC;
4100
4101 for (i = mlen, cp = mask->mac_addr.octet; i >= 8; i -= 8)
4102 *cp++ = 0xFF;
4103 if (i > 0)
4104 *cp = ~((1 << (8 - i)) - 1);
4105
4106 addr->mac_addr = *((struct ether_addr *)tei->paddr);
4107 for (i = 0; i < ETHER_ADDR_LEN; ++i)
4108 addr->mac_addr.octet[i] &= mask->mac_addr.octet[i];
4109
4110 if (mlen != 8 * ETHER_ADDR_LEN)
4111 *set_mask = 1;
4112 else
4113 *set_mask = 0;
4114 }
4115
4116 static int
4117 ta_prepare_add_mac_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
4118 void *ta_buf)
4119 {
4120 struct ta_buf_radix *tb;
4121 struct mac_radix_entry *ent;
4122 struct sockaddr *addr, *mask;
4123 int mlen, set_mask;
4124
4125 tb = (struct ta_buf_radix *)ta_buf;
4126
4127 mlen = tei->masklen;
4128 set_mask = 0;
4129
4130 if (tei->subtype == AF_LINK) {
4131 if (mlen > 8 * ETHER_ADDR_LEN)
4132 return (EINVAL);
4133 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
4134 ent->masklen = mlen;
4135
4136 addr = (struct sockaddr *)&ent->sa;
4137 mask = (struct sockaddr *)&tb->addr.mac.ma;
4138 tb->ent_ptr = ent;
4139 } else {
4140 /* Unknown CIDR type */
4141 return (EINVAL);
4142 }
4143
4144 tei_to_sockaddr_ent_mac(tei, addr, mask, &set_mask);
4145 /* Set pointers */
4146 tb->addr_ptr = addr;
4147 if (set_mask != 0)
4148 tb->mask_ptr = mask;
4149
4150 return (0);
4151 }
4152
4153 static int
4154 ta_add_mac_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
4155 void *ta_buf, uint32_t *pnum)
4156 {
4157 struct mac_radix_cfg *cfg;
4158 struct radix_node_head *rnh;
4159 struct radix_node *rn;
4160 struct ta_buf_radix *tb;
4161 uint32_t *old_value, value;
4162
4163 cfg = (struct mac_radix_cfg *)ta_state;
4164 tb = (struct ta_buf_radix *)ta_buf;
4165
4166 /* Save current entry value from @tei */
4167 rnh = ti->state;
4168 ((struct mac_radix_entry *)tb->ent_ptr)->value = tei->value;
4169
4170 /* Search for an entry first */
4171 rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
4172 if (rn != NULL) {
4173 if ((tei->flags & TEI_FLAGS_UPDATE) == 0)
4174 return (EEXIST);
4175 /* Record already exists. Update value if we're asked to */
4176 old_value = &((struct mac_radix_entry *)rn)->value;
4177
4178 value = *old_value;
4179 *old_value = tei->value;
4180 tei->value = value;
4181
4182 /* Indicate that update has happened instead of addition */
4183 tei->flags |= TEI_FLAGS_UPDATED;
4184 *pnum = 0;
4185
4186 return (0);
4187 }
4188
4189 if ((tei->flags & TEI_FLAGS_DONTADD) != 0)
4190 return (EFBIG);
4191
4192 rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, &rnh->rh, tb->ent_ptr);
4193 if (rn == NULL) {
4194 /* Unknown error */
4195 return (EINVAL);
4196 }
4197
4198 cfg->count++;
4199 tb->ent_ptr = NULL;
4200 *pnum = 1;
4201
4202 return (0);
4203 }
4204
4205 static int
4206 ta_prepare_del_mac_radix(struct ip_fw_chain *ch, struct tentry_info *tei,
4207 void *ta_buf)
4208 {
4209 struct ta_buf_radix *tb;
4210 struct sockaddr *addr, *mask;
4211 int mlen, set_mask;
4212
4213 tb = (struct ta_buf_radix *)ta_buf;
4214
4215 mlen = tei->masklen;
4216 set_mask = 0;
4217
4218 if (tei->subtype == AF_LINK) {
4219 if (mlen > 8 * ETHER_ADDR_LEN)
4220 return (EINVAL);
4221
4222 addr = (struct sockaddr *)&tb->addr.mac.sa;
4223 mask = (struct sockaddr *)&tb->addr.mac.ma;
4224 } else
4225 return (EINVAL);
4226
4227 tei_to_sockaddr_ent_mac(tei, addr, mask, &set_mask);
4228 tb->addr_ptr = addr;
4229 if (set_mask != 0)
4230 tb->mask_ptr = mask;
4231
4232 return (0);
4233 }
4234
4235 static int
4236 ta_del_mac_radix(void *ta_state, struct table_info *ti, struct tentry_info *tei,
4237 void *ta_buf, uint32_t *pnum)
4238 {
4239 struct mac_radix_cfg *cfg;
4240 struct radix_node_head *rnh;
4241 struct radix_node *rn;
4242 struct ta_buf_radix *tb;
4243
4244 cfg = (struct mac_radix_cfg *)ta_state;
4245 tb = (struct ta_buf_radix *)ta_buf;
4246 rnh = ti->state;
4247
4248 rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, &rnh->rh);
4249
4250 if (rn == NULL)
4251 return (ENOENT);
4252
4253 /* Save entry value to @tei */
4254 tei->value = ((struct mac_radix_entry *)rn)->value;
4255
4256 tb->ent_ptr = rn;
4257 cfg->count--;
4258 *pnum = 1;
4259
4260 return (0);
4261 }
4262
4263 static void
4264 ta_foreach_mac_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f,
4265 void *arg)
4266 {
4267 struct radix_node_head *rnh;
4268
4269 rnh = (struct radix_node_head *)(ti->state);
4270 rnh->rnh_walktree(&rnh->rh, (walktree_f_t *)f, arg);
4271 }
4272
4273 static void
4274 ta_dump_mac_radix_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo)
4275 {
4276 struct mac_radix_cfg *cfg;
4277
4278 cfg = (struct mac_radix_cfg *)ta_state;
4279
4280 tinfo->flags = IPFW_TATFLAGS_AFDATA | IPFW_TATFLAGS_AFITEM;
4281 tinfo->taclass4 = IPFW_TACLASS_RADIX;
4282 tinfo->count4 = cfg->count;
4283 tinfo->itemsize4 = sizeof(struct mac_radix_entry);
4284 }
4285
4286 static int
4287 ta_dump_mac_radix_tentry(void *ta_state, struct table_info *ti, void *e,
4288 ipfw_obj_tentry *tent)
4289 {
4290 struct mac_radix_entry *n = (struct mac_radix_entry *)e;
4291
4292 memcpy(tent->k.mac, n->sa.mac_addr.octet, ETHER_ADDR_LEN);
4293 tent->masklen = n->masklen;
4294 tent->subtype = AF_LINK;
4295 tent->v.kidx = n->value;
4296
4297 return (0);
4298 }
4299
4300 static int
4301 ta_find_mac_radix_tentry(void *ta_state, struct table_info *ti,
4302 ipfw_obj_tentry *tent)
4303 {
4304 struct radix_node_head *rnh;
4305 void *e;
4306
4307 e = NULL;
4308 if (tent->subtype == AF_LINK) {
4309 struct sa_mac sa;
4310 KEY_LEN(sa) = KEY_LEN_MAC;
4311 memcpy(tent->k.mac, sa.mac_addr.octet, ETHER_ADDR_LEN);
4312 rnh = (struct radix_node_head *)ti->state;
4313 e = rnh->rnh_matchaddr(&sa, &rnh->rh);
4314 }
4315
4316 if (e != NULL) {
4317 ta_dump_mac_radix_tentry(ta_state, ti, e, tent);
4318 return (0);
4319 }
4320
4321 return (ENOENT);
4322 }
4323
4324 struct table_algo mac_radix = {
4325 .name = "mac:radix",
4326 .type = IPFW_TABLE_MAC,
4327 .flags = TA_FLAG_DEFAULT,
4328 .ta_buf_size = sizeof(struct ta_buf_radix),
4329 .init = ta_init_mac_radix,
4330 .destroy = ta_destroy_mac_radix,
4331 .prepare_add = ta_prepare_add_mac_radix,
4332 .prepare_del = ta_prepare_del_mac_radix,
4333 .add = ta_add_mac_radix,
4334 .del = ta_del_mac_radix,
4335 .flush_entry = ta_flush_radix_entry,
4336 .foreach = ta_foreach_mac_radix,
4337 .dump_tentry = ta_dump_mac_radix_tentry,
4338 .find_tentry = ta_find_mac_radix_tentry,
4339 .dump_tinfo = ta_dump_mac_radix_tinfo,
4340 .need_modify = ta_need_modify_radix,
4341 };
4342
4343 void
4344 ipfw_table_algo_init(struct ip_fw_chain *ch)
4345 {
4346 size_t sz;
4347
4348 /*
4349 * Register all algorithms presented here.
4350 */
4351 sz = sizeof(struct table_algo);
4352 ipfw_add_table_algo(ch, &addr_radix, sz, &addr_radix.idx);
4353 ipfw_add_table_algo(ch, &addr_hash, sz, &addr_hash.idx);
4354 ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx);
4355 ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx);
4356 ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx);
4357 ipfw_add_table_algo(ch, &addr_kfib, sz, &addr_kfib.idx);
4358 ipfw_add_table_algo(ch, &mac_radix, sz, &mac_radix.idx);
4359 }
4360
4361 void
4362 ipfw_table_algo_destroy(struct ip_fw_chain *ch)
4363 {
4364
4365 ipfw_del_table_algo(ch, addr_radix.idx);
4366 ipfw_del_table_algo(ch, addr_hash.idx);
4367 ipfw_del_table_algo(ch, iface_idx.idx);
4368 ipfw_del_table_algo(ch, number_array.idx);
4369 ipfw_del_table_algo(ch, flow_hash.idx);
4370 ipfw_del_table_algo(ch, addr_kfib.idx);
4371 ipfw_del_table_algo(ch, mac_radix.idx);
4372 }
Cache object: d11c5a76955fa20ed877441974bce3e3
|