16 #include <sys/socket.h> 22 #include <vpp/app/version.h> 31 #include <quicly/constants.h> 32 #include <quicly/defaults.h> 35 #define quic_error(n,s) s, 70 kv->
key[1] = data->
quicly_ctx.transport_params.max_stream_data.bidi_local;
71 kv->
key[2] = data->
quicly_ctx.transport_params.max_stream_data.bidi_remote;
98 for (i = 0; i < num_threads; i++)
102 if (crctx->ckpair_index == ckpair->cert_key_index)
104 quic_crypto_context_make_key_from_crctx (&kv, crctx);
105 clib_bihash_add_del_24_8 (&qm->wrk_ctx[i].crypto_context_hash, &kv, 0 );
132 ASSERT (cr_index >> 24 == thread_index);
134 cr_index & 0x00ffffff);
146 for (i = 0; i < num_threads; i++)
150 vlib_cli_output (vm,
"[%d][Q]%U", i, format_crypto_context, crctx);
170 quicly_context_t *quicly_ctx;
171 ptls_iovec_t key_vec;
175 ptls_context_t *ptls_ctx;
178 ctx->c_thread_index);
183 crctx->
data = (
void *) data;
187 ptls_ctx->random_bytes = ptls_openssl_random_bytes;
188 ptls_ctx->get_time = &ptls_get_time;
189 ptls_ctx->key_exchanges = ptls_openssl_key_exchanges;
191 ptls_ctx->certificates.list =
NULL;
192 ptls_ctx->certificates.count = 0;
193 ptls_ctx->esni =
NULL;
194 ptls_ctx->on_client_hello =
NULL;
195 ptls_ctx->emit_certificate =
NULL;
196 ptls_ctx->sign_certificate =
NULL;
197 ptls_ctx->verify_certificate =
NULL;
198 ptls_ctx->ticket_lifetime = 86400;
199 ptls_ctx->max_early_data_size = 8192;
200 ptls_ctx->hkdf_label_prefix__obsolete =
NULL;
201 ptls_ctx->require_dhe_on_psk = 1;
203 clib_memcpy (quicly_ctx, &quicly_spec_context,
sizeof (quicly_context_t));
206 quicly_ctx->tls = ptls_ctx;
210 quicly_amend_ptls_context (quicly_ctx->tls);
213 quicly_ctx->transport_params.max_streams_uni = (uint64_t) 1 << 60;
214 quicly_ctx->transport_params.max_streams_bidi = (uint64_t) 1 << 60;
218 quicly_ctx->transport_params.max_stream_data.bidi_local =
220 quicly_ctx->transport_params.max_stream_data.bidi_remote =
222 quicly_ctx->transport_params.max_stream_data.uni =
QUIC_INT_MAX;
233 quicly_ctx->cid_encryptor =
234 quicly_new_default_cid_encryptor (&ptls_openssl_bfecb,
235 &ptls_openssl_aes128ecb,
236 &ptls_openssl_sha256, key_vec);
239 if (!ckpair || !ckpair->
key || !ckpair->
cert)
246 QUIC_DBG (1,
"failed to read private key from app configuration\n");
251 QUIC_DBG (1,
"failed to load certificate\n");
267 QUIC_DBG (2,
"No crypto engine specified, using %d",
273 QUIC_DBG (1,
"Quic does not support crypto engine %d",
275 return VNET_API_ERROR_MISSING_CERT_KEY;
280 if (clib_bihash_search_24_8
300 clib_bihash_add_del_24_8 (&qm->
301 wrk_ctx[ctx->c_thread_index].crypto_context_hash,
307 return VNET_API_ERROR_MISSING_CERT_KEY;
321 ctx->c_thread_index = thread_index;
323 QUIC_DBG (3,
"Allocated quic_ctx %u on thread %u",
324 ctx - qm->
ctx_pool[thread_index], thread_index);
325 return ctx - qm->
ctx_pool[thread_index];
331 QUIC_DBG (2,
"Free ctx %u %x", ctx->c_thread_index, ctx->c_c_index);
332 u32 thread_index = ctx->c_thread_index;
357 conn_data = (
u64) * quicly_get_data (conn);
358 return quic_ctx_get (conn_data & UINT32_MAX, conn_data >> 32);
364 *quicly_get_data (conn) =
365 (
void *) (((
u64) ctx->c_thread_index) << 32 | (
u64) ctx->c_c_index);
399 const quicly_cid_plaintext_t *
id)
401 kv->
key[0] = ((
u64) id->master_id) << 32 | (
u64) id->thread_id;
402 kv->
key[1] = id->node_id;
414 static quicly_context_t *
424 static quicly_context_t *
447 tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
453 QUIC_DBG (4,
"Stopping timer for ctx %u", ctx->c_c_index);
464 quicly_stream_t *stream;
477 quicly_stream_sync_recvbuf (stream, stream_data->
app_rx_data_len - max_deq);
502 QUIC_DBG (2,
"Deleting connection %u", ctx->c_c_index);
511 QUIC_DBG (2,
"Deleting conn with id %lu %lu from map", kv.
key[0],
518 quicly_free (ctx->
conn);
536 QUIC_DBG (2,
"QUIC connection %u/%u closed", ctx->c_thread_index,
581 len = packet->data.len;
587 QUIC_ERR (
"Too much data to send, max_enqueue %u, len %u",
602 QUIC_ASSERT (packet->dest.sa.sa_family == AF_INET);
603 struct sockaddr_in *sa4 = (
struct sockaddr_in *) &packet->dest.sa;
605 hdr.
rmt_ip.ip4.as_u32 = sa4->sin_addr.s_addr;
609 QUIC_ASSERT (packet->dest.sa.sa_family == AF_INET6);
610 struct sockaddr_in6 *sa6 = (
struct sockaddr_in6 *) &packet->dest.sa;
616 if (ret !=
sizeof (hdr))
618 QUIC_ERR (
"Not enough space to enqueue header");
624 QUIC_ERR (
"Not enough space to enqueue payload");
639 size_t num_packets,
i, max_packets;
640 quicly_packet_allocator_t *pa;
668 num_packets = max_packets;
669 if ((err = quicly_send (conn, packets, &num_packets)))
672 for (i = 0; i != num_packets; ++
i)
677 pa->free_packet (pa, packets[i]);
680 while (num_packets > 0 && num_packets == max_packets);
691 if (err && err != QUICLY_ERROR_PACKET_IGNORED
692 && err != QUICLY_ERROR_FREE_CONNECTION)
707 sctx->c_thread_index);
708 QUIC_DBG (2,
"DESTROYED_STREAM: session 0x%lx (%U)",
727 sctx->c_thread_index);
728 clib_warning (
"(NOT IMPLEMENTD) STOP_SENDING: session 0x%lx (%U)",
743 sctx->c_thread_index);
755 QUIC_DBG (3,
"received data: %lu bytes, offset %lu", len, off);
756 u32 max_enq, rlen, rv;
769 QUIC_DBG (3,
"Enqueuing %u at off %u in %u space", len, off, max_enq);
771 if (off < stream_data->app_rx_data_len)
773 QUIC_DBG (3,
"Session [idx %u, app_wrk %u, thread %u, rx-fifo 0x%llx]: " 774 "DUPLICATE PACKET (max_enq %u, len %u, " 775 "app_rx_data_len %u, off %u, ToBeNQ %u)",
785 QUIC_ERR (
"Session [idx %u, app_wrk %u, thread %u, rx-fifo 0x%llx]: " 786 "RX FIFO IS FULL (max_enq %u, len %u, " 787 "app_rx_data_len %u, off %u, ToBeNQ %u)",
799 QUIC_DBG (3,
"Session [idx %u, app_wrk %u, ti %u, rx-fifo 0x%llx]: " 800 "Enqueuing %u (rlen %u) at off %u in %u space, ",
803 stream_session->
thread_index, f, len, rlen, off, max_enq);
812 QUIC_ERR (
"Failed to ping app for RX");
843 rv = quicly_stream_sync_sendbuf (stream, 0);
849 size_t *
len,
int *wrote_all)
851 u32 deq_max, first_deq, max_rd_chunk, rem_offset;
860 QUIC_DBG (3,
"Emitting %u, offset %u", *len, off);
864 if (off + *len < deq_max)
871 *len = deq_max - off;
882 if (off < max_rd_chunk)
884 first_deq =
clib_min (*len, max_rd_chunk - off);
888 if (max_rd_chunk < off + *len)
890 rem_offset = max_rd_chunk < off ? off - max_rd_chunk : 0;
915 session_t *stream_session, *quic_session;
922 QUIC_DBG (2,
"on_stream_open called");
927 if (quicly_stream_is_self_initiated (stream))
940 QUIC_DBG (2,
"ACCEPTED stream_session 0x%lx ctx %u",
946 sctx->c_c_index = sctx_id;
951 if (quicly_stream_is_unidirectional (stream->stream_id))
952 stream_session->
flags |= SESSION_F_UNIDIRECTIONAL;
955 stream_data->
ctx_id = sctx_id;
966 quic_session =
session_get (qctx->c_s_index, qctx->c_thread_index);
972 QUIC_ERR (
"failed to allocate fifos");
982 QUIC_ERR (
"failed to notify accept worker app");
992 int code, uint64_t frame_type,
993 const char *reason,
size_t reason_len)
998 clib_warning (
"Session 0x%lx closed by peer (%U) %.*s ",
1000 reason_len, reason);
1034 tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
1038 tw_timer_expire_timers_1t_3w_1024sl_ov (tw, now);
1045 QUIC_DBG (4,
"Timer expired for conn %u at %ld", conn_index,
1055 tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
1056 int64_t next_timeout, next_interval;
1061 next_timeout = quicly_get_first_timeout (ctx->
conn);
1064 if (next_timeout == 0 || next_interval <= 0)
1072 quic_session =
session_get (ctx->c_s_index, ctx->c_thread_index);
1079 QUIC_ERR (
"Failed to enqueue builtin_tx %d", rv);
1087 QUIC_DBG (4,
"Timer set to %ld (int %ld) for ctx %u", next_timeout,
1088 next_interval, ctx->c_c_index);
1092 if (next_timeout == INT64_MAX)
1094 QUIC_DBG (4,
"timer for ctx %u already stopped", ctx->c_c_index);
1097 ctx->
timer_handle = tw_timer_start_1t_3w_1024sl_ov (tw, ctx->c_c_index,
1102 if (next_timeout == INT64_MAX)
1107 tw_timer_update_1t_3w_1024sl_ov (tw, ctx->
timer_handle,
1118 for (i = 0; i <
vec_len (expired_timers); i++)
1129 uint64_t quic_session_handle;
1132 quicly_stream_t *stream;
1133 quicly_conn_t *conn;
1141 QUIC_DBG (2,
"Opening new stream (qsession %u)", quic_session_handle);
1144 TRANSPORT_PROTO_QUIC)
1146 QUIC_ERR (
"received incompatible session");
1153 QUIC_ERR (
"Invalid app worker :(");
1171 sctx->c_c_index = sctx_index;
1177 if (!conn || !quicly_connection_is_ready (conn))
1181 quicly_open_stream (conn, &stream,
1182 sep->flags & SESSION_F_UNIDIRECTIONAL)))
1184 QUIC_DBG (2,
"Stream open failed with %d", rv);
1191 QUIC_DBG (2,
"Opened stream %d, creating session", stream->stream_id);
1194 QUIC_DBG (2,
"Allocated stream_session 0x%lx ctx %u",
1201 if (sep->flags & SESSION_F_UNIDIRECTIONAL)
1202 stream_session->
flags |= SESSION_F_UNIDIRECTIONAL;
1206 stream_data->
ctx_id = sctx->c_c_index;
1215 QUIC_ERR (
"failed to app_worker_init_connected");
1252 ctx->c_c_index = ctx_index;
1263 &sep->ip, sep->is_ip4);
1267 cargs->sep.transport_proto = TRANSPORT_PROTO_UDPC;
1269 cargs->api_context = ctx_index;
1274 cargs->sep_ext.ns_index = app->
ns_index;
1290 QUIC_DBG (2,
"Called quic_connect");
1310 ctx->c_thread_index);
1315 quicly_stream_t *stream = ctx->
stream;
1316 if (!quicly_stream_has_send_side (quicly_is_client (stream->conn),
1330 quicly_conn_t *conn = ctx->
conn;
1380 args->sep_ext = *sep;
1381 args->sep_ext.ns_index = app->
ns_index;
1382 args->sep_ext.transport_proto = TRANSPORT_PROTO_UDPC;
1387 udp_handle = args->handle;
1390 udp_listen_session->
opaque = lctx_index;
1395 clib_memcpy (&lctx->c_rmt_ip, &args->sep.peer.ip, sizeof (ip46_address_t));
1396 clib_memcpy (&lctx->c_lcl_ip, &args->sep.ip, sizeof (ip46_address_t));
1397 lctx->c_rmt_port = args->sep.peer.port;
1398 lctx->c_lcl_port = args->sep.port;
1399 lctx->c_is_ip4 = args->sep.is_ip4;
1400 lctx->c_fib_index = args->sep.fib_index;
1401 lctx->c_proto = TRANSPORT_PROTO_QUIC;
1405 lctx->c_s_index = quic_listen_session_index;
1411 QUIC_DBG (2,
"Listening UDP session 0x%lx",
1413 QUIC_DBG (2,
"Listening QUIC session 0x%lx", quic_listen_session_index);
1420 QUIC_DBG (2,
"Called quic_stop_listen");
1449 QUIC_DBG (2,
"Called quic_listener_get");
1459 u32 verbose = va_arg (*args,
u32);
1464 str =
format (str,
"[#%d][Q] ", ctx->c_thread_index);
1469 str =
format (str,
"Stream %ld conn %d",
1472 str =
format (str,
"Conn %d UDP %d", ctx->c_c_index,
1481 s =
format (s,
"%s\n", str);
1489 u32 qc_index = va_arg (*args,
u32);
1490 u32 thread_index = va_arg (*args,
u32);
1491 u32 verbose = va_arg (*args,
u32);
1500 u32 qc_index = va_arg (*args,
u32);
1501 u32 thread_index = va_arg (*args,
u32);
1503 s =
format (s,
"[#%d][Q] half-open app %u", thread_index,
1512 u32 tci = va_arg (*args,
u32);
1513 u32 thread_index = va_arg (*args,
u32);
1514 u32 verbose = va_arg (*args,
u32);
1528 struct sockaddr_in *sa4 = (
struct sockaddr_in *) sa;
1529 sa4->sin_family = AF_INET;
1530 sa4->sin_port =
port;
1531 sa4->sin_addr.s_addr = addr->ip4.as_u32;
1532 *salen =
sizeof (
struct sockaddr_in);
1536 struct sockaddr_in6 *sa6 = (
struct sockaddr_in6 *) sa;
1537 sa6->sin6_family = AF_INET6;
1538 sa6->sin6_port =
port;
1540 *salen =
sizeof (
struct sockaddr_in6);
1549 u32 ctx_id = ctx->c_c_index;
1550 u32 thread_index = ctx->c_thread_index;
1567 QUIC_ERR (
"failed to app_worker_init_connected");
1577 QUIC_ERR (
"failed to notify app %d", rv);
1588 quic_session =
session_get (ctx->c_s_index, thread_index);
1602 if (!quicly_connection_is_ready (ctx->
conn))
1605 if (!quicly_is_client (ctx->
conn))
1615 ptls_context_t **tls;
1616 quicly_context_t **_quicly_context;
1617 _quicly_context = (quicly_context_t **) conn;
1618 *_quicly_context = quicly_context;
1619 tls = (ptls_context_t **) quicly_get_tls (conn);
1620 *tls = quicly_context->tls;
1629 quicly_conn_t *conn;
1630 quicly_context_t *quicly_context;
1637 QUIC_DBG (2,
"Received conn %u (now %u)", temp_ctx->c_thread_index,
1643 new_ctx->c_thread_index = thread_index;
1644 new_ctx->c_c_index = new_ctx_id;
1647 conn = new_ctx->
conn;
1653 kv.
value = ((
u64) thread_index) << 32 | (
u64) new_ctx_id;
1654 QUIC_DBG (2,
"Registering conn with id %lu %lu", kv.
key[0], kv.
key[1]);
1661 udp_session->
opaque = new_ctx_id;
1662 udp_session->
flags &= ~SESSION_F_IS_MIGRATING;
1673 QUIC_DBG (2,
"Transferring conn %u to thread %u", ctx_index, dest_thread);
1694 QUIC_DBG (2,
"QSession is now connected (id %u)",
1699 struct sockaddr_in6 sa6;
1700 struct sockaddr *sa = (
struct sockaddr *) &sa6;
1704 quicly_conn_t *conn;
1708 quicly_context_t *quicly_ctx;
1718 api_context = ctx->c_s_index;
1724 ctx->c_thread_index = thread_index;
1725 ctx->c_c_index = ctx_index;
1727 QUIC_DBG (2,
"Quic connect returned %u. New ctx [%u]%x",
1728 is_fail, thread_index, (ctx) ? ctx_index : ~0);
1731 udp_session->
opaque = ctx_index;
1751 kv.
value = ((
u64) thread_index) << 32 | (
u64) ctx_index;
1752 QUIC_DBG (2,
"Registering conn with id %lu %lu", kv.
key[0], kv.
key[1]);
1782 ctx->c_thread_index);
1819 udp_listen_session =
1825 ctx->c_c_index = ctx_index;
1842 udp_session->
opaque = ctx_index;
1867 QUIC_DBG (3,
"Received app READ notification");
1883 quicly_stream_t *stream;
1889 (stream_session->
session_state >= SESSION_STATE_TRANSPORT_CLOSING))
1901 if (!quicly_sendstate_is_open (&stream->sendstate))
1903 QUIC_ERR (
"Warning: tried to send on closed stream");
1912 QUIC_DBG (3,
"TX but no data %d / %d", max_deq,
1917 rv = quicly_stream_sync_sendbuf (stream, 1);
1935 clib_bihash_16_8_t *
h;
1937 u32 index, thread_id;
1941 QUIC_DBG (3,
"Searching conn with id %lu %lu", kv.
key[0], kv.
key[1]);
1943 if (clib_bihash_search_16_8 (h, &kv, &kv))
1945 QUIC_DBG (3,
"connection not found");
1949 index = kv.
value & UINT32_MAX;
1950 thread_id = kv.
value >> 32;
1953 if (thread_id != caller_thread_index)
1955 QUIC_DBG (2,
"Connection is on wrong thread");
1979 quicly_context_t *quicly_ctx;
1983 quicly_conn_t *conn;
1993 QUIC_DBG (2,
"already accepted ctx 0x%x", ctx_index);
1998 if ((rv = quicly_accept (&conn, quicly_ctx,
NULL, &pctx->
sa,
2017 QUIC_DBG (2,
"Allocated quic_session, 0x%lx ctx %u",
2034 QUIC_DBG (2,
"Registering conn with id %lu %lu", kv.
key[0], kv.
key[1]);
2039 QUIC_ERR (
"failed to allocate fifos");
2047 QUIC_ERR (
"failed to notify accept worker app");
2063 QUIC_DBG (2,
"Sending stateless reset");
2065 quicly_datagram_t *dgram;
2067 quicly_context_t *quicly_ctx;
2068 if (pctx->
packet.cid.dest.plaintext.node_id != 0
2069 || pctx->
packet.cid.dest.plaintext.thread_id != 0)
2072 dgram = quicly_send_stateless_reset (quicly_ctx, &pctx->
sa,
NULL,
2073 &pctx->
packet.cid.dest.plaintext);
2090 quicly_context_t *quicly_ctx;
2099 if (full_len > cur_deq)
2101 QUIC_ERR (
"Not enough data in fifo RX");
2111 QUIC_ERR (
"Not enough data peeked in RX");
2119 plen = quicly_decode_packet (quicly_ctx, &pctx->
packet,
2122 if (plen == SIZE_MAX)
2138 else if (QUICLY_PACKET_IS_LONG_HEADER (pctx->
packet.octets.base[0]))
2162 u32 cur_deq, fifo_offset, max_packets,
i;
2166 if (udp_session->
flags & SESSION_F_IS_MIGRATING)
2168 QUIC_DBG (3,
"RX on migrating udp session");
2185 for (i = 0; i < max_packets; i++)
2191 cur_deq = max_deq - fifo_offset;
2194 max_packets = i + 1;
2199 fifo_offset = max_deq;
2200 max_packets = i + 1;
2201 QUIC_ERR (
"Fifo %d < header size in RX", cur_deq);
2205 fifo_offset, &packets_ctx[i]);
2210 max_packets = i + 1;
2215 for (i = 0; i < max_packets; i++)
2217 switch (packets_ctx[i].ptype)
2220 ctx =
quic_ctx_get (packets_ctx[i].ctx_index, thread_index);
2221 rv = quicly_receive (ctx->
conn,
NULL, &packets_ctx[i].
sa,
2223 if (rv && rv != QUICLY_ERROR_PACKET_IGNORED)
2225 QUIC_ERR (
"quicly_receive return error %U",
2237 ctx = prev_ctx =
NULL;
2238 for (i = 0; i < max_packets; i++)
2241 switch (packets_ctx[i].ptype)
2245 packets_ctx[i].thread_index);
2248 packets_ctx[i].thread_index);
2252 packets_ctx[i].thread_index);
2258 if (ctx != prev_ctx)
2339 .transport_options = {
2352 ptls_cipher_suite_t ** ciphers)
2370 (
"error while getting segment_manager_props_t, can't update fifo-size");
2381 u32 segment_size = 256 << 20;
2383 tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
2397 a->name =
format (0,
"quic");
2415 for (i = 0; i < num_threads; i++)
2423 "quic crypto contexts", 64, 128 << 10);
2426 clib_bihash_init_16_8 (&qm->
connection_hash,
"quic connections", 1024,
2443 ptls_openssl_cipher_suites);
2462 else if (
unformat (input,
"picotls"))
2487 if (tmp >= 0x100000000ULL)
2490 (0,
"fifo-size %llu (0x%llx) too large", tmp, tmp);
2520 em = &this_vlib_main->error_main;
2539 quicly_stats_t st, agg_stats;
2540 u32 i, nconn = 0, nstream = 0;
2543 for (i = 0; i < num_workers + 1; i++)
2548 if (quic_ctx_is_conn (ctx) && ctx->conn)
2550 quicly_get_stats (ctx->conn, &st);
2551 agg_stats.rtt.smoothed += st.rtt.smoothed;
2552 agg_stats.rtt.minimum += st.rtt.minimum;
2553 agg_stats.rtt.variance += st.rtt.variance;
2554 agg_stats.num_packets.received += st.num_packets.received;
2555 agg_stats.num_packets.sent += st.num_packets.sent;
2556 agg_stats.num_packets.lost += st.num_packets.lost;
2557 agg_stats.num_packets.ack_received += st.num_packets.ack_received;
2558 agg_stats.num_bytes.received += st.num_bytes.received;
2559 agg_stats.num_bytes.sent += st.num_bytes.sent;
2590 nconn > 0 ? agg_stats.rtt.minimum / nconn : 0);
2592 nconn > 0 ? agg_stats.rtt.smoothed / nconn : 0);
2594 nconn > 0 ? agg_stats.rtt.variance / nconn : 0);
2596 agg_stats.num_packets.received);
2600 agg_stats.num_packets.ack_received);
2608 quicly_cid_plaintext_t *mid = va_arg (*args, quicly_cid_plaintext_t *);
2609 s =
format (s,
"C%x_%x", mid->master_id, mid->thread_id);
2616 quicly_stream_t *stream = va_arg (*args, quicly_stream_t *);
2619 quicly_get_master_id (stream->conn), stream->stream_id);
2627 s =
format (s,
"[#%d][%x][Listener]", ctx->c_thread_index, ctx->c_c_index);
2635 quicly_stats_t quicly_stats;
2637 s =
format (s,
"[#%d][%x]", ctx->c_thread_index, ctx->c_c_index);
2641 s =
format (s,
"- no conn -\n");
2646 quicly_get_stats (ctx->
conn, &quicly_stats);
2648 s =
format (s,
"[RTT >%3d, ~%3d, V%3d, last %3d]",
2649 quicly_stats.rtt.minimum, quicly_stats.rtt.smoothed,
2650 quicly_stats.rtt.variance, quicly_stats.rtt.latest);
2651 s =
format (s,
" TX:%d RX:%d loss:%d ack:%d",
2652 quicly_stats.num_packets.sent,
2653 quicly_stats.num_packets.received,
2654 quicly_stats.num_packets.lost,
2655 quicly_stats.num_packets.ack_received);
2664 quicly_stream_t *stream = ctx->
stream;
2667 s =
format (s,
"[#%d][%x]", ctx->c_thread_index, ctx->c_c_index);
2671 if (!stream_session)
2673 s =
format (s,
"- no session -\n");
2678 s =
format (s,
"[rx %d tx %d]\n", rxs, txs);
2688 u8 show_listeners = 0, show_conn = 0, show_stream = 0;
2704 if (
unformat (line_input,
"listener"))
2706 else if (
unformat (line_input,
"conn"))
2708 else if (
unformat (line_input,
"stream"))
2718 for (
int i = 0;
i < num_workers + 1;
i++)
2723 if (quic_ctx_is_stream (ctx) && show_stream)
2724 vlib_cli_output (vm,
"%U", quic_format_stream_ctx, ctx);
2725 else if (quic_ctx_is_listener (ctx) && show_listeners)
2726 vlib_cli_output (vm,
"%U", quic_format_listener_ctx, ctx);
2727 else if (quic_ctx_is_conn (ctx) && show_conn)
2728 vlib_cli_output (vm,
"%U", quic_format_connection_ctx, ctx);
2741 .path =
"quic set crypto api",
2742 .short_help =
"quic set crypto api [picotls, vpp]",
2747 .path =
"quic set fifo-size",
2748 .short_help =
"quic set fifo-size N[K|M|G] (default 64K)",
2753 .path =
"show quic",
2754 .short_help =
"show quic",
2759 .path =
"show quic crypto context",
2760 .short_help =
"list quic crypto contextes",
2765 .version = VPP_BUILD_VER,
2766 .description =
"Quic transport protocol",
2767 .default_disabled = 1,
2785 if (tmp >= 0x100000000ULL)
2788 "fifo-size %llu (0x%llx) too large",
2793 else if (
unformat (input,
"conn-timeout %u", &i))
2795 else if (
unformat (input,
"fifo-prealloc %u", &i))
2818 .name =
"quic-input",
2819 .vector_size =
sizeof (
u32),
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
#define QUIC_RCV_MAX_BATCH_PACKETS
u8 data[QUIC_MAX_PACKET_SIZE]
static int quic_ctx_is_stream(quic_ctx_t *ctx)
int app_worker_lock_and_send_event(app_worker_t *app, session_t *s, u8 evt_type)
Send event to application.
u32 connection_index
Index of the transport connection associated to the session.
static quicly_context_t * quic_get_quicly_ctx_from_ctx(quic_ctx_t *ctx)
static quicly_closed_by_peer_t on_closed_by_peer
static int quic_process_one_rx_packet(u64 udp_session_handle, svm_fifo_t *f, u32 fifo_offset, quic_rx_packet_ctx_t *pctx)
int quic_udp_session_accepted_callback(session_t *udp_session)
int app_worker_init_accepted(session_t *s)
#define QUIC_ASSERT(truth)
static void quic_connection_delete(quic_ctx_t *ctx)
static void quic_check_quic_session_connected(quic_ctx_t *ctx)
uword * available_crypto_engines
Bitmap for registered engines.
static void quic_crypto_context_make_key_from_crctx(clib_bihash_kv_24_8_t *kv, crypto_context_t *crctx)
session_type_t session_type
Type built from transport and network protocol types.
static u32 svm_fifo_max_enqueue_prod(svm_fifo_t *f)
Maximum number of bytes that can be enqueued into fifo.
static u32 quic_stop_listen(u32 lctx_index)
quic_worker_ctx_t * wrk_ctx
static int quic_custom_app_rx_callback(transport_connection_t *tc)
static void quic_crypto_context_make_key_from_ctx(clib_bihash_kv_24_8_t *kv, quic_ctx_t *ctx)
quicly_stream_t * stream
STREAM ctx case.
u32 ns_index
Namespace the application belongs to.
static clib_error_t * quic_plugin_set_fifo_size_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
static int64_t quic_get_thread_time(u8 thread_index)
#define QUIC_SEND_PACKET_VEC_SIZE
#define QUIC_DEFAULT_CONN_TIMEOUT
struct _vnet_connect_args vnet_connect_args_t
static void quic_register_cipher_suite(crypto_engine_type_t type, ptls_cipher_suite_t **ciphers)
struct _vnet_unlisten_args_t vnet_unlisten_args_t
ptls_cipher_suite_t * quic_crypto_cipher_suites[]
static int quic_udp_session_rx_callback(session_t *udp_session)
#define QUIC_TSTAMP_RESOLUTION
u32 session_index
Index in thread pool where session was allocated.
#define session_cli_return_if_not_enabled()
#define clib_memcpy_fast(a, b, c)
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
void session_transport_delete_notify(transport_connection_t *tc)
Notification from transport that connection is being deleted.
transport_connection_t * session_get_transport(session_t *s)
static f64 vlib_time_now(vlib_main_t *vm)
svm_fifo_t * rx_fifo
Pointers to rx/tx buffers.
static session_t * session_get_if_valid(u64 si, u32 thread_index)
static int quic_on_receive(quicly_stream_t *stream, size_t off, const void *src, size_t len)
static session_t * listen_session_get_from_handle(session_handle_t handle)
static quic_ctx_t * quic_ctx_get(u32 ctx_index, u32 thread_index)
#define vec_terminate_c_string(V)
(If necessary) NULL terminate a vector containing a c-string.
int64_t time_now
worker time
static void quic_stop_ctx_timer(quic_ctx_t *ctx)
void session_send_rpc_evt_to_thread(u32 thread_index, void *fp, void *rpc_args)
int svm_fifo_peek(svm_fifo_t *f, u32 offset, u32 len, u8 *dst)
Peek data from fifo.
void session_transport_reset_notify(transport_connection_t *tc)
Notify application that connection has been reset.
static void svm_fifo_reset_has_deq_ntf(svm_fifo_t *f)
Clear has notification flag.
clib_bihash_16_8_t connection_hash
quic connection id -> conn handle
static int quic_find_packet_ctx(quic_rx_packet_ctx_t *pctx, u32 caller_thread_index)
static uword * clib_bitmap_set(uword *ai, uword i, uword value)
Sets the ith bit of a bitmap to new_value Removes trailing zeros from the bitmap. ...
static void quic_build_sockaddr(struct sockaddr *sa, socklen_t *salen, ip46_address_t *addr, u16 port, u8 is_ip4)
static u32 svm_fifo_max_enqueue(svm_fifo_t *f)
static session_t * session_get(u32 si, u32 thread_index)
static int quic_connect(transport_endpoint_cfg_t *tep)
int vnet_unlisten(vnet_unlisten_args_t *a)
static void quic_udp_session_reset_callback(session_t *s)
static void quic_timer_expired(u32 conn_index)
static int quic_connect_connection(session_endpoint_cfg_t *sep)
#define QUIC_ERROR_FULL_FIFO
f64 tstamp_ticks_per_clock
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
static void quic_expired_timers_dispatch(u32 *expired_timers)
int quic_fifo_egress_emit(quicly_stream_t *stream, size_t off, void *dst, size_t *len, int *wrote_all)
#define QUIC_DBG(_lvl, _fmt, _args...)
struct _vnet_bind_args_t vnet_listen_args_t
static session_handle_t session_handle(session_t *s)
struct _svm_fifo svm_fifo_t
void session_get_endpoint(session_t *s, transport_endpoint_t *tep, u8 is_lcl)
#define clib_memcpy(d, s, n)
u32 ctx_index
index in crypto context pool
u64 * counters_last_clear
static int quic_ctx_is_conn(quic_ctx_t *ctx)
void session_transport_closing_notify(transport_connection_t *tc)
Notification from transport that connection is being closed.
static int quic_send_packets(quic_ctx_t *ctx)
static void quic_on_quic_session_connected(quic_ctx_t *ctx)
static void quic_udp_session_cleanup_callback(session_t *udp_session, session_cleanup_ntf_t ntf)
static uword quic_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
void * data
protocol specific data
static u8 * quic_format_quicly_conn_id(u8 *s, va_list *args)
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
static clib_error_t * quic_plugin_crypto_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
u8 default_crypto_engine
Used if you do connect with CRYPTO_ENGINE_NONE (0)
static void quic_receive_connection(void *arg)
#define VLIB_INIT_FUNCTION(x)
#define QUIC_DEFAULT_FIFO_SIZE
struct _vnet_disconnect_args_t vnet_disconnect_args_t
static u32 svm_fifo_max_dequeue(svm_fifo_t *f)
Fifo max bytes to dequeue.
static int quic_reset_connection(u64 udp_session_handle, quic_rx_packet_ctx_t *pctx)
static u32 svm_fifo_max_dequeue_cons(svm_fifo_t *f)
Fifo max bytes to dequeue optimized for consumer.
static void quic_proto_on_close(u32 ctx_index, u32 thread_index)
static transport_connection_t * quic_connection_get(u32 ctx_index, u32 thread_index)
#define clib_error_return(e, args...)
static const transport_proto_vft_t quic_proto
static void quic_accept_connection(quic_rx_packet_ctx_t *pctx)
static u8 * quic_format_connection_ctx(u8 *s, va_list *args)
static void quic_ack_rx_data(session_t *stream_session)
static clib_error_t * quic_config_fn(vlib_main_t *vm, unformat_input_t *input)
int session_send_io_evt_to_thread(svm_fifo_t *f, session_evt_type_t evt_type)
ptls_handshake_properties_t hs_properties
static u32 quic_start_listen(u32 quic_listen_session_index, transport_endpoint_t *tep)
#define SESSION_INVALID_HANDLE
static u8 * svm_fifo_head(svm_fifo_t *f)
static int quic_on_stream_open(quicly_stream_open_t *self, quicly_stream_t *stream)
static session_t * get_stream_session_from_stream(quicly_stream_t *stream)
#define QUIC_MAX_PACKET_SIZE
static u32 svm_fifo_max_read_chunk(svm_fifo_t *f)
Max contiguous chunk of data that can be read.
struct _vnet_app_attach_args_t vnet_app_attach_args_t
struct _transport_proto_vft transport_proto_vft_t
struct _session_endpoint_cfg session_endpoint_cfg_t
#define QUIC_TIMER_HANDLE_INVALID
vl_api_fib_path_type_t type
char quic_iv[17]
quic initialization vector
static session_type_t session_type_from_proto_and_ip(transport_proto_t proto, u8 is_ip4)
static quic_ctx_t * quic_ctx_get_if_valid(u32 ctx_index, u32 thread_index)
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
static quicly_stream_open_t on_stream_open
static void quic_connection_closed(quic_ctx_t *ctx)
Called when quicly return an error This function interacts tightly with quic_proto_on_close.
int app_worker_accept_notify(app_worker_t *app_wrk, session_t *s)
static session_t * session_get_from_handle(session_handle_t handle)
session_t * app_listener_get_session(app_listener_t *al)
vlib_error_main_t error_main
static u32 quic_set_time_now(u32 thread_index)
static clib_error_t * quic_show_connections_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
static int quic_app_cert_key_pair_delete_callback(app_cert_key_pair_t *ckpair)
static u8 * quic_format_listener_ctx(u8 *s, va_list *args)
#define pool_put(P, E)
Free an object E in pool P.
#define APP_INVALID_INDEX
#define QUIC_ERR(_fmt, _args...)
struct _segment_manager_props segment_manager_props_t
int svm_fifo_enqueue(svm_fifo_t *f, u32 len, const u8 *src)
Enqueue data to fifo.
clib_bihash_24_8_t crypto_context_hash
per thread [params:crypto_ctx_index] hash
static u8 * format_quic_connection(u8 *s, va_list *args)
static void quic_update_conn_ctx(quicly_conn_t *conn, quicly_context_t *quicly_context)
u32 app_rx_data_len
bytes received, to be read by external app
u32 wrk_index
Worker index in global worker pool.
app_worker_t * app_worker_get_if_valid(u32 wrk_index)
static u8 * quic_format_quicly_stream_id(u8 *s, va_list *args)
static quicly_now_t quicly_vpp_now_cb
#define foreach_vlib_main(body)
static u32 quic_ctx_alloc(u32 thread_index)
static char * quic_error_strings[]
static int quic_udp_session_connected_callback(u32 quic_app_index, u32 ctx_index, session_t *udp_session, u8 is_fail)
u32 n_subscribers
refcount of sessions using said context
static u64 listen_session_get_handle(session_t *s)
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
format_function_t format_ip46_address
int vnet_application_attach(vnet_app_attach_args_t *a)
Attach application to vpp.
static session_t * session_get_from_handle_if_valid(session_handle_t handle)
#define clib_bitmap_alloc(v, n_bits)
Allocate a bitmap with the supplied number of bits.
static clib_error_t * quic_list_crypto_context_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
static void quic_store_conn_ctx(quicly_conn_t *conn, quic_ctx_t *ctx)
static u8 svm_fifo_set_event(svm_fifo_t *f)
Set fifo event flag.
quicly_conn_t * conn
QUIC ctx case.
static int quic_acquire_crypto_context(quic_ctx_t *ctx)
transport_connection_t connection
#define VLIB_EARLY_CONFIG_FUNCTION(x, n,...)
app_cert_key_pair_t * app_cert_key_pair_get_if_valid(u32 index)
#define VLIB_REGISTER_NODE(x,...)
static u64 quic_get_counter_value(u32 event_code)
u32 ckpair_index
certificate & key
session_handle_t listener_handle
Parent listener session index if the result of an accept.
static_always_inline uword vlib_get_thread_index(void)
static void quic_get_transport_listener_endpoint(u32 listener_index, transport_endpoint_t *tep, u8 is_lcl)
static void quic_release_crypto_context(u32 crypto_context_index, u8 thread_index)
ptls_cipher_suite_t *** quic_ciphers
available ciphers by crypto engine
static clib_error_t * quic_init(vlib_main_t *vm)
#define vec_free(V)
Free vector's memory (no header).
segment_manager_props_t sm_properties
Segment manager properties.
#define SESSION_CONN_HDR_LEN
#define clib_warning(format, args...)
static quic_main_t quic_main
ptls_encrypt_ticket_t super
static u8 * quic_format_stream_ctx(u8 *s, va_list *args)
Don't register connection in lookup Does not apply to local apps and transports using the network lay...
#define QUIC_SESSION_INVALID
struct _transport_connection transport_connection_t
static int quic_send_datagram(session_t *udp_session, quicly_datagram_t *packet)
static int quic_on_receive_reset(quicly_stream_t *stream, int err)
static int quic_add_segment_callback(u32 client_index, u64 seg_handle)
int app_worker_init_connected(app_worker_t *app_wrk, session_t *s)
static void quic_transfer_connection(u32 ctx_index, u32 dest_thread)
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
static int quic_connect_stream(session_t *quic_session, session_endpoint_cfg_t *sep)
static uword clib_bitmap_get(uword *ai, uword i)
Gets the ith bit value from a bitmap.
void quic_fifo_egress_shift(quicly_stream_t *stream, size_t delta)
static void quic_on_closed_by_peer(quicly_closed_by_peer_t *self, quicly_conn_t *conn, int code, uint64_t frame_type, const char *reason, size_t reason_len)
crypto_context_t * crypto_ctx_pool
per thread pool of crypto contexes
static transport_proto_t session_type_transport_proto(session_type_t st)
static void quic_udp_session_migrate_callback(session_t *s, session_handle_t new_sh)
static void quic_update_time(f64 now, u8 thread_index)
tw_timer_wheel_1t_3w_1024sl_ov_t timer_wheel
worker timer wheel
vlib_main_t vlib_node_runtime_t * node
int load_bio_certificate_chain(ptls_context_t *ctx, const char *cert_data)
application_t * application_get(u32 app_index)
static void quic_update_timer(quic_ctx_t *ctx)
static u32 session_thread_from_handle(session_handle_t handle)
void transport_register_protocol(transport_proto_t transport_proto, const transport_proto_vft_t *vft, fib_protocol_t fib_proto, u32 output_node)
Register transport virtual function table.
int vnet_app_add_cert_key_interest(u32 index, u32 app_index)
Ask for app cb on pair deletion.
static int quic_custom_tx_callback(void *s, u32 max_burst_size)
static transport_connection_t * quic_listener_get(u32 listener_index)
#define VLIB_CLI_COMMAND(x,...)
segment_manager_props_t * application_get_segment_manager_properties(u32 app_index)
apps acting as transports
app_listener_t * app_listener_get_w_handle(session_handle_t handle)
Get app listener for listener session handle.
static int quic_ctx_is_listener(quic_ctx_t *ctx)
static int quic_del_segment_callback(u32 client_index, u64 seg_handle)
static int quic_init_crypto_context(crypto_context_t *crctx, quic_ctx_t *ctx)
u32 quic_connection_ctx_id
Notify on transition to empty.
int vnet_listen(vnet_listen_args_t *a)
static u8 * format_quic_listener(u8 *s, va_list *args)
#define QUIC_APP_ACCEPT_NOTIFY_ERROR
static void clib_mem_free(void *p)
static void quic_set_udp_tx_evt(session_t *udp_session)
session_handle_t udp_session_handle
int svm_fifo_enqueue_with_offset(svm_fifo_t *f, u32 offset, u32 len, u8 *src)
Enqueue a future segment.
static void svm_fifo_add_want_deq_ntf(svm_fifo_t *f, u8 ntf_type)
Set specific want notification flag.
static void * clib_mem_alloc(uword size)
int vnet_connect(vnet_connect_args_t *a)
Notify on transition from full.
static crypto_context_t * quic_crypto_context_alloc(u8 thread_index)
static vlib_main_t * vlib_get_main(void)
#define QUIC_APP_CONNECT_NOTIFY_ERROR
u8 thread_index
Index of the thread that allocated the session.
session_t * session_alloc(u32 thread_index)
int vlib_main(vlib_main_t *volatile vm, unformat_input_t *input)
#define QUIC_APP_ALLOCATION_ERROR
static void quic_disconnect_transport(quic_ctx_t *ctx)
static session_cb_vft_t quic_app_cb_vft
quicly_context_t quicly_ctx
u8 * quic_format_err(u8 *s, va_list *args)
app_worker_t * app_worker_get(u32 wrk_index)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
static int64_t quic_get_time(quicly_now_t *self)
volatile u8 session_state
State in session layer state machine.
#define QUIC_APP_ERROR_CLOSE_NOTIFY
quicly_decoded_packet_t packet
u32 opaque
Opaque, for general use.
int app_worker_alloc_connects_segment_manager(app_worker_t *app)
static void quic_get_transport_endpoint(u32 ctx_index, u32 thread_index, transport_endpoint_t *tep, u8 is_lcl)
int vnet_disconnect_session(vnet_disconnect_args_t *a)
static void quic_crypto_context_free_if_needed(crypto_context_t *crctx, u8 thread_index)
void quic_increment_counter(u8 evt, u8 val)
static int quic_on_stop_sending(quicly_stream_t *stream, int err)
int session_send_io_evt_to_thread_custom(void *data, u32 thread_index, session_evt_type_t evt_type)
u8 app_crypto_engine_n_types(void)
u32 app_index
Index of owning app.
static struct option options[]
static void quic_ctx_free(quic_ctx_t *ctx)
static void quic_udp_session_disconnect_callback(session_t *s)
static crypto_context_t * quic_crypto_context_get(u32 cr_index, u32 thread_index)
char cid_key[QUIC_IV_LEN]
static vlib_thread_main_t * vlib_get_thread_main()
static u32 vlib_num_workers()
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
enum crypto_engine_type_ crypto_engine_type_t
u32 app_wrk_index
Index of the app worker that owns the session.
static u8 * format_quic_ctx(u8 *s, va_list *args)
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
quic_session_cache_t session_cache
int(* session_accept_callback)(session_t *new_session)
Notify server of newly accepted session.
quicly_cid_plaintext_t next_cid
static void quic_make_connection_key(clib_bihash_kv_16_8_t *kv, const quicly_cid_plaintext_t *id)
static void quic_on_stream_destroy(quicly_stream_t *stream, int err)
int quic_encrypt_ticket_cb(ptls_encrypt_ticket_t *_self, ptls_t *tls, int is_encrypt, ptls_buffer_t *dst, ptls_iovec_t src)
u32 app_tx_data_len
bytes sent
int svm_fifo_dequeue_drop(svm_fifo_t *f, u32 len)
Dequeue and drop bytes from fifo.
static quic_ctx_t * quic_get_conn_ctx(quicly_conn_t *conn)
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
static void quic_update_fifo_size()
vlib_node_registration_t quic_input_node
(constructor) VLIB_REGISTER_NODE (quic_input_node)
static quicly_context_t * quic_get_quicly_ctx_from_udp(u64 udp_session_handle)
int app_worker_connect_notify(app_worker_t *app_wrk, session_t *s, u32 opaque)
static void quic_common_get_transport_endpoint(quic_ctx_t *ctx, transport_endpoint_t *tep, u8 is_lcl)
static const quicly_stream_callbacks_t quic_stream_callbacks
static u8 * format_quic_half_open(u8 *s, va_list *args)
static int quic_sendable_packet_count(session_t *udp_session)
static void quic_show_aggregated_stats(vlib_main_t *vm)
int load_bio_private_key(ptls_context_t *ctx, const char *pk_data)