Skip to content

Commit bbbc246

Browse files
committed
policy: clean-up
Do not use the default decoder as NPRDS does not carry a name inside the NetworkPolicyResource type. Signed-off-by: Jarno Rajahalme <jarno@isovalent.com>
1 parent a811602 commit bbbc246

3 files changed

Lines changed: 66 additions & 44 deletions

File tree

cilium/network_policy.cc

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
#include "source/common/init/target_impl.h"
4646
#include "source/common/init/watcher_impl.h"
4747
#include "source/common/network/utility.h"
48-
#include "source/common/protobuf/message_validator_impl.h"
4948
#include "source/common/protobuf/protobuf.h"
5049
#include "source/common/protobuf/utility.h"
5150
#include "source/server/transport_socket_config_impl.h"
@@ -327,8 +326,10 @@ class ResourceMapOverlay {
327326
};
328327

329328
// helper for validating resource names.
330-
void validateResourceNameHasNoWhitespace(absl::string_view resource_name,
331-
absl::string_view subject) {
329+
void validateResourceName(absl::string_view resource_name, absl::string_view subject) {
330+
if (resource_name.empty()) {
331+
throw EnvoyException(fmt::format("{} must not be empty", subject));
332+
}
332333
if (std::ranges::any_of(resource_name, [](unsigned char c) { return absl::ascii_isspace(c); })) {
333334
throw EnvoyException(
334335
fmt::format("{} '{}' must not contain whitespace", subject, resource_name));
@@ -431,8 +432,8 @@ class NetworkPolicyMapImpl : public Envoy::Config::SubscriptionCallbacks,
431432
std::shared_ptr<const PolicyInstanceImpl>
432433
createOrReusePolicy(const std::string& resource_name, const cilium::NetworkPolicy& config,
433434
const PolicyStreamStateConstSharedPtr& policy_stream_state,
434-
const ResourceMap& old_resource_map,
435-
const ResourceMapOverlay* selector_resource_map);
435+
const ResourceMap& resource_map,
436+
const ResourceMapOverlay* pending_resource_map);
436437

437438
SelectorHandle createOrReuseSelector(const std::string& resource_name,
438439
const cilium::Selector& config, uint64_t update_version);
@@ -939,7 +940,7 @@ class PortNetworkPolicyRule : public Logger::Loggable<Logger::Id::config> {
939940

940941
PortNetworkPolicyRule(const NetworkPolicyMapImpl& parent,
941942
const cilium::PortNetworkPolicyRule& rule,
942-
const ResourceMapOverlay* selector_resource_map)
943+
const ResourceMapOverlay* resource_map)
943944
: name_(rule.name()),
944945
verdict_(rule.pass_precedence() ? RuleVerdict::Pass
945946
: (rule.deny() ? RuleVerdict::Deny : RuleVerdict::Allow)),
@@ -950,7 +951,7 @@ class PortNetworkPolicyRule : public Logger::Loggable<Logger::Id::config> {
950951
fmt::format("PortNetworkPolicyRule: pass_precedence {} must be lower than precedence {}",
951952
tier_last_precedence_, precedence_));
952953
}
953-
if (selector_resource_map) {
954+
if (resource_map) {
954955
if (rule.remote_policies_size()) {
955956
throw EnvoyException(
956957
"Delta Network Policy rule must use selectors instead of remote_policies");
@@ -959,7 +960,7 @@ class PortNetworkPolicyRule : public Logger::Loggable<Logger::Id::config> {
959960
for (const auto& selector : rule.selectors()) {
960961
ENVOY_LOG(trace, "Cilium L7 PortNetworkPolicyRule(): {} selector {} by rule: {}", verdict_,
961962
selector, name_);
962-
selectors_.emplace_back(selector_resource_map->getSelectorHandleOrThrow(selector));
963+
selectors_.emplace_back(resource_map->getSelectorHandleOrThrow(selector));
963964
}
964965
} else {
965966
if (rule.selectors_size()) {
@@ -1301,14 +1302,14 @@ class PortNetworkPolicyRules : public Logger::Loggable<Logger::Id::config> {
13011302
// we must add a default allow rule to retain the semantics of an empty rules.
13021303
void prepend(const NetworkPolicyMapImpl& parent,
13031304
const Protobuf::RepeatedPtrField<cilium::PortNetworkPolicyRule>& rules,
1304-
const ResourceMapOverlay* selector_resource_map) {
1305+
const ResourceMapOverlay* resource_map) {
13051306
if (initialized_ && rules.empty() != rules_.empty()) {
13061307
// add an explicit allow-all rule to keep the combined semantics
13071308
rules_.emplace(rules_.begin(), std::make_shared<PortNetworkPolicyRule>());
13081309
}
13091310
for (const auto& it : rules) {
13101311
rules_.emplace(rules_.begin(),
1311-
std::make_shared<PortNetworkPolicyRule>(parent, it, selector_resource_map));
1312+
std::make_shared<PortNetworkPolicyRule>(parent, it, resource_map));
13121313
updateFor(rules_.front());
13131314
}
13141315
initialized_ = true;
@@ -1715,7 +1716,7 @@ class PortNetworkPolicy : public Logger::Loggable<Logger::Id::config> {
17151716
public:
17161717
PortNetworkPolicy(const NetworkPolicyMapImpl& parent,
17171718
const Protobuf::RepeatedPtrField<cilium::PortNetworkPolicy>& rules,
1718-
const ResourceMapOverlay* selector_resource_map) {
1719+
const ResourceMapOverlay* resource_map) {
17191720
for (const auto& rule : rules) {
17201721
// Only TCP supported for HTTP
17211722
if (rule.protocol() == envoy::config::core::v3::SocketAddress::TCP) {
@@ -1874,10 +1875,10 @@ class PortNetworkPolicy : public Logger::Loggable<Logger::Id::config> {
18741875
// so the relative order of rules from this batch is reversed. This
18751876
// is harmless: equal-precedence rules are evaluated as alternatives
18761877
// (stable sort only affects presentation/debug ordering).
1877-
rules.prepend(parent, rule.rules(), selector_resource_map);
1878+
rules.prepend(parent, rule.rules(), resource_map);
18781879
} else {
18791880
// Rules with a non-trivial range go to the back of the list
1880-
rules.append(parent, rule.rules(), selector_resource_map);
1881+
rules.append(parent, rule.rules(), resource_map);
18811882
}
18821883
}
18831884
} else {
@@ -1958,11 +1959,11 @@ class PolicyInstanceImpl : public PolicyInstance {
19581959
PolicyInstanceImpl(const NetworkPolicyMapImpl& parent, uint64_t hash,
19591960
const cilium::NetworkPolicy& proto,
19601961
const PolicyStreamStateConstSharedPtr& policy_stream_state,
1961-
const ResourceMapOverlay* selector_resource_map)
1962+
const ResourceMapOverlay* resource_map)
19621963
: endpoint_id_(proto.endpoint_id()), hash_(hash), policy_proto_(proto), endpoint_ips_(proto),
19631964
parent_(parent), policy_stream_state_(policy_stream_state),
1964-
ingress_(parent, policy_proto_.ingress_per_port_policies(), selector_resource_map),
1965-
egress_(parent, policy_proto_.egress_per_port_policies(), selector_resource_map) {}
1965+
ingress_(parent, policy_proto_.ingress_per_port_policies(), resource_map),
1966+
egress_(parent, policy_proto_.egress_per_port_policies(), resource_map) {}
19661967

19671968
bool allowed(bool ingress, uint16_t proxy_id, uint32_t remote_id, uint16_t port,
19681969
Envoy::Http::RequestHeaderMap& headers,
@@ -2323,10 +2324,9 @@ void NetworkPolicyMapImpl::subscribe() {
23232324
if (subscription_use_delta_xds_) {
23242325
subscription_ = Cilium::subscribe(
23252326
"type.googleapis.com/cilium.NetworkPolicyResource", context_, *npds_stats_scope_, *this,
2326-
std::make_shared<NetworkPolicyResourceDecoder>(ProtobufMessage::getNullValidationVisitor(),
2327-
"name"),
2328-
subscription_use_delta_xds_, std::chrono::milliseconds(0),
2329-
std::move(on_transport_established), std::move(on_transport_close));
2327+
std::make_shared<NetworkPolicyResourceDecoder>(), subscription_use_delta_xds_,
2328+
std::chrono::milliseconds(0), std::move(on_transport_established),
2329+
std::move(on_transport_close));
23302330
} else {
23312331
subscription_ =
23322332
Cilium::subscribe("type.googleapis.com/cilium.NetworkPolicy", context_, *npds_stats_scope_,
@@ -2353,27 +2353,27 @@ void NetworkPolicyMapImpl::reopenIpcache() {
23532353

23542354
std::shared_ptr<const PolicyInstanceImpl> NetworkPolicyMapImpl::createOrReusePolicy(
23552355
const std::string& resource_name, const cilium::NetworkPolicy& config,
2356-
const PolicyStreamStateConstSharedPtr& policy_stream_state, const ResourceMap& old_resource_map,
2357-
const ResourceMapOverlay* selector_resource_map) {
2356+
const PolicyStreamStateConstSharedPtr& policy_stream_state, const ResourceMap& resource_map,
2357+
const ResourceMapOverlay* pending_resource_map) {
23582358
const uint64_t new_hash = MessageUtil::hash(config);
2359-
auto it = old_resource_map.find(resource_name);
2360-
if (it != old_resource_map.cend()) {
2359+
auto it = resource_map.find(resource_name);
2360+
if (it != resource_map.cend()) {
23612361
const auto* old_policy_entry = it->second.policyResourceEntry();
23622362
if (old_policy_entry == nullptr) {
23632363
return std::make_shared<const PolicyInstanceImpl>(*this, new_hash, config,
2364-
policy_stream_state, selector_resource_map);
2364+
policy_stream_state, pending_resource_map);
23652365
}
23662366
const auto& old_policy = old_policy_entry->policy;
23672367
if (old_policy && old_policy->hash_ == new_hash &&
23682368
Protobuf::util::MessageDifferencer::Equals(old_policy->policy_proto_, config) &&
2369-
!(selector_resource_map && policyUsesSelectors(config))) {
2369+
!(pending_resource_map && policyUsesSelectors(config))) {
23702370
ENVOY_LOG(trace, "New policy is equal to old one, not updating.");
23712371
return old_policy;
23722372
}
23732373
}
23742374

23752375
return std::make_shared<const PolicyInstanceImpl>(*this, new_hash, config, policy_stream_state,
2376-
selector_resource_map);
2376+
pending_resource_map);
23772377
}
23782378

23792379
SelectorHandle NetworkPolicyMapImpl::createOrReuseSelector(const std::string& resource_name,
@@ -2503,7 +2503,6 @@ absl::Status NetworkPolicyMapImpl::onConfigUpdate(
25032503
// SDS secrets will use this!
25042504
transport_factory_context_->setInitManager(version_init_manager);
25052505

2506-
const auto& old_resource_map = resource_map_;
25072506
const auto policy_stream_state =
25082507
is_new_stream
25092508
? std::make_shared<PolicyStreamState>(stream_generation, selector_map_.getVersion())
@@ -2514,7 +2513,7 @@ absl::Status NetworkPolicyMapImpl::onConfigUpdate(
25142513
for (const auto& resource : resources) {
25152514
const auto& config = dynamic_cast<const cilium::NetworkPolicy&>(resource.get().resource());
25162515
const std::string& resource_name = resource.get().name();
2517-
validateResourceNameHasNoWhitespace(resource_name, "Network Policy resource name");
2516+
validateResourceName(resource_name, "Network Policy resource name");
25182517
if (config.endpoint_ips().empty()) {
25192518
throw EnvoyException("Network Policy has no endpoint ips");
25202519
}
@@ -2523,8 +2522,8 @@ absl::Status NetworkPolicyMapImpl::onConfigUpdate(
25232522
"version {}",
25242523
config.endpoint_id(), config.endpoint_ips()[0], version_info);
25252524

2526-
auto policy = createOrReusePolicy(resource_name, config, policy_stream_state,
2527-
old_resource_map, nullptr);
2525+
auto policy =
2526+
createOrReusePolicy(resource_name, config, policy_stream_state, resource_map_, nullptr);
25282527
if (!resource_name.empty()) {
25292528
resource_entries.emplace_back(resource_name, ResourceKey::policyResource(policy));
25302529
}
@@ -2559,16 +2558,14 @@ absl::Status NetworkPolicyMapImpl::onConfigUpdate(
25592558
// policy_stream_state_ gets updated on first successful update,
25602559
// so 'is_new_stream' remains 'true' as long as the stream has not had a successful update yet.
25612560
const bool is_new_stream = stream_generation != policy_stream_state_->streamGeneration();
2562-
const auto& old_resource_map = resource_map_;
25632561

25642562
// first find if this is a selector-only update
25652563
bool updates_policies = false;
25662564
bool updates_selectors = false;
25672565
for (const auto& removed_resource : removed_resources) {
2568-
validateResourceNameHasNoWhitespace(removed_resource,
2569-
"Network Policy delta removed resource name");
2570-
auto resource_it = old_resource_map.find(removed_resource);
2571-
if (resource_it == old_resource_map.end()) {
2566+
validateResourceName(removed_resource, "Network Policy delta removed resource name");
2567+
auto resource_it = resource_map_.find(removed_resource);
2568+
if (resource_it == resource_map_.end()) {
25722569
continue;
25732570
}
25742571
if (resource_it->second.selectorResourceEntry()) {
@@ -2584,7 +2581,7 @@ absl::Status NetworkPolicyMapImpl::onConfigUpdate(
25842581
if (resource_name.empty()) {
25852582
throw EnvoyException("Network Policy delta resource has no name");
25862583
}
2587-
validateResourceNameHasNoWhitespace(resource_name, "Network Policy delta resource name");
2584+
validateResourceName(resource_name, "Network Policy delta resource name");
25882585
switch (typed_resource.resource_case()) {
25892586
case cilium::NetworkPolicyResource::kPolicy:
25902587
updates_policies = true;
@@ -2811,8 +2808,8 @@ absl::Status NetworkPolicyMapImpl::onConfigUpdate(
28112808
resource_name, config.endpoint_id(), config.endpoint_ips()[0],
28122809
system_version_info);
28132810

2814-
auto policy = createOrReusePolicy(resource_name, config, policy_stream_state,
2815-
old_resource_map, &pending_resource_map);
2811+
auto policy = createOrReusePolicy(resource_name, config, policy_stream_state, resource_map_,
2812+
&pending_resource_map);
28162813
if (!pending_resource_map.emplace(resource_name, ResourceKey::policyResource(policy))) {
28172814
throw EnvoyException(fmt::format(
28182815
"Network Policy delta update for version {} has duplicate resource key '{}' on {} "

cilium/network_policy.h

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <memory>
88
#include <string>
99

10+
#include "envoy/common/exception.h"
1011
#include "envoy/common/pure.h"
1112
#include "envoy/common/regex.h"
1213
#include "envoy/config/core/v3/base.pb.h"
@@ -24,7 +25,6 @@
2425
#include "source/common/common/logger.h"
2526
#include "source/common/common/macros.h"
2627
#include "source/common/common/thread.h"
27-
#include "source/common/config/opaque_resource_decoder_impl.h"
2828
#include "source/common/protobuf/message_validator_impl.h"
2929
#include "source/common/protobuf/protobuf.h"
3030
#include "source/common/protobuf/utility.h"
@@ -170,8 +170,34 @@ class NetworkPolicyDecoder : public Envoy::Config::OpaqueResourceDecoder {
170170
ProtobufMessage::ValidationVisitor& validation_visitor_;
171171
};
172172

173-
using NetworkPolicyResourceDecoder =
174-
Envoy::Config::OpaqueResourceDecoderImpl<cilium::NetworkPolicyResource>;
173+
// cilium::NetworkPolicyResource does not carry a resource name, but relies on the
174+
// DeltaDiscoveryRespons Resource wrapper to have the name. Hence can not use
175+
// Envoy::Config::OpaqueResourceDecoderImpl<cilium::NetworkPolicyResource>
176+
class NetworkPolicyResourceDecoder : public Envoy::Config::OpaqueResourceDecoder {
177+
public:
178+
NetworkPolicyResourceDecoder()
179+
: validation_visitor_(ProtobufMessage::getNullValidationVisitor()) {}
180+
181+
// Config::OpaqueResourceDecoder
182+
ProtobufTypes::MessagePtr decodeResource(const Protobuf::Any& resource) override {
183+
auto typed_message = std::make_unique<cilium::NetworkPolicyResource>();
184+
// If the Any is a synthetic empty message (e.g. because the resource field
185+
// was not set in Resource, this might be empty, so we shouldn't decode.
186+
if (!resource.type_url().empty()) {
187+
MessageUtil::anyConvertAndValidate<cilium::NetworkPolicyResource>(resource, *typed_message,
188+
validation_visitor_);
189+
}
190+
return typed_message;
191+
}
192+
193+
std::string resourceName(const Protobuf::Message&) override {
194+
throw EnvoyException(
195+
"NetworkPolicyResource does not carry a name and must be wrapped in Resource");
196+
}
197+
198+
private:
199+
ProtobufMessage::ValidationVisitor& validation_visitor_;
200+
};
175201

176202
/**
177203
* All Cilium L7 filter stats. @see stats_macros.h

tests/cilium_network_policy_test.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,7 @@ class CiliumNetworkPolicyTest : public ::testing::Test {
135135
std::string deltaUpdateFromYaml(const std::string& config) {
136136
envoy::service::discovery::v3::DeltaDiscoveryResponse message;
137137
MessageUtil::loadFromYaml(config, message, ProtobufMessage::getNullValidationVisitor());
138-
NetworkPolicyResourceDecoder network_policy_resource_decoder(
139-
ProtobufMessage::getNullValidationVisitor(), "name");
138+
NetworkPolicyResourceDecoder network_policy_resource_decoder;
140139
auto decoded_resources = std::make_unique<Config::DecodedResourcesWrapper>();
141140
for (const auto& resource : message.resources()) {
142141
decoded_resources->pushBack(

0 commit comments

Comments
 (0)