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