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