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 283MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables"); 284 285/* 286 * Utility structures/functions common to more than one algo 287 */ 288 289struct mod_item { 290 void *main_ptr; 291 size_t size; 292 void *main_ptr6; 293 size_t size6; 294}; 295 296static int badd(const void *key, void *item, void *base, size_t nmemb, 297 size_t size, int (*compar) (const void *, const void *)); 298static 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 327struct addr_radix_entry { 328 struct radix_node rn[2]; 329 struct sockaddr_in addr; 330 uint32_t value; 331 uint8_t masklen; 332}; 333 334struct 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 341struct addr_radix_xentry { 342 struct radix_node rn[2]; 343 struct sa_in6 addr6; 344 uint32_t value; 345 uint8_t masklen; 346}; 347 348struct 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 355struct sa_mac { 356 uint8_t mac_len; 357 struct ether_addr mac_addr; 358}; 359 360struct 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 381static int ta_lookup_addr_radix(struct table_info *ti, void *key, uint32_t keylen, 382 uint32_t *val); 383static int ta_init_addr_radix(struct ip_fw_chain *ch, void **ta_state, 384 struct table_info *ti, char *data, uint8_t tflags); 385static int flush_radix_entry(struct radix_node *rn, void *arg); 386static void ta_destroy_addr_radix(void *ta_state, struct table_info *ti); 387static void ta_dump_addr_radix_tinfo(void *ta_state, struct table_info *ti, 388 ipfw_ta_tinfo *tinfo); 389static int ta_dump_addr_radix_tentry(void *ta_state, struct table_info *ti, 390 void *e, ipfw_obj_tentry *tent); 391static int ta_find_addr_radix_tentry(void *ta_state, struct table_info *ti, 392 ipfw_obj_tentry *tent); 393static void ta_foreach_addr_radix(void *ta_state, struct table_info *ti, 394 ta_foreach_f *f, void *arg); 395static void tei_to_sockaddr_ent_addr(struct tentry_info *tei, struct sockaddr *sa, 396 struct sockaddr *ma, int *set_mask); 397static int ta_prepare_add_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 398 void *ta_buf); 399static int ta_add_addr_radix(void *ta_state, struct table_info *ti, 400 struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 401static int ta_prepare_del_addr_radix(struct ip_fw_chain *ch, struct tentry_info *tei, 402 void *ta_buf); 403static int ta_del_addr_radix(void *ta_state, struct table_info *ti, 404 struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 405static void ta_flush_radix_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 406 void *ta_buf); 407static int ta_need_modify_radix(void *ta_state, struct table_info *ti, 408 uint32_t count, uint64_t *pflags); 409 410static int 411ta_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 */ 446static int 447ta_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 467static int 468flush_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 480static void 481ta_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 */ 502static void 503ta_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 518static int 519ta_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 549static int 550ta_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 579static void 580ta_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 593static inline void ipv6_writemask(struct in6_addr *addr6, uint8_t mask); 594 595static inline void 596ipv6_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 607static void 608tei_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 659static int 660ta_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 713static int 714ta_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 776static int 777ta_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 814static int 815ta_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 853static void 854ta_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 865static int 866ta_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 879struct 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 918struct chashentry; 919 920SLIST_HEAD(chashbhead, chashentry); 921 922struct 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 933struct 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 943struct ta_buf_chash 944{ 945 void *ent_ptr; 946 struct chashentry ent; 947}; 948 949#ifdef INET 950static __inline uint32_t hash_ip(uint32_t addr, int hsize); 951#endif 952#ifdef INET6 953static __inline uint32_t hash_ip6(struct in6_addr *addr6, int hsize); 954static __inline uint16_t hash_ip64(struct in6_addr *addr6, int hsize); 955static __inline uint32_t hash_ip6_slow(struct in6_addr *addr6, void *key, 956 int mask, int hsize); 957static __inline uint32_t hash_ip6_al(struct in6_addr *addr6, void *key, int mask, 958 int hsize); 959#endif 960static int ta_lookup_chash_slow(struct table_info *ti, void *key, uint32_t keylen, 961 uint32_t *val); 962static int ta_lookup_chash_aligned(struct table_info *ti, void *key, 963 uint32_t keylen, uint32_t *val); 964static int ta_lookup_chash_64(struct table_info *ti, void *key, uint32_t keylen, 965 uint32_t *val); 966static int chash_parse_opts(struct chash_cfg *cfg, char *data); 967static void ta_print_chash_config(void *ta_state, struct table_info *ti, 968 char *buf, size_t bufsize); 969static int ta_log2(uint32_t v); 970static int ta_init_chash(struct ip_fw_chain *ch, void **ta_state, 971 struct table_info *ti, char *data, uint8_t tflags); 972static void ta_destroy_chash(void *ta_state, struct table_info *ti); 973static void ta_dump_chash_tinfo(void *ta_state, struct table_info *ti, 974 ipfw_ta_tinfo *tinfo); 975static int ta_dump_chash_tentry(void *ta_state, struct table_info *ti, 976 void *e, ipfw_obj_tentry *tent); 977static uint32_t hash_ent(struct chashentry *ent, int af, int mlen, 978 uint32_t size); 979static int tei_to_chash_ent(struct tentry_info *tei, struct chashentry *ent); 980static int ta_find_chash_tentry(void *ta_state, struct table_info *ti, 981 ipfw_obj_tentry *tent); 982static void ta_foreach_chash(void *ta_state, struct table_info *ti, 983 ta_foreach_f *f, void *arg); 984static int ta_prepare_add_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 985 void *ta_buf); 986static int ta_add_chash(void *ta_state, struct table_info *ti, 987 struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 988static int ta_prepare_del_chash(struct ip_fw_chain *ch, struct tentry_info *tei, 989 void *ta_buf); 990static int ta_del_chash(void *ta_state, struct table_info *ti, 991 struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 992static void ta_flush_chash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 993 void *ta_buf); 994static int ta_need_modify_chash(void *ta_state, struct table_info *ti, 995 uint32_t count, uint64_t *pflags); 996static int ta_prepare_mod_chash(void *ta_buf, uint64_t *pflags); 997static int ta_fill_mod_chash(void *ta_state, struct table_info *ti, void *ta_buf, 998 uint64_t *pflags); 999static void ta_modify_chash(void *ta_state, struct table_info *ti, void *ta_buf, 1000 uint64_t pflags); 1001static void ta_flush_mod_chash(void *ta_buf); 1002 1003#ifdef INET 1004static __inline uint32_t 1005hash_ip(uint32_t addr, int hsize) 1006{ 1007 1008 return (addr % (hsize - 1)); 1009} 1010#endif 1011 1012#ifdef INET6 1013static __inline uint32_t 1014hash_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 1024static __inline uint16_t 1025hash_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 1034static __inline uint32_t 1035hash_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 1045static __inline uint32_t 1046hash_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 1058static int 1059ta_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 1103static int 1104ta_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 1152static int 1153ta_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 1199static int 1200chash_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 1244static void 1245ta_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 1259static int 1260ta_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 */ 1276static int 1277ta_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 1330static void 1331ta_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 1353static void 1354ta_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 1371static int 1372ta_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 1398static uint32_t 1399hash_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 1421static int 1422tei_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 1459static int 1460ta_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 1515static void 1516ta_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 1534static int 1535ta_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 1556static int 1557ta_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 1631static int 1632ta_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 1642static int 1643ta_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 1694static void 1695ta_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 1710static int 1711ta_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 */ 1742static int 1743ta_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 */ 1776static int 1777ta_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 */ 1788static void 1789ta_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 */ 1854static void 1855ta_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 1866struct 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 1907struct ifidx { 1908 uint16_t kidx; 1909 uint16_t spare; 1910 uint32_t value; 1911}; 1912#define DEFAULT_IFIDX_SIZE 64 1913 1914struct iftable_cfg; 1915 1916struct 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 1924struct 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 1934struct ta_buf_ifidx 1935{ 1936 struct ifentry *ife; 1937 uint32_t value; 1938}; 1939 1940int compare_ifidx(const void *k, const void *v); 1941static struct ifidx * ifidx_find(struct table_info *ti, void *key); 1942static int ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen, 1943 uint32_t *val); 1944static int ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, 1945 struct table_info *ti, char *data, uint8_t tflags); 1946static void ta_change_ti_ifidx(void *ta_state, struct table_info *ti); 1947static int destroy_ifidx_locked(struct namedobj_instance *ii, 1948 struct named_object *no, void *arg); 1949static void ta_destroy_ifidx(void *ta_state, struct table_info *ti); 1950static void ta_dump_ifidx_tinfo(void *ta_state, struct table_info *ti, 1951 ipfw_ta_tinfo *tinfo); 1952static int ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 1953 void *ta_buf); 1954static int ta_add_ifidx(void *ta_state, struct table_info *ti, 1955 struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 1956static int ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 1957 void *ta_buf); 1958static int ta_del_ifidx(void *ta_state, struct table_info *ti, 1959 struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 1960static void ta_flush_ifidx_entry(struct ip_fw_chain *ch, 1961 struct tentry_info *tei, void *ta_buf); 1962static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex); 1963static int ta_need_modify_ifidx(void *ta_state, struct table_info *ti, 1964 uint32_t count, uint64_t *pflags); 1965static int ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags); 1966static int ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, 1967 void *ta_buf, uint64_t *pflags); 1968static void ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 1969 uint64_t pflags); 1970static void ta_flush_mod_ifidx(void *ta_buf); 1971static int ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e, 1972 ipfw_obj_tentry *tent); 1973static int ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, 1974 ipfw_obj_tentry *tent); 1975static int foreach_ifidx(struct namedobj_instance *ii, struct named_object *no, 1976 void *arg); 1977static void ta_foreach_ifidx(void *ta_state, struct table_info *ti, 1978 ta_foreach_f *f, void *arg); 1979 1980int 1981compare_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 */ 2003static int 2004badd(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 */ 2052static int 2053bdel(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 2072static struct ifidx * 2073ifidx_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 2083static int 2084ta_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 2099static int 2100ta_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 */ 2123static void 2124ta_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 2132static int 2133destroy_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 */ 2151static void 2152ta_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 */ 2175static void 2176ta_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 */ 2192static int 2193ta_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 2224static int 2225ta_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 */ 2288static int 2289ta_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 */ 2306static int 2307ta_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 */ 2358static void 2359ta_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 */ 2374static void 2375if_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 2418static int 2419ta_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 */ 2442static int 2443ta_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 */ 2460static int 2461ta_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 */ 2484static void 2485ta_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 */ 2506static void 2507ta_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 2516static int 2517ta_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 2531static int 2532ta_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 2555struct wa_ifidx { 2556 ta_foreach_f *f; 2557 void *arg; 2558}; 2559 2560static int 2561foreach_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 2574static void 2575ta_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 2589struct 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 2625struct numarray { 2626 uint32_t number; 2627 uint32_t value; 2628}; 2629 2630struct 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 2636struct ta_buf_numarray 2637{ 2638 struct numarray na; 2639}; 2640 2641int compare_numarray(const void *k, const void *v); 2642static struct numarray *numarray_find(struct table_info *ti, void *key); 2643static int ta_lookup_numarray(struct table_info *ti, void *key, 2644 uint32_t keylen, uint32_t *val); 2645static int ta_init_numarray(struct ip_fw_chain *ch, void **ta_state, 2646 struct table_info *ti, char *data, uint8_t tflags); 2647static void ta_destroy_numarray(void *ta_state, struct table_info *ti); 2648static void ta_dump_numarray_tinfo(void *ta_state, struct table_info *ti, 2649 ipfw_ta_tinfo *tinfo); 2650static int ta_prepare_add_numarray(struct ip_fw_chain *ch, 2651 struct tentry_info *tei, void *ta_buf); 2652static int ta_add_numarray(void *ta_state, struct table_info *ti, 2653 struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 2654static int ta_del_numarray(void *ta_state, struct table_info *ti, 2655 struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 2656static void ta_flush_numarray_entry(struct ip_fw_chain *ch, 2657 struct tentry_info *tei, void *ta_buf); 2658static int ta_need_modify_numarray(void *ta_state, struct table_info *ti, 2659 uint32_t count, uint64_t *pflags); 2660static int ta_prepare_mod_numarray(void *ta_buf, uint64_t *pflags); 2661static int ta_fill_mod_numarray(void *ta_state, struct table_info *ti, 2662 void *ta_buf, uint64_t *pflags); 2663static void ta_modify_numarray(void *ta_state, struct table_info *ti, 2664 void *ta_buf, uint64_t pflags); 2665static void ta_flush_mod_numarray(void *ta_buf); 2666static int ta_dump_numarray_tentry(void *ta_state, struct table_info *ti, 2667 void *e, ipfw_obj_tentry *tent); 2668static int ta_find_numarray_tentry(void *ta_state, struct table_info *ti, 2669 ipfw_obj_tentry *tent); 2670static void ta_foreach_numarray(void *ta_state, struct table_info *ti, 2671 ta_foreach_f *f, void *arg); 2672 2673int 2674compare_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 2690static struct numarray * 2691numarray_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 2701static int 2702ta_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 2717static int 2718ta_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 */ 2739static void 2740ta_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 */ 2755static void 2756ta_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 */ 2771static int 2772ta_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 2784static int 2785ta_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 */ 2834static int 2835ta_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 2863static void 2864ta_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 2875static int 2876ta_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 */ 2899static int 2900ta_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 */ 2917static int 2918ta_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 */ 2941static void 2942ta_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 */ 2963static void 2964ta_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 2973static int 2974ta_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 2987static int 2988ta_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 3003static void 3004ta_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 3018struct 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 3060struct fhashentry; 3061 3062SLIST_HEAD(fhashbhead, fhashentry); 3063 3064struct 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 3075struct fhashentry4 { 3076 struct fhashentry e; 3077 struct in_addr dip; 3078 struct in_addr sip; 3079}; 3080 3081struct fhashentry6 { 3082 struct fhashentry e; 3083 struct in6_addr dip6; 3084 struct in6_addr sip6; 3085}; 3086 3087struct fhash_cfg { 3088 struct fhashbhead *head; 3089 size_t size; 3090 size_t items; 3091 struct fhashentry4 fe4; 3092 struct fhashentry6 fe6; 3093}; 3094 3095struct ta_buf_fhash { 3096 void *ent_ptr; 3097 struct fhashentry6 fe6; 3098}; 3099 3100static __inline int cmp_flow_ent(struct fhashentry *a, 3101 struct fhashentry *b, size_t sz); 3102static __inline uint32_t hash_flow4(struct fhashentry4 *f, int hsize); 3103static __inline uint32_t hash_flow6(struct fhashentry6 *f, int hsize); 3104static uint32_t hash_flow_ent(struct fhashentry *ent, uint32_t size); 3105static int ta_lookup_fhash(struct table_info *ti, void *key, uint32_t keylen, 3106 uint32_t *val); 3107static int ta_init_fhash(struct ip_fw_chain *ch, void **ta_state, 3108struct table_info *ti, char *data, uint8_t tflags); 3109static void ta_destroy_fhash(void *ta_state, struct table_info *ti); 3110static void ta_dump_fhash_tinfo(void *ta_state, struct table_info *ti, 3111 ipfw_ta_tinfo *tinfo); 3112static int ta_dump_fhash_tentry(void *ta_state, struct table_info *ti, 3113 void *e, ipfw_obj_tentry *tent); 3114static int tei_to_fhash_ent(struct tentry_info *tei, struct fhashentry *ent); 3115static int ta_find_fhash_tentry(void *ta_state, struct table_info *ti, 3116 ipfw_obj_tentry *tent); 3117static void ta_foreach_fhash(void *ta_state, struct table_info *ti, 3118 ta_foreach_f *f, void *arg); 3119static int ta_prepare_add_fhash(struct ip_fw_chain *ch, 3120 struct tentry_info *tei, void *ta_buf); 3121static int ta_add_fhash(void *ta_state, struct table_info *ti, 3122 struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 3123static int ta_prepare_del_fhash(struct ip_fw_chain *ch, struct tentry_info *tei, 3124 void *ta_buf); 3125static int ta_del_fhash(void *ta_state, struct table_info *ti, 3126 struct tentry_info *tei, void *ta_buf, uint32_t *pnum); 3127static void ta_flush_fhash_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 3128 void *ta_buf); 3129static int ta_need_modify_fhash(void *ta_state, struct table_info *ti, 3130 uint32_t count, uint64_t *pflags); 3131static int ta_prepare_mod_fhash(void *ta_buf, uint64_t *pflags); 3132static int ta_fill_mod_fhash(void *ta_state, struct table_info *ti, 3133 void *ta_buf, uint64_t *pflags); 3134static void ta_modify_fhash(void *ta_state, struct table_info *ti, void *ta_buf, 3135 uint64_t pflags); 3136static void ta_flush_mod_fhash(void *ta_buf); 3137 3138static __inline int 3139cmp_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 3152static __inline uint32_t 3153hash_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 3162static __inline uint32_t 3163hash_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 3176static uint32_t 3177hash_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 3190static int 3191ta_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 */ 3257static int 3258ta_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 3311static void 3312ta_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 */ 3331static void 3332ta_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 3346static int 3347ta_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 3384static int 3385tei_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 3422static int 3423ta_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 3467static void 3468ta_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 3482static int 3483ta_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 3512static int 3513ta_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 3574static int 3575ta_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 3585static int 3586ta_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 3624static void 3625ta_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 3640static int 3641ta_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 */ 3659static int 3660ta_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 */ 3683static int 3684ta_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 */ 3695static void 3696ta_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 */ 3732static void 3733ta_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 3742struct 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 3776static int ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen, 3777 uint32_t *val); 3778static int kfib_parse_opts(int *pfib, char *data); 3779static void ta_print_kfib_config(void *ta_state, struct table_info *ti, 3780 char *buf, size_t bufsize); 3781static int ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, 3782 struct table_info *ti, char *data, uint8_t tflags); 3783static void ta_destroy_kfib(void *ta_state, struct table_info *ti); 3784static void ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, 3785 ipfw_ta_tinfo *tinfo); 3786static int ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e, 3787 ipfw_obj_tentry *tent); 3788static int ta_dump_kfib_tentry_int(int familt, const struct rtentry *rt, 3789 ipfw_obj_tentry *tent); 3790static int ta_find_kfib_tentry(void *ta_state, struct table_info *ti, 3791 ipfw_obj_tentry *tent); 3792static void ta_foreach_kfib(void *ta_state, struct table_info *ti, 3793 ta_foreach_f *f, void *arg); 3794 3795static int 3796ta_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' */ 3827static int 3828kfib_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 3855static void 3856ta_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 3866static int 3867ta_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 */ 3888static void 3889ta_destroy_kfib(void *ta_state, struct table_info *ti) 3890{ 3891 3892} 3893 3894/* 3895 * Provide algo-specific table info 3896 */ 3897static void 3898ta_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 3910static int 3911ta_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 3936static int 3937ta_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 3968struct kfib_dump_arg { 3969 struct rtentry *rt; 3970 int family; 3971 ta_foreach_f *f; 3972 void *arg; 3973}; 3974 3975static int 3976ta_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 3984static int 3985walk_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 3993static void 3994ta_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 4005struct 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 4019struct mac_radix_entry { 4020 struct radix_node rn[2]; 4021 uint32_t value; 4022 uint8_t masklen; 4023 struct sa_mac sa; 4024}; 4025 4026struct mac_radix_cfg { 4027 struct radix_node_head *head; 4028 size_t count; 4029}; 4030 4031static int 4032ta_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 4052static int 4053ta_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 4069static void 4070ta_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 4084static void 4085tei_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 4114static int 4115ta_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 4151static int 4152ta_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 4203static int 4204ta_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 4233static int 4234ta_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 4261static void 4262ta_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 4271static void 4272ta_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 4284static int 4285ta_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 4298static int 4299ta_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 4322struct 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 4341void 4342ipfw_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 4359void 4360ipfw_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