Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
719661c
docs: Add an explicit wildcard mode
krnowak Jun 7, 2021
9b84dfd
config: Implement explicit wildcard mode in delta gRPC
krnowak Jun 7, 2021
a5f4ed7
test: Add tests for explicit wildcar mode in delta gRPC
krnowak Jun 7, 2021
d78ec97
docs: Reword wildcard mode docs
krnowak Jun 7, 2021
2e8ba91
config: Fix build
krnowak Jun 7, 2021
f4ca629
config: Fix build
krnowak Jun 8, 2021
c008bcc
Merge remote-tracking branch 'origin/main' into krnowak/explicit-wild…
krnowak Jul 2, 2021
3fa6a37
Drop the entry in version history
krnowak Jul 2, 2021
3914615
Always send an asterisk as a wildcard subscription
krnowak Jul 6, 2021
1d53769
Better comments, drop redundant tests
krnowak Jul 6, 2021
fa83949
Add constants for wildcards
krnowak Jul 6, 2021
6748f53
Test fixes
krnowak Jul 6, 2021
02e5370
Merge remote-tracking branch 'origin/main' into krnowak/explicit-wild…
krnowak Jul 7, 2021
872e737
Revert "Test fixes"
krnowak Jul 8, 2021
502de45
Revert "Better comments, drop redundant tests"
krnowak Jul 8, 2021
4ba0fc4
Revert "Always send an asterisk as a wildcard subscription"
krnowak Jul 8, 2021
4e34600
New attempt at implementing new wildcard subscriptions
krnowak Jul 8, 2021
98c408b
Merge remote-tracking branch 'origin/main' into krnowak/explicit-wild…
krnowak Jul 14, 2021
18e9f70
Formatting fixes
krnowak Jul 14, 2021
d6e273f
Update wildcard handling in xds delta subscription state
krnowak Jul 14, 2021
db884fe
Change Wildcard into constexpr string view
krnowak Jul 16, 2021
9339a0f
Merge remote-tracking branch 'origin/main' into krnowak/explicit-wild…
krnowak Aug 10, 2021
cb44431
Rework legacy wildcard subscription handling
krnowak Aug 5, 2021
fcc53aa
Merge remote-tracking branch 'origin/main' into krnowak/explicit-wild…
krnowak Aug 12, 2021
9a1855d
Fix typos
krnowak Aug 12, 2021
e71317f
Rename function to placate clang tidy
krnowak Aug 12, 2021
cb93839
Try to improve coverage
krnowak Aug 13, 2021
b7dee94
Factor out legacy wildcard checks to a separate function
krnowak Aug 13, 2021
61361b8
Document the tests
krnowak Aug 13, 2021
63bba65
Fix formatting
krnowak Aug 13, 2021
da12ed5
Merge remote-tracking branch 'origin/main' into krnowak/explicit-wild…
krnowak Aug 31, 2021
e249133
Fix build after merge
krnowak Aug 31, 2021
88587b0
Get rid of containerContains
krnowak Aug 31, 2021
da99fc7
Fix formatting
krnowak Sep 1, 2021
d9f0803
Document the resource state machine
krnowak Sep 1, 2021
74532e9
Ignore resources that we did not request
krnowak Sep 3, 2021
3d55048
Add a test for ignoring superfluous resources
krnowak Sep 3, 2021
f8b758f
Fix formatting
krnowak Sep 3, 2021
fd76a69
Drop one assert
krnowak Sep 9, 2021
4d20de1
Try to preserve the legacy wildcard status on ineffective unsubscript…
krnowak Sep 9, 2021
ab65125
Expand a bit more on the ambiguous resource category in comments
krnowak Sep 17, 2021
c726d04
Update the comments in the xds_mux variant too
krnowak Sep 20, 2021
f9d846d
Constify some variables
krnowak Sep 28, 2021
bae8643
Drop unused member
krnowak Sep 28, 2021
d10ec21
Gate the explicit wildcard resource support
krnowak Oct 1, 2021
508fc9c
Merge remote-tracking branch 'origin/main' into krnowak/explicit-wild…
krnowak Oct 1, 2021
726d655
Fixes
krnowak Oct 1, 2021
649af01
Build fixes
krnowak Oct 4, 2021
6f4724b
Test the old implementation too
krnowak Oct 4, 2021
7d78a00
docs: Add a note about xds changes
krnowak Oct 4, 2021
93ec187
Fix clang tidy
krnowak Oct 5, 2021
52a66ee
Run ADS integration tests together with old and new DSS
krnowak Oct 5, 2021
044bceb
Add DSS to dictionary
krnowak Oct 5, 2021
559e50a
Merge remote-tracking branch 'origin/main' into krnowak/explicit-wild…
krnowak Oct 5, 2021
9a34a6b
Fix version history after merge
krnowak Oct 5, 2021
5e9a130
Merge remote-tracking branch 'origin/main' into krnowak/explicit-wild…
krnowak Oct 19, 2021
36b872b
test: Fix redis ADS integration test params
krnowak Oct 19, 2021
5a2aac2
Merge remote-tracking branch 'origin/main' into krnowak/explicit-wild…
krnowak Oct 20, 2021
55dfdfa
Shard the redis integration test to avoid timeouts
krnowak Oct 20, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions docs/root/api-docs/xds_protocol.rst
Original file line number Diff line number Diff line change
Expand Up @@ -427,13 +427,14 @@ names becomes empty, that means that the client is no longer interested in any r
specified type.

For :ref:`Listener <envoy_v3_api_msg_config.listener.v3.Listener>` and :ref:`Cluster <envoy_v3_api_msg_config.cluster.v3.Cluster>` resource
types, there is also a "wildcard" mode, which is triggered when the initial request on the stream
for that resource type contains no resource names. In this case, the server should use
site-specific business logic to determine the full set of resources that the client is interested
in, typically based on the client's :ref:`node <envoy_v3_api_msg_config.core.v3.Node>` identification. Note
that once a stream has entered wildcard mode for a given resource type, there is no way to change
the stream out of wildcard mode; resource names specified in any subsequent request on the stream
will be ignored.
types, there is also a "wildcard" mode, which is triggered by sending a request containing a special
resource name "*" in a list of resource names to subscribe to. As a special case, sending an initial
request with no resource names at all also triggers the wildcard mode. For wildcard requests,
the server should use site-specific business logic to determine the full set of resources that
the client is interested in, typically based on the client's :ref:`node <envoy_v3_api_msg_config.core.v3.Node>` identification.
The client can opt out from the wildcard mode by unsubscribing from the "*" resource name.
Additional resource names added to the subscription state while being opted-in into the wildcard
mode should not be ignored by the server.

Client Behavior
"""""""""""""""
Expand Down Expand Up @@ -535,6 +536,8 @@ being requested by the client, and if one of those resources springs into existe
server must send an update to the client informing it of the new resource. Clients that initially
see a resource that does not exist must be prepared for the resource to be created at any time.

.. _xds_protocol_unsubscribing_from_resources:

Unsubscribing From Resources
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand All @@ -553,7 +556,10 @@ Note that for :ref:`Listener <envoy_v3_api_msg_config.listener.v3.Listener>` and
resource types where the stream is in "wildcard" mode (see :ref:`How the client specifies what
resources to return <xds_protocol_resource_hints>` for details), the set of resources being
subscribed to is determined by the server instead of the client, so there is no mechanism
for the client to unsubscribe from resources.
for the client to unsubscribe from resources. The only resources that the client could unsubscribe
from are the resources that the client explicitly expressed the interest in before. Note that
the server may still send the resource to the client if the resource was also a part of the set
of resources determined by the server from the wildcard subscription.

Requesting Multiple Resources on a Single Stream
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -779,8 +785,8 @@ resources to avoid resending them over the network by sending them in
:ref:`initial_resource_versions <envoy_v3_api_field_service.discovery.v3.deltadiscoveryrequest.initial_resource_versions>`.
Because no state is assumed to be preserved from the previous stream, the reconnecting
client must provide the server with all resource names it is interested in. Note that for wildcard
requests (CDS/LDS/SRDS), the request must have no resources in both
:ref:`resource_names_subscribe <envoy_v3_api_field_service.discovery.v3.deltadiscoveryrequest.resource_names_subscribe>` and
requests (CDS/LDS/SRDS), the request must have only resources the client was explicitly interested in in
:ref:`resource_names_subscribe <envoy_v3_api_field_service.discovery.v3.deltadiscoveryrequest.resource_names_subscribe>` and no resources in
:ref:`resource_names_unsubscribe <envoy_v3_api_field_service.discovery.v3.deltadiscoveryrequest.resource_names_unsubscribe>`.

.. figure:: diagrams/incremental-reconnect.svg
Expand Down
1 change: 1 addition & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Incompatible Behavior Changes
* grpc_bridge_filter: the filter no longer collects grpc stats in favor of the existing grpc stats filter.
The behavior can be reverted by changing runtime key ``envoy.reloadable_features.grpc_bridge_stats_disabled``.
* tracing: update Apache SkyWalking tracer version to be compatible with 8.4.0 data collect protocol. This change will introduce incompatibility with SkyWalking 8.3.0.
* xds: added the explicit wildcard mode, which allows subscribing to specific resource names on top of a wildcard subscription. This means that the resource name ``*`` is reserved. This may mean that in some cases the initial wildcard subscription request on the stream will not be empty, but will have a non-empty list of resources with a special name among them. See :ref:`wildcard mode description <xds_protocol_resource_hints>` and :ref:`unsubscribing from resources <xds_protocol_unsubscribing_from_resources>` for details.

Minor Behavior Changes
----------------------
Expand Down
84 changes: 63 additions & 21 deletions source/common/config/delta_subscription_state.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,26 @@ DeltaSubscriptionState::DeltaSubscriptionState(std::string type_url,
[this](const auto& expired) {
Protobuf::RepeatedPtrField<std::string> removed_resources;
for (const auto& resource : expired) {
setResourceWaitingForServer(resource);
removed_resources.Add(std::string(resource));
if (auto maybe_resource = getResourceState(resource); maybe_resource.has_value()) {
maybe_resource->setAsWaitingForServer();
removed_resources.Add(std::string(resource));
}
}

watch_map_.onConfigUpdate({}, removed_resources, "");
},
dispatcher, dispatcher.timeSource()),
type_url_(std::move(type_url)), wildcard_(wildcard), watch_map_(watch_map),
type_url_(std::move(type_url)),
mode_(wildcard ? WildcardMode::Implicit : WildcardMode::Disabled), watch_map_(watch_map),
local_info_(local_info), dispatcher_(dispatcher) {}

void DeltaSubscriptionState::updateSubscriptionInterest(
const absl::flat_hash_set<std::string>& cur_added,
const absl::flat_hash_set<std::string>& cur_removed) {
for (const auto& a : cur_added) {
setResourceWaitingForServer(a);
// This adds a resource state that is waiting for the server for
// more information.
resource_state_[a] = ResourceState(ResourceType::ExplicitlyRequested);
// If interest in a resource is removed-then-added (all before a discovery request
// can be sent), we must treat it as a "new" addition: our user may have forgotten its
// copy of the resource after instructing us to remove it, and need to be reminded of it.
Expand All @@ -53,6 +58,31 @@ void DeltaSubscriptionState::updateSubscriptionInterest(
names_added_.erase(r);
names_removed_.insert(r);
}
switch (mode_) {
case WildcardMode::Implicit:
if (names_removed_.find("*") != names_removed_.end()) {

@dmitri-d dmitri-d Jun 8, 2021

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realised this implementation deviates from how wildcards are currently implemented: a subscription without any resource names is a wildcard one. A wildcard subscription stops being one when a resource name is added to it. If a subscription has the last resource name removed from it, it becomes a wildcard subscription (see https://github.com/envoyproxy/envoy/blob/main/source/common/config/watch_map.cc#L23 and https://github.com/envoyproxy/envoy/blob/main/source/common/config/watch_map.cc#L50).

Another issue is that we now have wildcard-state related logic in two places; I need to think about this...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another difference is that currently a wildcard subscription always stays a wildcard one: added or removed resources do not affect subscriptions' behaviour after markStreamFresh() has been called, and there's no difference with a regular subscription at other times.

After thinking about this, I think the way the current wildcard mode handles stream refresh might have a problem: it skips over all resource names that have been added, but doesn't remove corresponding resource states. Depending on how the server handles stream refresh (for example the server might reset its state and only send resources it considers necessary, ignoring client subscriptions), we might end up with different susbcription state on the client and the server.

I don't have a strong opinion about this, but I think a wildcard subscription should always stay one (i.e one cannot downgrade it to a regular subscription). If so, and to avoid the problem of an inconsistent state, I think a subscription in "new" wildcard mode should send all its state on stream refresh (alternatively, it should reset its state to the state at the time of creation).

WDYT? @markdroth?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current spec (without my changes in #16861) says the following:

For Listener and Cluster resource types, there is also a “wildcard” mode, which is triggered when the initial request on the stream for that resource type contains no resource names. In this case, the server should use site-specific business logic to determine the full set of resources that the client is interested in, typically based on the client’s node identification. Note that once a stream has entered wildcard mode for a given resource type, there is no way to change the stream out of wildcard mode; resource names specified in any subsequent request on the stream will be ignored.

And later:

Note that for Listener and Cluster resource types where the stream is in “wildcard” mode (see How the client specifies what resources to return for details), the set of resources being subscribed to is determined by the server instead of the client, so there is no mechanism for the client to unsubscribe from resources.

In other words, currently, wildcard mode for a given resource type is determined by the very first request for that resource type on the stream, and the stream stays in that mode forever -- it is not possible to later change a stream from wildcard mode to non-wildcard mode or vice-versa. If that first request has resource_names unset, then the stream is in wildcard mode for that resource type, and the resource_names field is ignored in all subsequent requests for that resource type. However, if the first request has resource_names set, then the stream is in non-wildcard mode for that resource type, and if there is later a request for that resource type with resource_names unset, that means to unsubscribe from all resources of that type; it does not mean to enter wildcard mode.

One way to think about the change we're making here is that we want to allow exiting wildcard mode after the initial request, but it will still not be possible to enter wildcard mode. (Entering wildcard mode later would break existing gRPC clients, which will send a request with resource_names unset to indicate unsubscribing to all resources of that type.)

Although I think a better way to think about it is what I described in #16861: Instead of wildcard being a mode for the stream as a whole, it's now going to be a special type of subscription (*), and the existing syntax of leaving resource_names unset will just be a syntactic alias for that special subscription.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One note about the wildcard mode:

One way to think about the change we're making here is that we want to allow exiting wildcard mode after the initial request, but it will still not be possible to enter wildcard mode. (Entering wildcard mode later would break existing gRPC clients, which will send a request with resource_names unset to indicate unsubscribing to all resources of that type.)

I actually implemented also reentering into the wildcard subscription in this PR, but the reentering can only be done by sending "*". I imagined the current workflow in general terms (or in terms of SotW) to be like (think of the graphs below as deterministic finite state automata that start at "stream init"):
wildcard-flow

And for incremental (delta) wildcard workflow would look like this:
wildcard-flow-incremental

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meh, there are typos like "unsubscribe to" where it should be "unsubscribe from", but hopefully those graphs help.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I'd very much like an explicit wildcard mode.

when reconnection comes into play, there is a chance that non-wildcard stream could become wildcard:

  1. client asks for A, B, C, it's marked as non-wildcard stream
  2. client removed A, B, C, network error happens
  3. client reconnect, not the server would think it's a wildcard stream and begin to send everything to it.

@markdroth

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code takes care of this scenario, what happens here at 3 is "client reconnects, but does not send any initial request, so the server shouldn't be sending anything back".

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stevenzzzz As @krnowak mentioned, that case should never happen, because if the client is no longer subscribed to any resources when it reconnects, it will not send any request for that resource type on the reconnected stream.

I don't see any value for an explicit wildcard mode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@krnowak It might be a good idea to change the PR title to reflect what it actually does. :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, changed the PR title and the commit message.

// we explicitly cancel the wildcard subscription
mode_ = WildcardMode::Disabled;
} else if (!names_added_.empty()) {
// switch to explicit mode if we requested some extra names
mode_ = WildcardMode::Explicit;
}
break;

case WildcardMode::Explicit:
if (names_removed_.find("*") != names_removed_.end()) {
// we explicitly cancel the wildcard subscription
mode_ = WildcardMode::Disabled;
}
break;

case WildcardMode::Disabled:
if (names_added_.find("*") != names_added_.end()) {
// we switch into an explicit wildcard subscription
mode_ = WildcardMode::Explicit;
}
break;
}
}

// Not having sent any requests yet counts as an "update pending" since you're supposed to resend
Expand Down Expand Up @@ -124,7 +154,7 @@ void DeltaSubscriptionState::handleGoodResponse(
{
const auto scoped_update = ttl_.scopedTtlUpdate();
for (const auto& resource : message.resources()) {
addResourceState(resource);
addResourceStateFromServer(resource);
}
}

Expand All @@ -140,8 +170,8 @@ void DeltaSubscriptionState::handleGoodResponse(
// initial_resource_versions messages, but will remind us to explicitly tell the server "I'm
// cancelling my subscription" when we lose interest.
for (const auto& resource_name : message.removed_resources()) {
if (resource_names_.find(resource_name) != resource_names_.end()) {
setResourceWaitingForServer(resource_name);
if (auto maybe_resource = getResourceState(resource_name); maybe_resource.has_value()) {
maybe_resource->setAsWaitingForServer();
}
}
ENVOY_LOG(debug, "Delta config for {} accepted with {} resources added, {} removed", type_url_,
Expand Down Expand Up @@ -177,16 +207,20 @@ DeltaSubscriptionState::getNextRequestAckless() {
if (!resource_state.waitingForServer()) {
(*request.mutable_initial_resource_versions())[resource_name] = resource_state.version();
}
// As mentioned above, fill resource_names_subscribe with everything, including names we
// have yet to receive any resource for unless this is a wildcard subscription, for which
// the first request on a stream must be without any resource names.
if (!wildcard_) {
// Add resource names to resource_names_subscribe only if this is not a wildcard subscription
// request or if we requested this resource explicitly (so we are actually in explicit
// wildcard mode).
if (mode_ == WildcardMode::Disabled ||
resource_state.type() == ResourceType::ExplicitlyRequested) {
names_added_.insert(resource_name);
}
}
// Wildcard subscription initial requests must have no resource_names_subscribe.
if (wildcard_) {
names_added_.clear();
// We are not clearing the names_added_ set. If we are in implicit wildcard subscription mode,
// then the set should already be empty. If we are in explicit wildcard mode then the set will
// contain the names we explicitly requested, but we need to add * to the list to make sure it's
// sent too.
if (mode_ == WildcardMode::Explicit) {
names_added_.insert("*");
}
names_removed_.clear();
}
Expand All @@ -213,7 +247,7 @@ DeltaSubscriptionState::getNextRequestWithAck(const UpdateAck& ack) {
return request;
}

void DeltaSubscriptionState::addResourceState(
void DeltaSubscriptionState::addResourceStateFromServer(
const envoy::service::discovery::v3::Resource& resource) {
if (resource.has_ttl()) {
ttl_.add(std::chrono::milliseconds(DurationUtil::durationToMilliseconds(resource.ttl())),
Expand All @@ -222,18 +256,26 @@ void DeltaSubscriptionState::addResourceState(
ttl_.clear(resource.name());
}

resource_state_[resource.name()] = ResourceState(resource);
resource_names_.insert(resource.name());
if (auto it = resource_state_.find(resource.name()); it != resource_state_.end()) {
auto old_type = it->second.type();
it->second = ResourceState(resource, old_type);
} else {
resource_state_.insert(
{resource.name(), ResourceState(resource, ResourceType::ReceivedFromServer)});
}
}

void DeltaSubscriptionState::setResourceWaitingForServer(const std::string& resource_name) {
resource_state_[resource_name] = ResourceState();
resource_names_.insert(resource_name);
OptRef<DeltaSubscriptionState::ResourceState>
DeltaSubscriptionState::getResourceState(const std::string& resource_name) {
auto itr = resource_state_.find(resource_name);
if (itr == resource_state_.end()) {
return {};
}
return {itr->second};
}

void DeltaSubscriptionState::removeResourceState(const std::string& resource_name) {
resource_state_.erase(resource_name);
resource_names_.erase(resource_name);
}

} // namespace Config
Expand Down
57 changes: 44 additions & 13 deletions source/common/config/delta_subscription_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,43 @@ class DeltaSubscriptionState : public Logger::Loggable<Logger::Id::config> {
void handleGoodResponse(const envoy::service::discovery::v3::DeltaDiscoveryResponse& message);
void handleBadResponse(const EnvoyException& e, UpdateAck& ack);

// This enumeration describes the resource type, which is only relevant for wildcard
// subscriptions. Depending on its type, the resource will or will not be resent on the initial
// wildcard subscription.
enum class ResourceType {
// Explicitly requested resource type means that we have asked about the resource by updating
// the subscription interest. Such resources are resent on the initial wildcard request.
ExplicitlyRequested,
// Received from server resources are resources that the state knows about only from the server
// response. Such resources are not resent on the initial wildcard request.
ReceivedFromServer,
};

// Determines the effective resource type. Explicitly requested type overrides the received from
// server type.
ResourceType effectiveResourceType(ResourceType old_type, ResourceType new_type) {
return (old_type == ResourceType::ReceivedFromServer) ? new_type : old_type;
}

class ResourceState {
public:
ResourceState(const envoy::service::discovery::v3::Resource& resource)
: version_(resource.version()) {}
ResourceState(absl::optional<std::string> version, ResourceType type)
: version_(std::move(version)), type_(type) {}

ResourceState(const envoy::service::discovery::v3::Resource& resource, ResourceType type)
: ResourceState(resource.version(), type) {}

// Builds a ResourceState in the waitingForServer state.
ResourceState() = default;
ResourceState(ResourceType type) : ResourceState(absl::nullopt, type) {}

ResourceType type() const { return type_; }

// If true, we currently have no version of this resource - we are waiting for the server to
// provide us with one.
bool waitingForServer() const { return version_ == absl::nullopt; }

void setAsWaitingForServer() { version_ = absl::nullopt; }

// Must not be called if waitingForServer() == true.
std::string version() const {
ASSERT(version_.has_value());
Expand All @@ -79,14 +104,24 @@ class DeltaSubscriptionState : public Logger::Loggable<Logger::Id::config> {

private:
absl::optional<std::string> version_;
ResourceType type_;
};

// Use these helpers to ensure resource_state_ and resource_names_ get updated together.
void addResourceState(const envoy::service::discovery::v3::Resource& resource);
void setResourceWaitingForServer(const std::string& resource_name);
void removeResourceState(const std::string& resource_name);
// Describes the wildcard mode the subscription is in.
enum class WildcardMode {
// This mode is being expressed by sending a wildcard subscription request with an empty
// resource subscription list.
Implicit,
// This mode is being expressed by sending a wildcard subscription request that contains "*"
// special name in the resource subscription list.
Explicit,
// This mode is means no wildcard subscription.
Disabled,
};

void populateDiscoveryRequest(envoy::service::discovery::v3::DeltaDiscoveryResponse& request);
void addResourceStateFromServer(const envoy::service::discovery::v3::Resource& resource);
OptRef<ResourceState> getResourceState(const std::string& resource_name);
void removeResourceState(const std::string& resource_name);

// A map from resource name to per-resource version. The keys of this map are exactly the resource
// names we are currently interested in. Those in the waitingForServer state currently don't have
Expand All @@ -99,13 +134,9 @@ class DeltaSubscriptionState : public Logger::Loggable<Logger::Id::config> {
// disable heartbeats for these resources (currently only VHDS).
const bool supports_heartbeats_;
TtlManager ttl_;
// The keys of resource_versions_. Only tracked separately because std::map does not provide an
// iterator into just its keys.
absl::flat_hash_set<std::string> resource_names_;

const std::string type_url_;
// Is the subscription is for a wildcard request.
const bool wildcard_;
WildcardMode mode_;
UntypedConfigUpdateCallbacks& watch_map_;
const LocalInfo::LocalInfo& local_info_;
Event::Dispatcher& dispatcher_;
Expand Down
5 changes: 4 additions & 1 deletion source/common/config/new_grpc_mux_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,10 @@ GrpcMuxWatchPtr NewGrpcMuxImpl::addWatch(const std::string& type_url,
auto entry = subscriptions_.find(type_url);
if (entry == subscriptions_.end()) {
// We don't yet have a subscription for type_url! Make one!
addSubscription(type_url, options.use_namespace_matching_, resources.empty());
// No resources or an existence of the special name implies that
// this is a wildcard request subscription.
const bool wildcard = resources.empty() || (resources.find("*") != resources.end());
addSubscription(type_url, options.use_namespace_matching_, wildcard);
return addWatch(type_url, resources, callbacks, resource_decoder, options);
}

Expand Down
3 changes: 2 additions & 1 deletion source/common/config/watch_map.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ void WatchMap::removeDeferredWatches() {
AddedRemoved
WatchMap::updateWatchInterest(Watch* watch,
const absl::flat_hash_set<std::string>& update_to_these_names) {
if (update_to_these_names.empty()) {
if (update_to_these_names.empty() ||
update_to_these_names.find("*") != update_to_these_names.end()) {
wildcard_watches_.insert(watch);
} else {
wildcard_watches_.erase(watch);
Expand Down
Loading