xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/load_balancer/load_balancer_encoder.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2022 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef QUICHE_QUIC_LOAD_BALANCER_LOAD_BALANCER_ENCODER_H_
6 #define QUICHE_QUIC_LOAD_BALANCER_LOAD_BALANCER_ENCODER_H_
7 
8 #include <algorithm>
9 #include <cstdint>
10 #include <optional>
11 
12 #include "absl/numeric/int128.h"
13 #include "quiche/quic/core/connection_id_generator.h"
14 #include "quiche/quic/core/crypto/quic_random.h"
15 #include "quiche/quic/core/quic_connection_id.h"
16 #include "quiche/quic/core/quic_versions.h"
17 #include "quiche/quic/load_balancer/load_balancer_config.h"
18 #include "quiche/quic/load_balancer/load_balancer_server_id.h"
19 
20 namespace quic {
21 
22 namespace test {
23 class LoadBalancerEncoderPeer;
24 }
25 
26 // Default length of a 4-tuple connection ID.
27 inline constexpr uint8_t kLoadBalancerUnroutableLen = 8;
28 // When the encoder is self-encoding the connection ID length, these are the
29 // bits of the first byte that do so.
30 constexpr uint8_t kLoadBalancerLengthMask = (1 << kConnectionIdLengthBits) - 1;
31 
32 // The bits of the connection ID first byte that encode the config ID.
33 constexpr uint8_t kLoadBalancerConfigIdMask = ~kLoadBalancerLengthMask;
34 // The config ID that means the connection ID does not contain routing
35 // information.
36 constexpr uint8_t kLoadBalancerUnroutableConfigId = kNumLoadBalancerConfigs;
37 // The bits of the connection ID first byte that correspond to a connection ID
38 // that does not contain routing information.
39 constexpr uint8_t kLoadBalancerUnroutablePrefix =
40     kLoadBalancerUnroutableConfigId << kConnectionIdLengthBits;
41 
42 // Interface which receives notifications when the current config is updated.
43 class QUIC_EXPORT_PRIVATE LoadBalancerEncoderVisitorInterface {
44  public:
~LoadBalancerEncoderVisitorInterface()45   virtual ~LoadBalancerEncoderVisitorInterface() {}
46 
47   // Called when a config is added where none existed.
48   //
49   // Connections that support address migration should retire unroutable
50   // connection IDs and replace them with routable ones using the new config,
51   // while avoiding sending a sudden storm of packets containing
52   // RETIRE_CONNECTION_ID and NEW_CONNECTION_ID frames.
53   virtual void OnConfigAdded(uint8_t config_id) = 0;
54   // Called when the config is changed.
55   //
56   // Existing routable connection IDs should be retired before the decoder stops
57   // supporting that config. The timing of this event is deployment-dependent
58   // and might be tied to the arrival of a new config at the encoder.
59   virtual void OnConfigChanged(uint8_t old_config_id,
60                                uint8_t new_config_id) = 0;
61   // Called when a config is deleted. The encoder will generate unroutable
62   // connection IDs from now on.
63   //
64   // New connections will not be able to support address migration until a new
65   // config arrives. Existing connections can retain connection IDs that use the
66   // deleted config, which will only become unroutable once the decoder also
67   // deletes it. The time of that deletion is deployment-dependent and might be
68   // tied to the arrival of a new config at the encoder.
69   virtual void OnConfigDeleted(uint8_t config_id) = 0;
70 };
71 
72 // Manages QUIC-LB configurations to properly encode a given server ID in a
73 // QUIC Connection ID.
74 class QUIC_EXPORT_PRIVATE LoadBalancerEncoder
75     : public ConnectionIdGeneratorInterface {
76  public:
LoadBalancerEncoder(QuicRandom & random,LoadBalancerEncoderVisitorInterface * const visitor,const bool len_self_encoded)77   LoadBalancerEncoder(QuicRandom& random,
78                       LoadBalancerEncoderVisitorInterface* const visitor,
79                       const bool len_self_encoded)
80       : LoadBalancerEncoder(random, visitor, len_self_encoded,
81                             kLoadBalancerUnroutableLen) {}
~LoadBalancerEncoder()82   ~LoadBalancerEncoder() override {}
83 
84   // Returns a newly created encoder with no active config, if
85   // |unroutable_connection_id_length| is valid. |visitor| specifies an optional
86   // interface to receive callbacks when config status changes.
87   // If |len_self_encoded| is true, then the first byte of any generated
88   // connection ids will encode the length. Otherwise, those bits will be
89   // random. |unroutable_connection_id_length| specifies the length of
90   // connection IDs to be generated when there is no active config. It must not
91   // be 0 and must not be larger than the RFC9000 maximum of 20.
92   static std::optional<LoadBalancerEncoder> Create(
93       QuicRandom& random, LoadBalancerEncoderVisitorInterface* visitor,
94       bool len_self_encoded,
95       uint8_t unroutable_connection_id_len = kLoadBalancerUnroutableLen);
96 
97   // Attempts to replace the current config and server_id with |config| and
98   // |server_id|. If the length |server_id| does not match the server_id_length
99   // of |config| or the ID of |config| matches the ID of the current config,
100   // returns false and leaves the current config unchanged. Otherwise, returns
101   // true. When the encoder runs out of nonces, it will delete the config and
102   // begin generating unroutable connection IDs.
103   bool UpdateConfig(const LoadBalancerConfig& config,
104                     LoadBalancerServerId server_id);
105 
106   // Delete the current config and generate unroutable connection IDs from now
107   // on.
108   virtual void DeleteConfig();
109 
110   // Returns the number of additional connection IDs that can be generated with
111   // the current config, or 0 if there is no current config.
num_nonces_left()112   absl::uint128 num_nonces_left() const { return num_nonces_left_; }
113 
114   // Functions below are declared virtual to enable mocking.
115   // Returns true if there is an active configuration.
IsEncoding()116   virtual bool IsEncoding() const { return config_.has_value(); }
117   // Returns true if there is an active configuration that uses encryption.
IsEncrypted()118   virtual bool IsEncrypted() const {
119     return config_.has_value() && config_->IsEncrypted();
120   }
len_self_encoded()121   virtual bool len_self_encoded() const { return len_self_encoded_; }
122 
123   // If there's an active config, generates a connection ID using it. If not,
124   // generates an unroutable connection_id. If there's an error, returns a zero-
125   // length Connection ID.
126   QuicConnectionId GenerateConnectionId();
127 
128   // Functions from ConnectionIdGeneratorInterface
129   std::optional<QuicConnectionId> GenerateNextConnectionId(
130       const QuicConnectionId& original) override;
131   std::optional<QuicConnectionId> MaybeReplaceConnectionId(
132       const QuicConnectionId& original,
133       const ParsedQuicVersion& version) override;
134   uint8_t ConnectionIdLength(uint8_t first_byte) const override;
135 
136  protected:
LoadBalancerEncoder(QuicRandom & random,LoadBalancerEncoderVisitorInterface * const visitor,const bool len_self_encoded,const uint8_t unroutable_connection_id_len)137   LoadBalancerEncoder(QuicRandom& random,
138                       LoadBalancerEncoderVisitorInterface* const visitor,
139                       const bool len_self_encoded,
140                       const uint8_t unroutable_connection_id_len)
141       : random_(random),
142         len_self_encoded_(len_self_encoded),
143         visitor_(visitor) {
144     std::fill_n(connection_id_lengths_, kNumLoadBalancerConfigs + 1,
145                 unroutable_connection_id_len);
146   }
147 
148  private:
149   friend class test::LoadBalancerEncoderPeer;
150 
151   QuicConnectionId MakeUnroutableConnectionId(uint8_t first_byte);
152 
153   QuicRandom& random_;
154   const bool len_self_encoded_;
155   LoadBalancerEncoderVisitorInterface* const visitor_;
156 
157   std::optional<LoadBalancerConfig> config_;
158   absl::uint128 seed_, num_nonces_left_ = 0;
159   std::optional<LoadBalancerServerId> server_id_;
160   uint8_t connection_id_lengths_[kNumLoadBalancerConfigs + 1];
161 };
162 
163 }  // namespace quic
164 
165 #endif  // QUICHE_QUIC_LOAD_BALANCER_LOAD_BALANCER_ENCODER_H_
166