1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2020 Alexander V. Chernikov 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 #include "opt_inet.h" 30 #include "opt_inet6.h" 31 #include "opt_route.h" 32 33 #include <sys/param.h> 34 #include <sys/eventhandler.h> 35 #include <sys/kernel.h> 36 #include <sys/sbuf.h> 37 #include <sys/lock.h> 38 #include <sys/rmlock.h> 39 #include <sys/malloc.h> 40 #include <sys/mbuf.h> 41 #include <sys/module.h> 42 #include <sys/kernel.h> 43 #include <sys/priv.h> 44 #include <sys/proc.h> 45 #include <sys/socket.h> 46 #include <sys/socketvar.h> 47 #include <sys/stdarg.h> 48 #include <sys/sysctl.h> 49 #include <sys/syslog.h> 50 #include <sys/queue.h> 51 #include <net/vnet.h> 52 53 #include <net/if.h> 54 #include <net/if_var.h> 55 56 #include <netinet/in.h> 57 #include <netinet/in_var.h> 58 #include <netinet/ip.h> 59 #include <netinet/ip_var.h> 60 #ifdef INET6 61 #include <netinet/ip6.h> 62 #include <netinet6/ip6_var.h> 63 #endif 64 65 #include <net/route.h> 66 #include <net/route/nhop.h> 67 #include <net/route/route_ctl.h> 68 #include <net/route/route_var.h> 69 #include <net/route/fib_algo.h> 70 71 /* 72 * Fib lookup framework. 73 * 74 * This framework enables accelerated longest-prefix-match lookups for the 75 * routing tables by adding the ability to dynamically attach/detach lookup 76 * algorithms implementation to/from the datapath. 77 * 78 * flm - fib lookup modules - implementation of particular lookup algorithm 79 * fd - fib data - instance of an flm bound to specific routing table 80 * 81 * This file provides main framework functionality. 82 * 83 * The following are the features provided by the framework 84 * 85 * 1) nexhops abstraction -> provides transparent referencing, indexing 86 * and efficient idx->ptr mappings for nexthop and nexthop groups. 87 * 2) Routing table synchronisation 88 * 3) dataplane attachment points 89 * 4) automatic algorithm selection based on the provided preference. 90 * 91 * 92 * DATAPATH 93 * For each supported address family, there is a an allocated array of fib_dp 94 * structures, indexed by fib number. Each array entry contains callback function 95 * and its argument. This function will be called with a family-specific lookup key, 96 * scope and provided argument. This array gets re-created every time when new algo 97 * instance gets created. Please take a look at the replace_rtables_family() function 98 * for more details. 99 * 100 */ 101 102 SYSCTL_DECL(_net_route); 103 SYSCTL_NODE(_net_route, OID_AUTO, algo, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 104 "Fib algorithm lookups"); 105 106 /* Algorithm sync policy */ 107 108 /* Time interval to bucket updates */ 109 VNET_DEFINE_STATIC(unsigned int, update_bucket_time_ms) = 50; 110 #define V_update_bucket_time_ms VNET(update_bucket_time_ms) 111 SYSCTL_UINT(_net_route_algo, OID_AUTO, bucket_time_ms, CTLFLAG_RW | CTLFLAG_VNET, 112 &VNET_NAME(update_bucket_time_ms), 0, "Time interval to calculate update rate"); 113 114 /* Minimum update rate to delay sync */ 115 VNET_DEFINE_STATIC(unsigned int, bucket_change_threshold_rate) = 500; 116 #define V_bucket_change_threshold_rate VNET(bucket_change_threshold_rate) 117 SYSCTL_UINT(_net_route_algo, OID_AUTO, bucket_change_threshold_rate, CTLFLAG_RW | CTLFLAG_VNET, 118 &VNET_NAME(bucket_change_threshold_rate), 0, "Minimum update rate to delay sync"); 119 120 /* Max allowed delay to sync */ 121 VNET_DEFINE_STATIC(unsigned int, fib_max_sync_delay_ms) = 1000; 122 #define V_fib_max_sync_delay_ms VNET(fib_max_sync_delay_ms) 123 SYSCTL_UINT(_net_route_algo, OID_AUTO, fib_max_sync_delay_ms, CTLFLAG_RW | CTLFLAG_VNET, 124 &VNET_NAME(fib_max_sync_delay_ms), 0, "Maximum time to delay sync (ms)"); 125 126 127 #ifdef INET6 128 VNET_DEFINE_STATIC(bool, algo_fixed_inet6) = false; 129 #define V_algo_fixed_inet6 VNET(algo_fixed_inet6) 130 SYSCTL_NODE(_net_route_algo, OID_AUTO, inet6, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 131 "IPv6 longest prefix match lookups"); 132 #endif 133 #ifdef INET 134 VNET_DEFINE_STATIC(bool, algo_fixed_inet) = false; 135 #define V_algo_fixed_inet VNET(algo_fixed_inet) 136 SYSCTL_NODE(_net_route_algo, OID_AUTO, inet, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 137 "IPv4 longest prefix match lookups"); 138 #endif 139 140 /* Fib instance counter */ 141 static uint32_t fib_gen = 0; 142 143 struct nhop_ref_table { 144 uint32_t count; 145 int32_t refcnt[0]; 146 }; 147 148 /* 149 * Nexthop indexes are allocated per-rib, and ribs are keyed by 150 * (fibnum, neighbor family). A route with a gateway belonging to another 151 * family (an IPv4 prefix via an IPv6 nexthop, RFC 5549) therefore gets 152 * its index from that other family's space, where it can collide with the 153 * index of a native nexthop. 154 * 155 * Keep one flat idx->nhop array, but give every index space a contiguous 156 * segment within it, so the array offset is nhaf_base + nhop index. 157 * The rib's own family always owns the first segment, making the offset 158 * identical to the nexthop index for every table with no cross-family nexthops. 159 */ 160 struct nhop_af_table { 161 uint8_t nhaf_family; /* AF owning this index space */ 162 bool nhaf_hit; /* true if out of index space */ 163 uint32_t nhaf_count; /* # of indexes reserved */ 164 uint32_t nhaf_base; /* offset within fd->nh_idx */ 165 }; 166 167 /* # of nhop index spaces per instance, currently 4o6 for now */ 168 #define FD_MAX_NH_AF 2 169 170 enum fib_callout_action { 171 FDA_NONE, /* No callout scheduled */ 172 FDA_REBUILD, /* Asks to rebuild algo instance */ 173 FDA_EVAL, /* Asks to evaluate if the current algo is still be best */ 174 FDA_BATCH, /* Asks to submit batch of updates to the algo */ 175 }; 176 177 struct fib_sync_status { 178 struct timeval diverge_time; /* ts when diverged */ 179 uint32_t num_changes; /* number of changes since sync */ 180 uint32_t bucket_changes; /* num changes within the current bucket */ 181 uint64_t bucket_id; /* 50ms bucket # */ 182 struct fib_change_queue fd_change_queue;/* list of scheduled entries */ 183 }; 184 185 /* 186 * Data structure for the fib lookup instance tied to the particular rib. 187 * 188 * Key: 189 * (f) - Protected by the FIB_MOD lock 190 * (r) - Protected by the RIB lock 191 */ 192 struct fib_data { 193 uint32_t number_nhops; /* (r) total size of the nhop arrays */ 194 uint32_t fd_dead:1, /* (f) Scheduled for deletion */ 195 fd_linked:1; /* (f) true if linked */ 196 uint32_t init_done:1, /* (r) true if init is competed */ 197 fd_need_rebuild:1, /* (r) true if rebuild scheduled */ 198 fd_batch:1, /* (r) true if batched notification scheduled */ 199 hit_nhops:1; /* (r) true if out of nhop limit */ 200 uint8_t fd_num_af; /* (r) # of nhop index spaces in use */ 201 uint8_t fd_family; /* family */ 202 uint32_t fd_fibnum; /* fibnum */ 203 uint32_t fd_failed_rebuilds; /* stat: failed rebuilds */ 204 uint32_t fd_gen; /* instance gen# */ 205 struct callout fd_callout; /* rebuild callout */ 206 enum fib_callout_action fd_callout_action; /* Callout action to take */ 207 void *fd_algo_data; /* algorithm data */ 208 struct nhop_af_table fd_af[FD_MAX_NH_AF]; /* (r) index space descriptors */ 209 struct nhop_object **nh_idx; /* nhop idx->ptr array */ 210 struct nhop_ref_table *nh_ref_table; /* array with # of nhop references */ 211 struct rib_head *fd_rh; /* RIB table we're attached to */ 212 struct rib_subscription *fd_rs; /* storing table subscription */ 213 struct fib_dp fd_dp; /* fib datapath data */ 214 struct vnet *fd_vnet; /* vnet fib belongs to */ 215 struct epoch_context fd_epoch_ctx; /* epoch context for deletion */ 216 struct fib_lookup_module *fd_flm;/* pointer to the lookup module */ 217 struct fib_sync_status fd_ss; /* State relevant to the rib sync */ 218 uint32_t fd_num_changes; /* number of changes since last callout */ 219 TAILQ_ENTRY(fib_data) entries; /* list of all fds in vnet */ 220 }; 221 222 static bool rebuild_fd(struct fib_data *fd, const char *reason); 223 static bool rebuild_fd_flm(struct fib_data *fd, struct fib_lookup_module *flm_new); 224 static void handle_fd_callout(void *_data); 225 static void destroy_fd_instance_epoch(epoch_context_t ctx); 226 static bool is_idx_free(struct fib_data *fd, uint32_t index); 227 static void set_algo_fixed(struct rib_head *rh); 228 static bool is_algo_fixed(struct rib_head *rh); 229 230 static uint32_t fib_ref_nhop(struct fib_data *fd, struct nhop_object *nh); 231 static void fib_unref_nhop(struct fib_data *fd, struct nhop_object *nh); 232 233 static struct fib_lookup_module *fib_check_best_algo(struct rib_head *rh, 234 struct fib_lookup_module *orig_flm); 235 static void fib_unref_algo(struct fib_lookup_module *flm); 236 static bool flm_error_check(const struct fib_lookup_module *flm, uint32_t fibnum); 237 238 struct mtx fib_mtx; 239 #define FIB_MOD_LOCK() mtx_lock(&fib_mtx) 240 #define FIB_MOD_UNLOCK() mtx_unlock(&fib_mtx) 241 #define FIB_MOD_LOCK_ASSERT() mtx_assert(&fib_mtx, MA_OWNED) 242 243 MTX_SYSINIT(fib_mtx, &fib_mtx, "algo list mutex", MTX_DEF); 244 245 /* Algorithm has to be this percent better than the current to switch */ 246 #define BEST_DIFF_PERCENT (5 * 256 / 100) 247 /* Schedule algo re-evaluation X seconds after a change */ 248 #define ALGO_EVAL_DELAY_MS 30000 249 /* Force algo re-evaluation after X changes */ 250 #define ALGO_EVAL_NUM_ROUTES 100 251 /* Try to setup algorithm X times */ 252 #define FIB_MAX_TRIES 32 253 /* Max amount of supported nexthops */ 254 #define FIB_MAX_NHOPS 262144 255 #define FIB_CALLOUT_DELAY_MS 50 256 257 258 /* Debug */ 259 static int flm_debug_level = LOG_NOTICE; 260 SYSCTL_INT(_net_route_algo, OID_AUTO, debug_level, CTLFLAG_RW | CTLFLAG_RWTUN, 261 &flm_debug_level, 0, "debuglevel"); 262 #define FLM_MAX_DEBUG_LEVEL LOG_DEBUG 263 #ifndef LOG_DEBUG2 264 #define LOG_DEBUG2 8 265 #endif 266 267 #define _PASS_MSG(_l) (flm_debug_level >= (_l)) 268 #define ALGO_PRINTF(_l, _fmt, ...) if (_PASS_MSG(_l)) { \ 269 printf("[fib_algo] %s: " _fmt "\n", __func__, ##__VA_ARGS__); \ 270 } 271 #define _ALGO_PRINTF(_fib, _fam, _aname, _gen, _func, _fmt, ...) \ 272 printf("[fib_algo] %s.%u (%s#%u) %s: " _fmt "\n",\ 273 print_family(_fam), _fib, _aname, _gen, _func, ## __VA_ARGS__) 274 #define _RH_PRINTF(_fib, _fam, _func, _fmt, ...) \ 275 printf("[fib_algo] %s.%u %s: " _fmt "\n", print_family(_fam), _fib, _func, ## __VA_ARGS__) 276 #define RH_PRINTF(_l, _rh, _fmt, ...) if (_PASS_MSG(_l)) { \ 277 _RH_PRINTF(_rh->rib_fibnum, _rh->rib_family, __func__, _fmt, ## __VA_ARGS__);\ 278 } 279 #define FD_PRINTF(_l, _fd, _fmt, ...) FD_PRINTF_##_l(_l, _fd, _fmt, ## __VA_ARGS__) 280 #define _FD_PRINTF(_l, _fd, _fmt, ...) if (_PASS_MSG(_l)) { \ 281 _ALGO_PRINTF(_fd->fd_fibnum, _fd->fd_family, _fd->fd_flm->flm_name, \ 282 _fd->fd_gen, __func__, _fmt, ## __VA_ARGS__); \ 283 } 284 #if FLM_MAX_DEBUG_LEVEL>=LOG_DEBUG2 285 #define FD_PRINTF_LOG_DEBUG2 _FD_PRINTF 286 #else 287 #define FD_PRINTF_LOG_DEBUG2(_l, _fd, _fmt, ...) 288 #endif 289 #if FLM_MAX_DEBUG_LEVEL>=LOG_DEBUG 290 #define FD_PRINTF_LOG_DEBUG _FD_PRINTF 291 #else 292 #define FD_PRINTF_LOG_DEBUG() 293 #endif 294 #if FLM_MAX_DEBUG_LEVEL>=LOG_INFO 295 #define FD_PRINTF_LOG_INFO _FD_PRINTF 296 #else 297 #define FD_PRINTF_LOG_INFO() 298 #endif 299 #define FD_PRINTF_LOG_NOTICE _FD_PRINTF 300 #define FD_PRINTF_LOG_ERR _FD_PRINTF 301 #define FD_PRINTF_LOG_WARNING _FD_PRINTF 302 303 304 /* List of all registered lookup algorithms */ 305 static TAILQ_HEAD(, fib_lookup_module) all_algo_list = TAILQ_HEAD_INITIALIZER(all_algo_list); 306 307 /* List of all fib lookup instances in the vnet */ 308 VNET_DEFINE_STATIC(TAILQ_HEAD(fib_data_head, fib_data), fib_data_list); 309 #define V_fib_data_list VNET(fib_data_list) 310 311 /* Datastructure for storing non-transient fib lookup module failures */ 312 struct fib_error { 313 int fe_family; 314 uint32_t fe_fibnum; /* failed rtable */ 315 struct fib_lookup_module *fe_flm; /* failed module */ 316 TAILQ_ENTRY(fib_error) entries;/* list of all errored entries */ 317 }; 318 VNET_DEFINE_STATIC(TAILQ_HEAD(fib_error_head, fib_error), fib_error_list); 319 #define V_fib_error_list VNET(fib_error_list) 320 321 /* Per-family array of fibnum -> {func, arg} mappings used in datapath */ 322 struct fib_dp_header { 323 struct epoch_context fdh_epoch_ctx; 324 uint32_t fdh_num_tables; 325 struct fib_dp fdh_idx[0]; 326 }; 327 328 /* 329 * Tries to add new non-transient algorithm error to the list of 330 * errors. 331 * Returns true on success. 332 */ 333 static bool 334 flm_error_add(struct fib_lookup_module *flm, uint32_t fibnum) 335 { 336 struct fib_error *fe; 337 338 fe = malloc(sizeof(struct fib_error), M_TEMP, M_NOWAIT | M_ZERO); 339 if (fe == NULL) 340 return (false); 341 fe->fe_flm = flm; 342 fe->fe_family = flm->flm_family; 343 fe->fe_fibnum = fibnum; 344 345 FIB_MOD_LOCK(); 346 /* Avoid duplicates by checking if error already exists first */ 347 if (flm_error_check(flm, fibnum)) { 348 FIB_MOD_UNLOCK(); 349 free(fe, M_TEMP); 350 return (true); 351 } 352 TAILQ_INSERT_HEAD(&V_fib_error_list, fe, entries); 353 FIB_MOD_UNLOCK(); 354 355 return (true); 356 } 357 358 /* 359 * True if non-transient error has been registered for @flm in @fibnum. 360 */ 361 static bool 362 flm_error_check(const struct fib_lookup_module *flm, uint32_t fibnum) 363 { 364 const struct fib_error *fe; 365 366 TAILQ_FOREACH(fe, &V_fib_error_list, entries) { 367 if ((fe->fe_flm == flm) && (fe->fe_fibnum == fibnum)) 368 return (true); 369 } 370 371 return (false); 372 } 373 374 /* 375 * Clear all errors of algo specified by @flm. 376 */ 377 static void 378 fib_error_clear_flm(struct fib_lookup_module *flm) 379 { 380 struct fib_error *fe, *fe_tmp; 381 382 FIB_MOD_LOCK_ASSERT(); 383 384 TAILQ_FOREACH_SAFE(fe, &V_fib_error_list, entries, fe_tmp) { 385 if (fe->fe_flm == flm) { 386 TAILQ_REMOVE(&V_fib_error_list, fe, entries); 387 free(fe, M_TEMP); 388 } 389 } 390 } 391 392 /* 393 * Clears all errors in current VNET. 394 */ 395 static void 396 fib_error_clear(void) 397 { 398 struct fib_error *fe, *fe_tmp; 399 400 FIB_MOD_LOCK_ASSERT(); 401 402 TAILQ_FOREACH_SAFE(fe, &V_fib_error_list, entries, fe_tmp) { 403 TAILQ_REMOVE(&V_fib_error_list, fe, entries); 404 free(fe, M_TEMP); 405 } 406 } 407 408 static const char * 409 print_op_result(enum flm_op_result result) 410 { 411 switch (result) { 412 case FLM_SUCCESS: 413 return "success"; 414 case FLM_REBUILD: 415 return "rebuild"; 416 case FLM_BATCH: 417 return "batch"; 418 case FLM_ERROR: 419 return "error"; 420 } 421 422 return "unknown"; 423 } 424 425 static const char * 426 print_family(int family) 427 { 428 429 if (family == AF_INET) 430 return ("inet"); 431 else if (family == AF_INET6) 432 return ("inet6"); 433 else 434 return ("unknown"); 435 } 436 437 /* 438 * Debug function used by lookup algorithms. 439 * Outputs message denoted by @fmt, prepended by "[fib_algo] inetX.Y (algo) " 440 */ 441 void 442 fib_printf(int level, struct fib_data *fd, const char *func, char *fmt, ...) 443 { 444 char buf[128]; 445 va_list ap; 446 447 if (level > flm_debug_level) 448 return; 449 450 va_start(ap, fmt); 451 vsnprintf(buf, sizeof(buf), fmt, ap); 452 va_end(ap); 453 454 _ALGO_PRINTF(fd->fd_fibnum, fd->fd_family, fd->fd_flm->flm_name, 455 fd->fd_gen, func, "%s", buf); 456 } 457 458 /* 459 * Outputs list of algorithms supported by the provided address family. 460 */ 461 static int 462 print_algos_sysctl(struct sysctl_req *req, int family) 463 { 464 struct fib_lookup_module *flm; 465 struct sbuf sbuf; 466 int error, count = 0; 467 468 error = sysctl_wire_old_buffer(req, 0); 469 if (error == 0) { 470 sbuf_new_for_sysctl(&sbuf, NULL, 512, req); 471 TAILQ_FOREACH(flm, &all_algo_list, entries) { 472 if (flm->flm_family == family) { 473 if (count++ > 0) 474 sbuf_cat(&sbuf, ", "); 475 sbuf_cat(&sbuf, flm->flm_name); 476 } 477 } 478 error = sbuf_finish(&sbuf); 479 sbuf_delete(&sbuf); 480 } 481 return (error); 482 } 483 484 #ifdef INET6 485 static int 486 print_algos_sysctl_inet6(SYSCTL_HANDLER_ARGS) 487 { 488 489 return (print_algos_sysctl(req, AF_INET6)); 490 } 491 SYSCTL_PROC(_net_route_algo_inet6, OID_AUTO, algo_list, 492 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 493 print_algos_sysctl_inet6, "A", "List of IPv6 lookup algorithms"); 494 #endif 495 496 #ifdef INET 497 static int 498 print_algos_sysctl_inet(SYSCTL_HANDLER_ARGS) 499 { 500 501 return (print_algos_sysctl(req, AF_INET)); 502 } 503 SYSCTL_PROC(_net_route_algo_inet, OID_AUTO, algo_list, 504 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 505 print_algos_sysctl_inet, "A", "List of IPv4 lookup algorithms"); 506 #endif 507 508 /* 509 * Calculate delay between repeated failures. 510 * Returns current delay in milliseconds. 511 */ 512 static uint32_t 513 callout_calc_delay_ms(struct fib_data *fd) 514 { 515 uint32_t shift; 516 517 if (fd->fd_failed_rebuilds > 10) 518 shift = 10; 519 else 520 shift = fd->fd_failed_rebuilds; 521 522 return ((1 << shift) * FIB_CALLOUT_DELAY_MS); 523 } 524 525 static void 526 schedule_callout(struct fib_data *fd, enum fib_callout_action action, int delay_ms) 527 { 528 529 FD_PRINTF(LOG_DEBUG, fd, "delay=%d action=%d", delay_ms, action); 530 fd->fd_callout_action = action; 531 callout_reset_sbt(&fd->fd_callout, SBT_1MS * delay_ms, 0, 532 handle_fd_callout, fd, 0); 533 } 534 535 static void 536 schedule_fd_rebuild(struct fib_data *fd, const char *reason) 537 { 538 539 RIB_WLOCK_ASSERT(fd->fd_rh); 540 541 if (!fd->fd_need_rebuild) { 542 fd->fd_need_rebuild = true; 543 /* Stop batch updates */ 544 fd->fd_batch = false; 545 546 /* 547 * Potentially re-schedules pending callout 548 * initiated by schedule_algo_eval. 549 */ 550 FD_PRINTF(LOG_INFO, fd, "Scheduling rebuild: %s (failures=%d)", 551 reason, fd->fd_failed_rebuilds); 552 schedule_callout(fd, FDA_REBUILD, callout_calc_delay_ms(fd)); 553 } 554 } 555 556 static void 557 sync_rib_gen(struct fib_data *fd) 558 { 559 FD_PRINTF(LOG_DEBUG, fd, "Sync gen %u -> %u", fd->fd_rh->rnh_gen, fd->fd_rh->rnh_gen_rib); 560 fd->fd_rh->rnh_gen = fd->fd_rh->rnh_gen_rib; 561 } 562 563 static int64_t 564 get_tv_diff_ms(const struct timeval *old_tv, const struct timeval *new_tv) 565 { 566 int64_t diff = 0; 567 568 diff = ((int64_t)(new_tv->tv_sec - old_tv->tv_sec)) * 1000; 569 diff += (new_tv->tv_usec - old_tv->tv_usec) / 1000; 570 571 return (diff); 572 } 573 574 static void 575 add_tv_diff_ms(struct timeval *tv, int ms) 576 { 577 tv->tv_sec += ms / 1000; 578 ms = ms % 1000; 579 if (ms * 1000 + tv->tv_usec < 1000000) 580 tv->tv_usec += ms * 1000; 581 else { 582 tv->tv_sec += 1; 583 tv->tv_usec = ms * 1000 + tv->tv_usec - 1000000; 584 } 585 } 586 587 /* 588 * Marks the time when algo state diverges from the rib state. 589 */ 590 static void 591 mark_diverge_time(struct fib_data *fd) 592 { 593 struct fib_sync_status *fd_ss = &fd->fd_ss; 594 595 getmicrouptime(&fd_ss->diverge_time); 596 fd_ss->bucket_id = 0; 597 fd_ss->bucket_changes = 0; 598 } 599 600 /* 601 * Calculates and updates the next algorithm sync time, based on the current activity. 602 * 603 * The intent is to provide reasonable balance between the update 604 * latency and efficient batching when changing large amount of routes. 605 * 606 * High-level algorithm looks the following: 607 * 1) all changes are bucketed in 50ms intervals 608 * 2) If amount of changes within the bucket is greater than the threshold, 609 * the update gets delayed, up to maximum delay threshold. 610 */ 611 static void 612 update_rebuild_delay(struct fib_data *fd, enum fib_callout_action action) 613 { 614 uint32_t bucket_id, new_delay = 0; 615 struct timeval tv; 616 617 /* Fetch all variables at once to ensure consistent reads */ 618 uint32_t bucket_time_ms = V_update_bucket_time_ms; 619 uint32_t threshold_rate = V_bucket_change_threshold_rate; 620 uint32_t max_delay_ms = V_fib_max_sync_delay_ms; 621 622 if (bucket_time_ms == 0) 623 bucket_time_ms = 50; 624 /* calculate per-bucket threshold rate */ 625 threshold_rate = threshold_rate * bucket_time_ms / 1000; 626 627 getmicrouptime(&tv); 628 629 struct fib_sync_status *fd_ss = &fd->fd_ss; 630 631 bucket_id = get_tv_diff_ms(&fd_ss->diverge_time, &tv) / bucket_time_ms; 632 633 if (fd_ss->bucket_id == bucket_id) { 634 fd_ss->bucket_changes++; 635 if (fd_ss->bucket_changes == threshold_rate) { 636 new_delay = (bucket_id + 2) * bucket_time_ms; 637 if (new_delay <= max_delay_ms) { 638 FD_PRINTF(LOG_DEBUG, fd, 639 "hit threshold of %u routes, delay update," 640 "bucket: %u, total delay: %u", 641 threshold_rate, bucket_id + 1, new_delay); 642 } else { 643 new_delay = 0; 644 FD_PRINTF(LOG_DEBUG, fd, 645 "maximum sync delay (%u ms) reached", max_delay_ms); 646 } 647 } else if ((bucket_id == 0) && (fd_ss->bucket_changes == 1)) 648 new_delay = bucket_time_ms; 649 } else { 650 fd_ss->bucket_id = bucket_id; 651 fd_ss->bucket_changes = 1; 652 } 653 654 if (new_delay > 0) { 655 /* Calculated time has been updated */ 656 struct timeval new_tv = fd_ss->diverge_time; 657 add_tv_diff_ms(&new_tv, new_delay); 658 659 int32_t delay_ms = get_tv_diff_ms(&tv, &new_tv); 660 schedule_callout(fd, action, delay_ms); 661 } 662 } 663 664 static void 665 update_algo_state(struct fib_data *fd) 666 { 667 668 RIB_WLOCK_ASSERT(fd->fd_rh); 669 670 if (fd->fd_batch || fd->fd_need_rebuild) { 671 enum fib_callout_action action = fd->fd_need_rebuild ? FDA_REBUILD : FDA_BATCH; 672 update_rebuild_delay(fd, action); 673 return; 674 } 675 676 if (fd->fd_num_changes++ == 0) { 677 /* Start callout to consider switch */ 678 if (!callout_pending(&fd->fd_callout)) 679 schedule_callout(fd, FDA_EVAL, ALGO_EVAL_DELAY_MS); 680 } else if (fd->fd_num_changes == ALGO_EVAL_NUM_ROUTES) { 681 /* Reset callout to exec immediately */ 682 if (fd->fd_callout_action == FDA_EVAL) 683 schedule_callout(fd, FDA_EVAL, 1); 684 } 685 } 686 687 static bool 688 need_immediate_sync(struct fib_data *fd, struct rib_cmd_info *rc) 689 { 690 struct nhop_object *nh; 691 692 /* Sync addition/removal of interface routes */ 693 switch (rc->rc_cmd) { 694 case RTM_ADD: 695 nh = rc->rc_nh_new; 696 if (!NH_IS_NHGRP(nh)) { 697 if (!(nh->nh_flags & NHF_GATEWAY)) 698 return (true); 699 if (nhop_get_rtflags(nh) & RTF_STATIC) 700 return (true); 701 } 702 break; 703 case RTM_DELETE: 704 nh = rc->rc_nh_old; 705 if (!NH_IS_NHGRP(nh)) { 706 if (!(nh->nh_flags & NHF_GATEWAY)) 707 return (true); 708 if (nhop_get_rtflags(nh) & RTF_STATIC) 709 return (true); 710 } 711 break; 712 } 713 714 return (false); 715 } 716 717 static bool 718 apply_rtable_changes(struct fib_data *fd) 719 { 720 enum flm_op_result result; 721 struct fib_change_queue *q = &fd->fd_ss.fd_change_queue; 722 723 result = fd->fd_flm->flm_change_rib_items_cb(fd->fd_rh, q, fd->fd_algo_data); 724 725 if (result == FLM_SUCCESS) { 726 sync_rib_gen(fd); 727 for (int i = 0; i < q->count; i++) 728 if (q->entries[i].nh_old) 729 fib_unref_nhop(fd, q->entries[i].nh_old); 730 q->count = 0; 731 } 732 fd->fd_batch = false; 733 734 return (result == FLM_SUCCESS); 735 } 736 737 static bool 738 fill_change_entry(struct fib_data *fd, struct fib_change_entry *ce, struct rib_cmd_info *rc) 739 { 740 int plen = 0; 741 742 switch (fd->fd_family) { 743 #ifdef INET 744 case AF_INET: 745 rt_get_inet_prefix_plen(rc->rc_rt, &ce->addr4, &plen, &ce->scopeid); 746 break; 747 #endif 748 #ifdef INET6 749 case AF_INET6: 750 rt_get_inet6_prefix_plen(rc->rc_rt, &ce->addr6, &plen, &ce->scopeid); 751 break; 752 #endif 753 } 754 755 ce->plen = plen; 756 ce->nh_old = rc->rc_nh_old; 757 ce->nh_new = rc->rc_nh_new; 758 if (ce->nh_new != NULL) { 759 if (fib_ref_nhop(fd, ce->nh_new) == 0) 760 return (false); 761 } 762 763 return (true); 764 } 765 766 static bool 767 queue_rtable_change(struct fib_data *fd, struct rib_cmd_info *rc) 768 { 769 struct fib_change_queue *q = &fd->fd_ss.fd_change_queue; 770 771 if (q->count >= q->size) { 772 uint32_t q_size; 773 774 if (q->size == 0) 775 q_size = 256; /* ~18k memory */ 776 else 777 q_size = q->size * 2; 778 779 size_t size = q_size * sizeof(struct fib_change_entry); 780 void *a = realloc(q->entries, size, M_TEMP, M_NOWAIT | M_ZERO); 781 if (a == NULL) { 782 FD_PRINTF(LOG_INFO, fd, "Unable to realloc queue for %u elements", 783 q_size); 784 return (false); 785 } 786 q->entries = a; 787 q->size = q_size; 788 } 789 790 return (fill_change_entry(fd, &q->entries[q->count++], rc)); 791 } 792 793 /* 794 * Rib subscription handler. Checks if the algorithm is ready to 795 * receive updates, handles nexthop refcounting and passes change 796 * data to the algorithm callback. 797 */ 798 static void 799 handle_rtable_change_cb(struct rib_head *rnh, struct rib_cmd_info *rc, 800 void *_data) 801 { 802 struct fib_data *fd = (struct fib_data *)_data; 803 enum flm_op_result result; 804 805 RIB_WLOCK_ASSERT(rnh); 806 807 /* 808 * There is a small gap between subscribing for route changes 809 * and initiating rtable dump. Avoid receiving route changes 810 * prior to finishing rtable dump by checking `init_done`. 811 */ 812 if (!fd->init_done) 813 return; 814 815 bool immediate_sync = need_immediate_sync(fd, rc); 816 817 /* Consider scheduling algorithm re-evaluation */ 818 update_algo_state(fd); 819 820 /* 821 * If algo requested rebuild, stop sending updates by default. 822 * This simplifies nexthop refcount handling logic. 823 */ 824 if (fd->fd_need_rebuild) { 825 if (immediate_sync) 826 rebuild_fd(fd, "rtable change type enforced sync"); 827 return; 828 } 829 830 /* 831 * Algo requested updates to be delivered in batches. 832 * Add the current change to the queue and return. 833 */ 834 if (fd->fd_batch) { 835 if (immediate_sync) { 836 if (!queue_rtable_change(fd, rc) || !apply_rtable_changes(fd)) 837 rebuild_fd(fd, "batch sync failed"); 838 } else { 839 if (!queue_rtable_change(fd, rc)) 840 schedule_fd_rebuild(fd, "batch queue failed"); 841 } 842 return; 843 } 844 845 /* 846 * Maintain guarantee that every nexthop returned by the dataplane 847 * lookup has > 0 refcount, so can be safely referenced within current 848 * epoch. 849 */ 850 if (rc->rc_nh_new != NULL) { 851 if (fib_ref_nhop(fd, rc->rc_nh_new) == 0) { 852 if (immediate_sync) 853 rebuild_fd(fd, "ran out of nhop indexes"); 854 else 855 schedule_fd_rebuild(fd, "ran out of nhop indexes"); 856 return; 857 } 858 } 859 860 result = fd->fd_flm->flm_change_rib_item_cb(rnh, rc, fd->fd_algo_data); 861 862 switch (result) { 863 case FLM_SUCCESS: 864 sync_rib_gen(fd); 865 /* Unref old nexthop on success */ 866 if (rc->rc_nh_old != NULL) 867 fib_unref_nhop(fd, rc->rc_nh_old); 868 break; 869 case FLM_BATCH: 870 871 /* 872 * Algo asks to batch the changes. 873 */ 874 if (queue_rtable_change(fd, rc)) { 875 if (!immediate_sync) { 876 fd->fd_batch = true; 877 mark_diverge_time(fd); 878 update_rebuild_delay(fd, FDA_BATCH); 879 break; 880 } 881 if (apply_rtable_changes(fd)) 882 break; 883 } 884 FD_PRINTF(LOG_ERR, fd, "batched sync failed, force the rebuild"); 885 886 case FLM_REBUILD: 887 888 /* 889 * Algo is not able to apply the update. 890 * Schedule algo rebuild. 891 */ 892 if (!immediate_sync) { 893 mark_diverge_time(fd); 894 schedule_fd_rebuild(fd, "algo requested rebuild"); 895 break; 896 } 897 898 FD_PRINTF(LOG_INFO, fd, "running sync rebuild"); 899 rebuild_fd(fd, "rtable change type enforced sync"); 900 break; 901 case FLM_ERROR: 902 903 /* 904 * Algo reported a non-recoverable error. 905 * Record the error and schedule rebuild, which will 906 * trigger best algo selection. 907 */ 908 FD_PRINTF(LOG_ERR, fd, "algo reported non-recoverable error"); 909 if (!flm_error_add(fd->fd_flm, fd->fd_fibnum)) 910 FD_PRINTF(LOG_ERR, fd, "failed to ban algo"); 911 schedule_fd_rebuild(fd, "algo reported non-recoverable error"); 912 } 913 } 914 915 static void 916 estimate_nhop_scale(const struct fib_data *old_fd, struct fib_data *fd) 917 { 918 uint32_t base = 0; 919 920 if (old_fd == NULL) { 921 fd->fd_num_af = 1; 922 fd->fd_af[0].nhaf_family = fd->fd_family; 923 // TODO: read from rtable 924 fd->fd_af[0].nhaf_count = 16; 925 } else { 926 fd->fd_num_af = old_fd->fd_num_af; 927 memcpy(fd->fd_af, old_fd->fd_af, sizeof(fd->fd_af)); 928 929 for (int i = 0; i < fd->fd_num_af; i++) { 930 struct nhop_af_table *nt; 931 932 nt = &fd->fd_af[i]; 933 nt->nhaf_hit = false; 934 if (!old_fd->fd_af[i].nhaf_hit) 935 continue; 936 if (nt->nhaf_count == 0) 937 /* half of the main family */ 938 nt->nhaf_count = 8; 939 else if (nt->nhaf_count < FIB_MAX_NHOPS) 940 nt->nhaf_count *= 2; 941 } 942 } 943 944 for (int i = 0; i < fd->fd_num_af; i++) { 945 fd->fd_af[i].nhaf_base = base; 946 base += fd->fd_af[i].nhaf_count; 947 } 948 fd->number_nhops = base; 949 } 950 951 struct walk_cbdata { 952 struct fib_data *fd; 953 flm_dump_t *func; 954 enum flm_op_result result; 955 }; 956 957 /* 958 * Handler called after all rtenties have been dumped. 959 * Performs post-dump framework checks and calls 960 * algo:flm_dump_end_cb(). 961 * 962 * Updates walk_cbdata result. 963 */ 964 static void 965 sync_algo_end_cb(struct rib_head *rnh, enum rib_walk_hook stage, void *_data) 966 { 967 struct walk_cbdata *w = (struct walk_cbdata *)_data; 968 struct fib_data *fd = w->fd; 969 970 RIB_WLOCK_ASSERT(w->fd->fd_rh); 971 972 if (rnh->rib_dying) { 973 w->result = FLM_ERROR; 974 return; 975 } 976 977 if (fd->hit_nhops) { 978 FD_PRINTF(LOG_INFO, fd, "ran out of nexthops at %u nhops", 979 fd->nh_ref_table->count); 980 if (w->result == FLM_SUCCESS) 981 w->result = FLM_REBUILD; 982 return; 983 } 984 985 if (stage != RIB_WALK_HOOK_POST || w->result != FLM_SUCCESS) 986 return; 987 988 /* Post-dump hook, dump successful */ 989 w->result = fd->fd_flm->flm_dump_end_cb(fd->fd_algo_data, &fd->fd_dp); 990 991 if (w->result == FLM_SUCCESS) { 992 /* Mark init as done to allow routing updates */ 993 fd->init_done = true; 994 } 995 } 996 997 /* 998 * Callback for each entry in rib. 999 * Calls algo:flm_dump_rib_item_cb func as a part of initial 1000 * route table synchronisation. 1001 */ 1002 static int 1003 sync_algo_cb(struct rtentry *rt, void *_data) 1004 { 1005 struct walk_cbdata *w = (struct walk_cbdata *)_data; 1006 1007 RIB_WLOCK_ASSERT(w->fd->fd_rh); 1008 1009 if (w->result == FLM_SUCCESS && w->func) { 1010 1011 /* 1012 * Reference nexthops to maintain guarantee that 1013 * each nexthop returned by datapath has > 0 references 1014 * and can be safely referenced within current epoch. 1015 */ 1016 struct nhop_object *nh = rt_get_raw_nhop(rt); 1017 if (fib_ref_nhop(w->fd, nh) != 0) 1018 w->result = w->func(rt, w->fd->fd_algo_data); 1019 else 1020 w->result = FLM_REBUILD; 1021 } 1022 1023 return (0); 1024 } 1025 1026 /* 1027 * Dump all routing table state to the algo instance. 1028 */ 1029 static enum flm_op_result 1030 sync_algo(struct fib_data *fd) 1031 { 1032 struct walk_cbdata w = { 1033 .fd = fd, 1034 .func = fd->fd_flm->flm_dump_rib_item_cb, 1035 .result = FLM_SUCCESS, 1036 }; 1037 1038 rib_walk_ext_locked(fd->fd_rh, sync_algo_cb, sync_algo_end_cb, &w); 1039 1040 FD_PRINTF(LOG_INFO, fd, 1041 "initial dump completed (rtable version: %d), result: %s", 1042 fd->fd_rh->rnh_gen, print_op_result(w.result)); 1043 1044 return (w.result); 1045 } 1046 1047 /* 1048 * Schedules epoch-backed @fd instance deletion. 1049 * * Unlinks @fd from the list of active algo instances. 1050 * * Removes rib subscription. 1051 * * Stops callout. 1052 * * Schedules actual deletion. 1053 * 1054 * Assume @fd is already unlinked from the datapath. 1055 */ 1056 static int 1057 schedule_destroy_fd_instance(struct fib_data *fd, bool in_callout) 1058 { 1059 bool is_dead; 1060 1061 NET_EPOCH_ASSERT(); 1062 RIB_WLOCK_ASSERT(fd->fd_rh); 1063 1064 FIB_MOD_LOCK(); 1065 is_dead = fd->fd_dead; 1066 if (!is_dead) 1067 fd->fd_dead = true; 1068 if (fd->fd_linked) { 1069 TAILQ_REMOVE(&V_fib_data_list, fd, entries); 1070 fd->fd_linked = false; 1071 } 1072 FIB_MOD_UNLOCK(); 1073 if (is_dead) 1074 return (0); 1075 1076 FD_PRINTF(LOG_INFO, fd, "DETACH"); 1077 1078 if (fd->fd_rs != NULL) 1079 rib_unsubscribe_locked(fd->fd_rs); 1080 1081 /* 1082 * After rib_unsubscribe() no _new_ handle_rtable_change_cb() calls 1083 * will be executed, hence no _new_ callout schedules will happen. 1084 */ 1085 callout_stop(&fd->fd_callout); 1086 1087 fib_epoch_call(destroy_fd_instance_epoch, &fd->fd_epoch_ctx); 1088 1089 return (0); 1090 } 1091 1092 /* 1093 * Wipe all fd instances from the list matching rib specified by @rh. 1094 * If @keep_first is set, remove all but the first record. 1095 */ 1096 static void 1097 fib_cleanup_algo(struct rib_head *rh, bool keep_first, bool in_callout) 1098 { 1099 struct fib_data_head tmp_head = TAILQ_HEAD_INITIALIZER(tmp_head); 1100 struct fib_data *fd, *fd_tmp; 1101 struct epoch_tracker et; 1102 1103 FIB_MOD_LOCK(); 1104 TAILQ_FOREACH_SAFE(fd, &V_fib_data_list, entries, fd_tmp) { 1105 if (fd->fd_rh == rh) { 1106 if (keep_first) { 1107 keep_first = false; 1108 continue; 1109 } 1110 TAILQ_REMOVE(&V_fib_data_list, fd, entries); 1111 fd->fd_linked = false; 1112 TAILQ_INSERT_TAIL(&tmp_head, fd, entries); 1113 } 1114 } 1115 FIB_MOD_UNLOCK(); 1116 1117 /* Pass 2: remove each entry */ 1118 NET_EPOCH_ENTER(et); 1119 TAILQ_FOREACH_SAFE(fd, &tmp_head, entries, fd_tmp) { 1120 if (!in_callout) 1121 RIB_WLOCK(fd->fd_rh); 1122 schedule_destroy_fd_instance(fd, in_callout); 1123 if (!in_callout) 1124 RIB_WUNLOCK(fd->fd_rh); 1125 } 1126 NET_EPOCH_EXIT(et); 1127 } 1128 1129 void 1130 fib_destroy_rib(struct rib_head *rh) 1131 { 1132 1133 /* 1134 * rnh has `is_dying` flag set, so setup of new fd's will fail at 1135 * sync_algo() stage, preventing new entries to be added to the list 1136 * of active algos. Remove all existing entries for the particular rib. 1137 */ 1138 fib_cleanup_algo(rh, false, false); 1139 } 1140 1141 /* 1142 * Finalises fd destruction by freeing all fd resources. 1143 */ 1144 static void 1145 destroy_fd_instance(struct fib_data *fd) 1146 { 1147 1148 FD_PRINTF(LOG_INFO, fd, "destroy fd %p", fd); 1149 1150 /* Call destroy callback first */ 1151 if (fd->fd_algo_data != NULL) 1152 fd->fd_flm->flm_destroy_cb(fd->fd_algo_data); 1153 1154 /* Nhop table */ 1155 if ((fd->nh_idx != NULL) && (fd->nh_ref_table != NULL)) { 1156 for (int i = 0; i < fd->number_nhops; i++) { 1157 if (!is_idx_free(fd, i)) { 1158 FD_PRINTF(LOG_DEBUG2, fd, " FREE nhop %d %p", 1159 i, fd->nh_idx[i]); 1160 nhop_free_any(fd->nh_idx[i]); 1161 } 1162 } 1163 free(fd->nh_idx, M_RTABLE); 1164 } 1165 if (fd->nh_ref_table != NULL) 1166 free(fd->nh_ref_table, M_RTABLE); 1167 1168 if (fd->fd_ss.fd_change_queue.entries != NULL) 1169 free(fd->fd_ss.fd_change_queue.entries, M_TEMP); 1170 1171 fib_unref_algo(fd->fd_flm); 1172 1173 free(fd, M_RTABLE); 1174 } 1175 1176 /* 1177 * Epoch callback indicating fd is safe to destroy 1178 */ 1179 static void 1180 destroy_fd_instance_epoch(epoch_context_t ctx) 1181 { 1182 struct fib_data *fd; 1183 1184 fd = __containerof(ctx, struct fib_data, fd_epoch_ctx); 1185 1186 CURVNET_SET(fd->fd_vnet); 1187 destroy_fd_instance(fd); 1188 CURVNET_RESTORE(); 1189 } 1190 1191 /* 1192 * Tries to setup fd instance. 1193 * - Allocates fd/nhop table 1194 * - Runs algo:flm_init_cb algo init 1195 * - Subscribes fd to the rib 1196 * - Runs rtable dump 1197 * - Adds instance to the list of active instances. 1198 * 1199 * Returns: operation result. Fills in @pfd with resulting fd on success. 1200 * 1201 */ 1202 static enum flm_op_result 1203 try_setup_fd_instance(struct fib_lookup_module *flm, struct rib_head *rh, 1204 struct fib_data *old_fd, struct fib_data **pfd) 1205 { 1206 struct fib_data *fd; 1207 size_t size; 1208 enum flm_op_result result; 1209 1210 /* Allocate */ 1211 fd = malloc(sizeof(struct fib_data), M_RTABLE, M_NOWAIT | M_ZERO); 1212 if (fd == NULL) { 1213 *pfd = NULL; 1214 RH_PRINTF(LOG_INFO, rh, "Unable to allocate fib_data structure"); 1215 return (FLM_REBUILD); 1216 } 1217 *pfd = fd; 1218 1219 fd->fd_rh = rh; 1220 fd->fd_family = rh->rib_family; 1221 fd->fd_fibnum = rh->rib_fibnum; 1222 callout_init_rm(&fd->fd_callout, &rh->rib_lock, 0); 1223 fd->fd_vnet = curvnet; 1224 fd->fd_flm = flm; 1225 1226 estimate_nhop_scale(old_fd, fd); 1227 1228 FIB_MOD_LOCK(); 1229 flm->flm_refcount++; 1230 fd->fd_gen = ++fib_gen; 1231 FIB_MOD_UNLOCK(); 1232 1233 FD_PRINTF(LOG_DEBUG, fd, "allocated fd %p", fd); 1234 1235 /* Allocate nhidx -> nhop_ptr table */ 1236 size = fd->number_nhops * sizeof(void *); 1237 fd->nh_idx = malloc(size, M_RTABLE, M_NOWAIT | M_ZERO); 1238 if (fd->nh_idx == NULL) { 1239 FD_PRINTF(LOG_INFO, fd, "Unable to allocate nhop table idx (sz:%zu)", size); 1240 return (FLM_REBUILD); 1241 } 1242 1243 /* Allocate nhop index refcount table */ 1244 size = sizeof(struct nhop_ref_table); 1245 size += fd->number_nhops * sizeof(uint32_t); 1246 fd->nh_ref_table = malloc(size, M_RTABLE, M_NOWAIT | M_ZERO); 1247 if (fd->nh_ref_table == NULL) { 1248 FD_PRINTF(LOG_INFO, fd, "Unable to allocate nhop refcount table (sz:%zu)", size); 1249 return (FLM_REBUILD); 1250 } 1251 FD_PRINTF(LOG_DEBUG, fd, "Allocated %u nhop indexes", fd->number_nhops); 1252 1253 /* Okay, we're ready for algo init */ 1254 void *old_algo_data = (old_fd != NULL) ? old_fd->fd_algo_data : NULL; 1255 result = flm->flm_init_cb(fd->fd_fibnum, fd, old_algo_data, &fd->fd_algo_data); 1256 if (result != FLM_SUCCESS) { 1257 FD_PRINTF(LOG_INFO, fd, "%s algo init failed", flm->flm_name); 1258 return (result); 1259 } 1260 1261 /* Try to subscribe */ 1262 if (flm->flm_change_rib_item_cb != NULL) { 1263 fd->fd_rs = rib_subscribe_locked(fd->fd_rh, 1264 handle_rtable_change_cb, fd, RIB_NOTIFY_IMMEDIATE); 1265 if (fd->fd_rs == NULL) { 1266 FD_PRINTF(LOG_INFO, fd, "failed to subscribe to the rib changes"); 1267 return (FLM_REBUILD); 1268 } 1269 } 1270 1271 /* Dump */ 1272 result = sync_algo(fd); 1273 if (result != FLM_SUCCESS) { 1274 FD_PRINTF(LOG_INFO, fd, "rib sync failed"); 1275 return (result); 1276 } 1277 FD_PRINTF(LOG_INFO, fd, "DUMP completed successfully."); 1278 1279 FIB_MOD_LOCK(); 1280 /* 1281 * Insert fd in the beginning of a list, to maintain invariant 1282 * that first matching entry for the AF/fib is always the active 1283 * one. 1284 */ 1285 TAILQ_INSERT_HEAD(&V_fib_data_list, fd, entries); 1286 fd->fd_linked = true; 1287 FIB_MOD_UNLOCK(); 1288 1289 return (FLM_SUCCESS); 1290 } 1291 1292 /* 1293 * Sets up algo @flm for table @rh and links it to the datapath. 1294 * 1295 */ 1296 static enum flm_op_result 1297 setup_fd_instance(struct fib_lookup_module *flm, struct rib_head *rh, 1298 struct fib_data *orig_fd, struct fib_data **pfd, bool attach) 1299 { 1300 struct fib_data *prev_fd, *new_fd; 1301 enum flm_op_result result; 1302 1303 NET_EPOCH_ASSERT(); 1304 RIB_WLOCK_ASSERT(rh); 1305 1306 prev_fd = orig_fd; 1307 new_fd = NULL; 1308 for (int i = 0; i < FIB_MAX_TRIES; i++) { 1309 result = try_setup_fd_instance(flm, rh, prev_fd, &new_fd); 1310 1311 if ((result == FLM_SUCCESS) && attach) { 1312 if (fib_set_datapath_ptr(new_fd, &new_fd->fd_dp)) 1313 sync_rib_gen(new_fd); 1314 else 1315 result = FLM_REBUILD; 1316 } 1317 1318 if ((prev_fd != NULL) && (prev_fd != orig_fd)) { 1319 schedule_destroy_fd_instance(prev_fd, false); 1320 prev_fd = NULL; 1321 } 1322 1323 RH_PRINTF(LOG_INFO, rh, "try %d: fib algo result: %s", i, 1324 print_op_result(result)); 1325 1326 if (result == FLM_REBUILD) { 1327 prev_fd = new_fd; 1328 new_fd = NULL; 1329 continue; 1330 } 1331 1332 break; 1333 } 1334 1335 if (result != FLM_SUCCESS) { 1336 RH_PRINTF(LOG_WARNING, rh, 1337 "%s algo instance setup failed, failures=%d", flm->flm_name, 1338 orig_fd ? orig_fd->fd_failed_rebuilds + 1 : 0); 1339 /* update failure count */ 1340 FIB_MOD_LOCK(); 1341 if (orig_fd != NULL) 1342 orig_fd->fd_failed_rebuilds++; 1343 FIB_MOD_UNLOCK(); 1344 1345 /* Ban algo on non-recoverable error */ 1346 if (result == FLM_ERROR) 1347 flm_error_add(flm, rh->rib_fibnum); 1348 1349 if ((prev_fd != NULL) && (prev_fd != orig_fd)) 1350 schedule_destroy_fd_instance(prev_fd, false); 1351 if (new_fd != NULL) { 1352 schedule_destroy_fd_instance(new_fd, false); 1353 new_fd = NULL; 1354 } 1355 } 1356 1357 *pfd = new_fd; 1358 return (result); 1359 } 1360 1361 /* 1362 * Tries to sync algo with the current rtable state, either 1363 * by executing batch update or rebuilding. 1364 * Returns true on success. 1365 */ 1366 static bool 1367 execute_callout_action(struct fib_data *fd) 1368 { 1369 enum fib_callout_action action = fd->fd_callout_action; 1370 struct fib_lookup_module *flm_new = NULL; 1371 bool result = true; 1372 1373 NET_EPOCH_ASSERT(); 1374 RIB_WLOCK_ASSERT(fd->fd_rh); 1375 1376 fd->fd_need_rebuild = false; 1377 fd->fd_batch = false; 1378 fd->fd_num_changes = 0; 1379 1380 /* First, check if we're still OK to use this algo */ 1381 if (!is_algo_fixed(fd->fd_rh)) 1382 flm_new = fib_check_best_algo(fd->fd_rh, fd->fd_flm); 1383 if (flm_new != NULL) 1384 action = FDA_REBUILD; 1385 1386 if (action == FDA_BATCH) { 1387 /* Try to sync */ 1388 if (!apply_rtable_changes(fd)) 1389 action = FDA_REBUILD; 1390 } 1391 1392 if (action == FDA_REBUILD) 1393 result = rebuild_fd_flm(fd, flm_new != NULL ? flm_new : fd->fd_flm); 1394 if (flm_new != NULL) 1395 fib_unref_algo(flm_new); 1396 1397 return (result); 1398 } 1399 1400 /* 1401 * Callout for all scheduled fd-related work. 1402 * - Checks if the current algo is still the best algo 1403 * - Synchronises algo instance to the rtable (batch usecase) 1404 * - Creates a new instance of an algo for af/fib if desired. 1405 */ 1406 static void 1407 handle_fd_callout(void *_data) 1408 { 1409 struct fib_data *fd = (struct fib_data *)_data; 1410 struct epoch_tracker et; 1411 1412 FD_PRINTF(LOG_INFO, fd, "running callout type=%d", fd->fd_callout_action); 1413 1414 NET_EPOCH_ENTER(et); 1415 CURVNET_SET(fd->fd_vnet); 1416 execute_callout_action(fd); 1417 CURVNET_RESTORE(); 1418 NET_EPOCH_EXIT(et); 1419 } 1420 1421 /* 1422 * Tries to create new algo instance based on @fd data. 1423 * Returns true on success. 1424 */ 1425 static bool 1426 rebuild_fd_flm(struct fib_data *fd, struct fib_lookup_module *flm_new) 1427 { 1428 struct fib_data *fd_new, *fd_tmp = NULL; 1429 bool result; 1430 1431 if (flm_new == fd->fd_flm) 1432 fd_tmp = fd; 1433 else 1434 FD_PRINTF(LOG_INFO, fd, "switching algo to %s", flm_new->flm_name); 1435 1436 result = setup_fd_instance(flm_new, fd->fd_rh, fd_tmp, &fd_new, true); 1437 if (result != FLM_SUCCESS) { 1438 FD_PRINTF(LOG_NOTICE, fd, "table rebuild failed"); 1439 return (false); 1440 } 1441 FD_PRINTF(LOG_INFO, fd_new, "switched to new instance"); 1442 1443 /* Remove old instance */ 1444 schedule_destroy_fd_instance(fd, true); 1445 1446 return (true); 1447 } 1448 1449 static bool 1450 rebuild_fd(struct fib_data *fd, const char *reason) 1451 { 1452 struct fib_lookup_module *flm_new = NULL; 1453 bool result; 1454 1455 if (!is_algo_fixed(fd->fd_rh)) 1456 flm_new = fib_check_best_algo(fd->fd_rh, fd->fd_flm); 1457 1458 FD_PRINTF(LOG_INFO, fd, "running sync rebuild: %s", reason); 1459 result = rebuild_fd_flm(fd, flm_new != NULL ? flm_new : fd->fd_flm); 1460 if (flm_new != NULL) 1461 fib_unref_algo(flm_new); 1462 1463 if (!result) { 1464 FD_PRINTF(LOG_ERR, fd, "sync rebuild failed"); 1465 schedule_fd_rebuild(fd, "sync rebuild failed"); 1466 } 1467 1468 return (result); 1469 } 1470 1471 /* 1472 * Finds algo by name/family. 1473 * Returns referenced algo or NULL. 1474 */ 1475 static struct fib_lookup_module * 1476 fib_find_algo(const char *algo_name, int family) 1477 { 1478 struct fib_lookup_module *flm; 1479 1480 FIB_MOD_LOCK(); 1481 TAILQ_FOREACH(flm, &all_algo_list, entries) { 1482 if ((strcmp(flm->flm_name, algo_name) == 0) && 1483 (family == flm->flm_family)) { 1484 flm->flm_refcount++; 1485 FIB_MOD_UNLOCK(); 1486 return (flm); 1487 } 1488 } 1489 FIB_MOD_UNLOCK(); 1490 1491 return (NULL); 1492 } 1493 1494 static void 1495 fib_unref_algo(struct fib_lookup_module *flm) 1496 { 1497 1498 FIB_MOD_LOCK(); 1499 flm->flm_refcount--; 1500 FIB_MOD_UNLOCK(); 1501 } 1502 1503 static int 1504 set_fib_algo(uint32_t fibnum, int family, struct sysctl_oid *oidp, struct sysctl_req *req) 1505 { 1506 struct fib_lookup_module *flm = NULL; 1507 struct fib_data *fd = NULL; 1508 char old_algo_name[32], algo_name[32]; 1509 struct rib_head *rh = NULL; 1510 enum flm_op_result result; 1511 struct epoch_tracker et; 1512 int error; 1513 1514 /* Fetch current algo/rib for af/family */ 1515 FIB_MOD_LOCK(); 1516 TAILQ_FOREACH(fd, &V_fib_data_list, entries) { 1517 if ((fd->fd_family == family) && (fd->fd_fibnum == fibnum)) 1518 break; 1519 } 1520 if (fd == NULL) { 1521 FIB_MOD_UNLOCK(); 1522 return (ENOENT); 1523 } 1524 rh = fd->fd_rh; 1525 strlcpy(old_algo_name, fd->fd_flm->flm_name, 1526 sizeof(old_algo_name)); 1527 FIB_MOD_UNLOCK(); 1528 1529 strlcpy(algo_name, old_algo_name, sizeof(algo_name)); 1530 error = sysctl_handle_string(oidp, algo_name, sizeof(algo_name), req); 1531 if (error != 0 || req->newptr == NULL) 1532 return (error); 1533 1534 if (strcmp(algo_name, old_algo_name) == 0) 1535 return (0); 1536 1537 /* New algorithm name is different */ 1538 flm = fib_find_algo(algo_name, family); 1539 if (flm == NULL) { 1540 RH_PRINTF(LOG_INFO, rh, "unable to find algo %s", algo_name); 1541 return (ESRCH); 1542 } 1543 1544 fd = NULL; 1545 NET_EPOCH_ENTER(et); 1546 RIB_WLOCK(rh); 1547 result = setup_fd_instance(flm, rh, NULL, &fd, true); 1548 RIB_WUNLOCK(rh); 1549 NET_EPOCH_EXIT(et); 1550 fib_unref_algo(flm); 1551 if (result != FLM_SUCCESS) 1552 return (EINVAL); 1553 1554 /* Disable automated jumping between algos */ 1555 FIB_MOD_LOCK(); 1556 set_algo_fixed(rh); 1557 FIB_MOD_UNLOCK(); 1558 /* Remove old instance(s) */ 1559 fib_cleanup_algo(rh, true, false); 1560 1561 /* Drain cb so user can unload the module after userret if so desired */ 1562 NET_EPOCH_DRAIN_CALLBACKS(); 1563 1564 return (0); 1565 } 1566 1567 #ifdef INET 1568 static int 1569 set_algo_inet_sysctl_handler(SYSCTL_HANDLER_ARGS) 1570 { 1571 1572 return (set_fib_algo(curthread->td_proc->p_fibnum, AF_INET, oidp, req)); 1573 } 1574 SYSCTL_PROC(_net_route_algo_inet, OID_AUTO, algo, 1575 CTLFLAG_VNET | CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0, 1576 set_algo_inet_sysctl_handler, "A", "Set IPv4 lookup algo"); 1577 #endif 1578 1579 #ifdef INET6 1580 static int 1581 set_algo_inet6_sysctl_handler(SYSCTL_HANDLER_ARGS) 1582 { 1583 1584 return (set_fib_algo(curthread->td_proc->p_fibnum, AF_INET6, oidp, req)); 1585 } 1586 SYSCTL_PROC(_net_route_algo_inet6, OID_AUTO, algo, 1587 CTLFLAG_VNET | CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0, 1588 set_algo_inet6_sysctl_handler, "A", "Set IPv6 lookup algo"); 1589 #endif 1590 1591 static struct nhop_object * 1592 dummy_lookup(void *algo_data, const struct flm_lookup_key key, uint32_t scopeid) 1593 { 1594 return (NULL); 1595 } 1596 1597 static void 1598 destroy_fdh_epoch(epoch_context_t ctx) 1599 { 1600 struct fib_dp_header *fdh; 1601 1602 fdh = __containerof(ctx, struct fib_dp_header, fdh_epoch_ctx); 1603 free(fdh, M_RTABLE); 1604 } 1605 1606 static struct fib_dp_header * 1607 alloc_fib_dp_array(uint32_t num_tables, bool waitok) 1608 { 1609 size_t sz; 1610 struct fib_dp_header *fdh; 1611 1612 sz = sizeof(struct fib_dp_header); 1613 sz += sizeof(struct fib_dp) * num_tables; 1614 fdh = malloc(sz, M_RTABLE, (waitok ? M_WAITOK : M_NOWAIT) | M_ZERO); 1615 if (fdh != NULL) { 1616 fdh->fdh_num_tables = num_tables; 1617 /* 1618 * Set dummy lookup function ptr always returning NULL, so 1619 * we can delay algo init. 1620 */ 1621 for (uint32_t i = 0; i < num_tables; i++) 1622 fdh->fdh_idx[i].f = dummy_lookup; 1623 } 1624 return (fdh); 1625 } 1626 1627 static struct fib_dp_header * 1628 get_fib_dp_header(struct fib_dp *dp) 1629 { 1630 1631 return (__containerof((void *)dp, struct fib_dp_header, fdh_idx)); 1632 } 1633 1634 /* 1635 * Replace per-family index pool @pdp with a new one which 1636 * contains updated callback/algo data from @fd. 1637 * Returns true on success. 1638 */ 1639 static bool 1640 replace_rtables_family(struct fib_dp **pdp, struct fib_data *fd, struct fib_dp *dp) 1641 { 1642 struct fib_dp_header *new_fdh, *old_fdh; 1643 1644 NET_EPOCH_ASSERT(); 1645 1646 FD_PRINTF(LOG_DEBUG, fd, "[vnet %p] replace with f:%p arg:%p", 1647 curvnet, dp->f, dp->arg); 1648 1649 FIB_MOD_LOCK(); 1650 old_fdh = get_fib_dp_header(*pdp); 1651 1652 if (old_fdh->fdh_idx[fd->fd_fibnum].f == dp->f) { 1653 /* 1654 * Function is the same, data pointer needs update. 1655 * Perform in-line replace without reallocation. 1656 */ 1657 old_fdh->fdh_idx[fd->fd_fibnum].arg = dp->arg; 1658 FD_PRINTF(LOG_DEBUG, fd, "FDH %p inline update", old_fdh); 1659 FIB_MOD_UNLOCK(); 1660 return (true); 1661 } 1662 1663 new_fdh = alloc_fib_dp_array(old_fdh->fdh_num_tables, false); 1664 FD_PRINTF(LOG_DEBUG, fd, "OLD FDH: %p NEW FDH: %p", old_fdh, new_fdh); 1665 if (new_fdh == NULL) { 1666 FIB_MOD_UNLOCK(); 1667 FD_PRINTF(LOG_WARNING, fd, "error attaching datapath"); 1668 return (false); 1669 } 1670 1671 memcpy(&new_fdh->fdh_idx[0], &old_fdh->fdh_idx[0], 1672 old_fdh->fdh_num_tables * sizeof(struct fib_dp)); 1673 /* Update relevant data structure for @fd */ 1674 new_fdh->fdh_idx[fd->fd_fibnum] = *dp; 1675 1676 /* Ensure memcpy() writes have completed */ 1677 atomic_thread_fence_rel(); 1678 /* Set new datapath pointer */ 1679 *pdp = &new_fdh->fdh_idx[0]; 1680 FIB_MOD_UNLOCK(); 1681 FD_PRINTF(LOG_DEBUG, fd, "update %p -> %p", old_fdh, new_fdh); 1682 1683 fib_epoch_call(destroy_fdh_epoch, &old_fdh->fdh_epoch_ctx); 1684 1685 return (true); 1686 } 1687 1688 static struct fib_dp ** 1689 get_family_dp_ptr(int family) 1690 { 1691 switch (family) { 1692 #ifdef INET 1693 case AF_INET: 1694 return (&V_inet_dp); 1695 #endif 1696 #ifdef INET6 1697 case AF_INET6: 1698 return (&V_inet6_dp); 1699 #endif 1700 } 1701 return (NULL); 1702 } 1703 1704 /* 1705 * Make datapath use fib instance @fd 1706 */ 1707 bool 1708 fib_set_datapath_ptr(struct fib_data *fd, struct fib_dp *dp) 1709 { 1710 struct fib_dp **pdp; 1711 1712 pdp = get_family_dp_ptr(fd->fd_family); 1713 return (replace_rtables_family(pdp, fd, dp)); 1714 } 1715 1716 /* 1717 * Grow datapath pointers array. 1718 * Called from sysctl handler on growing number of routing tables. 1719 */ 1720 static void 1721 grow_rtables_family(struct fib_dp **pdp, uint32_t new_num_tables) 1722 { 1723 struct fib_dp_header *new_fdh, *old_fdh = NULL; 1724 1725 new_fdh = alloc_fib_dp_array(new_num_tables, true); 1726 1727 FIB_MOD_LOCK(); 1728 if (*pdp != NULL) { 1729 old_fdh = get_fib_dp_header(*pdp); 1730 memcpy(&new_fdh->fdh_idx[0], &old_fdh->fdh_idx[0], 1731 old_fdh->fdh_num_tables * sizeof(struct fib_dp)); 1732 } 1733 1734 /* Wait till all writes completed */ 1735 atomic_thread_fence_rel(); 1736 1737 *pdp = &new_fdh->fdh_idx[0]; 1738 FIB_MOD_UNLOCK(); 1739 1740 if (old_fdh != NULL) 1741 fib_epoch_call(destroy_fdh_epoch, &old_fdh->fdh_epoch_ctx); 1742 } 1743 1744 /* 1745 * Grows per-AF arrays of datapath pointers for each supported family. 1746 * Called from fibs resize sysctl handler. 1747 */ 1748 void 1749 fib_grow_rtables(uint32_t new_num_tables) 1750 { 1751 1752 #ifdef INET 1753 grow_rtables_family(get_family_dp_ptr(AF_INET), new_num_tables); 1754 #endif 1755 #ifdef INET6 1756 grow_rtables_family(get_family_dp_ptr(AF_INET6), new_num_tables); 1757 #endif 1758 } 1759 1760 void 1761 fib_get_rtable_info(struct rib_head *rh, struct rib_rtable_info *rinfo) 1762 { 1763 1764 bzero(rinfo, sizeof(struct rib_rtable_info)); 1765 rinfo->num_prefixes = rh->rnh_prefixes; 1766 rinfo->num_nhops = nhops_get_count(rh); 1767 rinfo->num_nhgrp = nhgrp_get_count(rh); 1768 } 1769 1770 /* 1771 * Updates pointer to the algo data for the @fd. 1772 */ 1773 void 1774 fib_set_algo_ptr(struct fib_data *fd, void *algo_data) 1775 { 1776 RIB_WLOCK_ASSERT(fd->fd_rh); 1777 1778 fd->fd_algo_data = algo_data; 1779 } 1780 1781 /* 1782 * Calls @callback with @ctx after the end of a current epoch. 1783 */ 1784 void 1785 fib_epoch_call(epoch_callback_t callback, epoch_context_t ctx) 1786 { 1787 NET_EPOCH_CALL(callback, ctx); 1788 } 1789 1790 /* 1791 * Accessor to get rib instance @fd is attached to. 1792 */ 1793 struct rib_head * 1794 fib_get_rh(struct fib_data *fd) 1795 { 1796 1797 return (fd->fd_rh); 1798 } 1799 1800 /* 1801 * Accessor to export idx->nhop array 1802 */ 1803 struct nhop_object ** 1804 fib_get_nhop_array(struct fib_data *fd) 1805 { 1806 1807 return (fd->nh_idx); 1808 } 1809 1810 static uint32_t 1811 get_nhop_idx(struct nhop_object *nh) 1812 { 1813 if (NH_IS_NHGRP(nh)) 1814 return (nhgrp_get_idx((struct nhgrp_object *)nh)); 1815 1816 return (nhop_get_idx(nh)); 1817 } 1818 1819 static uint8_t 1820 get_nhop_family(struct nhop_object *nh) 1821 { 1822 1823 if (NH_IS_NHGRP(nh)) 1824 return (nhgrp_get_neigh_family((struct nhgrp_object *)nh)); 1825 1826 return (nhop_get_neigh_family(nh)); 1827 } 1828 1829 /* 1830 * Returns the index space of fd owning family, or NULL. 1831 */ 1832 static struct nhop_af_table * 1833 find_af_table(struct fib_data *fd, uint8_t family) 1834 { 1835 1836 for (int i = 0; i < fd->fd_num_af; i++) { 1837 if (fd->fd_af[i].nhaf_family == family) 1838 return (&fd->fd_af[i]); 1839 } 1840 1841 return (NULL); 1842 } 1843 1844 /* 1845 * Maps nh to its offset within the flat idx->nhop array of fd. 1846 */ 1847 static uint32_t 1848 get_nhop_off(struct fib_data *fd, struct nhop_object *nh) 1849 { 1850 struct nhop_af_table *nt = find_af_table(fd, get_nhop_family(nh)); 1851 uint32_t idx = get_nhop_idx(nh); 1852 1853 KASSERT(nt != NULL, ("no index space for the nhop family")); 1854 KASSERT(idx < nt->nhaf_count, ("invalid nhop index")); 1855 1856 return (nt->nhaf_base + idx); 1857 } 1858 1859 uint32_t 1860 fib_get_nhop_idx(struct fib_data *fd, struct nhop_object *nh) 1861 { 1862 1863 return (get_nhop_off(fd, nh)); 1864 } 1865 1866 static bool 1867 is_idx_free(struct fib_data *fd, uint32_t index) 1868 { 1869 1870 return (fd->nh_ref_table->refcnt[index] == 0); 1871 } 1872 1873 static uint32_t 1874 fib_ref_nhop(struct fib_data *fd, struct nhop_object *nh) 1875 { 1876 struct nhop_af_table *nt; 1877 uint32_t idx; 1878 uint8_t family; 1879 1880 RIB_WLOCK_ASSERT(fd->fd_rh); 1881 1882 family = get_nhop_family(nh); 1883 nt = find_af_table(fd, family); 1884 if (nt == NULL) { 1885 KASSERT(fd->fd_num_af < FD_MAX_NH_AF, 1886 ("out of nhop index spaces for %s", print_family(family))); 1887 nt = &fd->fd_af[fd->fd_num_af++]; 1888 nt->nhaf_family = family; 1889 } 1890 1891 idx = get_nhop_idx(nh); 1892 if (idx >= nt->nhaf_count) { 1893 nt->nhaf_hit = true; 1894 fd->hit_nhops = 1; 1895 return (0); 1896 } 1897 idx += nt->nhaf_base; 1898 1899 if (is_idx_free(fd, idx)) { 1900 nhop_ref_any(nh); 1901 fd->nh_idx[idx] = nh; 1902 fd->nh_ref_table->count++; 1903 FD_PRINTF(LOG_DEBUG2, fd, " REF nhop %u %p", idx, fd->nh_idx[idx]); 1904 } 1905 fd->nh_ref_table->refcnt[idx]++; 1906 1907 return (idx); 1908 } 1909 1910 struct nhop_release_data { 1911 struct nhop_object *nh; 1912 struct epoch_context ctx; 1913 }; 1914 1915 static void 1916 release_nhop_epoch(epoch_context_t ctx) 1917 { 1918 struct nhop_release_data *nrd; 1919 1920 nrd = __containerof(ctx, struct nhop_release_data, ctx); 1921 nhop_free_any(nrd->nh); 1922 free(nrd, M_TEMP); 1923 } 1924 1925 /* 1926 * Delays nexthop refcount release. 1927 * Datapath may have the datastructures not updated yet, so the old 1928 * nexthop may still be returned till the end of current epoch. Delay 1929 * refcount removal, as we may be removing the last instance, which will 1930 * trigger nexthop deletion, rendering returned nexthop invalid. 1931 */ 1932 static void 1933 fib_schedule_release_nhop(struct fib_data *fd, struct nhop_object *nh) 1934 { 1935 struct nhop_release_data *nrd; 1936 1937 nrd = malloc(sizeof(struct nhop_release_data), M_TEMP, M_NOWAIT | M_ZERO); 1938 if (nrd != NULL) { 1939 nrd->nh = nh; 1940 fib_epoch_call(release_nhop_epoch, &nrd->ctx); 1941 } else { 1942 /* 1943 * Unable to allocate memory. Leak nexthop to maintain guarantee 1944 * that each nhop can be referenced. 1945 */ 1946 FD_PRINTF(LOG_ERR, fd, "unable to schedule nhop %p deletion", nh); 1947 } 1948 } 1949 1950 static void 1951 fib_unref_nhop(struct fib_data *fd, struct nhop_object *nh) 1952 { 1953 uint32_t idx = get_nhop_off(fd, nh); 1954 1955 KASSERT(idx < fd->number_nhops, ("invalid nhop index")); 1956 KASSERT(nh == fd->nh_idx[idx], ("index table contains whong nh")); 1957 1958 fd->nh_ref_table->refcnt[idx]--; 1959 if (fd->nh_ref_table->refcnt[idx] == 0) { 1960 FD_PRINTF(LOG_DEBUG, fd, " FREE nhop %d %p", idx, fd->nh_idx[idx]); 1961 fib_schedule_release_nhop(fd, fd->nh_idx[idx]); 1962 } 1963 } 1964 1965 static void 1966 set_algo_fixed(struct rib_head *rh) 1967 { 1968 switch (rh->rib_family) { 1969 #ifdef INET 1970 case AF_INET: 1971 V_algo_fixed_inet = true; 1972 break; 1973 #endif 1974 #ifdef INET6 1975 case AF_INET6: 1976 V_algo_fixed_inet6 = true; 1977 break; 1978 #endif 1979 } 1980 } 1981 1982 static bool 1983 is_algo_fixed(struct rib_head *rh) 1984 { 1985 1986 switch (rh->rib_family) { 1987 #ifdef INET 1988 case AF_INET: 1989 return (V_algo_fixed_inet); 1990 #endif 1991 #ifdef INET6 1992 case AF_INET6: 1993 return (V_algo_fixed_inet6); 1994 #endif 1995 } 1996 return (false); 1997 } 1998 1999 /* 2000 * Runs the check on what would be the best algo for rib @rh, assuming 2001 * that the current algo is the one specified by @orig_flm. Note that 2002 * it can be NULL for initial selection. 2003 * 2004 * Returns referenced new algo or NULL if the current one is the best. 2005 */ 2006 static struct fib_lookup_module * 2007 fib_check_best_algo(struct rib_head *rh, struct fib_lookup_module *orig_flm) 2008 { 2009 uint8_t preference, curr_preference = 0, best_preference = 0; 2010 struct fib_lookup_module *flm, *best_flm = NULL; 2011 struct rib_rtable_info rinfo; 2012 int candidate_algos = 0; 2013 2014 fib_get_rtable_info(rh, &rinfo); 2015 2016 FIB_MOD_LOCK(); 2017 TAILQ_FOREACH(flm, &all_algo_list, entries) { 2018 if (flm->flm_family != rh->rib_family) 2019 continue; 2020 candidate_algos++; 2021 preference = flm->flm_get_pref(&rinfo); 2022 if (preference > best_preference) { 2023 if (!flm_error_check(flm, rh->rib_fibnum)) { 2024 best_preference = preference; 2025 best_flm = flm; 2026 } 2027 } 2028 if (flm == orig_flm) 2029 curr_preference = preference; 2030 } 2031 if ((best_flm != NULL) && (curr_preference + BEST_DIFF_PERCENT < best_preference)) 2032 best_flm->flm_refcount++; 2033 else 2034 best_flm = NULL; 2035 FIB_MOD_UNLOCK(); 2036 2037 RH_PRINTF(LOG_DEBUG, rh, "candidate_algos: %d, curr: %s(%d) result: %s(%d)", 2038 candidate_algos, orig_flm ? orig_flm->flm_name : "NULL", curr_preference, 2039 best_flm ? best_flm->flm_name : (orig_flm ? orig_flm->flm_name : "NULL"), 2040 best_preference); 2041 2042 return (best_flm); 2043 } 2044 2045 /* 2046 * Called when new route table is created. 2047 * Selects, allocates and attaches fib algo for the table. 2048 */ 2049 static bool 2050 fib_select_algo_initial(struct rib_head *rh, struct fib_dp *dp) 2051 { 2052 struct fib_lookup_module *flm; 2053 struct fib_data *fd = NULL; 2054 enum flm_op_result result; 2055 struct epoch_tracker et; 2056 2057 flm = fib_check_best_algo(rh, NULL); 2058 if (flm == NULL) { 2059 RH_PRINTF(LOG_CRIT, rh, "no algo selected"); 2060 return (false); 2061 } 2062 RH_PRINTF(LOG_INFO, rh, "selected algo %s", flm->flm_name); 2063 2064 NET_EPOCH_ENTER(et); 2065 RIB_WLOCK(rh); 2066 result = setup_fd_instance(flm, rh, NULL, &fd, false); 2067 RIB_WUNLOCK(rh); 2068 NET_EPOCH_EXIT(et); 2069 2070 RH_PRINTF(LOG_DEBUG, rh, "result=%d fd=%p", result, fd); 2071 if (result == FLM_SUCCESS) 2072 *dp = fd->fd_dp; 2073 else 2074 RH_PRINTF(LOG_CRIT, rh, "unable to setup algo %s", flm->flm_name); 2075 2076 fib_unref_algo(flm); 2077 2078 return (result == FLM_SUCCESS); 2079 } 2080 2081 /* 2082 * Sets up fib algo instances for the non-initialized RIBs in the @family. 2083 * Allocates temporary datapath index to amortize datapaint index updates 2084 * with large @num_tables. 2085 */ 2086 void 2087 fib_setup_family(int family, uint32_t num_tables) 2088 { 2089 struct fib_dp_header *new_fdh = alloc_fib_dp_array(num_tables, false); 2090 if (new_fdh == NULL) { 2091 ALGO_PRINTF(LOG_CRIT, "Unable to setup framework for %s", print_family(family)); 2092 return; 2093 } 2094 2095 for (int i = 0; i < num_tables; i++) { 2096 struct rib_head *rh = rt_tables_get_rnh(i, family); 2097 if (rh->rib_algo_init) 2098 continue; 2099 if (!fib_select_algo_initial(rh, &new_fdh->fdh_idx[i])) 2100 continue; 2101 2102 rh->rib_algo_init = true; 2103 } 2104 2105 FIB_MOD_LOCK(); 2106 struct fib_dp **pdp = get_family_dp_ptr(family); 2107 struct fib_dp_header *old_fdh = get_fib_dp_header(*pdp); 2108 2109 /* Update the items not touched by the new init, from the old data pointer */ 2110 for (int i = 0; i < num_tables; i++) { 2111 if (new_fdh->fdh_idx[i].f == dummy_lookup) 2112 new_fdh->fdh_idx[i] = old_fdh->fdh_idx[i]; 2113 } 2114 2115 /* Ensure all index writes have completed */ 2116 atomic_thread_fence_rel(); 2117 /* Set new datapath pointer */ 2118 *pdp = &new_fdh->fdh_idx[0]; 2119 2120 FIB_MOD_UNLOCK(); 2121 2122 fib_epoch_call(destroy_fdh_epoch, &old_fdh->fdh_epoch_ctx); 2123 } 2124 2125 /* 2126 * Registers fib lookup module within the subsystem. 2127 */ 2128 int 2129 fib_module_register(struct fib_lookup_module *flm) 2130 { 2131 2132 FIB_MOD_LOCK(); 2133 ALGO_PRINTF(LOG_INFO, "attaching %s to %s", flm->flm_name, 2134 print_family(flm->flm_family)); 2135 TAILQ_INSERT_TAIL(&all_algo_list, flm, entries); 2136 FIB_MOD_UNLOCK(); 2137 2138 return (0); 2139 } 2140 2141 /* 2142 * Tries to unregister fib lookup module. 2143 * 2144 * Returns 0 on success, EBUSY if module is still used 2145 * by some of the tables. 2146 */ 2147 int 2148 fib_module_unregister(struct fib_lookup_module *flm) 2149 { 2150 2151 FIB_MOD_LOCK(); 2152 if (flm->flm_refcount > 0) { 2153 FIB_MOD_UNLOCK(); 2154 return (EBUSY); 2155 } 2156 fib_error_clear_flm(flm); 2157 ALGO_PRINTF(LOG_INFO, "detaching %s from %s", flm->flm_name, 2158 print_family(flm->flm_family)); 2159 TAILQ_REMOVE(&all_algo_list, flm, entries); 2160 FIB_MOD_UNLOCK(); 2161 2162 return (0); 2163 } 2164 2165 void 2166 vnet_fib_init(void) 2167 { 2168 2169 TAILQ_INIT(&V_fib_data_list); 2170 } 2171 2172 void 2173 vnet_fib_destroy(void) 2174 { 2175 2176 FIB_MOD_LOCK(); 2177 fib_error_clear(); 2178 FIB_MOD_UNLOCK(); 2179 } 2180