Minor cleanup of the QUIC-LB library. Take review comments from late in the process and apply them to earlier classes.
PiperOrigin-RevId: 440172029
diff --git a/quiche/quic/load_balancer/load_balancer_config.cc b/quiche/quic/load_balancer/load_balancer_config.cc
index 2061abb..2ff5b20 100644
--- a/quiche/quic/load_balancer/load_balancer_config.cc
+++ b/quiche/quic/load_balancer/load_balancer_config.cc
@@ -17,7 +17,7 @@
// Validates all non-key parts of the input.
bool CommonValidation(const uint8_t config_id, const uint8_t server_id_len,
const uint8_t nonce_len) {
- if (config_id > 2 || server_id_len == 0 ||
+ if (config_id >= kNumLoadBalancerConfigs || server_id_len == 0 ||
nonce_len < kLoadBalancerMinNonceLen ||
nonce_len > kLoadBalancerMaxNonceLen ||
server_id_len >
@@ -54,25 +54,25 @@
// TakePlaintextFrom{Left,Right}() reads the left or right half of 'from' and
// expands it into a full encryption block ('to') in accordance with the
// internet-draft.
-void TakePlaintextFromLeft(uint8_t *to, uint8_t *from, uint8_t total_len,
+void TakePlaintextFromLeft(uint8_t *to, uint8_t *from, uint8_t plaintext_len,
uint8_t index) {
- uint8_t half = total_len / 2;
+ uint8_t half = plaintext_len / 2;
memset(to, 0, kLoadBalancerBlockSize - 1);
memcpy(to, from, half);
- if (total_len % 2) {
+ if (plaintext_len % 2) {
to[half] = from[half] & 0xf0;
}
to[kLoadBalancerBlockSize - 1] = index;
}
-void TakePlaintextFromRight(uint8_t *to, uint8_t *from, uint8_t total_len,
+void TakePlaintextFromRight(uint8_t *to, uint8_t *from, uint8_t plaintext_len,
uint8_t index) {
- const uint8_t half = total_len / 2;
+ const uint8_t half = plaintext_len / 2;
const uint8_t write_point = kLoadBalancerBlockSize - half;
- const uint8_t read_point = total_len - half;
+ const uint8_t read_point = plaintext_len - half;
memset((to + 1), 0, kLoadBalancerBlockSize - 1);
memcpy(to + write_point, from + read_point, half);
- if (total_len % 2) {
+ if (plaintext_len % 2) {
to[write_point - 1] = from[read_point - 1] & 0x0f;
}
to[0] = index;
@@ -81,21 +81,21 @@
// CiphertextXorWith{Left,Right}() takes the relevant end of the ciphertext in
// 'from' and XORs it with half of the ConnectionId stored at 'to', in
// accordance with the internet-draft.
-void CiphertextXorWithLeft(uint8_t *to, uint8_t *from, uint8_t total_len) {
- uint8_t half = total_len / 2;
+void CiphertextXorWithLeft(uint8_t *to, uint8_t *from, uint8_t plaintext_len) {
+ uint8_t half = plaintext_len / 2;
for (int i = 0; i < half; i++) {
*(to + i) ^= *(from + i);
}
- if (total_len % 2) {
+ if (plaintext_len % 2) {
*(to + half) ^= (*(from + half) & 0xf0);
}
}
-void CiphertextXorWithRight(uint8_t *to, uint8_t *from, uint8_t total_len) {
- const uint8_t half = total_len / 2;
- const uint8_t write_point = total_len - half;
+void CiphertextXorWithRight(uint8_t *to, uint8_t *from, uint8_t plaintext_len) {
+ const uint8_t half = plaintext_len / 2;
+ const uint8_t write_point = plaintext_len - half;
const uint8_t read_point = kLoadBalancerBlockSize - half;
- if (total_len % 2) {
+ if (plaintext_len % 2) {
*(to + write_point - 1) ^= (*(from + read_point - 1) & 0x0f);
}
for (int i = 0; i < half; i++) {
@@ -144,18 +144,18 @@
return false;
}
if (index % 2) { // Odd indices go from left to right
- TakePlaintextFromLeft(plaintext, target, total_len(), index);
+ TakePlaintextFromLeft(plaintext, target, plaintext_len(), index);
} else {
- TakePlaintextFromRight(plaintext, target, total_len(), index);
+ TakePlaintextFromRight(plaintext, target, plaintext_len(), index);
}
if (!BlockEncrypt(plaintext, ciphertext)) {
return false;
}
// XOR bits over the correct half.
if (index % 2) {
- CiphertextXorWithRight(target, ciphertext, total_len());
+ CiphertextXorWithRight(target, ciphertext, plaintext_len());
} else {
- CiphertextXorWithLeft(target, ciphertext, total_len());
+ CiphertextXorWithLeft(target, ciphertext, plaintext_len());
}
return true;
}
diff --git a/quiche/quic/load_balancer/load_balancer_config.h b/quiche/quic/load_balancer/load_balancer_config.h
index 8b21a1f..e7d7bcc 100644
--- a/quiche/quic/load_balancer/load_balancer_config.h
+++ b/quiche/quic/load_balancer/load_balancer_config.h
@@ -11,12 +11,14 @@
namespace quic {
+inline constexpr uint8_t kNumLoadBalancerConfigs = 3;
inline constexpr uint8_t kLoadBalancerKeyLen = 16;
// Regardless of key length, the AES block size is always 16 Bytes.
inline constexpr uint8_t kLoadBalancerBlockSize = 16;
// The spec says nonces can be 18 bytes, but 16 lets it be a uint128.
inline constexpr uint8_t kLoadBalancerMaxNonceLen = 16;
inline constexpr uint8_t kLoadBalancerMinNonceLen = 4;
+inline constexpr uint8_t kNumLoadBalancerCryptoPasses = 4;
// This the base class for QUIC-LB configuration. It contains configuration
// elements usable by both encoders (servers) and decoders (load balancers).
@@ -61,7 +63,10 @@
uint8_t config_id() const { return config_id_; }
uint8_t server_id_len() const { return server_id_len_; }
uint8_t nonce_len() const { return nonce_len_; }
- uint8_t total_len() const { return server_id_len_ + nonce_len_; }
+ // Returns length of all but the first octet.
+ uint8_t plaintext_len() const { return server_id_len_ + nonce_len_; }
+ // Returns length of the entire connection ID.
+ uint8_t total_len() const { return server_id_len_ + nonce_len_ + 1; }
bool IsEncrypted() const { return key_.has_value(); }
private:
diff --git a/quiche/quic/load_balancer/load_balancer_config_test.cc b/quiche/quic/load_balancer/load_balancer_config_test.cc
index 1dad91c..8c58c5d 100644
--- a/quiche/quic/load_balancer/load_balancer_config_test.cc
+++ b/quiche/quic/load_balancer/load_balancer_config_test.cc
@@ -67,7 +67,8 @@
EXPECT_EQ(config->config_id(), 0);
EXPECT_EQ(config->server_id_len(), 3);
EXPECT_EQ(config->nonce_len(), 4);
- EXPECT_EQ(config->total_len(), 7);
+ EXPECT_EQ(config->plaintext_len(), 7);
+ EXPECT_EQ(config->total_len(), 8);
EXPECT_FALSE(config->IsEncrypted());
auto config2 =
LoadBalancerConfig::Create(2, 6, 7, absl::string_view(raw_key, 16));
@@ -75,7 +76,8 @@
EXPECT_EQ(config2->config_id(), 2);
EXPECT_EQ(config2->server_id_len(), 6);
EXPECT_EQ(config2->nonce_len(), 7);
- EXPECT_EQ(config2->total_len(), 13);
+ EXPECT_EQ(config2->plaintext_len(), 13);
+ EXPECT_EQ(config2->total_len(), 14);
EXPECT_TRUE(config2->IsEncrypted());
}
diff --git a/quiche/quic/load_balancer/load_balancer_decoder.cc b/quiche/quic/load_balancer/load_balancer_decoder.cc
index ead70d8..4f328e8 100644
--- a/quiche/quic/load_balancer/load_balancer_decoder.cc
+++ b/quiche/quic/load_balancer/load_balancer_decoder.cc
@@ -17,7 +17,7 @@
}
void LoadBalancerDecoder::DeleteConfig(uint8_t config_id) {
- if (config_id > 2) {
+ if (config_id >= kNumLoadBalancerConfigs) {
QUIC_BUG(quic_bug_438896865_01)
<< "Decoder deleting config with invalid config_id "
<< static_cast<int>(config_id);
@@ -38,7 +38,7 @@
if (!config.has_value()) {
return absl::optional<LoadBalancerServerId>();
}
- if (connection_id.length() < (1 + config->total_len())) {
+ if (connection_id.length() < config->total_len()) {
// Connection ID wasn't long enough
return absl::optional<LoadBalancerServerId>();
}
@@ -50,7 +50,7 @@
absl::Span<const uint8_t>(data, config->server_id_len()));
}
uint8_t result[kQuicMaxConnectionIdWithLengthPrefixLength];
- if (config->total_len() == kLoadBalancerKeyLen) { // single pass
+ if (config->plaintext_len() == kLoadBalancerKeyLen) { // single pass
if (!config->BlockDecrypt(data, result)) {
return absl::optional<LoadBalancerServerId>();
}
@@ -58,9 +58,9 @@
// Do 3 or 4 passes. Only 3 are necessary if the server_id is short enough
// to fit in the first half of the connection ID (the decoder doesn't need
// to extract the nonce).
- memcpy(result, data, config->total_len());
+ memcpy(result, data, config->plaintext_len());
uint8_t end = (config->server_id_len() > config->nonce_len()) ? 1 : 2;
- for (uint8_t i = 4; i >= end; i--) {
+ for (uint8_t i = kNumLoadBalancerCryptoPasses; i >= end; i--) {
if (!config->EncryptionPass(result, i)) {
return absl::optional<LoadBalancerServerId>();
}
@@ -77,7 +77,7 @@
}
const uint8_t first_byte = connection_id.data()[0];
uint8_t codepoint = (first_byte >> 6);
- if (codepoint <= 2) {
+ if (codepoint < kNumLoadBalancerConfigs) {
return codepoint;
}
return absl::optional<uint8_t>();
diff --git a/quiche/quic/load_balancer/load_balancer_decoder.h b/quiche/quic/load_balancer/load_balancer_decoder.h
index 34c298c..2c326cb 100644
--- a/quiche/quic/load_balancer/load_balancer_decoder.h
+++ b/quiche/quic/load_balancer/load_balancer_decoder.h
@@ -17,16 +17,15 @@
// Returns false if the config_id codepoint is already occupied.
bool AddConfig(const LoadBalancerConfig& config);
- // Remove support for a config
+ // Remove support for a config. Does nothing if there is no config for
+ // |config_id|. Does nothing and creates a bug if |config_id| is greater than
+ // 2.
void DeleteConfig(const uint8_t config_id);
- // For these "Get" functions, the calling code might not know the length of
- // the connection ID. That's OK; if not, just send at least
- // kQuicMaxConnectionIdWithLengthPrefixLength bytes in a QuicConnectionId.
-
- // Extract a server ID from a connection ID. If there is no config for the
- // codepoint, the connection ID is too short, or there's a decrypt error,
- // returns empty.
+ // Extract a server ID from |connection_id|. If there is no config for the
+ // codepoint, |connection_id| is too short, or there's a decrypt error,
+ // returns empty. Will accept |connection_id| that is longer than necessary
+ // without error.
absl::optional<LoadBalancerServerId> GetServerId(
const QuicConnectionId& connection_id) const;
@@ -37,7 +36,7 @@
private:
// Decoders can support up to 3 configs at once.
- absl::optional<LoadBalancerConfig> config_[3];
+ absl::optional<LoadBalancerConfig> config_[kNumLoadBalancerConfigs];
};
} // namespace quic
diff --git a/quiche/quic/load_balancer/load_balancer_decoder_test.cc b/quiche/quic/load_balancer/load_balancer_decoder_test.cc
index 379bacd..e38fc0c 100644
--- a/quiche/quic/load_balancer/load_balancer_decoder_test.cc
+++ b/quiche/quic/load_balancer/load_balancer_decoder_test.cc
@@ -4,7 +4,6 @@
#include "quiche/quic/load_balancer/load_balancer_decoder.h"
-#include "absl/base/macros.h"
#include "quiche/quic/load_balancer/load_balancer_server_id.h"
#include "quiche/quic/platform/api/quic_expect_bug.h"
#include "quiche/quic/platform/api/quic_test.h"
@@ -51,11 +50,10 @@
0x5f, 0xee, 0x15, 0xda, 0x27, 0xc4}),
MakeServerId(kServerId, 8),
}};
- for (uint8_t i = 0; i < ABSL_ARRAYSIZE(test_vectors); i++) {
+ for (const auto& test : test_vectors) {
LoadBalancerDecoder decoder;
- EXPECT_TRUE(decoder.AddConfig(test_vectors[i].config));
- EXPECT_EQ(decoder.GetServerId(test_vectors[i].connection_id),
- test_vectors[i].server_id);
+ EXPECT_TRUE(decoder.AddConfig(test.config));
+ EXPECT_EQ(decoder.GetServerId(test.connection_id), test.server_id);
}
}
@@ -92,12 +90,10 @@
MakeServerId(kServerId, 9),
},
};
-
- for (uint8_t i = 0; i < ABSL_ARRAYSIZE(test_vectors); i++) {
+ for (const auto& test : test_vectors) {
LoadBalancerDecoder decoder;
- EXPECT_TRUE(decoder.AddConfig(test_vectors[i].config));
- EXPECT_EQ(decoder.GetServerId(test_vectors[i].connection_id),
- test_vectors[i].server_id);
+ EXPECT_TRUE(decoder.AddConfig(test.config));
+ EXPECT_EQ(decoder.GetServerId(test.connection_id), test.server_id);
}
}
diff --git a/quiche/quic/load_balancer/load_balancer_encoder.cc b/quiche/quic/load_balancer/load_balancer_encoder.cc
index 852e904..6a4655c 100644
--- a/quiche/quic/load_balancer/load_balancer_encoder.cc
+++ b/quiche/quic/load_balancer/load_balancer_encoder.cc
@@ -102,7 +102,7 @@
}
QuicConnectionId LoadBalancerEncoder::GenerateConnectionId() {
- uint8_t length = (config_.has_value()) ? (config_->total_len() + 1)
+ uint8_t length = (config_.has_value()) ? config_->total_len()
: unroutable_connection_id_len_;
uint8_t config_id = config_.has_value() ? (config_->config_id() << 6)
: kLoadBalancerUnroutableConfigId;
@@ -146,14 +146,14 @@
if (!WriteUint128(nonce_hash, config_->nonce_len(), rewriter)) {
return QuicConnectionId();
}
- } else if (config_->total_len() == kLoadBalancerBlockSize) {
+ } else if (config_->plaintext_len() == kLoadBalancerBlockSize) {
// Use one encryption pass.
if (!config_->BlockEncrypt(block_start, block_start)) {
QUIC_LOG(ERROR) << "Block encryption failed";
return QuicConnectionId();
}
} else {
- for (uint8_t i = 1; i <= 4; i++) {
+ for (uint8_t i = 1; i <= kNumLoadBalancerCryptoPasses; i++) {
if (!config_->EncryptionPass(block_start, i)) {
QUIC_LOG(ERROR) << "Block encryption failed";
return QuicConnectionId();
diff --git a/quiche/quic/load_balancer/load_balancer_encoder.h b/quiche/quic/load_balancer/load_balancer_encoder.h
index 98e1cdb..2dc33c6 100644
--- a/quiche/quic/load_balancer/load_balancer_encoder.h
+++ b/quiche/quic/load_balancer/load_balancer_encoder.h
@@ -54,8 +54,8 @@
public:
// Returns a newly created encoder with no active config, if
// |unroutable_connection_id_length| is valid. |visitor| specifies an optional
- // interface to receive callbacks when connection IDs need to be retired.
- // If |encode_length| is true, then the first byte of any generated
+ // interface to receive callbacks when config status changes.
+ // If |len_self_encoded| is true, then the first byte of any generated
// connection ids will encode the length. Otherwise, those bits will be
// random. |unroutable_connection_id_length| specifies the length of
// connection IDs to be generated when there is no active config. It must not
@@ -78,7 +78,7 @@
// on.
void DeleteConfig();
- // Returns the number of additional connections IDs that can be generated with
+ // Returns the number of additional connection IDs that can be generated with
// the current config, or 0 if there is no current config.
absl::uint128 num_nonces_left() const { return num_nonces_left_; }
diff --git a/quiche/quic/load_balancer/load_balancer_encoder_test.cc b/quiche/quic/load_balancer/load_balancer_encoder_test.cc
index ed6db41..c267a2d 100644
--- a/quiche/quic/load_balancer/load_balancer_encoder_test.cc
+++ b/quiche/quic/load_balancer/load_balancer_encoder_test.cc
@@ -155,28 +155,32 @@
EXPECT_EQ(visitor.num_adds(), 1u);
}
+struct LoadBalancerEncoderTestCase {
+ LoadBalancerConfig config;
+ LoadBalancerServerId server_id;
+ QuicConnectionId connection_id;
+};
+
TEST_F(LoadBalancerEncoderTest, UnencryptedConnectionIdTestVectors) {
- const uint8_t server_id_lens[] = {3, 8};
- const uint8_t nonce_lens[] = {4, 5};
- static_assert(sizeof(server_id_lens) == sizeof(nonce_lens));
- const std::vector<QuicConnectionId> expected_connection_ids{
- QuicConnectionId({0x07, 0xed, 0x79, 0x3a, 0x80, 0x49, 0x71, 0x8a}),
- QuicConnectionId({0x4d, 0xed, 0x79, 0x3a, 0x51, 0xd4, 0x9b, 0x8f, 0x5f,
- 0xee, 0x15, 0xda, 0x27, 0xc4}),
+ const struct LoadBalancerEncoderTestCase test_vectors[2] = {
+ {
+ *LoadBalancerConfig::CreateUnencrypted(0, 3, 4),
+ MakeServerId(kServerId, 3),
+ QuicConnectionId({0x07, 0xed, 0x79, 0x3a, 0x80, 0x49, 0x71, 0x8a}),
+ },
+ {
+ *LoadBalancerConfig::CreateUnencrypted(1, 8, 5),
+ MakeServerId(kServerId, 8),
+ QuicConnectionId({0x4d, 0xed, 0x79, 0x3a, 0x51, 0xd4, 0x9b, 0x8f,
+ 0x5f, 0xee, 0x15, 0xda, 0x27, 0xc4}),
+ },
};
- EXPECT_EQ(sizeof(server_id_lens), expected_connection_ids.size());
- for (uint8_t i = 0; i < sizeof(server_id_lens); i++) {
- uint8_t config_id = i % 3;
+ for (const auto &test : test_vectors) {
random_.AddNextValues(kNonceHigh, kNonceLow);
auto encoder = LoadBalancerEncoder::Create(random_, nullptr, true, 8);
- EXPECT_TRUE(encoder.has_value());
- auto config = LoadBalancerConfig::CreateUnencrypted(
- config_id, server_id_lens[i], nonce_lens[i]);
- EXPECT_TRUE(config.has_value());
- EXPECT_TRUE(encoder->UpdateConfig(
- *config, MakeServerId(kServerId, server_id_lens[i])));
+ EXPECT_TRUE(encoder->UpdateConfig(test.config, test.server_id));
absl::uint128 nonces_left = encoder->num_nonces_left();
- EXPECT_EQ(encoder->GenerateConnectionId(), expected_connection_ids[i]);
+ EXPECT_EQ(encoder->GenerateConnectionId(), test.connection_id);
EXPECT_EQ(encoder->num_nonces_left(), nonces_left - 1);
}
}
@@ -215,41 +219,48 @@
// (2) server_id_len > nonce_len, so there is a fourth decryption pass
// (3) the single-pass encryption case
// (4) An even total length.
- uint8_t server_id_lens[] = {3, 10, 8, 9};
- uint8_t nonce_lens[] = {4, 5, 8, 9};
- static_assert(sizeof(server_id_lens) == sizeof(nonce_lens));
- const std::vector<QuicConnectionId> expected_connection_ids{
- QuicConnectionId({0x07, 0xfb, 0xfe, 0x05, 0xf7, 0x31, 0xb4, 0x25}),
- QuicConnectionId({0x4f, 0x01, 0x09, 0x56, 0xfb, 0x5c, 0x1d, 0x4d, 0x86,
- 0xe0, 0x10, 0x18, 0x3e, 0x0b, 0x7d, 0x1e}),
- QuicConnectionId({0x90, 0x4d, 0xd2, 0xd0, 0x5a, 0x7b, 0x0d, 0xe9, 0xb2,
- 0xb9, 0x90, 0x7a, 0xfb, 0x5e, 0xcf, 0x8c, 0xc3}),
- QuicConnectionId({0x12, 0x7a, 0x28, 0x5a, 0x09, 0xf8, 0x52, 0x80, 0xf4,
- 0xfd, 0x6a, 0xbb, 0x43, 0x4a, 0x71, 0x59, 0xe4, 0xd3,
- 0xeb}),
+ const LoadBalancerEncoderTestCase test_vectors[4] = {
+ {
+ *LoadBalancerConfig::Create(0, 3, 4, kKey),
+ MakeServerId(kServerId, 3),
+ QuicConnectionId({0x07, 0xfb, 0xfe, 0x05, 0xf7, 0x31, 0xb4, 0x25}),
+ },
+ {
+ *LoadBalancerConfig::Create(1, 10, 5, kKey),
+ MakeServerId(kServerId, 10),
+ QuicConnectionId({0x4f, 0x01, 0x09, 0x56, 0xfb, 0x5c, 0x1d, 0x4d,
+ 0x86, 0xe0, 0x10, 0x18, 0x3e, 0x0b, 0x7d, 0x1e}),
+ },
+ {
+ *LoadBalancerConfig::Create(2, 8, 8, kKey),
+ MakeServerId(kServerId, 8),
+ QuicConnectionId({0x90, 0x4d, 0xd2, 0xd0, 0x5a, 0x7b, 0x0d, 0xe9,
+ 0xb2, 0xb9, 0x90, 0x7a, 0xfb, 0x5e, 0xcf, 0x8c,
+ 0xc3}),
+ },
+ {
+ *LoadBalancerConfig::Create(0, 9, 9, kKey),
+ MakeServerId(kServerId, 9),
+ QuicConnectionId({0x12, 0x7a, 0x28, 0x5a, 0x09, 0xf8, 0x52, 0x80,
+ 0xf4, 0xfd, 0x6a, 0xbb, 0x43, 0x4a, 0x71, 0x59,
+ 0xe4, 0xd3, 0xeb}),
+ },
};
- EXPECT_EQ(sizeof(server_id_lens), expected_connection_ids.size());
- for (uint8_t i = 0; i < sizeof(server_id_lens); i++) {
- uint8_t config_id = i % 3;
+ for (const auto &test : test_vectors) {
auto encoder = LoadBalancerEncoder::Create(random_, nullptr, true, 8);
EXPECT_TRUE(encoder.has_value());
- auto config = LoadBalancerConfig::Create(config_id, server_id_lens[i],
- nonce_lens[i], kKey);
- EXPECT_TRUE(config.has_value());
random_.AddNextValues(kNonceHigh, kNonceLow);
- EXPECT_TRUE(encoder->UpdateConfig(
- *config, MakeServerId(kServerId, server_id_lens[i])));
- EXPECT_EQ(encoder->GenerateConnectionId(), expected_connection_ids[i]);
+ EXPECT_TRUE(encoder->UpdateConfig(test.config, test.server_id));
+ EXPECT_EQ(encoder->GenerateConnectionId(), test.connection_id);
}
}
TEST_F(LoadBalancerEncoderTest, RunOutOfNonces) {
- const uint8_t config_id = 0, server_id_len = 3, nonce_len = 4;
+ const uint8_t server_id_len = 3;
TestLoadBalancerEncoderVisitor visitor;
auto encoder = LoadBalancerEncoder::Create(random_, &visitor, true, 8);
EXPECT_TRUE(encoder.has_value());
- auto config =
- LoadBalancerConfig::Create(config_id, server_id_len, nonce_len, kKey);
+ auto config = LoadBalancerConfig::Create(0, server_id_len, 4, kKey);
EXPECT_TRUE(config.has_value());
EXPECT_TRUE(
encoder->UpdateConfig(*config, MakeServerId(kServerId, server_id_len)));
diff --git a/quiche/quic/load_balancer/load_balancer_server_id_map.h b/quiche/quic/load_balancer/load_balancer_server_id_map.h
index 02671bb..2e79e66 100644
--- a/quiche/quic/load_balancer/load_balancer_server_id_map.h
+++ b/quiche/quic/load_balancer/load_balancer_server_id_map.h
@@ -13,7 +13,8 @@
// This class wraps an absl::flat_hash_map which associates server IDs to an
// arbitrary type T. It validates that all server ids are of the same fixed
-// length.
+// length. This might be used by a load balancer to connect a server ID with a
+// pool member data structure.
template <typename T>
class QUIC_EXPORT_PRIVATE LoadBalancerServerIdMap {
public: