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