performance is affected after merge OCSP changeset

Sergey Kandaurov pluknet at nginx.com
Thu Oct 21 16:41:05 UTC 2021


> On 21 Oct 2021, at 15:15, Roman Arutyunyan <arut at nginx.com> wrote:
> 
> On Tue, Oct 19, 2021 at 01:07:56PM +0300, Sergey Kandaurov wrote:
>> 
>> [..]
>> Below is alternative patch, it brings closer to how OCSP validation
>> is done with SSL_read_early_data(), with its inherent design flaws.
>> Namely, the case of regular SSL session reuse is still pessimized,
>> but that shouldn't bring further slowdown with ssl_ocsp disabled,
>> which is slow by itself.
>> 
>> # HG changeset patch
>> # User Sergey Kandaurov <pluknet at nginx.com>
>> # Date 1634637049 -10800
>> #      Tue Oct 19 12:50:49 2021 +0300
>> # Branch quic
>> # Node ID 6f26d6656b4ef97a3a245354bd7fa9e5c8671237
>> # Parent  1798acc01970ae5a03f785b7679fe34c32adcfea
>> QUIC: speeding up processing 0-RTT.
>> 
>> After fe919fd63b0b, processing QUIC streams was postponed until after handshake
>> completion, which means that 0-RTT is effectively off.  With ssl_ocsp enabled,
>> it could be further delayed.  This differs to how SSL_read_early_data() works.
> 
> differs FROM ?
> 
>> This change unlocks processing streams on successful 0-RTT packet decryption.
>> 

Both forms seem to be used, but "differs to" looks less popular.
Rewrote it this way:

This differs from how OCSP validation works with SSL_read_early_data().

>> diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c
>> --- a/src/event/quic/ngx_event_quic.c
>> +++ b/src/event/quic/ngx_event_quic.c
>> @@ -989,6 +989,21 @@ ngx_quic_process_payload(ngx_connection_
>>         }
>>     }
>> 
>> +    if (pkt->level == ssl_encryption_early_data && !qc->streams.initialized) {
>> +        rc = ngx_ssl_ocsp_validate(c);
>> +
>> +        if (rc == NGX_ERROR) {
>> +            return NGX_ERROR;
>> +        }
>> +
>> +        if (rc == NGX_AGAIN) {
>> +            c->ssl->handler = ngx_quic_init_streams;
>> +
>> +        } else {
>> +            ngx_quic_init_streams(c);
>> +        }
>> +    }
>> +
>>     if (pkt->level == ssl_encryption_handshake) {
>>         /*
>>          * RFC 9001, 4.9.1.  Discarding Initial Keys
>> diff --git a/src/event/quic/ngx_event_quic_ssl.c b/src/event/quic/ngx_event_quic_ssl.c
>> --- a/src/event/quic/ngx_event_quic_ssl.c
>> +++ b/src/event/quic/ngx_event_quic_ssl.c
>> @@ -463,6 +463,11 @@ ngx_quic_crypto_input(ngx_connection_t *
>>         return NGX_ERROR;
>>     }
>> 
>> +    if (qc->streams.initialized) {
>> +        /* done while processing 0-RTT */
>> +        return NGX_OK;
>> +    }
>> +
>>     rc = ngx_ssl_ocsp_validate(c);
>> 
>>     if (rc == NGX_ERROR) {
>> 
> 
> It would be nice to always call ngx_ssl_ocsp_validate() from the same source
> file (presumably ngx_event_quic_ssl.c).  But this does not seem to occur
> naturally so let's leave it as it is.
> 
> Looks good.
> 
> PS: Also, this can be further refactored to move ngx_ssl_ocsp_validate() inside
> ngx_quic_init_streams().  In this case we can only call ngx_quic_init_streams()
> both times.

This is feasible, if init streams closer to obtaining 0-RTT secret.
Actually, it is even better, I believe, and it's invoked just once
regardless of the number of 0-RTT packets.
Requirement for successful 0-RTT decryption doesn't buy us much.

N.B. I decided to leave in place "quic init streams" debug.
This is where streams are now actually initialized,
and it looks reasonable to see that logged only once.

# HG changeset patch
# User Sergey Kandaurov <pluknet at nginx.com>
# Date 1634832181 -10800
#      Thu Oct 21 19:03:01 2021 +0300
# Branch quic
# Node ID 11119f9fda599c890a93b348310f582e3c49ebb7
# Parent  1798acc01970ae5a03f785b7679fe34c32adcfea
QUIC: refactored OCSP validation in preparation for 0-RTT support.

diff --git a/src/event/quic/ngx_event_quic_ssl.c b/src/event/quic/ngx_event_quic_ssl.c
--- a/src/event/quic/ngx_event_quic_ssl.c
+++ b/src/event/quic/ngx_event_quic_ssl.c
@@ -361,7 +361,6 @@ static ngx_int_t
 ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data)
 {
     int                     n, sslerr;
-    ngx_int_t               rc;
     ngx_buf_t              *b;
     ngx_chain_t            *cl;
     ngx_ssl_conn_t         *ssl_conn;
@@ -463,19 +462,10 @@ ngx_quic_crypto_input(ngx_connection_t *
         return NGX_ERROR;
     }
 
-    rc = ngx_ssl_ocsp_validate(c);
-
-    if (rc == NGX_ERROR) {
+    if (ngx_quic_init_streams(c) != NGX_OK) {
         return NGX_ERROR;
     }
 
-    if (rc == NGX_AGAIN) {
-        c->ssl->handler = ngx_quic_init_streams;
-        return NGX_OK;
-    }
-
-    ngx_quic_init_streams(c);
-
     return NGX_OK;
 }
 
diff --git a/src/event/quic/ngx_event_quic_streams.c b/src/event/quic/ngx_event_quic_streams.c
--- a/src/event/quic/ngx_event_quic_streams.c
+++ b/src/event/quic/ngx_event_quic_streams.c
@@ -16,6 +16,7 @@
 static ngx_quic_stream_t *ngx_quic_create_client_stream(ngx_connection_t *c,
     uint64_t id);
 static ngx_int_t ngx_quic_init_stream(ngx_quic_stream_t *qs);
+static void ngx_quic_init_streams_handler(ngx_connection_t *c);
 static ngx_quic_stream_t *ngx_quic_create_stream(ngx_connection_t *c,
     uint64_t id);
 static void ngx_quic_empty_handler(ngx_event_t *ev);
@@ -369,9 +370,37 @@ ngx_quic_init_stream(ngx_quic_stream_t *
 }
 
 
-void
+ngx_int_t
 ngx_quic_init_streams(ngx_connection_t *c)
 {
+    ngx_int_t               rc;
+    ngx_quic_connection_t  *qc;
+
+    qc = ngx_quic_get_connection(c);
+
+    if (qc->streams.initialized) {
+        return NGX_OK;
+    }
+
+    rc = ngx_ssl_ocsp_validate(c);
+
+    if (rc == NGX_ERROR) {
+        return NGX_ERROR;
+    }
+
+    if (rc == NGX_AGAIN) {
+        c->ssl->handler = ngx_quic_init_streams_handler;
+        return NGX_OK;
+    }
+
+    ngx_quic_init_streams_handler(c);
+
+    return NGX_OK;
+}
+
+static void
+ngx_quic_init_streams_handler(ngx_connection_t *c)
+{
     ngx_queue_t            *q;
     ngx_quic_stream_t      *qs;
     ngx_quic_connection_t  *qc;
diff --git a/src/event/quic/ngx_event_quic_streams.h b/src/event/quic/ngx_event_quic_streams.h
--- a/src/event/quic/ngx_event_quic_streams.h
+++ b/src/event/quic/ngx_event_quic_streams.h
@@ -31,7 +31,7 @@ ngx_int_t ngx_quic_handle_stop_sending_f
 ngx_int_t ngx_quic_handle_max_streams_frame(ngx_connection_t *c,
     ngx_quic_header_t *pkt, ngx_quic_max_streams_frame_t *f);
 
-void ngx_quic_init_streams(ngx_connection_t *c);
+ngx_int_t ngx_quic_init_streams(ngx_connection_t *c);
 void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp,
     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
 ngx_quic_stream_t *ngx_quic_find_stream(ngx_rbtree_t *rbtree,
# HG changeset patch
# User Sergey Kandaurov <pluknet at nginx.com>
# Date 1634832186 -10800
#      Thu Oct 21 19:03:06 2021 +0300
# Branch quic
# Node ID b53e361bee7dfbb027507a717e6648234a06ef13
# Parent  11119f9fda599c890a93b348310f582e3c49ebb7
QUIC: speeding up processing 0-RTT.

After fe919fd63b0b, processing QUIC streams was postponed until after handshake
completion, which means that 0-RTT is effectively off.  With ssl_ocsp enabled,
it could be further delayed.  This differs from how OCSP validation works with
SSL_read_early_data().  With this change, processing QUIC streams is unlocked
when obtaining 0-RTT secret.

diff --git a/src/event/quic/ngx_event_quic_ssl.c b/src/event/quic/ngx_event_quic_ssl.c
--- a/src/event/quic/ngx_event_quic_ssl.c
+++ b/src/event/quic/ngx_event_quic_ssl.c
@@ -71,8 +71,20 @@ ngx_quic_set_read_secret(ngx_ssl_conn_t 
                    secret_len, rsecret);
 #endif
 
-    return ngx_quic_keys_set_encryption_secret(c->pool, 0, qc->keys, level,
-                                               cipher, rsecret, secret_len);
+    if (ngx_quic_keys_set_encryption_secret(c->pool, 0, qc->keys, level,
+                                            cipher, rsecret, secret_len)
+        != 1)
+    {
+        return 0;
+    }
+
+    if (level == ssl_encryption_early_data) {
+        if (ngx_quic_init_streams(c) != NGX_OK) {
+            return 0;
+        }
+    }
+
+    return 1;
 }
 
 
@@ -131,6 +143,10 @@ ngx_quic_set_encryption_secrets(ngx_ssl_
     }
 
     if (level == ssl_encryption_early_data) {
+        if (ngx_quic_init_streams(c) != NGX_OK) {
+            return 0;
+        }
+
         return 1;
     }
 

-- 
Sergey Kandaurov



More information about the nginx-devel mailing list