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