Tor 0.4.9.2-alpha-dev
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
conflux.c
Go to the documentation of this file.
1/* Copyright (c) 2021, The Tor Project, Inc. */
2/* See LICENSE for licensing information */
3
4/**
5 * \file conflux.c
6 * \brief Conflux multipath core algorithms
7 */
8
9#include "core/or/relay_msg.h"
10#define TOR_CONFLUX_PRIVATE
11
12#include "core/or/or.h"
13
14#include "core/or/circuit_st.h"
15#include "core/or/sendme.h"
16#include "core/or/relay.h"
20#include "core/or/circuitlist.h"
21#include "core/or/circuituse.h"
22#include "core/or/conflux.h"
26#include "core/or/conflux_st.h"
29#include "app/config/config.h"
30
31/** One million microseconds in a second */
32#define USEC_PER_SEC 1000000
33
34static inline uint64_t cwnd_sendable(const circuit_t *on_circ,
35 uint64_t in_usec, uint64_t our_usec);
36
37/* Track the total number of bytes used by all ooo_q so it can be used by the
38 * OOM handler to assess.
39 *
40 * When adding or subtracting to this value, use conflux_msg_alloc_cost(). */
41static uint64_t total_ooo_q_bytes = 0;
42
43/**
44 * Determine if we should multiplex a specific relay command or not.
45 *
46 * TODO: Version of this that is the set of forbidden commands
47 * on linked circuits
48 */
49bool
50conflux_should_multiplex(int relay_command)
51{
52 switch (relay_command) {
53 /* These are all fine to multiplex, and must be
54 * so that ordering is preserved */
55 case RELAY_COMMAND_BEGIN:
56 case RELAY_COMMAND_DATA:
57 case RELAY_COMMAND_END:
58 case RELAY_COMMAND_CONNECTED:
59 return true;
60
61 /* We can't multiplex these because they are
62 * circuit-specific */
63 case RELAY_COMMAND_SENDME:
64 case RELAY_COMMAND_EXTEND:
65 case RELAY_COMMAND_EXTENDED:
66 case RELAY_COMMAND_TRUNCATE:
67 case RELAY_COMMAND_TRUNCATED:
68 case RELAY_COMMAND_DROP:
69 return false;
70
71 /* We must multiplex RESOLVEs because their ordering
72 * impacts begin/end. */
73 case RELAY_COMMAND_RESOLVE:
74 case RELAY_COMMAND_RESOLVED:
75 return true;
76
77 /* These are all circuit-specific */
78 case RELAY_COMMAND_BEGIN_DIR:
79 case RELAY_COMMAND_EXTEND2:
80 case RELAY_COMMAND_EXTENDED2:
81 case RELAY_COMMAND_ESTABLISH_INTRO:
82 case RELAY_COMMAND_ESTABLISH_RENDEZVOUS:
83 case RELAY_COMMAND_INTRODUCE1:
84 case RELAY_COMMAND_INTRODUCE2:
85 case RELAY_COMMAND_RENDEZVOUS1:
86 case RELAY_COMMAND_RENDEZVOUS2:
87 case RELAY_COMMAND_INTRO_ESTABLISHED:
88 case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED:
89 case RELAY_COMMAND_INTRODUCE_ACK:
90 case RELAY_COMMAND_PADDING_NEGOTIATE:
91 case RELAY_COMMAND_PADDING_NEGOTIATED:
92 return false;
93
94 /* These must be multiplexed because their ordering
95 * relative to BEGIN/END must be preserved */
96 case RELAY_COMMAND_XOFF:
97 case RELAY_COMMAND_XON:
98 return true;
99
100 /* These two are not multiplexed, because they must
101 * be processed immediately to update sequence numbers
102 * before any other cells are processed on the circuit */
103 case RELAY_COMMAND_CONFLUX_SWITCH:
104 case RELAY_COMMAND_CONFLUX_LINK:
105 case RELAY_COMMAND_CONFLUX_LINKED:
106 case RELAY_COMMAND_CONFLUX_LINKED_ACK:
107 return false;
108
109 default:
110 log_warn(LD_BUG, "Conflux asked to multiplex unknown relay command %d",
111 relay_command);
112 return false;
113 }
114}
115
116/** Return the leg for a circuit in a conflux set. Return NULL if not found. */
119{
120 conflux_leg_t *leg_found = NULL;
121 tor_assert(cfx);
122 tor_assert(cfx->legs);
123
124 // Find the leg that the cell is written on
126 if (leg->circ == circ) {
127 leg_found = leg;
128 break;
129 }
130 } CONFLUX_FOR_EACH_LEG_END(leg);
131
132 return leg_found;
133}
134
135/**
136 * Gets the maximum last_seq_sent from all legs.
137 */
138uint64_t
140{
141 uint64_t max_seq_sent = 0;
142
144 if (leg->last_seq_sent > max_seq_sent) {
145 max_seq_sent = leg->last_seq_sent;
146 }
147 } CONFLUX_FOR_EACH_LEG_END(leg);
148
149 return max_seq_sent;
150}
151
152/**
153 * Gets the maximum last_seq_recv from all legs.
154 */
155uint64_t
157{
158 uint64_t max_seq_recv = 0;
159
161 if (leg->last_seq_recv > max_seq_recv) {
162 max_seq_recv = leg->last_seq_recv;
163 }
164 } CONFLUX_FOR_EACH_LEG_END(leg);
165
166 return max_seq_recv;
167}
168
169/** Return the total memory allocation the circuit is using by conflux. If this
170 * circuit is not a Conflux circuit, 0 is returned. */
171uint64_t
173{
174 if (circ->conflux) {
175 return smartlist_len(circ->conflux->ooo_q) * sizeof(void*)
176 + circ->conflux->ooo_q_alloc_cost;
177 }
178 return 0;
179}
180
181/** Return the total memory allocation in bytes by the subsystem.
182 *
183 * At the moment, only out of order queues are consiered. */
184uint64_t
186{
187 return total_ooo_q_bytes;
188}
189
190/** The OOM handler is asking us to try to free at least bytes_to_remove. */
191size_t
192conflux_handle_oom(size_t bytes_to_remove)
193{
194 (void) bytes_to_remove;
195
196 /* We are not doing anything on the sets, the OOM handler will trigger a
197 * circuit clean up which will affect conflux sets, by pruning oldest
198 * circuits. */
199
200 log_info(LD_CIRC, "OOM handler triggered. OOO queus allocation: %" PRIu64,
201 total_ooo_q_bytes);
202 return 0;
203}
204
205/**
206 * Returns true if a circuit has package window space to send, and is
207 * not blocked locally.
208 */
209static inline bool
211{
212 const congestion_control_t *cc = circuit_ccontrol(circ);
213 bool cc_sendable = true;
214
215 /* We consider ourselves blocked if we're within 1 sendme of the
216 * cwnd, because inflight is decremented before this check */
217 // TODO-329-TUNING: This subtraction not be right.. It depends
218 // on call order wrt decisions and sendme arrival
219 if (cc->inflight >= cc->cwnd) {
220 cc_sendable = false;
221 }
222
223 /* Origin circuits use the package window of the last hop, and
224 * have an outbound cell direction (towards exit). Otherwise,
225 * there is no cpath and direction is inbound. */
226 if (CIRCUIT_IS_ORIGIN(circ)) {
227 return cc_sendable && !circ->circuit_blocked_on_n_chan;
228 } else {
229 return cc_sendable && !circ->circuit_blocked_on_p_chan;
230 }
231}
232
233/**
234 * Return the circuit with the minimum RTT. Do not use any
235 * other circuit.
236 *
237 * This algorithm will minimize RTT always, and will not provide
238 * any throughput benefit. We expect it to be useful for VoIP/UDP
239 * use cases. Because it only uses one circuit on a leg at a time,
240 * it can have more than one circuit per guard (ie: to find
241 * lower-latency middles for the path).
242 */
243static const circuit_t *
245{
246 uint64_t min_rtt = UINT64_MAX;
247 const circuit_t *circ = NULL;
248
249 /* Can't get here without any legs. */
251
253
254 /* Ignore circuits with no RTT measurement */
255 if (leg->circ_rtts_usec && leg->circ_rtts_usec < min_rtt) {
256 circ = leg->circ;
257 min_rtt = leg->circ_rtts_usec;
258 }
259 } CONFLUX_FOR_EACH_LEG_END(leg);
260
261 /* If the minRTT circuit can't send, dont send on any circuit. */
262 if (!circ || !circuit_ready_to_send(circ)) {
263 return NULL;
264 }
265 return circ;
266}
267
268/**
269 * Favor the circuit with the lowest RTT that still has space in the
270 * congestion window.
271 *
272 * This algorithm will maximize total throughput at the expense of
273 * bloating out-of-order queues.
274 */
275static const circuit_t *
277{
278 uint64_t low_rtt = UINT64_MAX;
279 const circuit_t *circ = NULL;
280
281 /* Can't get here without any legs. */
283
285 /* If the package window is full, skip it */
286 if (!circuit_ready_to_send(leg->circ)) {
287 continue;
288 }
289
290 /* Ignore circuits with no RTT */
291 if (leg->circ_rtts_usec && leg->circ_rtts_usec < low_rtt) {
292 low_rtt = leg->circ_rtts_usec;
293 circ = leg->circ;
294 }
295 } CONFLUX_FOR_EACH_LEG_END(leg);
296
297 /* At this point, if we found a circuit, we've already validated that its
298 * congestion window has room. */
299 return circ;
300}
301
302/**
303 * Returns the amount of room in a cwnd on a circuit.
304 */
305static inline uint64_t
307{
308 const congestion_control_t *cc = circuit_ccontrol(on_circ);
309 tor_assert(cc);
310
311 if (cc->cwnd < cc->inflight)
312 return 0;
313
314 return cc->cwnd - cc->inflight;
315}
316
317/**
318 * Return the amount of congestion window we can send on
319 * on_circ during in_usec. However, if we're still in
320 * slow-start, send the whole window to establish the true
321 * cwnd.
322 */
323static inline uint64_t
324cwnd_sendable(const circuit_t *on_circ, uint64_t in_usec,
325 uint64_t our_usec)
326{
327 const congestion_control_t *cc = circuit_ccontrol(on_circ);
328 tor_assert(cc);
329 uint64_t cwnd_adjusted = cwnd_available(on_circ);
330
331 if (our_usec == 0 || in_usec == 0) {
332 log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
333 "cwnd_sendable: Missing RTT data. in_usec: %" PRIu64
334 " our_usec: %" PRIu64, in_usec, our_usec);
335 return cwnd_adjusted;
336 }
337
338 if (cc->in_slow_start) {
339 return cwnd_adjusted;
340 } else {
341 /* For any given leg, it has min_rtt/2 time before the 'primary'
342 * leg's acks start arriving. So, the amount of data this
343 * 'secondary' leg can send while the min_rtt leg transmits these
344 * acks is:
345 * (cwnd_leg/(leg_rtt/2))*min_rtt/2 = cwnd_leg*min_rtt/leg_rtt.
346 */
347 uint64_t sendable = cwnd_adjusted*in_usec/our_usec;
348 return MIN(cc->cwnd, sendable);
349 }
350}
351
352/**
353 * Returns true if we can switch to a new circuit, false otherwise.
354 *
355 * This function assumes we're primarily switching between two circuits,
356 * the current and the prev. If we're using more than two circuits, we
357 * need to set cfx_drain_pct to 100.
358 */
359static inline bool
361{
362 /* If we still expected to send more cells on this circuit,
363 * we're only allowed to switch if the previous circuit emptied. */
364 if (cfx->cells_until_switch > 0) {
365 /* If there is no prev leg, skip the inflight check. */
366 if (!cfx->prev_leg) {
367 return false;
368 }
369 const congestion_control_t *ccontrol =
371
372 /* If the inflight count has drained to below cfx_drain_pct
373 * of the congestion window, then we can switch.
374 * We check the sendme_inc because there may be un-ackable
375 * data in inflight as well, and we can still switch then. */
376 // TODO-329-TUNING: Should we try to switch if the prev_leg is
377 // ready to send, instead of this?
378 if (ccontrol->inflight < ccontrol->sendme_inc ||
379 100*ccontrol->inflight <=
381 return true;
382 }
383
384 return false;
385 }
386
387 return true;
388}
389
390/**
391 * Favor the circuit with the lowest RTT that still has space in the
392 * congestion window up to the ratio of RTTs.
393 *
394 * This algorithm should only use auxillary legs up to the point
395 * where their data arrives roughly the same time as the lowest
396 * RTT leg. It will not utilize the full cwnd of auxillary legs,
397 * except in slow start. Therefore, out-of-order queue bloat should
398 * be minimized to just the slow-start phase.
399 */
400static const circuit_t *
402{
403 uint64_t min_rtt = UINT64_MAX;
404 const conflux_leg_t *leg = NULL;
405
406 /* Can't get here without any legs. */
408
409 /* Find the leg with the minimum RTT.*/
411 /* Ignore circuits with invalid RTT */
412 if (l->circ_rtts_usec && l->circ_rtts_usec < min_rtt) {
413 min_rtt = l->circ_rtts_usec;
414 leg = l;
415 }
416 } CONFLUX_FOR_EACH_LEG_END(l);
417
418 /* If the package window is has room, use it */
419 if (leg && circuit_ready_to_send(leg->circ)) {
420 return leg->circ;
421 }
422
423 leg = NULL;
424
426 if (!circuit_ready_to_send(l->circ)) {
427 continue;
428 }
429
430 /* Pick a 'min_leg' with the lowest RTT that still has
431 * room in the congestion window. Note that this works for
432 * min_leg itself, up to inflight. */
433 if (l->circ_rtts_usec &&
434 cwnd_sendable(l->circ, min_rtt, l->circ_rtts_usec) > 0) {
435 leg = l;
436 }
437 } CONFLUX_FOR_EACH_LEG_END(l);
438
439 /* If the circuit can't send, don't send on any circuit. */
440 if (!leg || !circuit_ready_to_send(leg->circ)) {
441 return NULL;
442 }
443 return leg->circ;
444}
445
446/**
447 * This function is called when we want to send a relay cell on a
448 * conflux, as well as when we want to compute available space in
449 * to package from streams.
450 *
451 * It determines the circuit that relay command should be sent on,
452 * and sends a SWITCH cell if necessary.
453 *
454 * It returns the circuit we should send on. If no circuits are ready
455 * to send, it returns NULL.
456 */
457circuit_t *
459 circuit_t *orig_circ,
460 uint8_t relay_command)
461{
462 /* If this command should not be multiplexed, send it on the original
463 * circuit */
464 if (!conflux_should_multiplex(relay_command)) {
465 return orig_circ;
466 }
467
468 circuit_t *new_circ = conflux_decide_next_circ(cfx);
469
470 /* Because our congestion window only cover relay data command, we can end up
471 * in a situation where we need to send non data command when all circuits
472 * are at capacity. For those cases, keep using the *current* leg,
473 * so these commands arrive in-order. */
474 if (!new_circ && relay_command != RELAY_COMMAND_DATA) {
475 /* Curr leg should be set, because conflux_decide_next_circ() should
476 * have set it earlier. No BUG() here because the only caller BUG()s. */
477 if (!cfx->curr_leg) {
478 log_warn(LD_BUG, "No current leg for conflux with relay command %d",
479 relay_command);
480 return NULL;
481 }
482 return cfx->curr_leg->circ;
483 }
484
485 /*
486 * If we are switching to a new circuit, we need to send a SWITCH command.
487 * We also need to compute an estimate of how much data we can send on
488 * the new circuit before we are allowed to switch again, to rate
489 * limit the frequency of switching.
490 */
491 if (new_circ) {
492 conflux_leg_t *new_leg = conflux_get_leg(cfx, new_circ);
493 tor_assert(cfx->curr_leg);
494
495 if (new_circ != cfx->curr_leg->circ) {
496 // TODO-329-TUNING: This is one mechanism to rate limit switching,
497 // which should reduce the OOQ mem. However, we're not going to do that
498 // until we get some data on if the memory usage is high
499 cfx->cells_until_switch = 0;
500 //cwnd_sendable(new_circ,cfx->curr_leg->circ_rtts_usec,
501 // new_leg->circ_rtts_usec);
502
504
505 cfx->prev_leg = cfx->curr_leg;
506 cfx->curr_leg = new_leg;
507
508 tor_assert(cfx->prev_leg);
509 tor_assert(cfx->curr_leg);
510
511 uint64_t relative_seq = cfx->prev_leg->last_seq_sent -
513
515 cfx->curr_leg->last_seq_sent);
516 conflux_send_switch_command(cfx->curr_leg->circ, relative_seq);
518 }
519 }
520
521 return new_circ;
522}
523
524/** Called after conflux actually sent a cell on a circuit.
525 * This function updates sequence number counters, and
526 * switch counters.
527 */
528void
529conflux_note_cell_sent(conflux_t *cfx, circuit_t *circ, uint8_t relay_command)
530{
531 conflux_leg_t *leg = NULL;
532
533 if (!conflux_should_multiplex(relay_command)) {
534 return;
535 }
536
537 leg = conflux_get_leg(cfx, circ);
538 if (leg == NULL) {
539 log_fn(LOG_PROTOCOL_WARN, LD_BUG, "No Conflux leg after sending a cell");
540 return;
541 }
542
543 leg->last_seq_sent++;
544
545 if (cfx->cells_until_switch > 0) {
546 cfx->cells_until_switch--;
547 }
548}
549
550/** Find the leg with lowest non-zero curr_rtt_usec, and
551 * pick it for our current leg. */
552static inline bool
554{
555 conflux_leg_t *min_leg = NULL;
556
558 /* We need to skip 0-RTT legs, since this can happen at the exit
559 * when there is a race between BEGIN and LINKED_ACK, and BEGIN
560 * wins the race. The good news is that because BEGIN won,
561 * we don't need to consider those other legs, since they are
562 * slower. */
563 if (leg->circ_rtts_usec > 0) {
564 if (!min_leg || leg->circ_rtts_usec < min_leg->circ_rtts_usec) {
565 min_leg = leg;
566 }
567 }
568 } CONFLUX_FOR_EACH_LEG_END(leg);
569
570 if (!min_leg) {
571 // Get the 0th leg; if it does not exist, log the set.
572 // Bug 40827 managed to hit this, so let's dump the sets
573 // in case it happens again.
574 if (BUG(smartlist_len(cfx->legs) <= 0)) {
575 // Since we have no legs, we have no idea if this is really a client
576 // or server set. Try to find any that match:
577 log_warn(LD_BUG, "Matching client sets:");
578 conflux_log_set(LOG_WARN, cfx, true);
579 log_warn(LD_BUG, "Matching server sets:");
580 conflux_log_set(LOG_WARN, cfx, false);
581 log_warn(LD_BUG, "End conflux set dump");
582 return false;
583 }
584
585 min_leg = smartlist_get(cfx->legs, 0);
586 tor_assert(min_leg);
587 if (BUG(min_leg->linked_sent_usec == 0)) {
588 log_warn(LD_BUG, "Conflux has no legs with non-zero RTT. "
589 "Using first leg.");
591 }
592 }
593
594 // TODO-329-TUNING: We may want to initialize this to a cwnd, to
595 // minimize early switching?
596 //cfx->cells_until_switch = circuit_ccontrol(min_leg->circ)->cwnd;
597 cfx->cells_until_switch = 0;
598
599 cfx->curr_leg = min_leg;
600
601 return true;
602}
603
604/**
605 * Returns the circuit that conflux would send on next, if
606 * conflux_decide_circ_for_send were called. This is used to compute
607 * available space in the package window.
608 */
609circuit_t *
611{
612 // TODO-329-TUNING: Temporarily validate legs here. We can remove
613 // this once tuning is complete.
615
616 /* If the conflux set is tearing down and has no current leg,
617 * bail and give up */
618 if (cfx->in_full_teardown) {
619 return NULL;
620 }
621
622 /* If we don't have a current leg yet, pick one.
623 * (This is the only non-const operation in this function). */
624 if (!cfx->curr_leg) {
625 if (!conflux_pick_first_leg(cfx))
626 return NULL;
627 }
628
629 /* First, check if we can switch. */
630 if (!conflux_can_switch(cfx)) {
631 tor_assert(cfx->curr_leg);
632 circuit_t *curr_circ = cfx->curr_leg->circ;
633
634 /* If we can't switch, and the current circuit can't send,
635 * then return null. */
636 if (circuit_ready_to_send(curr_circ)) {
637 return curr_circ;
638 }
639 log_info(LD_CIRC, "Conflux can't switch; no circuit to send on.");
640 return NULL;
641 }
642
643 switch (cfx->params.alg) {
644 case CONFLUX_ALG_MINRTT: // latency (no ooq)
646 case CONFLUX_ALG_LOWRTT: // high throughput (high oooq)
648 case CONFLUX_ALG_CWNDRTT: // throughput (low oooq)
650 default:
651 return NULL;
652 }
653}
654
655/**
656 * Called when we have a new RTT estimate for a circuit.
657 */
658void
659conflux_update_rtt(conflux_t *cfx, circuit_t *circ, uint64_t rtt_usec)
660{
661 conflux_leg_t *leg = conflux_get_leg(cfx, circ);
662
663 if (!leg) {
664 log_warn(LD_BUG, "Got RTT update for circuit not in conflux");
665 return;
666 }
667
668 // Update RTT
669 leg->circ_rtts_usec = rtt_usec;
670
671 // TODO-329-ARTI: For UDP latency targeting, arti could decide to launch
672 // new a test leg to potentially replace this one, if a latency target
673 // was requested and we now exceed it. Since C-Tor client likely
674 // will not have UDP support, we aren't doing this here.
675}
676
677/**
678 * Comparison function for ooo_q pqueue.
679 *
680 * Ensures that lower sequence numbers are at the head of the pqueue.
681 */
682static int
683conflux_queue_cmp(const void *a, const void *b)
684{
685 // Compare a and b as conflux_cell_t using the seq field, and return a
686 // comparison result such that the lowest seq is at the head of the pqueue.
687 const conflux_msg_t *cell_a = a;
688 const conflux_msg_t *cell_b = b;
689
690 tor_assert(cell_a);
691 tor_assert(cell_b);
692
693 if (cell_a->seq < cell_b->seq) {
694 return -1;
695 } else if (cell_a->seq > cell_b->seq) {
696 return 1;
697 } else {
698 return 0;
699 }
700}
701
702/**
703 * Get the congestion control object for a conflux circuit.
704 *
705 * Because conflux can only be negotiated with the last hop, we
706 * can use the last hop of the cpath to obtain the congestion
707 * control object for origin circuits. For non-origin circuits,
708 * we can use the circuit itself.
709 */
712{
713 const congestion_control_t *ccontrol = NULL;
714 tor_assert(circ);
715
716 if (CIRCUIT_IS_ORIGIN(circ)) {
717 tor_assert(CONST_TO_ORIGIN_CIRCUIT(circ)->cpath);
718 tor_assert(CONST_TO_ORIGIN_CIRCUIT(circ)->cpath->prev);
719 ccontrol = CONST_TO_ORIGIN_CIRCUIT(circ)->cpath->prev->ccontrol;
720 } else {
721 ccontrol = circ->ccontrol;
722 }
723
724 /* Conflux circuits always have congestion control*/
725 tor_assert(ccontrol);
726 return ccontrol;
727}
728
729// TODO-329-TUNING: For LowRTT, we can at most switch every SENDME,
730// but for BLEST, we should switch at most every cwnd.. But
731// we do not know the other side's CWND here.. We can at best
732// asssume it is above the cwnd_min
733#define CONFLUX_MIN_LINK_INCREMENT 31
734/**
735 * Validate and handle RELAY_COMMAND_CONFLUX_SWITCH.
736 */
737int
739 crypt_path_t *layer_hint,
740 const relay_msg_t *msg)
741{
742 tor_assert(in_circ);
743 tor_assert(msg);
744
745 conflux_t *cfx = in_circ->conflux;
746 uint32_t relative_seq;
747 conflux_leg_t *leg;
748
749 if (!conflux_is_enabled(in_circ)) {
750 circuit_mark_for_close(in_circ, END_CIRC_REASON_TORPROTOCOL);
751 return -1;
752 }
753
754 /* If there is no conflux object negotiated, this is invalid.
755 * log and close circ */
756 if (!cfx) {
757 log_warn(LD_BUG, "Got a conflux switch command on a circuit without "
758 "conflux negotiated. Closing circuit.");
759
760 circuit_mark_for_close(in_circ, END_CIRC_REASON_TORPROTOCOL);
761 return -1;
762 }
763
764 // TODO-329-TUNING: Temporarily validate that we have all legs.
765 // After tuning is complete, we can remove this.
767
768 leg = conflux_get_leg(cfx, in_circ);
769
770 /* If we can't find the conflux leg, we got big problems..
771 * Close the circuit. */
772 if (!leg) {
773 log_warn(LD_BUG, "Got a conflux switch command on a circuit without "
774 "conflux leg. Closing circuit.");
775 circuit_mark_for_close(in_circ, END_CIRC_REASON_INTERNAL);
776 return -1;
777 }
778
779 // Check source hop via layer_hint
780 if (!conflux_validate_source_hop(in_circ, layer_hint)) {
781 log_warn(LD_BUG, "Got a conflux switch command on a circuit with "
782 "invalid source hop. Closing circuit.");
783 circuit_mark_for_close(in_circ, END_CIRC_REASON_TORPROTOCOL);
784 return -1;
785 }
786
787 relative_seq = conflux_cell_parse_switch(msg);
788
789 /*
790 * We have to make sure that the switch command is truely
791 * incrementing the sequence number, or else it becomes
792 * a side channel that can be spammed for traffic analysis.
793 */
794 // TODO-329-TUNING: This can happen. Disabling for now..
795 //if (relative_seq < CONFLUX_MIN_LINK_INCREMENT) {
796 // log_warn(LD_CIRC, "Got a conflux switch command with a relative "
797 // "sequence number less than the minimum increment. Closing "
798 // "circuit.");
799 // circuit_mark_for_close(in_circ, END_CIRC_REASON_TORPROTOCOL);
800 // return -1;
801 //}
802
803 // TODO-329-UDP: When Prop#340 exits and was negotiated, ensure we're
804 // in a packed cell, with another cell following, otherwise
805 // this is a spammed side-channel.
806 // - We definitely should never get switches back-to-back.
807 // - We should not get switches across all legs with no data
808 // But before Prop#340, it doesn't make much sense to do this.
809 // C-Tor is riddled with side-channels like this anyway, unless
810 // vanguards is in use. And this feature is not supported by
811 // onion servicees in C-Tor, so we're good there.
812
813 /* Update the absolute sequence number on this leg by the delta.
814 * Since this cell is not multiplexed, we do not count it towards
815 * absolute sequence numbers. We only increment the sequence
816 * numbers for multiplexed cells. Hence there is no +1 here. */
817 leg->last_seq_recv += relative_seq;
818
819 /* Mark this data as validated for controlport and vanguards
820 * dropped cell handling */
821 if (CIRCUIT_IS_ORIGIN(in_circ)) {
822 circuit_read_valid_data(TO_ORIGIN_CIRCUIT(in_circ), msg->length);
823 }
824
825 return 0;
826}
827
828/**
829 * Return the total number of required allocated to store `msg`.
830 */
831static inline size_t
833{
834 return msg->msg->length + sizeof(conflux_msg_t) + sizeof(relay_msg_t);
835}
836
837/**
838 * Process an incoming relay cell for conflux. Called from
839 * connection_edge_process_relay_cell().
840 *
841 * Returns true if the conflux system now has well-ordered cells to deliver
842 * to streams, false otherwise.
843 */
844bool
846 crypt_path_t *layer_hint, const relay_msg_t *msg)
847{
848 // TODO-329-TUNING: Temporarily validate legs here. We can remove
849 // this after tuning is complete.
851
852 conflux_leg_t *leg = conflux_get_leg(cfx, in_circ);
853 if (!leg) {
854 log_warn(LD_BUG, "Got a conflux cell on a circuit without "
855 "conflux leg. Closing circuit.");
856 circuit_mark_for_close(in_circ, END_CIRC_REASON_INTERNAL);
857 return false;
858 }
859
860 /* We need to make sure this cell came from the expected hop, or
861 * else it could be a data corruption attack from a middle node. */
862 if (!conflux_validate_source_hop(in_circ, layer_hint)) {
863 circuit_mark_for_close(in_circ, END_CIRC_REASON_TORPROTOCOL);
864 return false;
865 }
866
867 /* Update the running absolute sequence number */
868 leg->last_seq_recv++;
869
870 /* If this cell is next, fast-path it by processing the cell in-place */
871 if (leg->last_seq_recv == cfx->last_seq_delivered + 1) {
872 /* The cell is now ready to be processed, and rest of the queue should
873 * now be checked for remaining elements */
874 cfx->last_seq_delivered++;
875 return true;
876 } else if (BUG(leg->last_seq_recv <= cfx->last_seq_delivered)) {
877 log_warn(LD_BUG, "Got a conflux cell with a sequence number "
878 "less than the last delivered. Closing circuit.");
879 circuit_mark_for_close(in_circ, END_CIRC_REASON_INTERNAL);
880 return false;
881 } else {
882 conflux_msg_t *c_msg = tor_malloc_zero(sizeof(conflux_msg_t));
883 c_msg->seq = leg->last_seq_recv;
884 /* Notice the copy here. Reason is that we don't have ownership of the
885 * message. If we wanted to pull that off, we would need to change the
886 * whole calling stack and unit tests on either not touching it after this
887 * function indicates that it has taken it or never allocate it from the
888 * stack. This is simpler and less error prone but might show up in our
889 * profile (maybe?). The Maze is serious. It needs to be respected. */
890 c_msg->msg = relay_msg_copy(msg);
891 size_t cost = conflux_msg_alloc_cost(c_msg);
892
894 offsetof(conflux_msg_t, heap_idx), c_msg);
895
896 total_ooo_q_bytes += cost;
897 cfx->ooo_q_alloc_cost += cost;
898
899 /* This cell should not be processed yet, and the queue is not ready
900 * to process because the next absolute seqnum has not yet arrived */
901 return false;
902 }
903}
904
905/**
906 * Dequeue the top cell from our queue.
907 *
908 * Returns the cell as a conflux_cell_t, or NULL if the queue is empty
909 * or has a hole.
910 */
913{
914 conflux_msg_t *top = NULL;
915 if (smartlist_len(cfx->ooo_q) == 0)
916 return NULL;
917
918 top = smartlist_get(cfx->ooo_q, 0);
919
920 /* If the top cell is the next sequence number we need, then
921 * pop and return it. */
922 if (top->seq == cfx->last_seq_delivered+1) {
924 offsetof(conflux_msg_t, heap_idx));
925
926 size_t cost = conflux_msg_alloc_cost(top);
927 total_ooo_q_bytes -= cost;
928 cfx->ooo_q_alloc_cost -= cost;
929
930 cfx->last_seq_delivered++;
931 return top;
932 } else {
933 return NULL;
934 }
935}
936
937/** Free a given conflux msg object. */
938void
940{
941 if (msg) {
942 relay_msg_free(msg->msg);
943 tor_free(msg);
944 }
945}
Base circuit structure.
origin_circuit_t * TO_ORIGIN_CIRCUIT(circuit_t *x)
Definition: circuitlist.c:185
Header file for circuitlist.c.
#define CIRCUIT_IS_ORIGIN(c)
Definition: circuitlist.h:154
void circuit_read_valid_data(origin_circuit_t *circ, uint16_t relay_body_len)
Definition: circuituse.c:3202
Header file for circuituse.c.
Functions and types for monotonic times.
Header file for config.c.
void conflux_note_cell_sent(conflux_t *cfx, circuit_t *circ, uint8_t relay_command)
Definition: conflux.c:529
static uint64_t cwnd_sendable(const circuit_t *on_circ, uint64_t in_usec, uint64_t our_usec)
Definition: conflux.c:324
static bool conflux_pick_first_leg(conflux_t *cfx)
Definition: conflux.c:553
void conflux_update_rtt(conflux_t *cfx, circuit_t *circ, uint64_t rtt_usec)
Definition: conflux.c:659
static size_t conflux_msg_alloc_cost(conflux_msg_t *msg)
Definition: conflux.c:832
bool conflux_should_multiplex(int relay_command)
Definition: conflux.c:50
circuit_t * conflux_decide_next_circ(conflux_t *cfx)
Definition: conflux.c:610
static int conflux_queue_cmp(const void *a, const void *b)
Definition: conflux.c:683
static const circuit_t * conflux_decide_circ_lowrtt(const conflux_t *cfx)
Definition: conflux.c:276
static uint64_t cwnd_available(const circuit_t *on_circ)
Definition: conflux.c:306
uint64_t conflux_get_circ_bytes_allocation(const circuit_t *circ)
Definition: conflux.c:172
const congestion_control_t * circuit_ccontrol(const circuit_t *circ)
Definition: conflux.c:711
uint64_t conflux_get_max_seq_recv(const conflux_t *cfx)
Definition: conflux.c:156
uint64_t conflux_get_max_seq_sent(const conflux_t *cfx)
Definition: conflux.c:139
void conflux_relay_msg_free_(conflux_msg_t *msg)
Definition: conflux.c:939
static bool conflux_can_switch(const conflux_t *cfx)
Definition: conflux.c:360
circuit_t * conflux_decide_circ_for_send(conflux_t *cfx, circuit_t *orig_circ, uint8_t relay_command)
Definition: conflux.c:458
static const circuit_t * conflux_decide_circ_cwndrtt(const conflux_t *cfx)
Definition: conflux.c:401
conflux_msg_t * conflux_dequeue_relay_msg(conflux_t *cfx)
Definition: conflux.c:912
conflux_leg_t * conflux_get_leg(conflux_t *cfx, const circuit_t *circ)
Definition: conflux.c:118
bool conflux_process_relay_msg(conflux_t *cfx, circuit_t *in_circ, crypt_path_t *layer_hint, const relay_msg_t *msg)
Definition: conflux.c:845
static const circuit_t * conflux_decide_circ_minrtt(const conflux_t *cfx)
Definition: conflux.c:244
int conflux_process_switch_command(circuit_t *in_circ, crypt_path_t *layer_hint, const relay_msg_t *msg)
Definition: conflux.c:738
size_t conflux_handle_oom(size_t bytes_to_remove)
Definition: conflux.c:192
static bool circuit_ready_to_send(const circuit_t *circ)
Definition: conflux.c:210
uint64_t conflux_get_total_bytes_allocation(void)
Definition: conflux.c:185
Public APIs for conflux multipath support.
#define CONFLUX_FOR_EACH_LEG_BEGIN(cfx, var)
Definition: conflux.h:20
#define CONFLUX_NUM_LEGS(cfx)
Definition: conflux.h:26
uint32_t conflux_cell_parse_switch(const relay_msg_t *msg)
Definition: conflux_cell.c:287
bool conflux_send_switch_command(circuit_t *send_circ, uint64_t relative_seq)
Definition: conflux_cell.c:311
Header file for conflux_cell.c.
Header file for conflux_params.c.
uint8_t conflux_params_get_drain_pct(void)
void conflux_log_set(int loglevel, const conflux_t *cfx, bool is_client)
Header file for conflux_pool.c.
Structure definitions for conflux multipath.
void conflux_validate_stream_lists(const conflux_t *cfx)
Definition: conflux_util.c:373
void conflux_validate_legs(const conflux_t *cfx)
Definition: conflux_util.c:405
bool conflux_validate_source_hop(circuit_t *in_circ, crypt_path_t *layer_hint)
Definition: conflux_util.c:145
Header file for conflux_util.c.
Public APIs for congestion control.
Structure definitions for congestion control.
#define log_fn(severity, domain, args,...)
Definition: log.h:283
#define LD_BUG
Definition: log.h:86
#define LD_CIRC
Definition: log.h:82
#define LOG_WARN
Definition: log.h:53
#define tor_free(p)
Definition: malloc.h:56
Master header file for Tor-specific functionality.
Origin circuit structure.
Header file for relay.c.
relay_msg_t * relay_msg_copy(const relay_msg_t *msg)
Definition: relay_msg.c:68
Header file for relay_msg.c.
Header file for sendme.c.
void * smartlist_pqueue_pop(smartlist_t *sl, int(*compare)(const void *a, const void *b), ptrdiff_t idx_field_offset)
Definition: smartlist.c:755
void smartlist_pqueue_add(smartlist_t *sl, int(*compare)(const void *a, const void *b), ptrdiff_t idx_field_offset, void *item)
Definition: smartlist.c:726
unsigned int circuit_blocked_on_n_chan
Definition: circuit_st.h:92
unsigned int circuit_blocked_on_p_chan
Definition: circuit_st.h:95
struct conflux_t * conflux
Definition: circuit_st.h:273
struct congestion_control_t * ccontrol
Definition: circuit_st.h:260
uint64_t last_seq_sent
Definition: conflux_st.h:66
uint64_t last_seq_recv
Definition: conflux_st.h:47
uint64_t circ_rtts_usec
Definition: conflux_st.h:75
uint64_t linked_sent_usec
Definition: conflux_st.h:79
circuit_t * circ
Definition: conflux_st.h:82
uint64_t seq
Definition: conflux.h:33
relay_msg_t * msg
Definition: conflux.h:42
smartlist_t * ooo_q
Definition: conflux_st.h:103
struct conflux_leg_t * curr_leg
Definition: conflux_st.h:123
struct conflux_params_t params
Definition: conflux_st.h:88
struct conflux_leg_t * prev_leg
Definition: conflux_st.h:127
uint64_t cells_until_switch
Definition: conflux_st.h:119
size_t ooo_q_alloc_cost
Definition: conflux_st.h:109
uint64_t last_seq_delivered
Definition: conflux_st.h:114
smartlist_t * legs
Definition: conflux_st.h:93
bool in_full_teardown
Definition: conflux_st.h:135
struct crypt_path_t * prev
Definition: crypt_path_st.h:78
struct congestion_control_t * ccontrol
Definition: crypt_path_st.h:87
crypt_path_t * cpath
#define tor_assert(expr)
Definition: util_bug.h:103