Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion cilium/network_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,11 @@ Network::FilterStatus Instance::onData(Buffer::Instance& data, bool end_stream)
go_parser_->setOrigEndStream(end_stream);
} else if (!l7proto_.empty()) {
const auto& metadata = conn.streamInfo().dynamicMetadata();
bool changed = log_entry_.updateFromMetadata(l7proto_, metadata.filter_metadata().at(l7proto_));
const auto& filter_metadata = metadata.filter_metadata();
const auto metadata_it = filter_metadata.find(l7proto_);
const Protobuf::Struct empty_metadata;
bool changed = log_entry_.updateFromMetadata(
l7proto_, metadata_it != filter_metadata.end() ? metadata_it->second : empty_metadata);

// Policy may have changed since the connection was established, get fresh policy
const auto policy_fs =
Expand Down
4 changes: 4 additions & 0 deletions cilium/network_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ namespace Envoy {
namespace Filter {
namespace CiliumL3 {

class NetworkFilterTestPeer;

/**
* Shared configuration for Cilium network filter worker
* Instances. Each new network connection (on each worker thread)
Expand Down Expand Up @@ -67,6 +69,8 @@ class Instance : public Network::Filter, Logger::Loggable<Logger::Id::filter> {
Network::FilterStatus onWrite(Buffer::Instance&, bool end_stream) override;

private:
friend class NetworkFilterTestPeer;

// helper to be used either directly from onNewConnection (no L7 LB),
// or from upstream callback (l7 lb)
bool enforceNetworkPolicy(const Cilium::CiliumPolicyFilterState* policy_fs,
Expand Down
11 changes: 11 additions & 0 deletions tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,17 @@ envoy_cc_test(
],
)

envoy_cc_test(
name = "network_filter_test",
srcs = ["network_filter_test.cc"],
repository = "@envoy",
deps = [
"//cilium:network_filter_lib",
"@envoy//test/mocks/network:network_mocks",
"@envoy//test/mocks/server:listener_factory_context_mocks",
],
)

envoy_cc_test(
name = "cilium_tcp_integration_test",
srcs = ["cilium_tcp_integration_test.cc"],
Expand Down
98 changes: 98 additions & 0 deletions tests/network_filter_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#include <cstdint>
#include <memory>
#include <string>

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "cilium/api/network_filter.pb.h"
#include "cilium/filter_state_cilium_policy.h"
#include "cilium/network_filter.h"
#include "cilium/network_policy.h"

#include "envoy/buffer/buffer.h"
#include "envoy/network/address.h"
#include "envoy/network/connection.h"
#include "envoy/network/filter.h"
#include "envoy/stream_info/filter_state.h"
#include "envoy/stream_info/stream_info.h"
#include "envoy/upstream/host_description.h"

#include "source/common/buffer/buffer_impl.h"

#include "test/mocks/network/mocks.h"
#include "test/mocks/server/listener_factory_context.h"

namespace Envoy {
namespace Filter {
namespace CiliumL3 {

class NetworkFilterTestPeer {
public:
static void setL7Proto(Instance& instance, std::string l7proto) {
instance.l7proto_ = std::move(l7proto);
}

static const Cilium::AccessLog::Entry& logEntry(const Instance& instance) {
return instance.log_entry_;
}
};

} // namespace CiliumL3
} // namespace Filter

namespace {

using testing::NiceMock;

class TestReadFilterCallbacks : public Network::MockReadFilterCallbacks {
public:
TestReadFilterCallbacks() {
ON_CALL(*this, addUpstreamCallback(testing::_))
.WillByDefault(testing::Invoke([](const UpstreamCallback&) {}));
ON_CALL(*this, iterateUpstreamCallbacks(testing::_, testing::_))
.WillByDefault(testing::Return(true));
}

MOCK_METHOD(void, addUpstreamCallback, (const UpstreamCallback& cb), (override));
MOCK_METHOD(bool, iterateUpstreamCallbacks,
(Upstream::HostDescriptionConstSharedPtr, StreamInfo::StreamInfo&), (override));
};

class AllowAllPolicyResolver : public Cilium::PolicyResolver {
public:
uint32_t resolvePolicyId(const Network::Address::Ip*) const override { return 123; }

const Cilium::PolicyInstance& getPolicy(const std::string&) const override {
return Cilium::NetworkPolicyMap::getAllowAllEgressPolicy();
}

bool exists(const std::string&) const override { return true; }
};

TEST(CiliumNetworkFilterTest, MissingMetadataNamespaceDoesNotCrash) {
NiceMock<Server::Configuration::MockListenerFactoryContext> context;
::cilium::NetworkFilter proto_config;
auto config = std::make_shared<Filter::CiliumL3::Config>(proto_config, context);
Filter::CiliumL3::Instance instance(config);

NiceMock<TestReadFilterCallbacks> callbacks;
callbacks.connection_.stream_info_.filter_state_->setData(
Cilium::CiliumPolicyFilterState::key(),
std::make_shared<Cilium::CiliumPolicyFilterState>(
0, 456, false, false, 80, std::string("pod"), std::string(""),
std::make_shared<AllowAllPolicyResolver>(), 7, ""),
StreamInfo::FilterState::StateType::ReadOnly,
StreamInfo::FilterState::LifeSpan::Connection);
instance.initializeReadFilterCallbacks(callbacks);
Filter::CiliumL3::NetworkFilterTestPeer::setL7Proto(instance, "test.l7");

Buffer::OwnedImpl data("hello");
EXPECT_EQ(instance.onData(data, false), Network::FilterStatus::Continue);
EXPECT_EQ(callbacks.connection_.state_, Network::Connection::State::Open);
EXPECT_EQ(Filter::CiliumL3::NetworkFilterTestPeer::logEntry(instance).entry_.generic_l7().proto(),
"test.l7");
}

} // namespace
} // namespace Envoy