1 QUIC Connection ID Cache 2 ======================== 3 4 The connection ID cache is responsible for managing connection IDs, both local 5 and remote. 6 7 Remote Connection IDs 8 --------------------- 9 10 For remote connection IDs, we need to be able to: 11 12 * add new IDs per connection; 13 * pick a non-retired ID associated from those available for a connection and 14 * select a connection ID by sequence number and retire that and all older IDs. 15 16 The cache will be implemented as a double ended queue as part of the 17 QUIC_CONNECTION object. The queue will be sorted by sequence number 18 and must maintain a count of the number of connection IDs present. 19 There is no requirement to maintain a global mapping since remote IDs 20 are only used when sending packets, not receiving them. 21 22 In MVP, a many-to-1 matching of Connection IDs per Connection object 23 is required. Refer third paragraph in [5.1]. 24 25 When picking a non-retired connection ID for MVP, the youngest available will 26 be chosen. 27 28 Local Connection IDs 29 -------------------- 30 31 For local connection IDs, we need to be able to: 32 33 * generate a new connection ID and associate it with a connection; 34 * query if a connection ID is present; 35 * for a server, map a connection ID to a QUIC_CONNECTION; 36 * drop all connection IDs associated with a QUIC_CONNECTION; 37 * select a connection ID by sequence number and retire that and all older IDs 38 and 39 * select a connection ID by sequence number and drop that and all older IDs. 40 41 All connection IDs issued by our stack must be the same length because 42 short form packets include the connection ID but no length byte. Random 43 connection IDs of this length will be allocated. Note that no additional 44 information will be contained in the connection ID. 45 46 There will be one global set of local connection IDs, `QUIC_ROUTE_TABLE`, 47 which is shared by all connections over all SSL_CTX objects. This is 48 used to dispatch incoming datagrams to their correct destination and 49 will be implemented as a dictionary. 50 51 ### Notes 52 53 * For MVP, it would be sufficient to only use a zero length connection ID. 54 * For MVP, a connection ID to QUIC_CONNECTION mapping need not be implemented. 55 * Post MVP, funnelling all received packets through a single socket is 56 likely to be bottleneck. 57 An alternative would be receiving from <host address, source port> pairs. 58 * For MVP, the local connection ID cache need only have one element. 59 I.e. there is no requirement to implement any form of lookup. 60 61 Routes 62 ------ 63 64 A pair of connection IDs identify a route between the two ends of the 65 communication. This contains the connection IDs of both ends of the 66 connection and the common sequence number. We need to be able to: 67 68 * select a connection ID by sequence number and retire that and all older IDs 69 and 70 * select a connection ID by sequence number and drop that and all older IDs. 71 72 It is likely that operations on local and remote connection IDs can be 73 subsumed by the route functionality. 74 75 ID Retirement 76 ------------- 77 78 Connection IDs are retired by either a [NEW_CONNECTION_ID] or 79 a [RETIRE_CONNECTION_ID] frame and this is acknowledged by a 80 RETIRE_CONNECTION_ID or a NEW_CONNECTION_ID frame respectively. 81 82 When a retirement frame is received, we can immediately _remove_ the 83 IDs covered from our cache and then send back an acknowledgement of 84 the retirement. 85 86 If we want to retire a frame, we send a retirement frame and mark the 87 IDs covered in our cache as _retired_. This means that we cannot send 88 using any of these IDs but can still receive using them. Once our peer 89 acknowledges the retirement, we can _remove_ the IDs. 90 91 It is possible to receive out of order packets **after** receiving a 92 retirement notification. It's unclear what to do with these, however 93 dropping them seems reasonable. The alternative would be to maintain 94 the route in a _deletable_ state until all packets in flight at the time 95 of retirement have been acked. 96 97 API 98 --- 99 100 QUIC connection IDs are defined in #18949 but some extra functions 101 are available: 102 103 ```c 104 /* QUIC connection ID representation. */ 105 #define QUIC_MAX_CONN_ID_LEN 20 106 107 typedef struct quic_conn_id_st { 108 unsigned char id_len; 109 unsigned char id[QUIC_MAX_CONN_ID_LEN]; 110 #if 0 111 /* likely required later, although this might not be the ideal location */ 112 unsigned char reset_token[16]; /* stateless reset token is per conn ID */ 113 #endif 114 } QUIC_CONN_ID; 115 116 static ossl_unused ossl_inline int ossl_quic_conn_id_eq(const QUIC_CONN_ID *a, 117 const QUIC_CONN_ID *b); 118 119 /* New functions */ 120 int ossl_quic_conn_id_set(QUIC_CONN_ID *cid, unsigned char *id, 121 unsigned int id_len); 122 123 int ossl_quic_conn_id_generate(QUIC_CONN_ID *cid); 124 ``` 125 126 ### Remote Connection ID APIs 127 128 ```c 129 typedef struct quic_remote_conn_id_cache_st QUIC_REMOTE_CONN_ID_CACHE; 130 131 /* 132 * Allocate and free a remote connection ID cache 133 */ 134 QUIC_REMOTE_CONN_ID_CACHE *ossl_quic_remote_conn_id_cache_new( 135 size_t id_limit /* [active_connection_id_limit] */ 136 ); 137 void ossl_quic_remote_conn_id_cache_free(QUIC_REMOTE_CONN_ID_CACHE *cache); 138 139 /* 140 * Add a remote connection ID to the cache 141 */ 142 int ossl_quic_remote_conn_id_cache_add(QUIC_REMOTE_CONN_ID_CACHE *cache, 143 const QUIC_CONNECTION *conn, 144 const unsigned char *conn_id, 145 size_t conn_id_len, 146 uint64_t seq_no); 147 148 /* 149 * Query a remote connection for a connection ID. 150 * Each connection can have multiple connection IDs associated with different 151 * routes. This function returns one of these in a non-specified manner. 152 */ 153 int ossl_quic_remote_conn_id_cache_get0_conn_id( 154 const QUIC_REMOTE_CONN_ID_CACHE *cache, 155 const QUIC_CONNECTION *conn, QUIC_CONN_ID **cid); 156 157 /* 158 * Retire remote connection IDs up to and including the one determined by the 159 * sequence number. 160 */ 161 int ossl_quic_remote_conn_id_cache_retire( 162 QUIC_REMOTE_CONN_ID_CACHE *cache, uint64_t seq_no); 163 164 /* 165 * Remove remote connection IDs up to and including the one determined by the 166 * sequence number. 167 */ 168 int ossl_quic_remote_conn_id_cache_remove( 169 QUIC_REMOTE_CONN_ID_CACHE *cache, uint64_t seq_no); 170 ``` 171 172 ### Local Connection ID APIs 173 174 ```c 175 typedef struct quic_local_conn_id_cache_st QUIC_LOCAL_CONN_ID_CACHE; 176 177 /* 178 * Allocate and free a local connection ID cache 179 */ 180 QUIC_LOCAL_CONN_ID_CACHE *ossl_quic_local_conn_id_cache_new(void); 181 void ossl_quic_local_conn_id_cache_free(QUIC_LOCAL_CONN_ID_CACHE *cache); 182 183 /* 184 * Generate a new random local connection ID and associate it with a connection. 185 * For MVP this could just be a zero length ID. 186 */ 187 int ossl_quic_local_conn_id_cache_new_conn_id(QUIC_LOCAL_CONN_ID_CACHE *cache, 188 QUIC_CONNECTION *conn, 189 QUIC_CONN_ID **cid); 190 191 /* 192 * Remove a local connection and all associated cached IDs 193 */ 194 int ossl_quic_local_conn_id_cache_remove_conn(QUIC_LOCAL_CONN_ID_CACHE *cache, 195 const QUIC_CONNECTION *conn); 196 197 /* 198 * Lookup a local connection by ID. 199 * Returns the connection or NULL if absent. 200 */ 201 QUIC_CONNECTION *ossl_quic_local_conn_id_cache_get0_conn( 202 const QUIC_LOCAL_CONN_ID_CACHE *cache, 203 const unsigned char *conn_id, size_t conn_id_len); 204 205 /* 206 * Retire local connection IDs up to and including the one specified by the 207 * sequence number. 208 */ 209 int ossl_quic_local_conn_id_cache_retire( 210 QUIC_LOCAL_CONN_ID_CACHE *cache, uint64_t from_seq_no); 211 212 /* 213 * Remove local connection IDs up to and including the one specified by the 214 * sequence number. 215 */ 216 int ossl_quic_local_conn_id_cache_remove( 217 QUIC_LOCAL_CONN_ID_CACHE *cache, uint64_t from_seq_no); 218 ``` 219 220 ### Routes 221 222 Additional status and source information is also included. 223 224 ```c 225 typedef struct quic_route_st QUIC_ROUTE; 226 typedef struct quic_route_table QUIC_ROUTE_TABLE; 227 228 struct quic_route_st { 229 QUIC_CONNECTION *conn; 230 QUIC_CONN_ID local; 231 QUIC_CONN_ID remote; 232 uint64_t seq_no; /* Sequence number for both ends */ 233 unsigned int retired : 1; /* Connection ID has been retired */ 234 #if 0 235 /* Later will require */ 236 BIO_ADDR remote_address;/* remote source address */ 237 #endif 238 }; 239 240 QUIC_ROUTE_TABLE *ossl_quic_route_table_new(void); 241 void ossl_quic_route_table_free(QUIC_ROUTE_TABLE *routes); 242 ``` 243 244 ### Add route to route table 245 246 ```c 247 int ossl_route_table_add_route(QUIC_ROUTE_TABLE *cache, 248 QUIC_ROUTE_TABLE *route); 249 ``` 250 251 ### Route query 252 253 ```c 254 /* 255 * Query a route table entry by either local or remote ID 256 */ 257 QUIC_ROUTE *ossl_route_table_get0_route_from_local( 258 const QUIC_ROUTE_TABLE *cache, 259 const unsigned char *conn_id, size_t conn_id_len); 260 QUIC_ROUTE *ossl_route_table_get0_route_from_remote( 261 const QUIC_ROUTE_TABLE *cache, 262 const unsigned char *conn_id, size_t conn_id_len); 263 ``` 264 265 ### Route retirement 266 267 ```c 268 /* 269 * Retire by sequence number up to and including the one specified. 270 */ 271 int ossl_quic_route_table_retire(QUIC_ROUTE_TABLE *routes, 272 QUIC_CONNECTION *conn, 273 uint64_t seq_no); 274 275 /* 276 * Delete by sequence number up to and including the one specified. 277 */ 278 int ossl_quic_route_table_remove(QUIC_ROUTE_TABLE *routes, 279 QUIC_CONNECTION *conn, 280 uint64_t seq_no); 281 ``` 282 283 [5.1]: (https://datatracker.ietf.org/doc/html/rfc9000#section-5.1) 284 [active_connection_id_limit]: (https://datatracker.ietf.org/doc/html/rfc9000#section-18.2) 285 [NEW_CONNECTION_ID]: (https://datatracker.ietf.org/doc/html/rfc9000#section-19.15) 286 [RETIRE_CONNECTION_ID]: (https://datatracker.ietf.org/doc/html/rfc9000#section-19.16) 287 [retired]: (https://datatracker.ietf.org/doc/html/rfc9000#section-5.1.2) 288