From 2e4523816ca0e366a4f597a0e5fdb93fccc887a5 Mon Sep 17 00:00:00 2001 From: Mathias Raoul Date: Tue, 19 Jan 2021 14:02:34 +0000 Subject: [PATCH] quic: quicly v0.1.2 update - update quic plugin with new quicly/picotls API - remove packet allocator - remove crypto batching - update picotls plugin - add cli for quicly congestion control configuration Type: feature Change-Id: If76ef31c43b430eea2f7674539b2112aee0f351e Signed-off-by: Mathias Raoul --- build/external/packages/quicly.mk | 6 +- .../quicly_0.1.2-vpp/0001-cmake-install.patch | 60 ++ src/plugins/quic/CMakeLists.txt | 4 +- src/plugins/quic/error.c | 6 +- src/plugins/quic/quic.c | 224 ++++--- src/plugins/quic/quic.h | 32 +- src/plugins/quic/quic_crypto.c | 684 +++++++-------------- src/plugins/quic/quic_crypto.h | 17 +- src/plugins/tlspicotls/pico_vpp_crypto.c | 37 +- 9 files changed, 451 insertions(+), 619 deletions(-) create mode 100644 build/external/patches/quicly_0.1.2-vpp/0001-cmake-install.patch diff --git a/build/external/packages/quicly.mk b/build/external/packages/quicly.mk index 29abad8b56c..d1fffc9650c 100644 --- a/build/external/packages/quicly.mk +++ b/build/external/packages/quicly.mk @@ -1,4 +1,4 @@ -# Copyright (c) 2019 Cisco and/or its affiliates. +# Copyright (c) 2021 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: @@ -11,9 +11,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -quicly_version := 0.1.0-vpp +quicly_version := 0.1.2-vpp quicly_tarball := quicly_$(quicly_version).tar.gz -quicly_tarball_md5sum := 223f62c4dda7cbb1d907956cafcfd3f0 +quicly_tarball_md5sum := 5b184b1733ba027843ab6605d931f752 quicly_tarball_strip_dirs := 1 quicly_url := https://github.com/vpp-quic/quicly/releases/download/v$(quicly_version)/quicly_$(quicly_version).tar.gz diff --git a/build/external/patches/quicly_0.1.2-vpp/0001-cmake-install.patch b/build/external/patches/quicly_0.1.2-vpp/0001-cmake-install.patch new file mode 100644 index 00000000000..36148064d39 --- /dev/null +++ b/build/external/patches/quicly_0.1.2-vpp/0001-cmake-install.patch @@ -0,0 +1,60 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index f5478d3..156df4c 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -65,6 +65,8 @@ IF (WITH_DTRACE) + ENDIF () + ENDIF () + ++SET(CMAKE_POSITION_INDEPENDENT_CODE ON) ++ + ADD_LIBRARY(quicly ${QUICLY_LIBRARY_FILES}) + + ADD_CUSTOM_COMMAND( +@@ -84,6 +86,16 @@ TARGET_LINK_LIBRARIES(examples-echo quicly ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS} + + ADD_EXECUTABLE(udpfw t/udpfw.c) + ++INSTALL ( ++ DIRECTORY ${CMAKE_SOURCE_DIR}/include/ ++ DESTINATION include ++ FILES_MATCHING PATTERN "*.h") ++ ++INSTALL(TARGETS quicly ++ RUNTIME DESTINATION bin ++ LIBRARY DESTINATION lib ++ ARCHIVE DESTINATION lib) ++ + ADD_CUSTOM_TARGET(check env BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR} WITH_DTRACE=${WITH_DTRACE} prove --exec "sh -c" -v ${CMAKE_CURRENT_BINARY_DIR}/*.t t/*.t + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS cli test.t) +Submodule deps/picotls contains untracked content +Submodule deps/picotls contains modified content +diff --git a/deps/picotls/CMakeLists.txt b/deps/picotls/CMakeLists.txt +index 874b9be..14411e2 100644 +--- a/deps/picotls/CMakeLists.txt ++++ b/deps/picotls/CMakeLists.txt +@@ -12,6 +12,7 @@ IF (WITH_DTRACE) + MESSAGE(STATUS "Enabling USDT support") + ENDIF () + ++SET(CMAKE_POSITION_INDEPENDENT_CODE ON) + SET(CMAKE_C_FLAGS "-std=c99 -Wall -O2 -g ${CC_WARNING_FLAGS} ${CMAKE_C_FLAGS}") + INCLUDE_DIRECTORIES( + deps/cifra/src/ext +@@ -131,6 +132,15 @@ ELSE () + MESSAGE(WARNING "Disabling OpenSSL support (requires 1.0.1 or newer)") + ENDIF () + ++INSTALL (DIRECTORY ${CMAKE_SOURCE_DIR}/include/ ++ DESTINATION include ++ FILES_MATCHING PATTERN "*.h") ++ ++INSTALL(TARGETS picotls-core picotls-openssl ++ RUNTIME DESTINATION bin ++ LIBRARY DESTINATION lib ++ ARCHIVE DESTINATION lib) ++ + ADD_CUSTOM_TARGET(check env BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR} prove --exec '' -v ${CMAKE_CURRENT_BINARY_DIR}/*.t t/*.t WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${TEST_EXES} cli) + + IF (CMAKE_SYSTEM_NAME STREQUAL "Linux") \ No newline at end of file diff --git a/src/plugins/quic/CMakeLists.txt b/src/plugins/quic/CMakeLists.txt index 859b6d98c4c..35d72c21685 100644 --- a/src/plugins/quic/CMakeLists.txt +++ b/src/plugins/quic/CMakeLists.txt @@ -1,5 +1,5 @@ -# Copyright (c) 2019 Cisco +# Copyright (c) 2021 Cisco # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: @@ -13,7 +13,7 @@ # limitations under the License. unset(QUIC_LINK_LIBRARIES) -set(EXPECTED_QUICLY_VERSION "0.1.0-vpp") +set(EXPECTED_QUICLY_VERSION "0.1.2-vpp") find_path(QUICLY_INCLUDE_DIR NAMES quicly.h) find_path(PICOTLS_INCLUDE_DIR NAMES picotls.h) diff --git a/src/plugins/quic/error.c b/src/plugins/quic/error.c index ed2ca111e83..3fc8584e4fd 100644 --- a/src/plugins/quic/error.c +++ b/src/plugins/quic/error.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -62,8 +62,8 @@ quic_format_err (u8 * s, va_list * args) case QUICLY_TRANSPORT_ERROR_INTERNAL: s = format (s, "QUICLY_TRANSPORT_ERROR_INTERNAL"); break; - case QUICLY_TRANSPORT_ERROR_SERVER_BUSY: - s = format (s, "QUICLY_TRANSPORT_ERROR_SERVER_BUSY"); + case QUICLY_TRANSPORT_ERROR_CONNECTION_REFUSED: + s = format (s, "QUICLY_TRANSPORT_ERROR_CONNECTION_REFUSED"); break; case QUICLY_TRANSPORT_ERROR_FLOW_CONTROL: s = format (s, "QUICLY_TRANSPORT_ERROR_FLOW_CONTROL"); diff --git a/src/plugins/quic/quic.c b/src/plugins/quic/quic.c index 7f879cc582e..b120a46f7e8 100644 --- a/src/plugins/quic/quic.c +++ b/src/plugins/quic/quic.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -51,7 +51,7 @@ static int quic_reset_connection (u64 udp_session_handle, static void quic_proto_on_close (u32 ctx_index, u32 thread_index); static quicly_stream_open_t on_stream_open; -static quicly_closed_by_peer_t on_closed_by_peer; +static quicly_closed_by_remote_t on_closed_by_remote; static quicly_now_t quicly_vpp_now_cb; /* Crypto contexts */ @@ -91,33 +91,6 @@ quic_crypto_context_free_if_needed (crypto_context_t * crctx, u8 thread_index) pool_put (qm->wrk_ctx[thread_index].crypto_ctx_pool, crctx); } -static quicly_datagram_t * -quic_alloc_packet (quicly_packet_allocator_t * self, size_t payloadsize) -{ - quicly_datagram_t *packet; - if ((packet = - clib_mem_alloc (sizeof (*packet) + payloadsize + - sizeof (quic_encrypt_cb_ctx))) == NULL) - return NULL; - packet->data.base = - (uint8_t *) packet + sizeof (*packet) + sizeof (quic_encrypt_cb_ctx); - quic_encrypt_cb_ctx *encrypt_cb_ctx = - (quic_encrypt_cb_ctx *) ((uint8_t *) packet + sizeof (*packet)); - - clib_memset (encrypt_cb_ctx, 0, sizeof (*encrypt_cb_ctx)); - return packet; -} - -static void -quic_free_packet (quicly_packet_allocator_t * self, - quicly_datagram_t * packet) -{ - clib_mem_free (packet); -} - -quicly_packet_allocator_t quic_packet_allocator = - { quic_alloc_packet, quic_free_packet }; - static int quic_app_cert_key_pair_delete_callback (app_cert_key_pair_t * ckpair) { @@ -213,6 +186,35 @@ quic_set_max_packets_per_key_fn (vlib_main_t * vm, return 0; } +static clib_error_t * +quic_set_cc_fn (vlib_main_t *vm, unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + quic_main_t *qm = &quic_main; + clib_error_t *e = 0; + + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "reno")) + qm->default_quic_cc = QUIC_CC_RENO; + else if (unformat (line_input, "cubic")) + qm->default_quic_cc = QUIC_CC_CUBIC; + else + { + e = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } + } +done: + unformat_free (line_input); + return e; +} + static void quic_release_crypto_context (u32 crypto_context_index, u8 thread_index) { @@ -261,21 +263,29 @@ quic_init_crypto_context (crypto_context_t * crctx, quic_ctx_t * ctx) ptls_ctx->encrypt_ticket = &qm->session_cache.super; clib_memcpy (quicly_ctx, &quicly_spec_context, sizeof (quicly_context_t)); - quicly_ctx->max_packet_size = QUIC_MAX_PACKET_SIZE; quicly_ctx->max_packets_per_key = qm->max_packets_per_key; quicly_ctx->tls = ptls_ctx; quicly_ctx->stream_open = &on_stream_open; - quicly_ctx->closed_by_peer = &on_closed_by_peer; + quicly_ctx->closed_by_remote = &on_closed_by_remote; quicly_ctx->now = &quicly_vpp_now_cb; quicly_amend_ptls_context (quicly_ctx->tls); - quicly_ctx->packet_allocator = &quic_packet_allocator; - quicly_ctx->crypto_engine = &quic_crypto_engine; + if (qm->vnet_crypto_enabled && + qm->default_crypto_engine == CRYPTO_ENGINE_VPP) + quicly_ctx->crypto_engine = &quic_crypto_engine; + else + quicly_ctx->crypto_engine = &quicly_default_crypto_engine; + quicly_ctx->transport_params.max_data = QUIC_INT_MAX; quicly_ctx->transport_params.max_streams_uni = (uint64_t) 1 << 60; quicly_ctx->transport_params.max_streams_bidi = (uint64_t) 1 << 60; quicly_ctx->transport_params.max_idle_timeout = qm->connection_timeout; + if (qm->default_quic_cc == QUIC_CC_CUBIC) + quicly_ctx->init_cc = &quicly_cc_cubic_init; + else if (qm->default_quic_cc == QUIC_CC_RENO) + quicly_ctx->init_cc = &quicly_cc_reno_init; + app = application_get (ctx->parent_app_id); quicly_ctx->transport_params.max_stream_data.bidi_local = app->sm_properties.rx_fifo_size - 1; @@ -283,6 +293,7 @@ quic_init_crypto_context (crypto_context_t * crctx, quic_ctx_t * ctx) app->sm_properties.tx_fifo_size - 1; quicly_ctx->transport_params.max_stream_data.uni = QUIC_INT_MAX; + quicly_ctx->transport_params.max_udp_payload_size = QUIC_MAX_PACKET_SIZE; if (!app->quic_iv_set) { ptls_openssl_random_bytes (app->quic_iv, QUIC_IV_LEN - 1); @@ -632,7 +643,8 @@ quic_connection_closed (quic_ctx_t * ctx) } static int -quic_send_datagram (session_t * udp_session, quicly_datagram_t * packet) +quic_send_datagram (session_t *udp_session, struct iovec *packet, + quicly_address_t *dest, quicly_address_t *src) { u32 max_enqueue; session_dgram_hdr_t hdr; @@ -640,7 +652,7 @@ quic_send_datagram (session_t * udp_session, quicly_datagram_t * packet) svm_fifo_t *f; transport_connection_t *tc; - len = packet->data.len; + len = packet->iov_len; f = udp_session->tx_fifo; tc = session_get_transport (udp_session); max_enqueue = svm_fifo_max_enqueue (f); @@ -661,15 +673,15 @@ quic_send_datagram (session_t * udp_session, quicly_datagram_t * packet) /* Read dest address from quicly-provided sockaddr */ if (hdr.is_ip4) { - QUIC_ASSERT (packet->dest.sa.sa_family == AF_INET); - struct sockaddr_in *sa4 = (struct sockaddr_in *) &packet->dest.sa; + QUIC_ASSERT (dest->sa.sa_family == AF_INET); + struct sockaddr_in *sa4 = (struct sockaddr_in *) &dest->sa; hdr.rmt_port = sa4->sin_port; hdr.rmt_ip.ip4.as_u32 = sa4->sin_addr.s_addr; } else { - QUIC_ASSERT (packet->dest.sa.sa_family == AF_INET6); - struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &packet->dest.sa; + QUIC_ASSERT (dest->sa.sa_family == AF_INET6); + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &dest->sa; hdr.rmt_port = sa6->sin6_port; clib_memcpy (&hdr.rmt_ip.ip6, &sa6->sin6_addr, 16); } @@ -680,7 +692,7 @@ quic_send_datagram (session_t * udp_session, quicly_datagram_t * packet) QUIC_ERR ("Not enough space to enqueue header"); return QUIC_ERROR_FULL_FIFO; } - ret = svm_fifo_enqueue (f, len, packet->data.base); + ret = svm_fifo_enqueue (f, len, packet->iov_base); if (ret != len) { QUIC_ERR ("Not enough space to enqueue payload"); @@ -695,14 +707,18 @@ quic_send_datagram (session_t * udp_session, quicly_datagram_t * packet) static int quic_send_packets (quic_ctx_t * ctx) { - quic_main_t *qm = &quic_main; - quicly_datagram_t *packets[QUIC_SEND_PACKET_VEC_SIZE]; + struct iovec packets[QUIC_SEND_PACKET_VEC_SIZE]; + uint8_t + buf[QUIC_SEND_PACKET_VEC_SIZE * quic_get_quicly_ctx_from_ctx (ctx) + ->transport_params.max_udp_payload_size]; session_t *udp_session; quicly_conn_t *conn; size_t num_packets, i, max_packets; - quicly_packet_allocator_t *pa; + quicly_address_t dest, src; + + num_packets = QUIC_SEND_PACKET_VEC_SIZE; + int err = 0; - u32 thread_index = vlib_get_thread_index (); /* We have sctx, get qctx */ if (quic_ctx_is_stream (ctx)) @@ -723,26 +739,23 @@ quic_send_packets (quic_ctx_t * ctx) if (quic_sendable_packet_count (udp_session) < 2) goto stop_sending; - pa = quic_get_quicly_ctx_from_ctx (ctx)->packet_allocator; do { max_packets = quic_sendable_packet_count (udp_session); if (max_packets < 2) break; num_packets = max_packets; - if ((err = quicly_send (conn, packets, &num_packets))) + if ((err = quicly_send (conn, &dest, &src, packets, &num_packets, buf, + sizeof (buf)))) goto quicly_error; - quic_crypto_batch_tx_packets (&qm->wrk_ctx - [thread_index].crypto_context_batch); - for (i = 0; i != num_packets; ++i) { - quic_crypto_finalize_send_packet (packets[i]); - if ((err = quic_send_datagram (udp_session, packets[i]))) + + if ((err = + quic_send_datagram (udp_session, &packets[i], &dest, &src))) goto quicly_error; - pa->free_packet (pa, packets[i]); } } while (num_packets > 0 && num_packets == max_packets); @@ -1043,9 +1056,9 @@ quic_on_stream_open (quicly_stream_open_t * self, quicly_stream_t * stream) } 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) +quic_on_closed_by_remote (quicly_closed_by_remote_t *self, quicly_conn_t *conn, + int code, uint64_t frame_type, const char *reason, + size_t reason_len) { quic_ctx_t *ctx = quic_get_conn_ctx (conn); #if QUIC_DEBUG >= 2 @@ -1760,7 +1773,7 @@ quic_udp_session_connected_callback (u32 quic_app_index, u32 ctx_index, session_t * udp_session, session_error_t err) { - QUIC_DBG (2, "QSession is now connected (id %u)", + QUIC_DBG (2, "UDP Session is now connected (id %u)", udp_session->session_index); /* This should always be called before quic_connect returns since UDP always * connects instantly. */ @@ -1793,8 +1806,7 @@ quic_udp_session_connected_callback (u32 quic_app_index, u32 ctx_index, ctx->c_thread_index = thread_index; ctx->c_c_index = ctx_index; - QUIC_DBG (2, "Quic connect returned %u. New ctx [%u]%x", - is_fail, thread_index, (ctx) ? ctx_index : ~0); + QUIC_DBG (2, "New ctx [%u]%x", thread_index, (ctx) ? ctx_index : ~0); ctx->udp_session_handle = session_handle (udp_session); udp_session->opaque = ctx_index; @@ -2131,19 +2143,31 @@ quic_reset_connection (u64 udp_session_handle, quic_rx_packet_ctx_t * pctx) * CID, ... */ QUIC_DBG (2, "Sending stateless reset"); int rv; - quicly_datagram_t *dgram; session_t *udp_session; quicly_context_t *quicly_ctx; if (pctx->packet.cid.dest.plaintext.node_id != 0 || pctx->packet.cid.dest.plaintext.thread_id != 0) return 0; quicly_ctx = quic_get_quicly_ctx_from_udp (udp_session_handle); - dgram = quicly_send_stateless_reset (quicly_ctx, &pctx->sa, NULL, - &pctx->packet.cid.dest.plaintext); - if (dgram == NULL) + quic_ctx_t *qctx = quic_ctx_get (pctx->ctx_index, pctx->thread_index); + + quicly_address_t src; + uint8_t payload[quicly_ctx->transport_params.max_udp_payload_size]; + size_t payload_len = + quicly_send_stateless_reset (quicly_ctx, &src.sa, payload); + if (payload_len == 0) return 1; + + struct iovec packet; + packet.iov_len = payload_len; + packet.iov_base = payload; + + struct _st_quicly_conn_public_t *conn = + (struct _st_quicly_conn_public_t *) qctx->conn; + udp_session = session_get_from_handle (udp_session_handle); - rv = quic_send_datagram (udp_session, dgram); + rv = quic_send_datagram (udp_session, &packet, &conn->remote.address, + &conn->local.address); quic_set_udp_tx_evt (udp_session); return rv; } @@ -2185,8 +2209,10 @@ quic_process_one_rx_packet (u64 udp_session_handle, svm_fifo_t * f, quic_build_sockaddr (&pctx->sa, &pctx->salen, &pctx->ph.rmt_ip, pctx->ph.rmt_port, pctx->ph.is_ip4); quicly_ctx = quic_get_quicly_ctx_from_udp (udp_session_handle); - plen = quicly_decode_packet (quicly_ctx, &pctx->packet, - pctx->data, pctx->ph.data_length); + + size_t off = 0; + plen = quicly_decode_packet (quicly_ctx, &pctx->packet, pctx->data, + pctx->ph.data_length, &off); if (plen == SIZE_MAX) { @@ -2197,7 +2223,9 @@ quic_process_one_rx_packet (u64 udp_session_handle, svm_fifo_t * f, if (rv == QUIC_PACKET_TYPE_RECEIVE) { pctx->ptype = QUIC_PACKET_TYPE_RECEIVE; - if (quic_main.vnet_crypto_enabled) + + if (quic_main.vnet_crypto_enabled && + quic_main.default_crypto_engine == CRYPTO_ENGINE_VPP) { quic_ctx_t *qctx = quic_ctx_get (pctx->ctx_index, thread_index); quic_crypto_decrypt_packet (qctx, pctx); @@ -2227,7 +2255,6 @@ static int quic_udp_session_rx_callback (session_t * udp_session) { /* Read data from UDP rx_fifo and pass it to the quicly conn. */ - quic_main_t *qm = &quic_main; quic_ctx_t *ctx = NULL, *prev_ctx = NULL; svm_fifo_t *f = udp_session->rx_fifo; u32 max_deq; @@ -2236,7 +2263,7 @@ quic_udp_session_rx_callback (session_t * udp_session) u32 thread_index = vlib_get_thread_index (); u32 cur_deq, fifo_offset, max_packets, i; - quic_rx_packet_ctx_t packets_ctx[QUIC_RCV_MAX_BATCH_PACKETS]; + quic_rx_packet_ctx_t packets_ctx[QUIC_RCV_MAX_PACKETS]; if (udp_session->flags & SESSION_F_IS_MIGRATING) { @@ -2250,13 +2277,12 @@ rx_start: return 0; fifo_offset = 0; - max_packets = QUIC_RCV_MAX_BATCH_PACKETS; + max_packets = QUIC_RCV_MAX_PACKETS; #if CLIB_DEBUG > 0 clib_memset (packets_ctx, 0xfa, - QUIC_RCV_MAX_BATCH_PACKETS * sizeof (quic_rx_packet_ctx_t)); + QUIC_RCV_MAX_PACKETS * sizeof (quic_rx_packet_ctx_t)); #endif - for (i = 0; i < max_packets; i++) { packets_ctx[i].thread_index = UINT32_MAX; @@ -2287,9 +2313,6 @@ rx_start: } } - quic_crypto_batch_rx_packets (&qm-> - wrk_ctx[thread_index].crypto_context_batch); - for (i = 0; i < max_packets; i++) { switch (packets_ctx[i].ptype) @@ -2424,7 +2447,9 @@ static const transport_proto_vft_t quic_proto = { /* *INDENT-ON* */ static quicly_stream_open_t on_stream_open = { quic_on_stream_open }; -static quicly_closed_by_peer_t on_closed_by_peer = { quic_on_closed_by_peer }; +static quicly_closed_by_remote_t on_closed_by_remote = { + quic_on_closed_by_remote +}; static quicly_now_t quicly_vpp_now_cb = { quic_get_time }; static void @@ -2502,9 +2527,6 @@ quic_init (vlib_main_t * vm) tw->last_run_time = vlib_time_now (vlib_get_main ()); clib_bihash_init_24_8 (&qm->wrk_ctx[i].crypto_context_hash, "quic crypto contexts", 64, 128 << 10); - - qm->wrk_ctx[i].crypto_context_batch.nb_rx_packets = 0; - qm->wrk_ctx[i].crypto_context_batch.nb_tx_packets = 0; } clib_bihash_init_16_8 (&qm->connection_hash, "quic connections", 1024, @@ -2522,18 +2544,26 @@ quic_init (vlib_main_t * vm) clib_bitmap_alloc (qm->available_crypto_engines, app_crypto_engine_n_types ()); - quic_register_cipher_suite (CRYPTO_ENGINE_VPP, quic_crypto_cipher_suites); quic_register_cipher_suite (CRYPTO_ENGINE_PICOTLS, ptls_openssl_cipher_suites); - qm->default_crypto_engine = CRYPTO_ENGINE_VPP; - qm->max_packets_per_key = DEFAULT_MAX_PACKETS_PER_KEY; - clib_rwlock_init (&qm->crypto_keys_quic_rw_lock); + qm->default_crypto_engine = CRYPTO_ENGINE_PICOTLS; vnet_crypto_main_t *cm = &crypto_main; if (vec_len (cm->engines) == 0) qm->vnet_crypto_enabled = 0; else qm->vnet_crypto_enabled = 1; + if (qm->vnet_crypto_enabled == 1) + { + quic_register_cipher_suite (CRYPTO_ENGINE_VPP, + quic_crypto_cipher_suites); + qm->default_crypto_engine = CRYPTO_ENGINE_VPP; + } + + qm->max_packets_per_key = DEFAULT_MAX_PACKETS_PER_KEY; + clib_rwlock_init (&qm->crypto_keys_quic_rw_lock); + + qm->default_quic_cc = QUIC_CC_RENO; vec_free (a->name); return 0; @@ -2757,6 +2787,26 @@ quic_format_connection_ctx (u8 * s, va_list * args) quicly_stats.num_packets.received, quicly_stats.num_packets.lost, quicly_stats.num_packets.ack_received); + s = + format (s, "\ncwnd:%u ssthresh:%u recovery_end:%lu", quicly_stats.cc.cwnd, + quicly_stats.cc.ssthresh, quicly_stats.cc.recovery_end); + + quicly_context_t *quicly_ctx = quic_get_quicly_ctx_from_ctx (ctx); + if (quicly_ctx->init_cc == &quicly_cc_cubic_init) + { + s = format ( + s, + "\nk:%d w_max:%u w_last_max:%u avoidance_start:%ld last_sent_time:%ld", + quicly_stats.cc.state.cubic.k, quicly_stats.cc.state.cubic.w_max, + quicly_stats.cc.state.cubic.w_last_max, + quicly_stats.cc.state.cubic.avoidance_start, + quicly_stats.cc.state.cubic.last_sent_time); + } + else if (quicly_ctx->init_cc == &quicly_cc_reno_init) + { + s = format (s, " stash:%u", quicly_stats.cc.state.reno.stash); + } + return s; } @@ -2840,10 +2890,9 @@ done: } /* *INDENT-OFF* */ -VLIB_CLI_COMMAND (quic_plugin_crypto_command, static) = -{ +VLIB_CLI_COMMAND (quic_plugin_crypto_command, static) = { .path = "quic set crypto api", - .short_help = "quic set crypto api [picotls, vpp]", + .short_help = "quic set crypto api [picotls|vpp]", .function = quic_plugin_crypto_command_fn, }; VLIB_CLI_COMMAND(quic_plugin_set_fifo_size_command, static)= @@ -2870,6 +2919,11 @@ VLIB_CLI_COMMAND (quic_set_max_packets_per_key, static) = .short_help = "set quic max_packets_per_key 16777216", .function = quic_set_max_packets_per_key_fn, }; +VLIB_CLI_COMMAND (quic_set_cc, static) = { + .path = "set quic cc", + .short_help = "set quic cc [reno|cubic]", + .function = quic_set_cc_fn, +}; VLIB_PLUGIN_REGISTER () = { .version = VPP_BUILD_VER, diff --git a/src/plugins/quic/quic.h b/src/plugins/quic/quic.h index a576650a0c6..901bdbc39b2 100644 --- a/src/plugins/quic/quic.h +++ b/src/plugins/quic/quic.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -47,8 +47,7 @@ #define QUIC_MAX_COALESCED_PACKET 4 -#define QUIC_SEND_MAX_BATCH_PACKETS 16 -#define QUIC_RCV_MAX_BATCH_PACKETS 16 +#define QUIC_RCV_MAX_PACKETS 16 #define QUIC_DEFAULT_CONN_TIMEOUT (30 * 1000) /* 30 seconds */ @@ -134,6 +133,12 @@ typedef enum quic_ctx_flags_ QUIC_F_IS_LISTENER = (1 << 1), } quic_ctx_flags_t; +typedef enum quic_cc_type +{ + QUIC_CC_RENO, + QUIC_CC_CUBIC, +} quic_cc_type_t; + /* This structure is used to implement the concept of VPP connection for QUIC. * We create one per connection and one per stream. */ typedef struct quic_ctx_ @@ -210,25 +215,6 @@ typedef struct quic_crypto_context_data_ ptls_context_t ptls_ctx; } quic_crypto_context_data_t; -typedef struct quic_encrypt_cb_ctx_ -{ - quicly_datagram_t *packet; - struct quic_finalize_send_packet_cb_ctx_ - { - size_t payload_from; - size_t first_byte_at; - ptls_cipher_context_t *hp; - } snd_ctx[QUIC_MAX_COALESCED_PACKET]; - size_t snd_ctx_count; -} quic_encrypt_cb_ctx; - -typedef struct quic_crypto_batch_ctx_ -{ - vnet_crypto_op_t aead_crypto_tx_packets_ops[QUIC_SEND_MAX_BATCH_PACKETS], - aead_crypto_rx_packets_ops[QUIC_RCV_MAX_BATCH_PACKETS]; - size_t nb_tx_packets, nb_rx_packets; -} quic_crypto_batch_ctx_t; - typedef struct quic_worker_ctx_ { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); @@ -237,7 +223,6 @@ typedef struct quic_worker_ctx_ quicly_cid_plaintext_t next_cid; crypto_context_t *crypto_ctx_pool; /**< per thread pool of crypto contexes */ clib_bihash_24_8_t crypto_context_hash; /**< per thread [params:crypto_ctx_index] hash */ - quic_crypto_batch_ctx_t crypto_context_batch; } quic_worker_ctx_t; typedef struct quic_rx_packet_ctx_ @@ -268,6 +253,7 @@ typedef struct quic_main_ uword *available_crypto_engines; /**< Bitmap for registered engines */ u8 default_crypto_engine; /**< Used if you do connect with CRYPTO_ENGINE_NONE (0) */ u64 max_packets_per_key; /**< number of packets that can be sent without a key update */ + u8 default_quic_cc; ptls_handshake_properties_t hs_properties; quic_session_cache_t session_cache; diff --git a/src/plugins/quic/quic_crypto.c b/src/plugins/quic/quic_crypto.c index 35dddf63c71..5e90563885e 100644 --- a/src/plugins/quic/quic_crypto.c +++ b/src/plugins/quic/quic_crypto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -12,8 +12,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include -#include #include #include @@ -25,14 +23,13 @@ extern quic_main_t quic_main; extern quic_ctx_t *quic_get_conn_ctx (quicly_conn_t * conn); - -typedef void (*quicly_do_transform_fn) (ptls_cipher_context_t *, void *, - const void *, size_t); +vnet_crypto_main_t *cm = &crypto_main; struct cipher_context_t { ptls_cipher_context_t super; vnet_crypto_op_t op; + vnet_crypto_op_id_t id; u32 key_index; }; @@ -41,139 +38,35 @@ struct aead_crypto_context_t ptls_aead_context_t super; vnet_crypto_op_t op; u32 key_index; + vnet_crypto_op_id_t id; + uint8_t iv[PTLS_MAX_IV_SIZE]; + uint8_t static_iv[PTLS_MAX_IV_SIZE]; }; -static size_t -quic_crypto_offload_aead_decrypt (quic_ctx_t * qctx, - ptls_aead_context_t * _ctx, void *_output, - const void *input, size_t inlen, - uint64_t decrypted_pn, const void *aad, - size_t aadlen); - -vnet_crypto_main_t *cm = &crypto_main; - -void -quic_crypto_batch_tx_packets (quic_crypto_batch_ctx_t * batch_ctx) -{ - vlib_main_t *vm = vlib_get_main (); - - if (batch_ctx->nb_tx_packets <= 0) - return; - - clib_rwlock_reader_lock (&quic_main.crypto_keys_quic_rw_lock); - vnet_crypto_process_ops (vm, batch_ctx->aead_crypto_tx_packets_ops, - batch_ctx->nb_tx_packets); - clib_rwlock_reader_unlock (&quic_main.crypto_keys_quic_rw_lock); - - for (int i = 0; i < batch_ctx->nb_tx_packets; i++) - clib_mem_free (batch_ctx->aead_crypto_tx_packets_ops[i].iv); - - batch_ctx->nb_tx_packets = 0; -} - -void -quic_crypto_batch_rx_packets (quic_crypto_batch_ctx_t * batch_ctx) -{ - vlib_main_t *vm = vlib_get_main (); - - if (batch_ctx->nb_rx_packets <= 0) - return; - - clib_rwlock_reader_lock (&quic_main.crypto_keys_quic_rw_lock); - vnet_crypto_process_ops (vm, batch_ctx->aead_crypto_rx_packets_ops, - batch_ctx->nb_rx_packets); - clib_rwlock_reader_unlock (&quic_main.crypto_keys_quic_rw_lock); - - for (int i = 0; i < batch_ctx->nb_rx_packets; i++) - clib_mem_free (batch_ctx->aead_crypto_rx_packets_ops[i].iv); - - batch_ctx->nb_rx_packets = 0; -} - -void -build_iv (ptls_aead_context_t * ctx, uint8_t * iv, uint64_t seq) -{ - size_t iv_size = ctx->algo->iv_size, i; - const uint8_t *s = ctx->static_iv; - uint8_t *d = iv; - /* build iv */ - for (i = iv_size - 8; i != 0; --i) - *d++ = *s++; - i = 64; - do - { - i -= 8; - *d++ = *s++ ^ (uint8_t) (seq >> i); - } - while (i != 0); -} - -static void -do_finalize_send_packet (ptls_cipher_context_t * hp, - quicly_datagram_t * packet, - size_t first_byte_at, size_t payload_from) -{ - uint8_t hpmask[1 + QUICLY_SEND_PN_SIZE] = { - 0 - }; - size_t i; - - ptls_cipher_init (hp, - packet->data.base + payload_from - QUICLY_SEND_PN_SIZE + - QUICLY_MAX_PN_SIZE); - ptls_cipher_encrypt (hp, hpmask, hpmask, sizeof (hpmask)); - - packet->data.base[first_byte_at] ^= - hpmask[0] & - (QUICLY_PACKET_IS_LONG_HEADER (packet->data.base[first_byte_at]) ? 0xf : - 0x1f); - - for (i = 0; i != QUICLY_SEND_PN_SIZE; ++i) - packet->data.base[payload_from + i - QUICLY_SEND_PN_SIZE] ^= - hpmask[i + 1]; -} - -void -quic_crypto_finalize_send_packet (quicly_datagram_t * packet) -{ - quic_encrypt_cb_ctx *encrypt_cb_ctx = - (quic_encrypt_cb_ctx *) ((uint8_t *) packet + sizeof (*packet)); - - for (int i = 0; i < encrypt_cb_ctx->snd_ctx_count; i++) - { - do_finalize_send_packet (encrypt_cb_ctx->snd_ctx[i].hp, - packet, - encrypt_cb_ctx->snd_ctx[i].first_byte_at, - encrypt_cb_ctx->snd_ctx[i].payload_from); - } - encrypt_cb_ctx->snd_ctx_count = 0; -} - static int -quic_crypto_setup_cipher (quicly_crypto_engine_t * engine, - quicly_conn_t * conn, size_t epoch, int is_enc, - ptls_cipher_context_t ** hp_ctx, - ptls_aead_context_t ** aead_ctx, - ptls_aead_algorithm_t * aead, - ptls_hash_algorithm_t * hash, const void *secret) +quic_crypto_setup_cipher (quicly_crypto_engine_t *engine, quicly_conn_t *conn, + size_t epoch, int is_enc, + ptls_cipher_context_t **header_protect_ctx, + ptls_aead_context_t **packet_protect_ctx, + ptls_aead_algorithm_t *aead, + ptls_hash_algorithm_t *hash, const void *secret) { uint8_t hpkey[PTLS_MAX_SECRET_SIZE]; int ret; - *aead_ctx = NULL; + *packet_protect_ctx = NULL; + /* generate new header protection key */ - if (hp_ctx != NULL) + if (header_protect_ctx != NULL) { - *hp_ctx = NULL; - ret = ptls_hkdf_expand_label (hash, hpkey, aead->ctr_cipher->key_size, - ptls_iovec_init (secret, - hash->digest_size), - "quic hp", ptls_iovec_init (NULL, 0), - NULL); - if (ret) + *header_protect_ctx = NULL; + if ((ret = ptls_hkdf_expand_label ( + hash, hpkey, aead->ctr_cipher->key_size, + ptls_iovec_init (secret, hash->digest_size), "quic hp", + ptls_iovec_init (NULL, 0), NULL)) != 0) goto Exit; - *hp_ctx = ptls_cipher_new (aead->ctr_cipher, is_enc, hpkey); - if (NULL == *hp_ctx) + if ((*header_protect_ctx = + ptls_cipher_new (aead->ctr_cipher, is_enc, hpkey)) == NULL) { ret = PTLS_ERROR_NO_MEMORY; goto Exit; @@ -181,9 +74,8 @@ quic_crypto_setup_cipher (quicly_crypto_engine_t * engine, } /* generate new AEAD context */ - *aead_ctx = ptls_aead_new (aead, hash, is_enc, secret, - QUICLY_AEAD_BASE_LABEL); - if (NULL == *aead_ctx) + if ((*packet_protect_ctx = ptls_aead_new (aead, hash, is_enc, secret, + QUICLY_AEAD_BASE_LABEL)) == NULL) { ret = PTLS_ERROR_NO_MEMORY; goto Exit; @@ -195,9 +87,9 @@ quic_crypto_setup_cipher (quicly_crypto_engine_t * engine, if (qctx->ingress_keys.aead_ctx != NULL) qctx->key_phase_ingress++; - qctx->ingress_keys.aead_ctx = *aead_ctx; - if (hp_ctx != NULL) - qctx->ingress_keys.hp_ctx = *hp_ctx; + qctx->ingress_keys.aead_ctx = *packet_protect_ctx; + if (header_protect_ctx != NULL) + qctx->ingress_keys.hp_ctx = *header_protect_ctx; } ret = 0; @@ -205,39 +97,47 @@ quic_crypto_setup_cipher (quicly_crypto_engine_t * engine, Exit: if (ret) { - if (*aead_ctx != NULL) + if (packet_protect_ctx && *packet_protect_ctx != NULL) { - ptls_aead_free (*aead_ctx); - *aead_ctx = NULL; + ptls_aead_free (*packet_protect_ctx); + *packet_protect_ctx = NULL; } - if (hp_ctx && *hp_ctx != NULL) + if (header_protect_ctx && *header_protect_ctx != NULL) { - ptls_cipher_free (*hp_ctx); - *hp_ctx = NULL; + ptls_cipher_free (*header_protect_ctx); + *header_protect_ctx = NULL; } } ptls_clear_memory (hpkey, sizeof (hpkey)); return ret; } -void -quic_crypto_finalize_send_packet_cb (struct st_quicly_crypto_engine_t - *engine, quicly_conn_t * conn, - ptls_cipher_context_t * hp, - ptls_aead_context_t * aead, - quicly_datagram_t * packet, - size_t first_byte_at, - size_t payload_from, int coalesced) +static size_t +quic_crypto_aead_decrypt (quic_ctx_t *qctx, ptls_aead_context_t *_ctx, + void *_output, const void *input, size_t inlen, + uint64_t decrypted_pn, const void *aad, + size_t aadlen) { - quic_encrypt_cb_ctx *encrypt_cb_ctx = - (quic_encrypt_cb_ctx *) ((uint8_t *) packet + sizeof (*packet)); - - encrypt_cb_ctx->snd_ctx[encrypt_cb_ctx->snd_ctx_count].hp = hp; - encrypt_cb_ctx->snd_ctx[encrypt_cb_ctx->snd_ctx_count].first_byte_at = - first_byte_at; - encrypt_cb_ctx->snd_ctx[encrypt_cb_ctx->snd_ctx_count].payload_from = - payload_from; - encrypt_cb_ctx->snd_ctx_count++; + vlib_main_t *vm = vlib_get_main (); + + struct aead_crypto_context_t *ctx = (struct aead_crypto_context_t *) _ctx; + + vnet_crypto_op_init (&ctx->op, ctx->id); + ctx->op.aad = (u8 *) aad; + ctx->op.aad_len = aadlen; + ctx->op.iv = ctx->iv; + ptls_aead__build_iv (ctx->super.algo, ctx->op.iv, ctx->static_iv, + decrypted_pn); + ctx->op.src = (u8 *) input; + ctx->op.dst = _output; + ctx->op.key_index = ctx->key_index; + ctx->op.len = inlen - ctx->super.algo->tag_size; + ctx->op.tag_len = ctx->super.algo->tag_size; + ctx->op.tag = ctx->op.src + ctx->op.len; + + vnet_crypto_process_ops (vm, &(ctx->op), 1); + + return ctx->op.len; } void @@ -310,13 +210,11 @@ quic_crypto_decrypt_packet (quic_ctx_t * qctx, quic_rx_packet_ctx_t * pctx) return; } - if ((ptlen = - quic_crypto_offload_aead_decrypt (qctx, aead, - pctx->packet.octets.base + aead_off, - pctx->packet.octets.base + aead_off, - pctx->packet.octets.len - aead_off, - pn, pctx->packet.octets.base, - aead_off)) == SIZE_MAX) + if ((ptlen = quic_crypto_aead_decrypt ( + qctx, aead, pctx->packet.octets.base + aead_off, + pctx->packet.octets.base + aead_off, + pctx->packet.octets.len - aead_off, pn, pctx->packet.octets.base, + aead_off)) == SIZE_MAX) { fprintf (stderr, "%s: aead decryption failure (pn: %d)\n", __FUNCTION__, pn); @@ -330,71 +228,92 @@ quic_crypto_decrypt_packet (quic_ctx_t * qctx, quic_rx_packet_ctx_t * pctx) pctx->packet.decrypted.key_phase = qctx->key_phase_ingress; } -#ifdef QUIC_HP_CRYPTO -static void -quic_crypto_cipher_do_init (ptls_cipher_context_t * _ctx, const void *iv) -{ - struct cipher_context_t *ctx = (struct cipher_context_t *) _ctx; - vnet_crypto_op_id_t id; - if (!strcmp (ctx->super.algo->name, "AES128-CTR")) - { - id = VNET_CRYPTO_OP_AES_128_CTR_ENC; - } - else if (!strcmp (ctx->super.algo->name, "AES256-CTR")) - { - id = VNET_CRYPTO_OP_AES_256_CTR_ENC; - } - else - { - QUIC_DBG (1, "%s, Invalid crypto cipher : ", __FUNCTION__, - _ctx->algo->name); - assert (0); - } - vnet_crypto_op_init (&ctx->op, id); - ctx->op.iv = (u8 *) iv; - ctx->op.key_index = ctx->key_index; -} - -static void -quic_crypto_cipher_dispose (ptls_cipher_context_t * _ctx) -{ - /* Do nothing */ -} - -static void -quic_crypto_cipher_encrypt (ptls_cipher_context_t * _ctx, void *output, - const void *input, size_t _len) +void +quic_crypto_encrypt_packet (struct st_quicly_crypto_engine_t *engine, + quicly_conn_t *conn, + ptls_cipher_context_t *header_protect_ctx, + ptls_aead_context_t *packet_protect_ctx, + ptls_iovec_t datagram, size_t first_byte_at, + size_t payload_from, uint64_t packet_number, + int coalesced) { vlib_main_t *vm = vlib_get_main (); - struct cipher_context_t *ctx = (struct cipher_context_t *) _ctx; - ctx->op.src = (u8 *) input; - ctx->op.dst = output; - ctx->op.len = _len; + struct cipher_context_t *hp_ctx = + (struct cipher_context_t *) header_protect_ctx; + struct aead_crypto_context_t *aead_ctx = + (struct aead_crypto_context_t *) packet_protect_ctx; + + void *input = datagram.base + payload_from; + void *output = input; + size_t inlen = + datagram.len - payload_from - packet_protect_ctx->algo->tag_size; + const void *aad = datagram.base + first_byte_at; + size_t aadlen = payload_from - first_byte_at; + + /* Build AEAD encrypt crypto operation */ + vnet_crypto_op_init (&aead_ctx->op, aead_ctx->id); + aead_ctx->op.aad = (u8 *) aad; + aead_ctx->op.aad_len = aadlen; + aead_ctx->op.iv = aead_ctx->iv; + ptls_aead__build_iv (aead_ctx->super.algo, aead_ctx->op.iv, + aead_ctx->static_iv, packet_number); + aead_ctx->op.key_index = aead_ctx->key_index; + aead_ctx->op.src = (u8 *) input; + aead_ctx->op.dst = output; + aead_ctx->op.len = inlen; + aead_ctx->op.tag_len = aead_ctx->super.algo->tag_size; + aead_ctx->op.tag = aead_ctx->op.src + inlen; + vnet_crypto_process_ops (vm, &(aead_ctx->op), 1); + assert (aead_ctx->op.status == VNET_CRYPTO_OP_STATUS_COMPLETED); + + /* Build Header protection crypto operation */ + ptls_aead_supplementary_encryption_t supp = { + .ctx = header_protect_ctx, + .input = + datagram.base + payload_from - QUICLY_SEND_PN_SIZE + QUICLY_MAX_PN_SIZE + }; - vnet_crypto_process_ops (vm, &ctx->op, 1); + /* Build Header protection crypto operation */ + vnet_crypto_op_init (&hp_ctx->op, hp_ctx->id); + memset (supp.output, 0, sizeof (supp.output)); + hp_ctx->op.iv = (u8 *) supp.input; + hp_ctx->op.key_index = hp_ctx->key_index; + hp_ctx->op.src = (u8 *) supp.output; + hp_ctx->op.dst = (u8 *) supp.output; + hp_ctx->op.len = sizeof (supp.output); + vnet_crypto_process_ops (vm, &(hp_ctx->op), 1); + assert (hp_ctx->op.status == VNET_CRYPTO_OP_STATUS_COMPLETED); + + datagram.base[first_byte_at] ^= + supp.output[0] & + (QUICLY_PACKET_IS_LONG_HEADER (datagram.base[first_byte_at]) ? 0xf : 0x1f); + for (size_t i = 0; i != QUICLY_SEND_PN_SIZE; ++i) + datagram.base[payload_from + i - QUICLY_SEND_PN_SIZE] ^= + supp.output[i + 1]; } static int -quic_crypto_cipher_setup_crypto (ptls_cipher_context_t * _ctx, int is_enc, - const void *key, const EVP_CIPHER * cipher, - quicly_do_transform_fn do_transform) +quic_crypto_cipher_setup_crypto (ptls_cipher_context_t *_ctx, int is_enc, + const void *key, const EVP_CIPHER *cipher) { struct cipher_context_t *ctx = (struct cipher_context_t *) _ctx; - ctx->super.do_dispose = quic_crypto_cipher_dispose; - ctx->super.do_init = quic_crypto_cipher_do_init; - ctx->super.do_transform = do_transform; - vlib_main_t *vm = vlib_get_main (); vnet_crypto_alg_t algo; if (!strcmp (ctx->super.algo->name, "AES128-CTR")) { algo = VNET_CRYPTO_ALG_AES_128_CTR; + ctx->id = is_enc ? VNET_CRYPTO_OP_AES_128_CTR_ENC : + VNET_CRYPTO_OP_AES_128_CTR_DEC; + ptls_openssl_aes128ctr.setup_crypto (_ctx, is_enc, key); } else if (!strcmp (ctx->super.algo->name, "AES256-CTR")) { algo = VNET_CRYPTO_ALG_AES_256_CTR; + ctx->id = is_enc ? VNET_CRYPTO_OP_AES_256_CTR_ENC : + VNET_CRYPTO_OP_AES_256_CTR_DEC; + ptls_openssl_aes256ctr.setup_crypto (_ctx, is_enc, key); } else { @@ -403,8 +322,13 @@ quic_crypto_cipher_setup_crypto (ptls_cipher_context_t * _ctx, int is_enc, assert (0); } - ctx->key_index = vnet_crypto_key_add (vm, algo, - (u8 *) key, _ctx->algo->key_size); + if (quic_main.vnet_crypto_enabled) + { + clib_rwlock_writer_lock (&quic_main.crypto_keys_quic_rw_lock); + ctx->key_index = + vnet_crypto_key_add (vm, algo, (u8 *) key, _ctx->algo->key_size); + clib_rwlock_writer_unlock (&quic_main.crypto_keys_quic_rw_lock); + } return 0; } @@ -413,193 +337,20 @@ static int quic_crypto_aes128ctr_setup_crypto (ptls_cipher_context_t * ctx, int is_enc, const void *key) { - return quic_crypto_cipher_setup_crypto (ctx, 1, key, EVP_aes_128_ctr (), - quic_crypto_cipher_encrypt); + return quic_crypto_cipher_setup_crypto (ctx, 1, key, EVP_aes_128_ctr ()); } static int quic_crypto_aes256ctr_setup_crypto (ptls_cipher_context_t * ctx, int is_enc, const void *key) { - return quic_crypto_cipher_setup_crypto (ctx, 1, key, EVP_aes_256_ctr (), - quic_crypto_cipher_encrypt); -} - -#endif // QUIC_HP_CRYPTO - -void -quic_crypto_aead_encrypt_init (ptls_aead_context_t * _ctx, const void *iv, - const void *aad, size_t aadlen) -{ - quic_main_t *qm = &quic_main; - u32 thread_index = vlib_get_thread_index (); - - struct aead_crypto_context_t *ctx = (struct aead_crypto_context_t *) _ctx; - - vnet_crypto_op_id_t id; - if (!strcmp (ctx->super.algo->name, "AES128-GCM")) - { - id = VNET_CRYPTO_OP_AES_128_GCM_ENC; - } - else if (!strcmp (ctx->super.algo->name, "AES256-GCM")) - { - id = VNET_CRYPTO_OP_AES_256_GCM_ENC; - } - else - { - assert (0); - } - - quic_crypto_batch_ctx_t *quic_crypto_batch_ctx = - &qm->wrk_ctx[thread_index].crypto_context_batch; - - vnet_crypto_op_t *vnet_op = - &quic_crypto_batch_ctx->aead_crypto_tx_packets_ops - [quic_crypto_batch_ctx->nb_tx_packets]; - vnet_crypto_op_init (vnet_op, id); - vnet_op->aad = (u8 *) aad; - vnet_op->aad_len = aadlen; - vnet_op->iv = clib_mem_alloc (PTLS_MAX_IV_SIZE); - clib_memcpy (vnet_op->iv, iv, PTLS_MAX_IV_SIZE); - vnet_op->key_index = ctx->key_index; -} - -size_t -quic_crypto_aead_encrypt_update (ptls_aead_context_t * _ctx, void *output, - const void *input, size_t inlen) -{ - struct aead_crypto_context_t *ctx = (struct aead_crypto_context_t *) _ctx; - - quic_main_t *qm = &quic_main; - u32 thread_index = vlib_get_thread_index (); - quic_crypto_batch_ctx_t *quic_crypto_batch_ctx = - &qm->wrk_ctx[thread_index].crypto_context_batch; - - vnet_crypto_op_t *vnet_op = - &quic_crypto_batch_ctx->aead_crypto_tx_packets_ops - [quic_crypto_batch_ctx->nb_tx_packets]; - vnet_op->src = (u8 *) input; - vnet_op->dst = output; - vnet_op->len = inlen; - vnet_op->tag_len = ctx->super.algo->tag_size; - - vnet_op->tag = vnet_op->src + inlen; - - return 0; -} - -size_t -quic_crypto_aead_encrypt_final (ptls_aead_context_t * _ctx, void *output) -{ - quic_main_t *qm = &quic_main; - u32 thread_index = vlib_get_thread_index (); - quic_crypto_batch_ctx_t *quic_crypto_batch_ctx = - &qm->wrk_ctx[thread_index].crypto_context_batch; - - vnet_crypto_op_t *vnet_op = - &quic_crypto_batch_ctx-> - aead_crypto_tx_packets_ops[quic_crypto_batch_ctx->nb_tx_packets]; - quic_crypto_batch_ctx->nb_tx_packets++; - return vnet_op->len + vnet_op->tag_len; -} - -size_t -quic_crypto_aead_decrypt (ptls_aead_context_t * _ctx, void *_output, - const void *input, size_t inlen, const void *iv, - const void *aad, size_t aadlen) -{ - vlib_main_t *vm = vlib_get_main (); - struct aead_crypto_context_t *ctx = (struct aead_crypto_context_t *) _ctx; - - vnet_crypto_op_id_t id; - if (!strcmp (ctx->super.algo->name, "AES128-GCM")) - { - id = VNET_CRYPTO_OP_AES_128_GCM_DEC; - } - else if (!strcmp (ctx->super.algo->name, "AES256-GCM")) - { - id = VNET_CRYPTO_OP_AES_256_GCM_DEC; - } - else - { - assert (0); - } - - vnet_crypto_op_init (&ctx->op, id); - ctx->op.aad = (u8 *) aad; - ctx->op.aad_len = aadlen; - ctx->op.iv = (u8 *) iv; - - ctx->op.src = (u8 *) input; - ctx->op.dst = _output; - ctx->op.key_index = ctx->key_index; - ctx->op.len = inlen - ctx->super.algo->tag_size; - - ctx->op.tag_len = ctx->super.algo->tag_size; - ctx->op.tag = ctx->op.src + ctx->op.len; - - vnet_crypto_process_ops (vm, &ctx->op, 1); - - if (ctx->op.status != VNET_CRYPTO_OP_STATUS_COMPLETED) - return SIZE_MAX; - - return ctx->op.len; -} - -static size_t -quic_crypto_offload_aead_decrypt (quic_ctx_t * qctx, - ptls_aead_context_t * _ctx, void *_output, - const void *input, size_t inlen, - uint64_t decrypted_pn, const void *aad, - size_t aadlen) -{ - struct aead_crypto_context_t *ctx = (struct aead_crypto_context_t *) _ctx; - vnet_crypto_op_id_t id; - if (!strcmp (ctx->super.algo->name, "AES128-GCM")) - { - id = VNET_CRYPTO_OP_AES_128_GCM_DEC; - } - else if (!strcmp (ctx->super.algo->name, "AES256-GCM")) - { - id = VNET_CRYPTO_OP_AES_256_GCM_DEC; - } - else - { - return SIZE_MAX; - } - - quic_main_t *qm = &quic_main; - quic_crypto_batch_ctx_t *quic_crypto_batch_ctx = - &qm->wrk_ctx[qctx->c_thread_index].crypto_context_batch; - - vnet_crypto_op_t *vnet_op = - &quic_crypto_batch_ctx->aead_crypto_rx_packets_ops - [quic_crypto_batch_ctx->nb_rx_packets]; - - vnet_crypto_op_init (vnet_op, id); - vnet_op->aad = (u8 *) aad; - vnet_op->aad_len = aadlen; - vnet_op->iv = clib_mem_alloc (PTLS_MAX_IV_SIZE); - build_iv (_ctx, vnet_op->iv, decrypted_pn); - vnet_op->src = (u8 *) input; - vnet_op->dst = _output; - vnet_op->key_index = ctx->key_index; - vnet_op->len = inlen - ctx->super.algo->tag_size; - vnet_op->tag_len = ctx->super.algo->tag_size; - vnet_op->tag = vnet_op->src + vnet_op->len; - quic_crypto_batch_ctx->nb_rx_packets++; - return vnet_op->len; -} - -static void -quic_crypto_aead_dispose_crypto (ptls_aead_context_t * _ctx) -{ - + return quic_crypto_cipher_setup_crypto (ctx, 1, key, EVP_aes_256_ctr ()); } static int -quic_crypto_aead_setup_crypto (ptls_aead_context_t * _ctx, int is_enc, - const void *key, const EVP_CIPHER * cipher) +quic_crypto_aead_setup_crypto (ptls_aead_context_t *_ctx, int is_enc, + const void *key, const void *iv, + const EVP_CIPHER *cipher) { vlib_main_t *vm = vlib_get_main (); struct aead_crypto_context_t *ctx = (struct aead_crypto_context_t *) _ctx; @@ -608,10 +359,16 @@ quic_crypto_aead_setup_crypto (ptls_aead_context_t * _ctx, int is_enc, if (!strcmp (ctx->super.algo->name, "AES128-GCM")) { algo = VNET_CRYPTO_ALG_AES_128_GCM; + ctx->id = is_enc ? VNET_CRYPTO_OP_AES_128_GCM_ENC : + VNET_CRYPTO_OP_AES_128_GCM_DEC; + ptls_openssl_aes128gcm.setup_crypto (_ctx, is_enc, key, iv); } else if (!strcmp (ctx->super.algo->name, "AES256-GCM")) { algo = VNET_CRYPTO_ALG_AES_256_GCM; + ctx->id = is_enc ? VNET_CRYPTO_OP_AES_256_GCM_ENC : + VNET_CRYPTO_OP_AES_256_GCM_DEC; + ptls_openssl_aes256gcm.setup_crypto (_ctx, is_enc, key, iv); } else { @@ -622,64 +379,97 @@ quic_crypto_aead_setup_crypto (ptls_aead_context_t * _ctx, int is_enc, if (quic_main.vnet_crypto_enabled) { - ctx->super.do_decrypt = quic_crypto_aead_decrypt; - - ctx->super.do_encrypt_init = quic_crypto_aead_encrypt_init; - ctx->super.do_encrypt_update = quic_crypto_aead_encrypt_update; - ctx->super.do_encrypt_final = quic_crypto_aead_encrypt_final; - ctx->super.dispose_crypto = quic_crypto_aead_dispose_crypto; + clib_memcpy (ctx->static_iv, iv, ctx->super.algo->iv_size); clib_rwlock_writer_lock (&quic_main.crypto_keys_quic_rw_lock); ctx->key_index = vnet_crypto_key_add (vm, algo, (u8 *) key, _ctx->algo->key_size); clib_rwlock_writer_unlock (&quic_main.crypto_keys_quic_rw_lock); } - else - { - if (!strcmp (ctx->super.algo->name, "AES128-GCM")) - ptls_openssl_aes128gcm.setup_crypto (_ctx, is_enc, key); - else if (!strcmp (ctx->super.algo->name, "AES256-GCM")) - ptls_openssl_aes256gcm.setup_crypto (_ctx, is_enc, key); - } return 0; } static int -quic_crypto_aead_aes128gcm_setup_crypto (ptls_aead_context_t * ctx, - int is_enc, const void *key) +quic_crypto_aead_aes128gcm_setup_crypto (ptls_aead_context_t *ctx, int is_enc, + const void *key, const void *iv) { - return quic_crypto_aead_setup_crypto (ctx, is_enc, key, EVP_aes_128_gcm ()); + return quic_crypto_aead_setup_crypto (ctx, is_enc, key, iv, + EVP_aes_128_gcm ()); } static int -quic_crypto_aead_aes256gcm_setup_crypto (ptls_aead_context_t * ctx, - int is_enc, const void *key) +quic_crypto_aead_aes256gcm_setup_crypto (ptls_aead_context_t *ctx, int is_enc, + const void *key, const void *iv) +{ + return quic_crypto_aead_setup_crypto (ctx, is_enc, key, iv, + EVP_aes_256_gcm ()); +} + +int +quic_encrypt_ticket_cb (ptls_encrypt_ticket_t *_self, ptls_t *tls, + int is_encrypt, ptls_buffer_t *dst, ptls_iovec_t src) { - return quic_crypto_aead_setup_crypto (ctx, is_enc, key, EVP_aes_256_gcm ()); + quic_session_cache_t *self = (void *) _self; + int ret; + + if (is_encrypt) + { + + /* replace the cached entry along with a newly generated session id */ + clib_mem_free (self->data.base); + if ((self->data.base = clib_mem_alloc (src.len)) == NULL) + return PTLS_ERROR_NO_MEMORY; + + ptls_get_context (tls)->random_bytes (self->id, sizeof (self->id)); + clib_memcpy (self->data.base, src.base, src.len); + self->data.len = src.len; + + /* store the session id in buffer */ + if ((ret = ptls_buffer_reserve (dst, sizeof (self->id))) != 0) + return ret; + clib_memcpy (dst->base + dst->off, self->id, sizeof (self->id)); + dst->off += sizeof (self->id); + } + else + { + /* check if session id is the one stored in cache */ + if (src.len != sizeof (self->id)) + return PTLS_ERROR_SESSION_NOT_FOUND; + if (clib_memcmp (self->id, src.base, sizeof (self->id)) != 0) + return PTLS_ERROR_SESSION_NOT_FOUND; + + /* return the cached value */ + if ((ret = ptls_buffer_reserve (dst, self->data.len)) != 0) + return ret; + clib_memcpy (dst->base + dst->off, self->data.base, self->data.len); + dst->off += self->data.len; + } + + return 0; } -#ifdef QUIC_HP_CRYPTO ptls_cipher_algorithm_t quic_crypto_aes128ctr = { "AES128-CTR", PTLS_AES128_KEY_SIZE, - 1, PTLS_AES_IV_SIZE, - sizeof (struct cipher_context_t), aes128ctr_setup_crypto + 1, + PTLS_AES_IV_SIZE, + sizeof (struct cipher_context_t), + quic_crypto_aes128ctr_setup_crypto }; ptls_cipher_algorithm_t quic_crypto_aes256ctr = { - "AES256-CTR", PTLS_AES256_KEY_SIZE, 1 /* block size */ , - PTLS_AES_IV_SIZE, sizeof (struct cipher_context_t), aes256ctr_setup_crypto + "AES256-CTR", + PTLS_AES256_KEY_SIZE, + 1 /* block size */, + PTLS_AES_IV_SIZE, + sizeof (struct cipher_context_t), + quic_crypto_aes256ctr_setup_crypto }; -#endif ptls_aead_algorithm_t quic_crypto_aes128gcm = { "AES128-GCM", -#ifdef QUIC_HP_CRYPTO &quic_crypto_aes128ctr, -#else - &ptls_openssl_aes128ctr, -#endif &ptls_openssl_aes128ecb, PTLS_AES128_KEY_SIZE, PTLS_AESGCM_IV_SIZE, @@ -690,11 +480,7 @@ ptls_aead_algorithm_t quic_crypto_aes128gcm = { ptls_aead_algorithm_t quic_crypto_aes256gcm = { "AES256-GCM", -#ifdef QUIC_HP_CRYPTO &quic_crypto_aes256ctr, -#else - &ptls_openssl_aes256ctr, -#endif &ptls_openssl_aes256ecb, PTLS_AES256_KEY_SIZE, PTLS_AESGCM_IV_SIZE, @@ -717,54 +503,8 @@ ptls_cipher_suite_t *quic_crypto_cipher_suites[] = { &quic_crypto_aes256gcmsha384, &quic_crypto_aes128gcmsha256, NULL }; -quicly_crypto_engine_t quic_crypto_engine = { - quic_crypto_setup_cipher, quic_crypto_finalize_send_packet_cb -}; - -int -quic_encrypt_ticket_cb (ptls_encrypt_ticket_t * _self, ptls_t * tls, - int is_encrypt, ptls_buffer_t * dst, ptls_iovec_t src) -{ - quic_session_cache_t *self = (void *) _self; - int ret; - - if (is_encrypt) - { - - /* replace the cached entry along with a newly generated session id */ - clib_mem_free (self->data.base); - if ((self->data.base = clib_mem_alloc (src.len)) == NULL) - return PTLS_ERROR_NO_MEMORY; - - ptls_get_context (tls)->random_bytes (self->id, sizeof (self->id)); - clib_memcpy (self->data.base, src.base, src.len); - self->data.len = src.len; - - /* store the session id in buffer */ - if ((ret = ptls_buffer_reserve (dst, sizeof (self->id))) != 0) - return ret; - clib_memcpy (dst->base + dst->off, self->id, sizeof (self->id)); - dst->off += sizeof (self->id); - - } - else - { - - /* check if session id is the one stored in cache */ - if (src.len != sizeof (self->id)) - return PTLS_ERROR_SESSION_NOT_FOUND; - if (clib_memcmp (self->id, src.base, sizeof (self->id)) != 0) - return PTLS_ERROR_SESSION_NOT_FOUND; - - /* return the cached value */ - if ((ret = ptls_buffer_reserve (dst, self->data.len)) != 0) - return ret; - clib_memcpy (dst->base + dst->off, self->data.base, self->data.len); - dst->off += self->data.len; - } - - return 0; -} +quicly_crypto_engine_t quic_crypto_engine = { quic_crypto_setup_cipher, + quic_crypto_encrypt_packet }; /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/quic/quic_crypto.h b/src/plugins/quic/quic_crypto.h index 930b31b2cb4..2adb20237a3 100644 --- a/src/plugins/quic/quic_crypto.h +++ b/src/plugins/quic/quic_crypto.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Cisco and/or its affiliates. + * Copyright (c) 2021 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -19,8 +19,6 @@ #include struct quic_ctx_t; -struct quic_rx_packet_ctx_t; -struct quic_crypto_batch_ctx_t; extern ptls_cipher_suite_t *quic_crypto_cipher_suites[]; @@ -29,21 +27,8 @@ int quic_encrypt_ticket_cb (ptls_encrypt_ticket_t * _self, ptls_t * tls, ptls_iovec_t src); void quic_crypto_decrypt_packet (quic_ctx_t * qctx, quic_rx_packet_ctx_t * pctx); -void quic_crypto_batch_tx_packets (quic_crypto_batch_ctx_t * batch_ctx); -void quic_crypto_batch_rx_packets (quic_crypto_batch_ctx_t * batch_ctx); -void quic_crypto_finalize_send_packet (quicly_datagram_t * packet); - -void -quic_crypto_finalize_send_packet_cb (struct st_quicly_crypto_engine_t *engine, - quicly_conn_t * conn, - ptls_cipher_context_t * hp, - ptls_aead_context_t * aead, - quicly_datagram_t * packet, - size_t first_byte_at, - size_t payload_from, int coalesced); #endif /* __included_vpp_quic_crypto_h__ */ - /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/tlspicotls/pico_vpp_crypto.c b/src/plugins/tlspicotls/pico_vpp_crypto.c index 8e724ea8b1a..3805ff3c981 100644 --- a/src/plugins/tlspicotls/pico_vpp_crypto.c +++ b/src/plugins/tlspicotls/pico_vpp_crypto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Intel and/or its affiliates. + * Copyright (c) 2021 Intel and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: @@ -42,6 +42,8 @@ struct vpp_aead_context_t vnet_crypto_alg_t alg; u32 key_index; u32 chunk_index; + uint8_t iv[PTLS_MAX_IV_SIZE]; + uint8_t static_iv[PTLS_MAX_IV_SIZE]; }; static void @@ -128,8 +130,8 @@ ptls_vpp_crypto_cipher_setup_crypto (ptls_cipher_context_t * _ctx, int is_enc, } size_t -ptls_vpp_crypto_aead_decrypt (ptls_aead_context_t * _ctx, void *_output, - const void *input, size_t inlen, const void *iv, +ptls_vpp_crypto_aead_decrypt (ptls_aead_context_t *_ctx, void *_output, + const void *input, size_t inlen, uint64_t seq, const void *aad, size_t aadlen) { vlib_main_t *vm = vlib_get_main (); @@ -139,7 +141,7 @@ ptls_vpp_crypto_aead_decrypt (ptls_aead_context_t * _ctx, void *_output, ctx->op.dst = _output; ctx->op.src = (void *) input; ctx->op.len = inlen - tag_size;; - ctx->op.iv = (void *) iv; + ctx->op.iv = ctx->static_iv; ctx->op.aad = (void *) aad; ctx->op.aad_len = aadlen; ctx->op.tag = (void *) input + inlen - tag_size; @@ -152,11 +154,13 @@ ptls_vpp_crypto_aead_decrypt (ptls_aead_context_t * _ctx, void *_output, } static void -ptls_vpp_crypto_aead_encrypt_init (ptls_aead_context_t * _ctx, const void *iv, +ptls_vpp_crypto_aead_encrypt_init (ptls_aead_context_t *_ctx, uint64_t seq, const void *aad, size_t aadlen) { struct vpp_aead_context_t *ctx = (struct vpp_aead_context_t *) _ctx; - ctx->op.iv = (void *) iv; + ctx->op.iv = ctx->iv; + ptls_aead__build_iv (ctx->super.algo, ctx->op.iv, ctx->static_iv, seq); + ctx->op.iv = ctx->static_iv; ctx->op.aad = (void *) aad; ctx->op.aad_len = aadlen; ctx->op.n_chunks = 2; @@ -200,10 +204,10 @@ ptls_vpp_crypto_aead_dispose_crypto (ptls_aead_context_t * _ctx) /* Do nothing */ } - static int -ptls_vpp_crypto_aead_setup_crypto (ptls_aead_context_t * _ctx, int is_enc, - const void *key, vnet_crypto_alg_t alg) +ptls_vpp_crypto_aead_setup_crypto (ptls_aead_context_t *_ctx, int is_enc, + const void *key, const void *iv, + vnet_crypto_alg_t alg) { struct vlib_main_t *vm = vlib_get_main (); struct vpp_aead_context_t *ctx = (struct vpp_aead_context_t *) _ctx; @@ -241,6 +245,7 @@ ptls_vpp_crypto_aead_setup_crypto (ptls_aead_context_t * _ctx, int is_enc, vnet_crypto_key_add (vm, ctx->alg, (void *) key, key_len); clib_rwlock_writer_unlock (&picotls_main.crypto_keys_rw_lock); ctx->chunk_index = 0; + clib_memcpy (ctx->static_iv, iv, ctx->super.algo->iv_size); ctx->super.do_decrypt = ptls_vpp_crypto_aead_decrypt; ctx->super.do_encrypt_init = ptls_vpp_crypto_aead_encrypt_init; @@ -268,18 +273,20 @@ ptls_vpp_crypto_aes256ctr_setup_crypto (ptls_cipher_context_t * ctx, } static int -ptls_vpp_crypto_aead_aes128gcm_setup_crypto (ptls_aead_context_t * ctx, - int is_enc, const void *key) +ptls_vpp_crypto_aead_aes128gcm_setup_crypto (ptls_aead_context_t *ctx, + int is_enc, const void *key, + const void *iv) { - return ptls_vpp_crypto_aead_setup_crypto (ctx, is_enc, key, + return ptls_vpp_crypto_aead_setup_crypto (ctx, is_enc, key, iv, VNET_CRYPTO_ALG_AES_128_GCM); } static int -ptls_vpp_crypto_aead_aes256gcm_setup_crypto (ptls_aead_context_t * ctx, - int is_enc, const void *key) +ptls_vpp_crypto_aead_aes256gcm_setup_crypto (ptls_aead_context_t *ctx, + int is_enc, const void *key, + const void *iv) { - return ptls_vpp_crypto_aead_setup_crypto (ctx, is_enc, key, + return ptls_vpp_crypto_aead_setup_crypto (ctx, is_enc, key, iv, VNET_CRYPTO_ALG_AES_256_GCM); } -- 2.16.6