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