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