circuitmux.c (38504B)
1 /* * Copyright (c) 2012-2021, The Tor Project, Inc. */ 2 /* See LICENSE for licensing information */ 3 4 /** 5 * \file circuitmux.c 6 * \brief Circuit mux/cell selection abstraction 7 * 8 * A circuitmux is responsible for <b>MU</b>ltiple<b>X</b>ing all of the 9 * circuits that are writing on a single channel. It keeps track of which of 10 * these circuits has something to write (aka, "active" circuits), and which 11 * one should write next. A circuitmux corresponds 1:1 with a channel. 12 * 13 * There can be different implementations of the circuitmux's rules (which 14 * decide which circuit is next to write). 15 * 16 * A circuitmux exposes three distinct 17 * interfaces to other components: 18 * 19 * To channels, which each have a circuitmux_t, the supported operations 20 * (invoked from relay.c) are: 21 * 22 * circuitmux_get_first_active_circuit(): 23 * 24 * Pick one of the circuitmux's active circuits to send cells from. 25 * 26 * circuitmux_notify_xmit_cells(): 27 * 28 * Notify the circuitmux that cells have been sent on a circuit. 29 * 30 * To circuits, the exposed operations are: 31 * 32 * circuitmux_attach_circuit(): 33 * 34 * Attach a circuit to the circuitmux; this will allocate any policy- 35 * specific data wanted for this circuit and add it to the active 36 * circuits list if it has queued cells. 37 * 38 * circuitmux_detach_circuit(): 39 * 40 * Detach a circuit from the circuitmux, freeing associated structures. 41 * 42 * circuitmux_clear_num_cells(): 43 * 44 * Clear the circuitmux's cell counter for this circuit. 45 * 46 * circuitmux_set_num_cells(): 47 * 48 * Set the circuitmux's cell counter for this circuit. One of 49 * circuitmuc_clear_num_cells() or circuitmux_set_num_cells() MUST be 50 * called when the number of cells queued on a circuit changes. 51 * 52 * See circuitmux.h for the circuitmux_policy_t data structure, which contains 53 * a table of function pointers implementing a circuit selection policy, and 54 * circuitmux_ewma.c for an example of a circuitmux policy. Circuitmux 55 * policies can be manipulated with: 56 * 57 * circuitmux_get_policy(): 58 * 59 * Return the current policy for a circuitmux_t, if any. 60 * 61 * circuitmux_clear_policy(): 62 * 63 * Remove a policy installed on a circuitmux_t, freeing all associated 64 * data. The circuitmux will revert to the built-in round-robin behavior. 65 * 66 * circuitmux_set_policy(): 67 * 68 * Install a policy on a circuitmux_t; the appropriate callbacks will be 69 * made to attach all existing circuits to the new policy. 70 **/ 71 72 #define CIRCUITMUX_PRIVATE 73 74 #include "core/or/or.h" 75 #include "core/or/channel.h" 76 #include "core/or/circuitlist.h" 77 #include "core/or/circuitmux.h" 78 #include "core/or/relay.h" 79 80 #include "core/or/or_circuit_st.h" 81 82 #include "lib/crypt_ops/crypto_util.h" 83 84 /* 85 * Private typedefs for circuitmux.c 86 */ 87 88 /* 89 * Hash table entry (yeah, calling it chanid_circid_muxinfo_s seems to 90 * break the hash table code). 91 */ 92 typedef struct chanid_circid_muxinfo_t chanid_circid_muxinfo_t; 93 94 /* 95 * Anything the mux wants to store per-circuit in the map; right now just 96 * a count of queued cells. 97 */ 98 99 typedef struct circuit_muxinfo_t circuit_muxinfo_t; 100 101 /* 102 * This struct holds whatever we want to store per attached circuit on a 103 * circuitmux_t; right now, just the count of queued cells and the direction. 104 */ 105 106 struct circuit_muxinfo_t { 107 /* Count of cells on this circuit at last update */ 108 unsigned int cell_count; 109 /* Direction of flow */ 110 cell_direction_t direction; 111 /* Policy-specific data */ 112 circuitmux_policy_circ_data_t *policy_data; 113 /* Mark bit for consistency checker */ 114 unsigned int mark:1; 115 }; 116 117 /* 118 * A map from channel ID and circuit ID to a circuit_muxinfo_t for that 119 * circuit. 120 */ 121 122 struct chanid_circid_muxinfo_t { 123 HT_ENTRY(chanid_circid_muxinfo_t) node; 124 uint64_t chan_id; 125 circid_t circ_id; 126 circuit_muxinfo_t muxinfo; 127 }; 128 129 /* 130 * Static function declarations 131 */ 132 133 static inline int 134 chanid_circid_entries_eq(chanid_circid_muxinfo_t *a, 135 chanid_circid_muxinfo_t *b); 136 static inline unsigned int 137 chanid_circid_entry_hash(chanid_circid_muxinfo_t *a); 138 static chanid_circid_muxinfo_t * 139 circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ); 140 static void 141 circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ); 142 static void 143 circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ); 144 145 /* Static global variables */ 146 147 /** Count the destroy balance to debug destroy queue logic */ 148 static int64_t global_destroy_ctr = 0; 149 150 /* Function definitions */ 151 152 /** 153 * Helper for chanid_circid_cell_count_map_t hash table: compare the channel 154 * ID and circuit ID for a and b, and return less than, equal to, or greater 155 * than zero appropriately. 156 */ 157 158 static inline int 159 chanid_circid_entries_eq(chanid_circid_muxinfo_t *a, 160 chanid_circid_muxinfo_t *b) 161 { 162 return a->chan_id == b->chan_id && a->circ_id == b->circ_id; 163 } 164 165 /** 166 * Helper: return a hash based on circuit ID and channel ID in a. 167 */ 168 169 static inline unsigned int 170 chanid_circid_entry_hash(chanid_circid_muxinfo_t *a) 171 { 172 uint8_t data[8 + 4]; 173 set_uint64(data, a->chan_id); 174 set_uint32(data + 8, a->circ_id); 175 return (unsigned) siphash24g(data, sizeof(data)); 176 } 177 178 /* Emit a bunch of hash table stuff */ 179 HT_PROTOTYPE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node, 180 chanid_circid_entry_hash, chanid_circid_entries_eq); 181 HT_GENERATE2(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node, 182 chanid_circid_entry_hash, chanid_circid_entries_eq, 0.6, 183 tor_reallocarray_, tor_free_); 184 185 /* 186 * Circuitmux alloc/free functions 187 */ 188 189 /** 190 * Allocate a new circuitmux_t 191 */ 192 193 circuitmux_t * 194 circuitmux_alloc(void) 195 { 196 circuitmux_t *rv = NULL; 197 198 rv = tor_malloc_zero(sizeof(*rv)); 199 rv->chanid_circid_map = tor_malloc_zero(sizeof(*( rv->chanid_circid_map))); 200 HT_INIT(chanid_circid_muxinfo_map, rv->chanid_circid_map); 201 destroy_cell_queue_init(&rv->destroy_cell_queue); 202 203 return rv; 204 } 205 206 /** 207 * Detach all circuits from a circuitmux (use before circuitmux_free()) 208 * 209 * If <b>detached_out</b> is non-NULL, add every detached circuit_t to 210 * detached_out. 211 */ 212 213 void 214 circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out) 215 { 216 chanid_circid_muxinfo_t **i = NULL, *to_remove; 217 channel_t *chan = NULL; 218 circuit_t *circ = NULL; 219 220 tor_assert(cmux); 221 222 i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map); 223 while (i) { 224 to_remove = *i; 225 226 if (! to_remove) { 227 log_warn(LD_BUG, "Somehow, an HT iterator gave us a NULL pointer."); 228 break; 229 } else { 230 /* Find a channel and circuit */ 231 chan = channel_find_by_global_id(to_remove->chan_id); 232 if (chan) { 233 circ = 234 circuit_get_by_circid_channel_even_if_marked(to_remove->circ_id, 235 chan); 236 if (circ) { 237 /* Clear the circuit's mux for this direction */ 238 if (to_remove->muxinfo.direction == CELL_DIRECTION_OUT) { 239 /* 240 * Update active_circuits et al.; this does policy notifies, so 241 * comes before freeing policy data 242 */ 243 244 if (to_remove->muxinfo.cell_count > 0) { 245 circuitmux_make_circuit_inactive(cmux, circ); 246 } 247 248 if (detached_out) 249 smartlist_add(detached_out, circ); 250 } else if (circ->magic == OR_CIRCUIT_MAGIC) { 251 /* 252 * Update active_circuits et al.; this does policy notifies, so 253 * comes before freeing policy data 254 */ 255 256 if (to_remove->muxinfo.cell_count > 0) { 257 circuitmux_make_circuit_inactive(cmux, circ); 258 } 259 260 if (detached_out) 261 smartlist_add(detached_out, circ); 262 } else { 263 /* Complain and move on */ 264 log_warn(LD_CIRC, 265 "Circuit %u/channel %"PRIu64 " had direction == " 266 "CELL_DIRECTION_IN, but isn't an or_circuit_t", 267 (unsigned)to_remove->circ_id, 268 (to_remove->chan_id)); 269 } 270 271 /* Free policy-specific data if we have it */ 272 if (to_remove->muxinfo.policy_data) { 273 /* 274 * If we have policy data, assert that we have the means to 275 * free it 276 */ 277 tor_assert(cmux->policy); 278 tor_assert(cmux->policy->free_circ_data); 279 /* Call free_circ_data() */ 280 cmux->policy->free_circ_data(cmux, 281 cmux->policy_data, 282 circ, 283 to_remove->muxinfo.policy_data); 284 to_remove->muxinfo.policy_data = NULL; 285 } 286 } else { 287 /* Complain and move on */ 288 log_warn(LD_CIRC, 289 "Couldn't find circuit %u (for channel %"PRIu64 ")", 290 (unsigned)to_remove->circ_id, 291 (to_remove->chan_id)); 292 } 293 } else { 294 /* Complain and move on */ 295 log_warn(LD_CIRC, 296 "Couldn't find channel %"PRIu64 " (for circuit id %u)", 297 (to_remove->chan_id), 298 (unsigned)to_remove->circ_id); 299 } 300 301 /* Assert that we don't have un-freed policy data for this circuit */ 302 tor_assert(to_remove->muxinfo.policy_data == NULL); 303 } 304 305 i = HT_NEXT_RMV(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i); 306 307 /* Free it */ 308 tor_free(to_remove); 309 } 310 311 cmux->n_circuits = 0; 312 cmux->n_active_circuits = 0; 313 cmux->n_cells = 0; 314 } 315 316 /** Reclaim all circuit IDs currently marked as unusable on <b>chan</b> because 317 * of pending destroy cells in <b>cmux</b>. 318 * 319 * This function must be called AFTER circuits are unlinked from the (channel, 320 * circuid-id) map with circuit_unlink_all_from_channel(), but before calling 321 * circuitmux_free(). 322 */ 323 void 324 circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, channel_t *chan) 325 { 326 destroy_cell_t *cell; 327 TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) { 328 channel_mark_circid_usable(chan, cell->circid); 329 } 330 } 331 332 /** 333 * Free a circuitmux_t; the circuits must be detached first with 334 * circuitmux_detach_all_circuits(). 335 */ 336 337 void 338 circuitmux_free_(circuitmux_t *cmux) 339 { 340 if (!cmux) return; 341 342 tor_assert(cmux->n_circuits == 0); 343 tor_assert(cmux->n_active_circuits == 0); 344 345 /* 346 * Free policy-specific data if we have any; we don't 347 * need to do circuitmux_set_policy(cmux, NULL) to cover 348 * the circuits because they would have been handled in 349 * circuitmux_detach_all_circuits() before this was 350 * called. 351 */ 352 if (cmux->policy && cmux->policy->free_cmux_data) { 353 if (cmux->policy_data) { 354 cmux->policy->free_cmux_data(cmux, cmux->policy_data); 355 cmux->policy_data = NULL; 356 } 357 } else tor_assert(cmux->policy_data == NULL); 358 359 if (cmux->chanid_circid_map) { 360 HT_CLEAR(chanid_circid_muxinfo_map, cmux->chanid_circid_map); 361 tor_free(cmux->chanid_circid_map); 362 } 363 364 /* 365 * We're throwing away some destroys; log the counter and 366 * adjust the global counter by the queue size. 367 */ 368 if (cmux->destroy_cell_queue.n > 0) { 369 cmux->destroy_ctr -= cmux->destroy_cell_queue.n; 370 global_destroy_ctr -= cmux->destroy_cell_queue.n; 371 log_debug(LD_CIRC, 372 "Freeing cmux at %p with %u queued destroys; the last cmux " 373 "destroy balance was %"PRId64", global is %"PRId64, 374 cmux, cmux->destroy_cell_queue.n, 375 (cmux->destroy_ctr), 376 (global_destroy_ctr)); 377 } else { 378 log_debug(LD_CIRC, 379 "Freeing cmux at %p with no queued destroys, the cmux destroy " 380 "balance was %"PRId64", global is %"PRId64, 381 cmux, 382 (cmux->destroy_ctr), 383 (global_destroy_ctr)); 384 } 385 386 destroy_cell_queue_clear(&cmux->destroy_cell_queue); 387 388 tor_free(cmux); 389 } 390 391 /* 392 * Circuitmux policy control functions 393 */ 394 395 /** 396 * Remove any policy installed on cmux; all policy data will be freed and 397 * cmux behavior will revert to the built-in round-robin active_circuits 398 * mechanism. 399 */ 400 401 void 402 circuitmux_clear_policy(circuitmux_t *cmux) 403 { 404 tor_assert(cmux); 405 406 /* Internally, this is just setting policy to NULL */ 407 circuitmux_set_policy(cmux, NULL); 408 } 409 410 /** 411 * Return the policy currently installed on a circuitmux_t 412 */ 413 414 MOCK_IMPL(const circuitmux_policy_t *, 415 circuitmux_get_policy, (circuitmux_t *cmux)) 416 { 417 tor_assert(cmux); 418 419 return cmux->policy; 420 } 421 422 /** 423 * Set policy; allocate for new policy, detach all circuits from old policy 424 * if any, attach them to new policy, and free old policy data. 425 */ 426 427 void 428 circuitmux_set_policy(circuitmux_t *cmux, 429 const circuitmux_policy_t *pol) 430 { 431 const circuitmux_policy_t *old_pol = NULL, *new_pol = NULL; 432 circuitmux_policy_data_t *old_pol_data = NULL, *new_pol_data = NULL; 433 chanid_circid_muxinfo_t **i = NULL; 434 channel_t *chan = NULL; 435 uint64_t last_chan_id_searched = 0; 436 circuit_t *circ = NULL; 437 438 tor_assert(cmux); 439 440 /* Set up variables */ 441 old_pol = cmux->policy; 442 old_pol_data = cmux->policy_data; 443 new_pol = pol; 444 445 /* Check if this is the trivial case */ 446 if (old_pol == new_pol) return; 447 448 /* Allocate data for new policy, if any */ 449 if (new_pol && new_pol->alloc_cmux_data) { 450 /* 451 * If alloc_cmux_data is not null, then we expect to get some policy 452 * data. Assert that we also have free_cmux_data so we can free it 453 * when the time comes, and allocate it. 454 */ 455 tor_assert(new_pol->free_cmux_data); 456 new_pol_data = new_pol->alloc_cmux_data(cmux); 457 tor_assert(new_pol_data); 458 } 459 460 /* Install new policy and new policy data on cmux */ 461 cmux->policy = new_pol; 462 cmux->policy_data = new_pol_data; 463 464 /* Iterate over all circuits, attaching/detaching each one */ 465 i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map); 466 while (i) { 467 /* Assert that this entry isn't NULL */ 468 tor_assert(*i); 469 470 /* 471 * Get the channel; since normal case is all circuits on the mux share a 472 * channel, we cache last_chan_id_searched 473 */ 474 if (!chan || last_chan_id_searched != (*i)->chan_id) { 475 chan = channel_find_by_global_id((*i)->chan_id); 476 last_chan_id_searched = (*i)->chan_id; 477 } 478 tor_assert(chan); 479 480 /* Get the circuit */ 481 circ = circuit_get_by_circid_channel_even_if_marked((*i)->circ_id, chan); 482 tor_assert(circ); 483 484 /* Need to tell old policy it becomes inactive (i.e., it is active) ? */ 485 if (old_pol && old_pol->notify_circ_inactive && 486 (*i)->muxinfo.cell_count > 0) { 487 old_pol->notify_circ_inactive(cmux, old_pol_data, circ, 488 (*i)->muxinfo.policy_data); 489 } 490 491 /* Need to free old policy data? */ 492 if ((*i)->muxinfo.policy_data) { 493 /* Assert that we have the means to free it if we have policy data */ 494 tor_assert(old_pol); 495 tor_assert(old_pol->free_circ_data); 496 /* Free it */ 497 old_pol->free_circ_data(cmux, old_pol_data, circ, 498 (*i)->muxinfo.policy_data); 499 (*i)->muxinfo.policy_data = NULL; 500 } 501 502 /* Need to allocate new policy data? */ 503 if (new_pol && new_pol->alloc_circ_data) { 504 /* 505 * If alloc_circ_data is not null, we expect to get some per-circuit 506 * policy data. Assert that we also have free_circ_data so we can 507 * free it when the time comes, and allocate it. 508 */ 509 tor_assert(new_pol->free_circ_data); 510 (*i)->muxinfo.policy_data = 511 new_pol->alloc_circ_data(cmux, new_pol_data, circ, 512 (*i)->muxinfo.direction, 513 (*i)->muxinfo.cell_count); 514 } 515 516 /* Need to make active on new policy? */ 517 if (new_pol && new_pol->notify_circ_active && 518 (*i)->muxinfo.cell_count > 0) { 519 new_pol->notify_circ_active(cmux, new_pol_data, circ, 520 (*i)->muxinfo.policy_data); 521 } 522 523 /* Advance to next circuit map entry */ 524 i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i); 525 } 526 527 /* Free data for old policy, if any */ 528 if (old_pol_data) { 529 /* 530 * If we had old policy data, we should have an old policy and a free 531 * function for it. 532 */ 533 tor_assert(old_pol); 534 tor_assert(old_pol->free_cmux_data); 535 old_pol->free_cmux_data(cmux, old_pol_data); 536 old_pol_data = NULL; 537 } 538 } 539 540 /* 541 * Circuitmux/circuit attachment status inquiry functions 542 */ 543 544 /** 545 * Query the direction of an attached circuit 546 */ 547 548 cell_direction_t 549 circuitmux_attached_circuit_direction(circuitmux_t *cmux, circuit_t *circ) 550 { 551 chanid_circid_muxinfo_t *hashent = NULL; 552 553 /* Try to find a map entry */ 554 hashent = circuitmux_find_map_entry(cmux, circ); 555 556 /* 557 * This function should only be called on attached circuits; assert that 558 * we had a map entry. 559 */ 560 tor_assert(hashent); 561 562 /* Return the direction from the map entry */ 563 return hashent->muxinfo.direction; 564 } 565 566 /** 567 * Find an entry in the cmux's map for this circuit or return NULL if there 568 * is none. 569 */ 570 571 static chanid_circid_muxinfo_t * 572 circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ) 573 { 574 chanid_circid_muxinfo_t search, *hashent = NULL; 575 576 /* Sanity-check parameters */ 577 tor_assert(cmux); 578 tor_assert(cmux->chanid_circid_map); 579 tor_assert(circ); 580 581 /* Check if we have n_chan */ 582 if (circ->n_chan) { 583 /* Okay, let's see if it's attached for n_chan/n_circ_id */ 584 search.chan_id = circ->n_chan->global_identifier; 585 search.circ_id = circ->n_circ_id; 586 587 /* Query */ 588 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map, 589 &search); 590 } 591 592 /* Found something? */ 593 if (hashent) { 594 /* 595 * Assert that the direction makes sense for a hashent we found by 596 * n_chan/n_circ_id before we return it. 597 */ 598 tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_OUT); 599 } else { 600 /* Not there, have we got a p_chan/p_circ_id to try? */ 601 if (circ->magic == OR_CIRCUIT_MAGIC) { 602 search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; 603 /* Check for p_chan */ 604 if (TO_OR_CIRCUIT(circ)->p_chan) { 605 search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier; 606 /* Okay, search for that */ 607 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map, 608 &search); 609 /* Find anything? */ 610 if (hashent) { 611 /* Assert that the direction makes sense before we return it */ 612 tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_IN); 613 } 614 } 615 } 616 } 617 618 /* Okay, hashent is it if it was there */ 619 return hashent; 620 } 621 622 /** 623 * Query whether a circuit is attached to a circuitmux 624 */ 625 626 int 627 circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ) 628 { 629 chanid_circid_muxinfo_t *hashent = NULL; 630 631 /* Look if it's in the circuit map */ 632 hashent = circuitmux_find_map_entry(cmux, circ); 633 634 return (hashent != NULL); 635 } 636 637 /** 638 * Query whether a circuit is active on a circuitmux 639 */ 640 641 int 642 circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ) 643 { 644 chanid_circid_muxinfo_t *hashent = NULL; 645 int is_active = 0; 646 647 tor_assert(cmux); 648 tor_assert(circ); 649 650 /* Look if it's in the circuit map */ 651 hashent = circuitmux_find_map_entry(cmux, circ); 652 if (hashent) { 653 /* Check the number of cells on this circuit */ 654 is_active = (hashent->muxinfo.cell_count > 0); 655 } 656 /* else not attached, so not active */ 657 658 return is_active; 659 } 660 661 /** 662 * Query number of available cells for a circuit on a circuitmux 663 */ 664 665 unsigned int 666 circuitmux_num_cells_for_circuit(circuitmux_t *cmux, circuit_t *circ) 667 { 668 chanid_circid_muxinfo_t *hashent = NULL; 669 unsigned int n_cells = 0; 670 671 tor_assert(cmux); 672 tor_assert(circ); 673 674 /* Look if it's in the circuit map */ 675 hashent = circuitmux_find_map_entry(cmux, circ); 676 if (hashent) { 677 /* Just get the cell count for this circuit */ 678 n_cells = hashent->muxinfo.cell_count; 679 } 680 /* else not attached, so 0 cells */ 681 682 return n_cells; 683 } 684 685 /** 686 * Query total number of available cells on a circuitmux 687 */ 688 689 MOCK_IMPL(unsigned int, 690 circuitmux_num_cells, (circuitmux_t *cmux)) 691 { 692 tor_assert(cmux); 693 694 return cmux->n_cells + cmux->destroy_cell_queue.n; 695 } 696 697 /** 698 * Query total number of circuits active on a circuitmux 699 */ 700 701 unsigned int 702 circuitmux_num_active_circuits(circuitmux_t *cmux) 703 { 704 tor_assert(cmux); 705 706 return cmux->n_active_circuits; 707 } 708 709 /** 710 * Query total number of circuits attached to a circuitmux 711 */ 712 713 unsigned int 714 circuitmux_num_circuits(circuitmux_t *cmux) 715 { 716 tor_assert(cmux); 717 718 return cmux->n_circuits; 719 } 720 721 /* 722 * Functions for circuit code to call to update circuit status 723 */ 724 725 /** 726 * Attach a circuit to a circuitmux, for the specified direction. 727 */ 728 729 MOCK_IMPL(void, 730 circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ, 731 cell_direction_t direction)) 732 { 733 channel_t *chan = NULL; 734 uint64_t channel_id; 735 circid_t circ_id; 736 chanid_circid_muxinfo_t search, *hashent = NULL; 737 unsigned int cell_count; 738 739 tor_assert(cmux); 740 tor_assert(circ); 741 tor_assert(direction == CELL_DIRECTION_IN || 742 direction == CELL_DIRECTION_OUT); 743 744 /* 745 * Figure out which channel we're using, and get the circuit's current 746 * cell count and circuit ID; assert that the circuit is not already 747 * attached to another mux. 748 */ 749 if (direction == CELL_DIRECTION_OUT) { 750 /* It's n_chan */ 751 chan = circ->n_chan; 752 cell_count = circ->n_chan_cells.n; 753 circ_id = circ->n_circ_id; 754 } else { 755 /* We want p_chan */ 756 chan = TO_OR_CIRCUIT(circ)->p_chan; 757 cell_count = TO_OR_CIRCUIT(circ)->p_chan_cells.n; 758 circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; 759 } 760 /* Assert that we did get a channel */ 761 tor_assert(chan); 762 /* Assert that the circuit ID is sensible */ 763 tor_assert(circ_id != 0); 764 765 /* Get the channel ID */ 766 channel_id = chan->global_identifier; 767 768 /* See if we already have this one */ 769 search.chan_id = channel_id; 770 search.circ_id = circ_id; 771 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map, 772 &search); 773 774 if (hashent) { 775 /* 776 * This circuit was already attached to this cmux; make sure the 777 * directions match and update the cell count and active circuit count. 778 */ 779 log_info(LD_CIRC, 780 "Circuit %u on channel %"PRIu64 " was already attached to " 781 "(trying to attach to %p)", 782 (unsigned)circ_id, (channel_id), 783 cmux); 784 785 /* 786 * The mux pointer on this circuit and the direction in result should 787 * match; otherwise assert. 788 */ 789 tor_assert(hashent->muxinfo.direction == direction); 790 791 /* 792 * Looks okay; just update the cell count and active circuits if we must 793 */ 794 if (hashent->muxinfo.cell_count > 0 && cell_count == 0) { 795 --(cmux->n_active_circuits); 796 circuitmux_make_circuit_inactive(cmux, circ); 797 } else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) { 798 ++(cmux->n_active_circuits); 799 circuitmux_make_circuit_active(cmux, circ); 800 } 801 cmux->n_cells -= hashent->muxinfo.cell_count; 802 cmux->n_cells += cell_count; 803 hashent->muxinfo.cell_count = cell_count; 804 } else { 805 /* 806 * New circuit; add an entry and update the circuit/active circuit 807 * counts. 808 */ 809 log_debug(LD_CIRC, 810 "Attaching circuit %u on channel %"PRIu64 " to cmux %p", 811 (unsigned)circ_id, (channel_id), cmux); 812 813 /* Insert it in the map */ 814 hashent = tor_malloc_zero(sizeof(*hashent)); 815 hashent->chan_id = channel_id; 816 hashent->circ_id = circ_id; 817 hashent->muxinfo.cell_count = cell_count; 818 hashent->muxinfo.direction = direction; 819 /* Allocate policy specific circuit data if we need it */ 820 if (cmux->policy->alloc_circ_data) { 821 /* Assert that we have the means to free policy-specific data */ 822 tor_assert(cmux->policy->free_circ_data); 823 /* Allocate it */ 824 hashent->muxinfo.policy_data = 825 cmux->policy->alloc_circ_data(cmux, 826 cmux->policy_data, 827 circ, 828 direction, 829 cell_count); 830 /* If we wanted policy data, it's an error not to get any */ 831 tor_assert(hashent->muxinfo.policy_data); 832 } 833 HT_INSERT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, 834 hashent); 835 836 /* Update counters */ 837 ++(cmux->n_circuits); 838 if (cell_count > 0) { 839 ++(cmux->n_active_circuits); 840 circuitmux_make_circuit_active(cmux, circ); 841 } 842 cmux->n_cells += cell_count; 843 } 844 } 845 846 /** 847 * Detach a circuit from a circuitmux and update all counters as needed; 848 * no-op if not attached. 849 */ 850 851 MOCK_IMPL(void, 852 circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ)) 853 { 854 chanid_circid_muxinfo_t search, *hashent = NULL; 855 /* 856 * Use this to keep track of whether we found it for n_chan or 857 * p_chan for consistency checking. 858 * 859 * The 0 initializer is not a valid cell_direction_t value. 860 * We assert that it has been replaced with a valid value before it is used. 861 */ 862 cell_direction_t last_searched_direction = 0; 863 864 tor_assert(cmux); 865 tor_assert(cmux->chanid_circid_map); 866 tor_assert(circ); 867 868 /* See if we have it for n_chan/n_circ_id */ 869 if (circ->n_chan) { 870 search.chan_id = circ->n_chan->global_identifier; 871 search.circ_id = circ->n_circ_id; 872 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map, 873 &search); 874 last_searched_direction = CELL_DIRECTION_OUT; 875 } 876 877 /* Got one? If not, see if it's an or_circuit_t and try p_chan/p_circ_id */ 878 if (!hashent) { 879 if (circ->magic == OR_CIRCUIT_MAGIC) { 880 search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; 881 if (TO_OR_CIRCUIT(circ)->p_chan) { 882 search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier; 883 hashent = HT_FIND(chanid_circid_muxinfo_map, 884 cmux->chanid_circid_map, 885 &search); 886 last_searched_direction = CELL_DIRECTION_IN; 887 } 888 } 889 } 890 891 tor_assert(last_searched_direction == CELL_DIRECTION_OUT 892 || last_searched_direction == CELL_DIRECTION_IN); 893 894 /* 895 * If hashent isn't NULL, we have a circuit to detach; don't remove it from 896 * the map until later of circuitmux_make_circuit_inactive() breaks. 897 */ 898 if (hashent) { 899 /* Update counters */ 900 --(cmux->n_circuits); 901 if (hashent->muxinfo.cell_count > 0) { 902 --(cmux->n_active_circuits); 903 /* This does policy notifies, so comes before freeing policy data */ 904 circuitmux_make_circuit_inactive(cmux, circ); 905 } 906 cmux->n_cells -= hashent->muxinfo.cell_count; 907 908 /* Free policy-specific data if we have it */ 909 if (hashent->muxinfo.policy_data) { 910 /* If we have policy data, assert that we have the means to free it */ 911 tor_assert(cmux->policy); 912 tor_assert(cmux->policy->free_circ_data); 913 /* Call free_circ_data() */ 914 cmux->policy->free_circ_data(cmux, 915 cmux->policy_data, 916 circ, 917 hashent->muxinfo.policy_data); 918 hashent->muxinfo.policy_data = NULL; 919 } 920 921 /* Consistency check: the direction must match the direction searched */ 922 tor_assert(last_searched_direction == hashent->muxinfo.direction); 923 924 /* Now remove it from the map */ 925 HT_REMOVE(chanid_circid_muxinfo_map, cmux->chanid_circid_map, hashent); 926 927 /* Wipe and free the hash entry */ 928 // This isn't sensitive, but we want to be sure to know if we're accessing 929 // this accidentally. 930 memwipe(hashent, 0xef, sizeof(*hashent)); 931 tor_free(hashent); 932 } 933 } 934 935 /** 936 * Make a circuit active; update active list and policy-specific info, but 937 * we don't mess with the counters or hash table here. 938 */ 939 940 static void 941 circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ) 942 { 943 tor_assert(cmux); 944 tor_assert(cmux->policy); 945 tor_assert(circ); 946 947 /* Policy-specific notification */ 948 if (cmux->policy->notify_circ_active) { 949 /* Okay, we need to check the circuit for policy data now */ 950 chanid_circid_muxinfo_t *hashent = circuitmux_find_map_entry(cmux, circ); 951 /* We should have found something */ 952 tor_assert(hashent); 953 /* Notify */ 954 cmux->policy->notify_circ_active(cmux, cmux->policy_data, 955 circ, hashent->muxinfo.policy_data); 956 } 957 } 958 959 /** 960 * Make a circuit inactive; update active list and policy-specific info, but 961 * we don't mess with the counters or hash table here. 962 */ 963 964 static void 965 circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ) 966 { 967 tor_assert(cmux); 968 tor_assert(cmux->policy); 969 tor_assert(circ); 970 971 /* Policy-specific notification */ 972 if (cmux->policy->notify_circ_inactive) { 973 /* Okay, we need to check the circuit for policy data now */ 974 chanid_circid_muxinfo_t *hashent = circuitmux_find_map_entry(cmux, circ); 975 /* We should have found something */ 976 tor_assert(hashent); 977 /* Notify */ 978 cmux->policy->notify_circ_inactive(cmux, cmux->policy_data, 979 circ, hashent->muxinfo.policy_data); 980 } 981 } 982 983 /** 984 * Clear the cell counter for a circuit on a circuitmux 985 */ 986 987 void 988 circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ) 989 { 990 /* This is the same as setting the cell count to zero */ 991 circuitmux_set_num_cells(cmux, circ, 0); 992 } 993 994 /** 995 * Set the cell counter for a circuit on a circuitmux 996 */ 997 998 void 999 circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ, 1000 unsigned int n_cells) 1001 { 1002 chanid_circid_muxinfo_t *hashent = NULL; 1003 1004 tor_assert(cmux); 1005 tor_assert(circ); 1006 1007 /* Search for this circuit's entry */ 1008 hashent = circuitmux_find_map_entry(cmux, circ); 1009 /* Assert that we found one */ 1010 tor_assert(hashent); 1011 1012 /* Update cmux cell counter */ 1013 cmux->n_cells -= hashent->muxinfo.cell_count; 1014 cmux->n_cells += n_cells; 1015 1016 /* Do we need to notify a cmux policy? */ 1017 if (cmux->policy->notify_set_n_cells) { 1018 /* Call notify_set_n_cells */ 1019 cmux->policy->notify_set_n_cells(cmux, 1020 cmux->policy_data, 1021 circ, 1022 hashent->muxinfo.policy_data, 1023 n_cells); 1024 } 1025 1026 /* 1027 * Update cmux active circuit counter: is the old cell count > 0 and the 1028 * new cell count == 0 ? 1029 */ 1030 if (hashent->muxinfo.cell_count > 0 && n_cells == 0) { 1031 --(cmux->n_active_circuits); 1032 hashent->muxinfo.cell_count = n_cells; 1033 circuitmux_make_circuit_inactive(cmux, circ); 1034 /* Is the old cell count == 0 and the new cell count > 0 ? */ 1035 } else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) { 1036 ++(cmux->n_active_circuits); 1037 hashent->muxinfo.cell_count = n_cells; 1038 circuitmux_make_circuit_active(cmux, circ); 1039 } else { 1040 hashent->muxinfo.cell_count = n_cells; 1041 } 1042 } 1043 1044 /* 1045 * Functions for channel code to call to get a circuit to transmit from or 1046 * notify that cells have been transmitted. 1047 */ 1048 1049 /** 1050 * Pick a circuit to send from, using the active circuits list or a 1051 * circuitmux policy if one is available. This is called from channel.c. 1052 * 1053 * If we would rather send a destroy cell, return NULL and set 1054 * *<b>destroy_queue_out</b> to the destroy queue. 1055 * 1056 * If we have nothing to send, set *<b>destroy_queue_out</b> to NULL and 1057 * return NULL. 1058 */ 1059 1060 circuit_t * 1061 circuitmux_get_first_active_circuit(circuitmux_t *cmux, 1062 destroy_cell_queue_t **destroy_queue_out) 1063 { 1064 circuit_t *circ = NULL; 1065 1066 tor_assert(cmux); 1067 tor_assert(cmux->policy); 1068 /* This callback is mandatory. */ 1069 tor_assert(cmux->policy->pick_active_circuit); 1070 tor_assert(destroy_queue_out); 1071 1072 *destroy_queue_out = NULL; 1073 1074 if (cmux->destroy_cell_queue.n && 1075 (!cmux->last_cell_was_destroy || cmux->n_active_circuits == 0)) { 1076 /* We have destroy cells to send, and either we just sent a relay cell, 1077 * or we have no relay cells to send. */ 1078 1079 /* XXXX We should let the cmux policy have some say in this eventually. */ 1080 /* XXXX Alternating is not a terribly brilliant approach here. */ 1081 *destroy_queue_out = &cmux->destroy_cell_queue; 1082 1083 cmux->last_cell_was_destroy = 1; 1084 } else if (cmux->n_active_circuits > 0) { 1085 /* We also must have a cell available for this to be the case */ 1086 tor_assert(cmux->n_cells > 0); 1087 /* Do we have a policy-provided circuit selector? */ 1088 circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data); 1089 cmux->last_cell_was_destroy = 0; 1090 } else { 1091 tor_assert(cmux->n_cells == 0); 1092 tor_assert(cmux->destroy_cell_queue.n == 0); 1093 } 1094 1095 return circ; 1096 } 1097 1098 /** 1099 * Notify the circuitmux that cells have been sent on a circuit; this 1100 * is called from channel.c. 1101 */ 1102 1103 void 1104 circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ, 1105 unsigned int n_cells) 1106 { 1107 chanid_circid_muxinfo_t *hashent = NULL; 1108 int becomes_inactive = 0; 1109 1110 tor_assert(cmux); 1111 tor_assert(circ); 1112 1113 if (n_cells == 0) return; 1114 1115 /* 1116 * To handle this, we have to: 1117 * 1118 * 1.) Adjust the circuit's cell counter in the cmux hash table 1119 * 2.) Move the circuit to the tail of the active_circuits linked list 1120 * for this cmux, or make the circuit inactive if the cell count 1121 * went to zero. 1122 * 3.) Call cmux->policy->notify_xmit_cells(), if any 1123 */ 1124 1125 /* Find the hash entry */ 1126 hashent = circuitmux_find_map_entry(cmux, circ); 1127 /* Assert that we found one */ 1128 tor_assert(hashent); 1129 1130 /* Adjust the cell counter and assert that we had that many cells to send */ 1131 tor_assert(n_cells <= hashent->muxinfo.cell_count); 1132 hashent->muxinfo.cell_count -= n_cells; 1133 /* Do we need to make the circuit inactive? */ 1134 if (hashent->muxinfo.cell_count == 0) becomes_inactive = 1; 1135 /* Adjust the mux cell counter */ 1136 cmux->n_cells -= n_cells; 1137 1138 /* 1139 * We call notify_xmit_cells() before making the circuit inactive if needed, 1140 * so the policy can always count on this coming in on an active circuit. 1141 */ 1142 if (cmux->policy->notify_xmit_cells) { 1143 cmux->policy->notify_xmit_cells(cmux, cmux->policy_data, circ, 1144 hashent->muxinfo.policy_data, 1145 n_cells); 1146 } 1147 1148 /* 1149 * Now make the circuit inactive if needed; this will call the policy's 1150 * notify_circ_inactive() if present. 1151 */ 1152 if (becomes_inactive) { 1153 --(cmux->n_active_circuits); 1154 circuitmux_make_circuit_inactive(cmux, circ); 1155 } 1156 } 1157 1158 /** 1159 * Notify the circuitmux that a destroy was sent, so we can update 1160 * the counter. 1161 */ 1162 1163 void 1164 circuitmux_notify_xmit_destroy(circuitmux_t *cmux) 1165 { 1166 tor_assert(cmux); 1167 1168 --(cmux->destroy_ctr); 1169 --(global_destroy_ctr); 1170 log_debug(LD_CIRC, 1171 "Cmux at %p sent a destroy, cmux counter is now %"PRId64", " 1172 "global counter is now %"PRId64, 1173 cmux, 1174 (cmux->destroy_ctr), 1175 (global_destroy_ctr)); 1176 } 1177 1178 /*DOCDOC */ 1179 void 1180 circuitmux_append_destroy_cell(channel_t *chan, 1181 circuitmux_t *cmux, 1182 circid_t circ_id, 1183 uint8_t reason) 1184 { 1185 destroy_cell_queue_append(&cmux->destroy_cell_queue, circ_id, reason); 1186 1187 /* Destroy entering the queue, update counters */ 1188 ++(cmux->destroy_ctr); 1189 ++global_destroy_ctr; 1190 log_debug(LD_CIRC, 1191 "Cmux at %p queued a destroy for circ %u, cmux counter is now " 1192 "%"PRId64", global counter is now %"PRId64, 1193 cmux, circ_id, 1194 (cmux->destroy_ctr), 1195 (global_destroy_ctr)); 1196 1197 /* XXXX Duplicate code from append_cell_to_circuit_queue */ 1198 if (!channel_has_queued_writes(chan)) { 1199 /* There is no data at all waiting to be sent on the outbuf. Add a 1200 * cell, so that we can notice when it gets flushed, flushed_some can 1201 * get called, and we can start putting more data onto the buffer then. 1202 */ 1203 log_debug(LD_GENERAL, "Primed a buffer."); 1204 channel_flush_from_first_active_circuit(chan, 1); 1205 } 1206 } 1207 1208 /*DOCDOC; for debugging 12184. This runs slowly. */ 1209 int64_t 1210 circuitmux_count_queued_destroy_cells(const channel_t *chan, 1211 const circuitmux_t *cmux) 1212 { 1213 int64_t n_destroy_cells = cmux->destroy_ctr; 1214 int64_t destroy_queue_size = cmux->destroy_cell_queue.n; 1215 1216 int64_t manual_total = 0; 1217 int64_t manual_total_in_map = 0; 1218 destroy_cell_t *cell; 1219 1220 TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) { 1221 circid_t id; 1222 ++manual_total; 1223 1224 id = cell->circid; 1225 if (circuit_id_in_use_on_channel(id, (channel_t*)chan)) 1226 ++manual_total_in_map; 1227 } 1228 1229 if (n_destroy_cells != destroy_queue_size || 1230 n_destroy_cells != manual_total || 1231 n_destroy_cells != manual_total_in_map) { 1232 log_warn(LD_BUG, " Discrepancy in counts for queued destroy cells on " 1233 "circuitmux. n=%"PRId64". queue_size=%"PRId64". " 1234 "manual_total=%"PRId64". manual_total_in_map=%"PRId64".", 1235 (n_destroy_cells), 1236 (destroy_queue_size), 1237 (manual_total), 1238 (manual_total_in_map)); 1239 } 1240 1241 return n_destroy_cells; 1242 } 1243 1244 /** 1245 * Compare cmuxes to see which is more preferred; return < 0 if 1246 * cmux_1 has higher priority (i.e., cmux_1 < cmux_2 in the scheduler's 1247 * sort order), > 0 if cmux_2 has higher priority, or 0 if they are 1248 * equally preferred. 1249 * 1250 * If the cmuxes have different cmux policies or the policy does not 1251 * support the cmp_cmux method, return 0. 1252 */ 1253 1254 MOCK_IMPL(int, 1255 circuitmux_compare_muxes, (circuitmux_t *cmux_1, circuitmux_t *cmux_2)) 1256 { 1257 const circuitmux_policy_t *policy; 1258 1259 tor_assert(cmux_1); 1260 tor_assert(cmux_2); 1261 1262 if (cmux_1 == cmux_2) { 1263 /* Equivalent because they're the same cmux */ 1264 return 0; 1265 } 1266 1267 if (cmux_1->policy && cmux_2->policy) { 1268 if (cmux_1->policy == cmux_2->policy) { 1269 policy = cmux_1->policy; 1270 1271 if (policy->cmp_cmux) { 1272 /* Okay, we can compare! */ 1273 return policy->cmp_cmux(cmux_1, cmux_1->policy_data, 1274 cmux_2, cmux_2->policy_data); 1275 } else { 1276 /* 1277 * Equivalent because the policy doesn't know how to compare between 1278 * muxes. 1279 */ 1280 return 0; 1281 } 1282 } else { 1283 /* Equivalent because they have different policies */ 1284 return 0; 1285 } 1286 } else { 1287 /* Equivalent because one or both are missing a policy */ 1288 return 0; 1289 } 1290 }