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