Skip to content

Commit

Permalink
QUIC RCIDM: Minor updates
Browse files Browse the repository at this point in the history
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from #23022)
  • Loading branch information
hlandau authored and t8m committed Jan 11, 2024
1 parent ad08c81 commit 9eabb30
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 25 deletions.
15 changes: 14 additions & 1 deletion doc/designs/quic-design/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ in which API calls can be made on different threads.
**MSST:** Multi-stream single-thread. Refers to a type of multi-stream QUIC
usage in which API calls must not be made concurrently.

**NCID:** New Connection ID. Refers to a QUIC `NEW_CONNECTION_ID` frame.

**Numbered CID:** Refers to a Connection ID which has a sequence number assigned
to it. All CIDs other than Initial ODCIDs and Retry ODCIDs have a sequence
number assigned. See also Unnumbered CID.

**ODCID:** Original Destination CID. This is the DCID found in the first Initial
packet sent by a client, and is used to generate the secrets for encrypting
Initial packets. It is only used temporarily.
Expand Down Expand Up @@ -195,7 +201,8 @@ an API object. As such, a `QUIC_CONNECTION` is to a `QUIC_CHANNEL` what a
`QUIC_XSO` is to a `QUIC_STREAM`.

**RCID:** Remote CID. Refers to a CID which has been provided to us by a peer
and which we can place in the DCID field of an outgoing packet. See also LCID.
and which we can place in the DCID field of an outgoing packet. See also LCID,
Unnumbered CID and Numbered CID.

**RCIDM:** Remote CID Manager. Tracks RCIDs which have been provided to us by a
peer. See also LCIDM.
Expand Down Expand Up @@ -284,6 +291,12 @@ to a *send stream buffer*, and that data is eventually TX'd by the TXP and QTX.)
**Uni:** Abbreviation of unidirectional, referring to a QUIC unidirectional
stream.

**Unnumbered CID:** Refers to a CID which does not have a sequence number
associated with it and therefore cannot be referred to by a `NEW_CONNECTION_ID`
or `RETIRE_CONNECTION_ID` frame's sequence number fields. The only unnumbered
CIDs are Initial ODCIDs and Retry ODCIDs. These CIDs are exceptionally retired
automatically during handshake confirmation. See also Numbered CID.

**URXE:** Unprocessed RX entry. Structure containing yet-undecrypted received
datagrams pending processing. Stored in a queue known as the URXL.
Ownership of URXEs is shared between DEMUX and QRX.
Expand Down
2 changes: 1 addition & 1 deletion fuzz/quic-rcidm.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len)
goto err;
}

ossl_quic_rcidm_add_from_initial(rcidm, &arg_cid);
ossl_quic_rcidm_add_from_server_retry(rcidm, &arg_cid);
break;

case CMD_ADD_FROM_NCID:
Expand Down
17 changes: 9 additions & 8 deletions include/internal/quic_rcidm.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
* QUIC Remote Connection ID Manager
* =================================
*
* This manages connection IDs for the TX side, which is to say that it tracks
* remote CIDs (RCIDs) which a peer has issued to us and which we can use as the
* DCID of packets we transmit. It is entirely separate from the LCIDM, which
* handles routing received packets by their DCIDs.
* This manages connection IDs for the TX side. The RCIDM tracks remote CIDs
* (RCIDs) which a peer has issued to us and which we can use as the DCID of
* packets we transmit. It is entirely separate from the LCIDM, which handles
* routing received packets by their DCIDs.
*
* RCIDs fall into four categories:
*
Expand All @@ -42,8 +42,8 @@ typedef struct quic_rcidm_st QUIC_RCIDM;
/*
* Creates a new RCIDM. Returns NULL on failure.
*
* For a client, initial_rcid is the client's Initial ODCID.
* For a server, initial_rcid is NULL.
* For a client, initial_odcid is the client's Initial ODCID.
* For a server, initial_odcid is NULL.
*/
QUIC_RCIDM *ossl_quic_rcidm_new(const QUIC_CONN_ID *initial_odcid);

Expand Down Expand Up @@ -135,12 +135,13 @@ void ossl_quic_rcidm_request_roll(QUIC_RCIDM *rcidm);
* packets using the RCID may still be in flight. The caller must determine an
* appropriate delay using knowledge of network conditions (RTT, etc.) which is
* outside the scope of the RCIDM. The caller is responsible for implementing
* this delay.
* this delay based on the last time a packet was transmitted using the RCID
* being retired.
*/
int ossl_quic_rcidm_pop_retire_seq_num(QUIC_RCIDM *rcid, uint64_t *seq_num);

/*
* Like ossl_quic_rcidm_pop_retire_seek_num, but does not pop the item from the
* Like ossl_quic_rcidm_pop_retire_seq_num, but does not pop the item from the
* queue. If this call succeeds, the next call to
* ossl_quic_rcidm_pop_retire_seq_num is guaranteed to output the same sequence
* number.
Expand Down
39 changes: 24 additions & 15 deletions ssl/quic/quic_rcidm.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ static void rcidm_update(QUIC_RCIDM *rcidm);
static void rcidm_set_preferred_rcid(QUIC_RCIDM *rcidm,
const QUIC_CONN_ID *rcid);

#define PACKETS_PER_RCID 1000
#define PACKETS_PER_RCID 10000

#define INITIAL_SEQ_NUM 0
#define PREF_ADDR_SEQ_NUM 1
Expand Down Expand Up @@ -124,7 +124,7 @@ enum {
};

typedef struct rcid_st {
OSSL_LIST_MEMBER(retiring, struct rcid_st); /* valid iff retire == 1 */
OSSL_LIST_MEMBER(retiring, struct rcid_st); /* valid iff RETIRING */

QUIC_CONN_ID cid; /* The actual CID string for this RCID */
uint64_t seq_num;
Expand Down Expand Up @@ -162,6 +162,11 @@ struct quic_rcidm_st {
/*
* The current RCID we prefer to use (value undefined if
* !have_preferred_rcid).
*
* This is preferentially set to a numbered RCID (represented by an RCID
* object) if we have one (in which case preferred_rcid == cur_rcid->cid);
* otherwise it is set to one of the unnumbered RCIDs (the Initial ODCID or
* Retry ODCID) if available (and cur_rcid == NULL).
*/
QUIC_CONN_ID preferred_rcid;

Expand Down Expand Up @@ -189,11 +194,11 @@ struct quic_rcidm_st {
PRIORITY_QUEUE_OF(RCID) *rcids;

/*
* Current RCID we are using. This may differ from the first item in the
* priority queue if we received NCID frames out of order. For example if we
* get seq 5, switch to it immediately, then get seq 4, we want to keep
* using seq 5 until we decide to roll again rather than immediately switch
* to seq 4. Never points to an object on the retiring_list.
* Current RCID object we are using. This may differ from the first item in
* the priority queue if we received NCID frames out of order. For example
* if we get seq 5, switch to it immediately, then get seq 4, we want to
* keep using seq 5 until we decide to roll again rather than immediately
* switch to seq 4. Never points to an object on the retiring_list.
*/
RCID *cur_rcid;

Expand Down Expand Up @@ -229,6 +234,14 @@ struct quic_rcidm_st {
unsigned int roll_requested : 1;
};

/*
* Caller must periodically pop retired RCIDs and handle them. If the caller
* fails to do so, fail safely rather than start exhibiting integer rollover.
* Limit the total number of numbered RCIDs to an implausibly large but safe
* value.
*/
#define MAX_NUMBERED_RCIDS (SIZE_MAX / 2)

static void rcidm_transition_rcid(QUIC_RCIDM *rcidm, RCID *rcid,
unsigned int state);

Expand All @@ -254,7 +267,6 @@ static void rcidm_check_rcid(QUIC_RCIDM *rcidm, RCID *rcid)
|| rcid->state == RCID_STATE_RETIRING);
assert(rcidm->num_changes == 0 || rcidm->handshake_complete);
assert(rcid->state != RCID_STATE_RETIRING || rcidm->num_retiring > 0);
assert(rcidm->num_retiring < SIZE_MAX / 2);
}

static int rcid_cmp(const RCID *a, const RCID *b)
Expand All @@ -263,10 +275,6 @@ static int rcid_cmp(const RCID *a, const RCID *b)
return -1;
if (a->seq_num > b->seq_num)
return 1;
if ((uintptr_t)a < (uintptr_t)b)
return -1;
if ((uintptr_t)a > (uintptr_t)b)
return 1;
return 0;
}

Expand Down Expand Up @@ -337,7 +345,9 @@ static RCID *rcidm_create_rcid(QUIC_RCIDM *rcidm, uint64_t seq_num,
RCID *rcid;

if (cid->id_len < 1 || cid->id_len > QUIC_MAX_CONN_ID_LEN
|| seq_num > OSSL_QUIC_VLINT_MAX)
|| seq_num > OSSL_QUIC_VLINT_MAX
|| ossl_pqueue_RCID_num(rcidm->rcids) + rcidm->num_retiring
> MAX_NUMBERED_RCIDS)
return NULL;

if ((rcid = OPENSSL_zalloc(sizeof(*rcid))) == NULL)
Expand All @@ -351,7 +361,6 @@ static RCID *rcidm_create_rcid(QUIC_RCIDM *rcidm, uint64_t seq_num,
rcid->state = RCID_STATE_PENDING;

if (!ossl_pqueue_RCID_push(rcidm->rcids, rcid, &rcid->pq_idx)) {
assert(0);
OPENSSL_free(rcid);
return NULL;
}
Expand Down Expand Up @@ -501,7 +510,7 @@ static void rcidm_update(QUIC_RCIDM *rcidm)
* If there are no RCIDs from NCID frames we can use, go through the various
* kinds of bootstrapping RCIDs we can use in order of priority.
*/
if (rcidm->added_retry_odcid) {
if (rcidm->added_retry_odcid && !rcidm->handshake_complete) {
rcidm_set_preferred_rcid(rcidm, &rcidm->retry_odcid);
return;
}
Expand Down
5 changes: 5 additions & 0 deletions test/quic_rcidm_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ static const QUIC_CONN_ID cid8_3 = { 8, { 3 } };
static const QUIC_CONN_ID cid8_4 = { 8, { 4 } };
static const QUIC_CONN_ID cid8_5 = { 8, { 5 } };

/*
* 0: Client, Initial ODCID
* 1: Client, Initial ODCID + Retry ODCID
* 2: Server, doesn't start with Initial ODCID
*/
static int test_rcidm(int idx)
{
int testresult = 0;
Expand Down

0 comments on commit 9eabb30

Please sign in to comment.