16 #include <sys/socket.h> 22 #include <vpp/app/version.h> 30 #include <quicly/constants.h> 31 #include <quicly/defaults.h> 39 #define quic_error(n,s) s, 44 #define DEFAULT_MAX_PACKETS_PER_KEY 16777216 76 kv->
key[1] = data->
quicly_ctx.transport_params.max_stream_data.bidi_local;
77 kv->
key[2] = data->
quicly_ctx.transport_params.max_stream_data.bidi_remote;
94 static quicly_datagram_t *
107 clib_memset (encrypt_cb_ctx, 0,
sizeof (*encrypt_cb_ctx));
113 quicly_datagram_t *
packet)
131 for (i = 0; i < num_threads; i++)
165 ASSERT (cr_index >> 24 == thread_index);
167 cr_index & 0x00ffffff);
179 for (i = 0; i < num_threads; i++)
229 quicly_context_t *quicly_ctx;
230 ptls_iovec_t key_vec;
234 ptls_context_t *ptls_ctx;
237 ctx->c_thread_index);
242 crctx->
data = (
void *) data;
246 ptls_ctx->random_bytes = ptls_openssl_random_bytes;
247 ptls_ctx->get_time = &ptls_get_time;
248 ptls_ctx->key_exchanges = ptls_openssl_key_exchanges;
250 ptls_ctx->certificates.list = NULL;
251 ptls_ctx->certificates.count = 0;
252 ptls_ctx->esni = NULL;
253 ptls_ctx->on_client_hello = NULL;
254 ptls_ctx->emit_certificate = NULL;
255 ptls_ctx->sign_certificate = NULL;
256 ptls_ctx->verify_certificate = NULL;
257 ptls_ctx->ticket_lifetime = 86400;
258 ptls_ctx->max_early_data_size = 8192;
259 ptls_ctx->hkdf_label_prefix__obsolete = NULL;
260 ptls_ctx->require_dhe_on_psk = 1;
262 clib_memcpy (quicly_ctx, &quicly_spec_context,
sizeof (quicly_context_t));
266 quicly_ctx->tls = ptls_ctx;
270 quicly_amend_ptls_context (quicly_ctx->tls);
275 quicly_ctx->transport_params.max_streams_uni = (uint64_t) 1 << 60;
276 quicly_ctx->transport_params.max_streams_bidi = (uint64_t) 1 << 60;
280 quicly_ctx->transport_params.max_stream_data.bidi_local =
282 quicly_ctx->transport_params.max_stream_data.bidi_remote =
284 quicly_ctx->transport_params.max_stream_data.uni =
QUIC_INT_MAX;
295 quicly_ctx->cid_encryptor =
296 quicly_new_default_cid_encryptor (&ptls_openssl_bfecb,
297 &ptls_openssl_aes128ecb,
298 &ptls_openssl_sha256, key_vec);
301 if (!ckpair || !ckpair->
key || !ckpair->
cert)
308 QUIC_DBG (1,
"failed to read private key from app configuration\n");
313 QUIC_DBG (1,
"failed to load certificate\n");
329 QUIC_DBG (2,
"No crypto engine specified, using %d",
335 QUIC_DBG (1,
"Quic does not support crypto engine %d",
337 return VNET_API_ERROR_MISSING_CERT_KEY;
342 if (clib_bihash_search_24_8
362 clib_bihash_add_del_24_8 (&qm->
363 wrk_ctx[ctx->c_thread_index].crypto_context_hash,
369 return VNET_API_ERROR_MISSING_CERT_KEY;
383 ctx->c_thread_index = thread_index;
385 QUIC_DBG (3,
"Allocated quic_ctx %u on thread %u",
386 ctx - qm->
ctx_pool[thread_index], thread_index);
387 return ctx - qm->
ctx_pool[thread_index];
393 QUIC_DBG (2,
"Free ctx %u %x", ctx->c_thread_index, ctx->c_c_index);
394 u32 thread_index = ctx->c_thread_index;
419 conn_data = (
u64) * quicly_get_data (conn);
420 return quic_ctx_get (conn_data & UINT32_MAX, conn_data >> 32);
426 *quicly_get_data (conn) =
427 (
void *) (((
u64) ctx->c_thread_index) << 32 | (
u64) ctx->c_c_index);
461 const quicly_cid_plaintext_t *
id)
463 kv->
key[0] = ((
u64) id->master_id) << 32 | (
u64) id->thread_id;
464 kv->
key[1] = id->node_id;
476 static quicly_context_t *
486 static quicly_context_t *
509 tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
515 QUIC_DBG (4,
"Stopping timer for ctx %u", ctx->c_c_index);
526 quicly_stream_t *stream;
539 quicly_stream_sync_recvbuf (stream, stream_data->
app_rx_data_len - max_deq);
564 QUIC_DBG (2,
"Deleting connection %u", ctx->c_c_index);
573 QUIC_DBG (2,
"Deleting conn with id %lu %lu from map", kv.
key[0],
580 quicly_free (ctx->
conn);
598 QUIC_DBG (2,
"QUIC connection %u/%u closed", ctx->c_thread_index,
643 len = packet->data.len;
649 QUIC_ERR (
"Too much data to send, max_enqueue %u, len %u",
664 QUIC_ASSERT (packet->dest.sa.sa_family == AF_INET);
665 struct sockaddr_in *sa4 = (
struct sockaddr_in *) &packet->dest.sa;
667 hdr.
rmt_ip.ip4.as_u32 = sa4->sin_addr.s_addr;
671 QUIC_ASSERT (packet->dest.sa.sa_family == AF_INET6);
672 struct sockaddr_in6 *sa6 = (
struct sockaddr_in6 *) &packet->dest.sa;
678 if (ret !=
sizeof (hdr))
680 QUIC_ERR (
"Not enough space to enqueue header");
686 QUIC_ERR (
"Not enough space to enqueue payload");
702 size_t num_packets,
i, max_packets;
703 quicly_packet_allocator_t *pa;
732 num_packets = max_packets;
733 if ((err = quicly_send (conn, packets, &num_packets)))
739 for (i = 0; i != num_packets; ++
i)
745 pa->free_packet (pa, packets[i]);
748 while (num_packets > 0 && num_packets == max_packets);
759 if (err && err != QUICLY_ERROR_PACKET_IGNORED
760 && err != QUICLY_ERROR_FREE_CONNECTION)
775 sctx->c_thread_index);
776 QUIC_DBG (2,
"DESTROYED_STREAM: session 0x%lx (%U)",
795 sctx->c_thread_index);
796 clib_warning (
"(NOT IMPLEMENTD) STOP_SENDING: session 0x%lx (%U)",
810 sctx->c_thread_index);
821 QUIC_DBG (3,
"received data: %lu bytes, offset %lu", len, off);
822 u32 max_enq, rlen, rv;
838 QUIC_DBG (3,
"Enqueuing %u at off %u in %u space", len, off, max_enq);
840 if (off < stream_data->app_rx_data_len)
842 QUIC_DBG (3,
"Session [idx %u, app_wrk %u, thread %u, rx-fifo 0x%llx]: " 843 "DUPLICATE PACKET (max_enq %u, len %u, " 844 "app_rx_data_len %u, off %u, ToBeNQ %u)",
854 QUIC_ERR (
"Session [idx %u, app_wrk %u, thread %u, rx-fifo 0x%llx]: " 855 "RX FIFO IS FULL (max_enq %u, len %u, " 856 "app_rx_data_len %u, off %u, ToBeNQ %u)",
868 QUIC_DBG (3,
"Session [idx %u, app_wrk %u, ti %u, rx-fifo 0x%llx]: " 869 "Enqueuing %u (rlen %u) at off %u in %u space, ",
872 stream_session->
thread_index, f, len, rlen, off, max_enq);
881 QUIC_ERR (
"Failed to ping app for RX");
914 rv = quicly_stream_sync_sendbuf (stream, 0);
920 size_t *
len,
int *wrote_all)
932 QUIC_DBG (3,
"Emitting %u, offset %u", *len, off);
936 if (off + *len < deq_max)
943 *len = deq_max - off;
970 session_t *stream_session, *quic_session;
977 QUIC_DBG (2,
"on_stream_open called");
982 if (quicly_stream_is_self_initiated (stream))
995 QUIC_DBG (2,
"ACCEPTED stream_session 0x%lx ctx %u",
1001 sctx->c_c_index = sctx_id;
1006 if (quicly_stream_is_unidirectional (stream->stream_id))
1007 stream_session->
flags |= SESSION_F_UNIDIRECTIONAL;
1010 stream_data->
ctx_id = sctx_id;
1021 quic_session =
session_get (qctx->c_s_index, qctx->c_thread_index);
1027 QUIC_ERR (
"failed to allocate fifos");
1037 QUIC_ERR (
"failed to notify accept worker app");
1047 int code, uint64_t frame_type,
1048 const char *reason,
size_t reason_len)
1053 clib_warning (
"Session 0x%lx closed by peer (%U) %.*s ",
1055 reason_len, reason);
1089 tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
1093 tw_timer_expire_timers_1t_3w_1024sl_ov (tw, now);
1100 QUIC_DBG (4,
"Timer expired for conn %u at %ld", conn_index,
1110 tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
1111 int64_t next_timeout, next_interval;
1116 next_timeout = quicly_get_first_timeout (ctx->
conn);
1119 if (next_timeout == 0 || next_interval <= 0)
1127 quic_session =
session_get (ctx->c_s_index, ctx->c_thread_index);
1134 QUIC_ERR (
"Failed to enqueue builtin_tx %d", rv);
1142 QUIC_DBG (4,
"Timer set to %ld (int %ld) for ctx %u", next_timeout,
1143 next_interval, ctx->c_c_index);
1147 if (next_timeout == INT64_MAX)
1149 QUIC_DBG (4,
"timer for ctx %u already stopped", ctx->c_c_index);
1152 ctx->
timer_handle = tw_timer_start_1t_3w_1024sl_ov (tw, ctx->c_c_index,
1157 if (next_timeout == INT64_MAX)
1162 tw_timer_update_1t_3w_1024sl_ov (tw, ctx->
timer_handle,
1173 for (i = 0; i <
vec_len (expired_timers); i++)
1183 uint64_t quic_session_handle;
1186 quicly_stream_t *stream;
1187 quicly_conn_t *conn;
1196 QUIC_DBG (2,
"Opening new stream (qsession %u)", quic_session_handle);
1199 TRANSPORT_PROTO_QUIC)
1201 QUIC_ERR (
"received incompatible session");
1208 QUIC_ERR (
"Invalid app worker :(");
1226 sctx->c_c_index = sctx_index;
1232 if (!conn || !quicly_connection_is_ready (conn))
1236 if ((rv = quicly_open_stream (conn, &stream, is_unidir)))
1238 QUIC_DBG (2,
"Stream open failed with %d", rv);
1245 QUIC_DBG (2,
"Opened stream %d, creating session", stream->stream_id);
1248 QUIC_DBG (2,
"Allocated stream_session 0x%lx ctx %u",
1256 stream_session->
flags |= SESSION_F_UNIDIRECTIONAL;
1260 stream_data->
ctx_id = sctx->c_c_index;
1269 QUIC_ERR (
"failed to app_worker_init_connected");
1307 ctx->c_c_index = ctx_index;
1318 &sep->ip, sep->is_ip4);
1322 cargs->sep.transport_proto = TRANSPORT_PROTO_UDP;
1324 cargs->api_context = ctx_index;
1329 cargs->sep_ext.ns_index = app->
ns_index;
1346 QUIC_DBG (2,
"Called quic_connect");
1366 ctx->c_thread_index);
1372 quicly_stream_t *stream = ctx->
stream;
1373 if (!quicly_stream_has_send_side (quicly_is_client (stream->conn),
1376 quicly_sendstate_shutdown (&stream->sendstate, ctx->
bytes_written +
1379 err = quicly_stream_sync_sendbuf (stream, 1);
1382 QUIC_DBG (1,
"sendstate_shutdown failed for stream session %lu",
1396 quicly_conn_t *conn = ctx->
conn;
1446 args->sep_ext = *sep;
1447 args->sep_ext.ns_index = app->
ns_index;
1448 args->sep_ext.transport_proto = TRANSPORT_PROTO_UDP;
1454 udp_handle = args->handle;
1457 udp_listen_session->
opaque = lctx_index;
1462 clib_memcpy (&lctx->c_rmt_ip, &args->sep.peer.ip, sizeof (ip46_address_t));
1463 clib_memcpy (&lctx->c_lcl_ip, &args->sep.ip, sizeof (ip46_address_t));
1464 lctx->c_rmt_port = args->sep.peer.port;
1465 lctx->c_lcl_port = args->sep.port;
1466 lctx->c_is_ip4 = args->sep.is_ip4;
1467 lctx->c_fib_index = args->sep.fib_index;
1468 lctx->c_proto = TRANSPORT_PROTO_QUIC;
1472 lctx->c_s_index = quic_listen_session_index;
1478 QUIC_DBG (2,
"Listening UDP session 0x%lx",
1480 QUIC_DBG (2,
"Listening QUIC session 0x%lx", quic_listen_session_index);
1487 QUIC_DBG (2,
"Called quic_stop_listen");
1516 QUIC_DBG (2,
"Called quic_listener_get");
1526 u32 verbose = va_arg (*args,
u32);
1531 str =
format (str,
"[#%d][Q] ", ctx->c_thread_index);
1536 str =
format (str,
"Stream %ld conn %d",
1539 str =
format (str,
"Conn %d UDP %d", ctx->c_c_index,
1549 s =
format (s,
"%s\n", str);
1557 u32 qc_index = va_arg (*args,
u32);
1558 u32 thread_index = va_arg (*args,
u32);
1559 u32 verbose = va_arg (*args,
u32);
1568 u32 qc_index = va_arg (*args,
u32);
1569 u32 thread_index = va_arg (*args,
u32);
1571 s =
format (s,
"[#%d][Q] half-open app %u", thread_index,
1580 u32 tci = va_arg (*args,
u32);
1581 u32 thread_index = va_arg (*args,
u32);
1582 u32 verbose = va_arg (*args,
u32);
1596 struct sockaddr_in *sa4 = (
struct sockaddr_in *) sa;
1597 sa4->sin_family = AF_INET;
1598 sa4->sin_port =
port;
1599 sa4->sin_addr.s_addr = addr->ip4.as_u32;
1600 *salen =
sizeof (
struct sockaddr_in);
1604 struct sockaddr_in6 *sa6 = (
struct sockaddr_in6 *) sa;
1605 sa6->sin6_family = AF_INET6;
1606 sa6->sin6_port =
port;
1608 *salen =
sizeof (
struct sockaddr_in6);
1617 u32 ctx_id = ctx->c_c_index;
1618 u32 thread_index = ctx->c_thread_index;
1635 QUIC_ERR (
"failed to app_worker_init_connected");
1645 QUIC_ERR (
"failed to notify app %d", rv);
1656 quic_session =
session_get (ctx->c_s_index, thread_index);
1670 if (!quicly_connection_is_ready (ctx->
conn))
1673 if (!quicly_is_client (ctx->
conn))
1683 ptls_context_t **tls;
1684 quicly_context_t **_quicly_context;
1685 _quicly_context = (quicly_context_t **) conn;
1686 *_quicly_context = quicly_context;
1687 tls = (ptls_context_t **) quicly_get_tls (conn);
1688 *tls = quicly_context->tls;
1697 quicly_conn_t *conn;
1698 quicly_context_t *quicly_context;
1705 QUIC_DBG (2,
"Received conn %u (now %u)", temp_ctx->c_thread_index,
1711 new_ctx->c_thread_index = thread_index;
1712 new_ctx->c_c_index = new_ctx_id;
1715 conn = new_ctx->
conn;
1721 kv.
value = ((
u64) thread_index) << 32 | (
u64) new_ctx_id;
1722 QUIC_DBG (2,
"Registering conn with id %lu %lu", kv.
key[0], kv.
key[1]);
1729 udp_session->
opaque = new_ctx_id;
1730 udp_session->
flags &= ~SESSION_F_IS_MIGRATING;
1741 QUIC_DBG (2,
"Transferring conn %u to thread %u", ctx_index, dest_thread);
1763 QUIC_DBG (2,
"QSession is now connected (id %u)",
1768 struct sockaddr_in6 sa6;
1769 struct sockaddr *sa = (
struct sockaddr *) &sa6;
1773 quicly_conn_t *conn;
1777 quicly_context_t *quicly_ctx;
1787 api_context = ctx->c_s_index;
1793 ctx->c_thread_index = thread_index;
1794 ctx->c_c_index = ctx_index;
1796 QUIC_DBG (2,
"Quic connect returned %u. New ctx [%u]%x",
1797 is_fail, thread_index, (ctx) ? ctx_index : ~0);
1800 udp_session->
opaque = ctx_index;
1820 kv.
value = ((
u64) thread_index) << 32 | (
u64) ctx_index;
1821 QUIC_DBG (2,
"Registering conn with id %lu %lu", kv.
key[0], kv.
key[1]);
1851 ctx->c_thread_index);
1888 udp_listen_session =
1894 ctx->c_c_index = ctx_index;
1911 udp_session->
opaque = ctx_index;
1936 QUIC_DBG (3,
"Received app READ notification");
1952 quicly_stream_t *stream;
1958 (stream_session->
session_state >= SESSION_STATE_TRANSPORT_CLOSING))
1970 if (!quicly_sendstate_is_open (&stream->sendstate))
1972 QUIC_ERR (
"Warning: tried to send on closed stream");
1981 QUIC_DBG (3,
"TX but no data %d / %d", max_deq,
1986 rv = quicly_stream_sync_sendbuf (stream, 1);
2004 clib_bihash_16_8_t *
h;
2010 QUIC_DBG (3,
"Searching conn with id %lu %lu", kv.
key[0], kv.
key[1]);
2012 if (clib_bihash_search_16_8 (h, &kv, &kv))
2014 QUIC_DBG (3,
"connection not found");
2018 index = kv.
value & UINT32_MAX;
2019 thread_id = kv.
value >> 32;
2022 if (thread_id != caller_thread_index)
2024 QUIC_DBG (2,
"Connection is on wrong thread");
2036 if (!quicly_is_destination (ctx->
conn, NULL, &pctx->
sa, &pctx->
packet))
2048 quicly_context_t *quicly_ctx;
2052 quicly_conn_t *conn;
2062 QUIC_DBG (2,
"already accepted ctx 0x%x", ctx->c_s_index);
2067 if ((rv = quicly_accept (&conn, quicly_ctx, NULL, &pctx->
sa,
2086 QUIC_DBG (2,
"Allocated quic_session, 0x%lx ctx %u",
2103 QUIC_DBG (2,
"Registering conn with id %lu %lu", kv.
key[0], kv.
key[1]);
2108 QUIC_ERR (
"failed to allocate fifos");
2116 QUIC_ERR (
"failed to notify accept worker app");
2132 QUIC_DBG (2,
"Sending stateless reset");
2134 quicly_datagram_t *dgram;
2136 quicly_context_t *quicly_ctx;
2137 if (pctx->
packet.cid.dest.plaintext.node_id != 0
2138 || pctx->
packet.cid.dest.plaintext.thread_id != 0)
2141 dgram = quicly_send_stateless_reset (quicly_ctx, &pctx->
sa, NULL,
2142 &pctx->
packet.cid.dest.plaintext);
2159 quicly_context_t *quicly_ctx;
2168 if (full_len > cur_deq)
2170 QUIC_ERR (
"Not enough data in fifo RX");
2180 QUIC_ERR (
"Not enough data peeked in RX");
2188 plen = quicly_decode_packet (quicly_ctx, &pctx->
packet,
2191 if (plen == SIZE_MAX)
2212 else if (QUICLY_PACKET_IS_LONG_HEADER (pctx->
packet.octets.base[0]))
2237 u32 cur_deq, fifo_offset, max_packets,
i;
2241 if (udp_session->
flags & SESSION_F_IS_MIGRATING)
2243 QUIC_DBG (3,
"RX on migrating udp session");
2260 for (i = 0; i < max_packets; i++)
2266 cur_deq = max_deq - fifo_offset;
2269 max_packets = i + 1;
2274 fifo_offset = max_deq;
2275 max_packets = i + 1;
2276 QUIC_ERR (
"Fifo %d < header size in RX", cur_deq);
2280 fifo_offset, &packets_ctx[i]);
2285 max_packets = i + 1;
2291 wrk_ctx[thread_index].crypto_context_batch);
2293 for (i = 0; i < max_packets; i++)
2295 switch (packets_ctx[i].ptype)
2298 ctx =
quic_ctx_get (packets_ctx[i].ctx_index, thread_index);
2299 rv = quicly_receive (ctx->
conn, NULL, &packets_ctx[i].
sa,
2301 if (rv && rv != QUICLY_ERROR_PACKET_IGNORED)
2303 QUIC_ERR (
"quicly_receive return error %U",
2315 ctx = prev_ctx = NULL;
2316 for (i = 0; i < max_packets; i++)
2319 switch (packets_ctx[i].ptype)
2323 packets_ctx[i].thread_index);
2326 packets_ctx[i].thread_index);
2330 packets_ctx[i].thread_index);
2336 if (ctx != prev_ctx)
2417 .transport_options = {
2432 ptls_cipher_suite_t ** ciphers)
2450 (
"error while getting segment_manager_props_t, can't update fifo-size");
2461 u32 segment_size = 256 << 20;
2463 tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
2477 a->name =
format (0,
"quic");
2496 for (i = 0; i < num_threads; i++)
2504 "quic crypto contexts", 64, 128 << 10);
2510 clib_bihash_init_16_8 (&qm->
connection_hash,
"quic connections", 1024,
2527 ptls_openssl_cipher_suites);
2560 else if (
unformat (line_input,
"picotls"))
2591 if (tmp >= 0x100000000ULL)
2594 (0,
"fifo-size %llu (0x%llx) too large", tmp, tmp);
2624 em = &this_vlib_main->error_main;
2643 quicly_stats_t st, agg_stats;
2644 u32 i, nconn = 0, nstream = 0;
2647 for (i = 0; i < num_workers + 1; i++)
2654 quicly_get_stats (ctx->
conn, &st);
2655 agg_stats.rtt.smoothed += st.rtt.smoothed;
2656 agg_stats.rtt.minimum += st.rtt.minimum;
2657 agg_stats.rtt.variance += st.rtt.variance;
2658 agg_stats.num_packets.received += st.num_packets.received;
2659 agg_stats.num_packets.sent += st.num_packets.sent;
2660 agg_stats.num_packets.lost += st.num_packets.lost;
2661 agg_stats.num_packets.ack_received += st.num_packets.ack_received;
2662 agg_stats.num_bytes.received += st.num_bytes.received;
2663 agg_stats.num_bytes.sent += st.num_bytes.sent;
2694 nconn > 0 ? agg_stats.rtt.minimum / nconn : 0);
2696 nconn > 0 ? agg_stats.rtt.smoothed / nconn : 0);
2698 nconn > 0 ? agg_stats.rtt.variance / nconn : 0);
2700 agg_stats.num_packets.received);
2704 agg_stats.num_packets.ack_received);
2712 quicly_cid_plaintext_t *mid = va_arg (*args, quicly_cid_plaintext_t *);
2713 s =
format (s,
"C%x_%x", mid->master_id, mid->thread_id);
2720 quicly_stream_t *stream = va_arg (*args, quicly_stream_t *);
2723 quicly_get_master_id (stream->conn), stream->stream_id);
2731 s =
format (s,
"[#%d][%x][Listener]", ctx->c_thread_index, ctx->c_c_index);
2739 quicly_stats_t quicly_stats;
2741 s =
format (s,
"[#%d][%x]", ctx->c_thread_index, ctx->c_c_index);
2745 s =
format (s,
"- no conn -\n");
2750 quicly_get_stats (ctx->
conn, &quicly_stats);
2752 s =
format (s,
"[RTT >%3d, ~%3d, V%3d, last %3d]",
2753 quicly_stats.rtt.minimum, quicly_stats.rtt.smoothed,
2754 quicly_stats.rtt.variance, quicly_stats.rtt.latest);
2755 s =
format (s,
" TX:%d RX:%d loss:%d ack:%d",
2756 quicly_stats.num_packets.sent,
2757 quicly_stats.num_packets.received,
2758 quicly_stats.num_packets.lost,
2759 quicly_stats.num_packets.ack_received);
2768 quicly_stream_t *stream = ctx->
stream;
2771 s =
format (s,
"[#%d][%x]", ctx->c_thread_index, ctx->c_c_index);
2775 if (!stream_session)
2777 s =
format (s,
"- no session -\n");
2782 s =
format (s,
"[rx %d tx %d]\n", rxs, txs);
2792 u8 show_listeners = 0, show_conn = 0, show_stream = 0;
2808 if (
unformat (line_input,
"listener"))
2810 else if (
unformat (line_input,
"conn"))
2812 else if (
unformat (line_input,
"stream"))
2822 for (
int i = 0;
i < num_workers + 1;
i++)
2845 .path =
"quic set crypto api",
2846 .short_help =
"quic set crypto api [picotls, vpp]",
2851 .path =
"quic set fifo-size",
2852 .short_help =
"quic set fifo-size N[K|M|G] (default 64K)",
2857 .path =
"show quic",
2858 .short_help =
"show quic",
2863 .path =
"show quic crypto context",
2864 .short_help =
"list quic crypto contextes",
2869 .path =
"set quic max_packets_per_key",
2870 .short_help =
"set quic max_packets_per_key 16777216",
2875 .version = VPP_BUILD_VER,
2876 .description =
"Quic transport protocol",
2877 .default_disabled = 1,
2901 if (tmp >= 0x100000000ULL)
2904 "fifo-size %llu (0x%llx) too large",
2910 else if (
unformat (input,
"conn-timeout %u", &i))
2912 else if (
unformat (input,
"fifo-prealloc %u", &i))
2939 .name =
"quic-input",
2940 .vector_size =
sizeof (
u32),
quicly_packet_allocator_t quic_packet_allocator
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
#define QUIC_RCV_MAX_BATCH_PACKETS
#define SESSION_CLI_STATE_LEN
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)
vnet_crypto_engine_t * engines
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.
int app_worker_connect_notify(app_worker_t *app_wrk, session_t *s, session_error_t err, u32 opaque)
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)
#define pool_foreach(VAR, POOL)
Iterate through pool.
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()
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 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 void quic_on_stop_sending(quicly_stream_t *stream, int err)
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)
struct quic_encrypt_cb_ctx_ quic_encrypt_cb_ctx
#define QUIC_DBG(_lvl, _fmt, _args...)
struct _vnet_bind_args_t vnet_listen_args_t
static int quic_custom_tx_callback(void *s, transport_send_params_t *sp)
static session_handle_t session_handle(session_t *s)
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)
clib_rwlock_t crypto_keys_quic_rw_lock
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)
static clib_error_t * quic_plugin_crypto_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
static int quic_udp_session_connected_callback(u32 quic_app_index, u32 ctx_index, session_t *udp_session, session_error_t err)
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.
description fragment has unexpected format
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 int quic_on_stream_open(quicly_stream_open_t *self, quicly_stream_t *stream)
#define QUIC_MAX_PACKET_SIZE
void quic_fifo_egress_emit(quicly_stream_t *stream, size_t off, void *dst, size_t *len, int *wrote_all)
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
quic_ctx_t * quic_get_conn_ctx(quicly_conn_t *conn)
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 void clib_rwlock_init(clib_rwlock_t *p)
static quicly_stream_open_t on_stream_open
static void quic_on_receive_reset(quicly_stream_t *stream, int err)
static void quic_connection_closed(quic_ctx_t *ctx)
Called when quicly return an error This function interacts tightly with quic_proto_on_close.
quicly_crypto_engine_t quic_crypto_engine
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)
void quic_crypto_batch_rx_packets(quic_crypto_batch_ctx_t *batch_ctx)
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)
description malformed packet
#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)
#define DEFAULT_MAX_PACKETS_PER_KEY
u64 max_packets_per_key
number of packets that can be sent without a key update
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[]
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)
sll srl srl sll sra u16x4 i
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_CLI_ID_LEN
#define SESSION_CONN_HDR_LEN
static void quic_on_receive(quicly_stream_t *stream, size_t off, const void *src, size_t len)
static clib_error_t * quic_set_max_packets_per_key_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
#define clib_warning(format, args...)
ptls_encrypt_ticket_t super
static u8 * quic_format_stream_ctx(u8 *s, va_list *args)
Don't register connection in lookup.
#define QUIC_SESSION_INVALID
struct _transport_connection transport_connection_t
static int quic_send_datagram(session_t *udp_session, quicly_datagram_t *packet)
void quic_crypto_decrypt_packet(quic_ctx_t *qctx, quic_rx_packet_ctx_t *pctx)
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
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.
vlib_main_t vlib_node_runtime_t * node
int vnet_app_add_cert_key_interest(u32 index, u32 app_index)
Ask for app cb on pair deletion.
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)
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
u32 quic_connection_ctx_id
static quicly_datagram_t * quic_alloc_packet(quicly_packet_allocator_t *self, size_t payloadsize)
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
void quic_crypto_batch_tx_packets(quic_crypto_batch_ctx_t *batch_ctx)
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.
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
#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)
static session_t * get_stream_session_and_ctx_from_stream(quicly_stream_t *stream, quic_ctx_t **ctx)
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)
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.
static void quic_free_packet(quicly_packet_allocator_t *self, quicly_datagram_t *packet)
enum session_error_ session_error_t
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)
quic_crypto_batch_ctx_t crypto_context_batch
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
void quic_crypto_finalize_send_packet(quicly_datagram_t *packet)
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.
struct _svm_fifo svm_fifo_t
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)
vnet_crypto_main_t crypto_main
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)
u8 * format_crypto_context(u8 *s, va_list *args)