https://github.com/cilium/cilium
Raw File
Tip revision: 9c129474a19c027a3d87de084fd3fef0825b2322 authored by derailed on 03 October 2023, 20:34:24 UTC
Ensures prometheus metrics associated with a deleted node are no longer reported.
Tip revision: 9c12947
ipsec_from_lxc_test.c
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* Copyright Authors of Cilium */

#define HAVE_LPM_TRIE_MAP_TYPE
#include "common.h"
#include <bpf/ctx/skb.h>
#include "pktgen.h"

/* We need to define LXC_IPV4 and LXC_IP to match v4_pod_one and v6_pod_one to
 * pass the source IP verification of bpf_lxc.
 */
#define LXC_IPV4 (__be32)v4_pod_one
#define LXC_IP_X
volatile __u32 LXC_IP_1 = bpf_htonl((0xfd) << 24 | (0x04) << 16 | (0) << 8 | (0));
volatile __u32 LXC_IP_2 = bpf_htonl((0) << 24 | (0) << 16 | (0) << 8 | (0));
volatile __u32 LXC_IP_3 = bpf_htonl((0) << 24 | (0) << 16 | (0) << 8 | (0));
volatile __u32 LXC_IP_4 = bpf_htonl((0) << 24 | (0) << 16 | (0) << 8 | (0x1));
#define ROUTER_IP
#include "config_replacement.h"
#undef ROUTER_IP

#define NODE_ID 2333
#define ENCRYPT_KEY 3
#define ENABLE_IPV4
#define ENABLE_IPV6
#define ENABLE_IPSEC
#define TUNNEL_MODE
#define HAVE_ENCAP
#define ENCAP_IFINDEX 4

#include "bpf_lxc.c"

#define FROM_CONTAINER 0

struct {
	__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
	__uint(key_size, sizeof(__u32));
	__uint(max_entries, 1);
	__array(values, int());
} entry_call_map __section(".maps") = {
	.values = {
		[FROM_CONTAINER] = &cil_from_container,
	},
};

static __always_inline int
pktgen_from_lxc(struct __ctx_buff *ctx)
{
	struct pktgen builder;
	struct ethhdr *l2;
	struct iphdr *l3;
	struct tcphdr *l4;
	void *data;

	pktgen__init(&builder, ctx);

	l2 = pktgen__push_ethhdr(&builder);
	if (!l2)
		return TEST_ERROR;
	ethhdr__set_macs(l2, (__u8 *)mac_one, (__u8 *)mac_two);

	l3 = pktgen__push_default_iphdr(&builder);
	if (!l3)
		return TEST_ERROR;
	l3->saddr = v4_pod_one;
	l3->daddr = v4_pod_two;

	l4 = pktgen__push_default_tcphdr(&builder);
	if (!l4)
		return TEST_ERROR;
	l4->source = tcp_src_one;
	l4->dest = tcp_svc_one;

	data = pktgen__push_data(&builder, default_data, sizeof(default_data));
	if (!data)
		return TEST_ERROR;

	pktgen__finish(&builder);
	return 0;
}

PKTGEN("tc", "01_ipv4_from_lxc_no_node_id")
int ipv4_from_lxc_no_node_id_pktgen(struct __ctx_buff *ctx)
{
	return pktgen_from_lxc(ctx);
}

SETUP("tc", "01_ipv4_from_lxc_no_node_id")
int ipv4_from_lxc_no_node_id_setup(struct __ctx_buff *ctx)
{
	struct policy_key policy_key = { .egress = 1 };
	struct policy_entry policy_value = {};

	map_update_elem(&POLICY_MAP, &policy_key, &policy_value, BPF_ANY);

	struct ipcache_key cache_key = {};
	struct remote_endpoint_info cache_value = {};

	cache_key.lpm_key.prefixlen = IPCACHE_PREFIX_LEN(32);
	cache_key.family = ENDPOINT_KEY_IPV4;
	cache_key.ip4 = v4_pod_two;
	cache_value.sec_label = 233;
	cache_value.tunnel_endpoint = v4_node_two;
	cache_value.key = ENCRYPT_KEY;
	map_update_elem(&IPCACHE_MAP, &cache_key, &cache_value, BPF_ANY);

	__u32 encrypt_key = 0;
	struct encrypt_config encrypt_value = { .encrypt_key = 3 };

	map_update_elem(&ENCRYPT_MAP, &encrypt_key, &encrypt_value, BPF_ANY);

	tail_call_static(ctx, &entry_call_map, FROM_CONTAINER);
	return TEST_ERROR;
}

CHECK("tc", "01_ipv4_from_lxc_no_node_id")
int ipv4_from_lxc_no_node_id_check(__maybe_unused const struct __ctx_buff *ctx)
{
	void *data;
	void *data_end;
	__u32 *status_code;

	struct metrics_value *entry = NULL;
	struct metrics_key key = {};

	test_init();

	data = (void *)(long)ctx->data;
	data_end = (void *)(long)ctx->data_end;

	if (data + sizeof(*status_code) > data_end)
		test_fatal("status code out of bounds");

	status_code = data;
	assert(*status_code == CTX_ACT_DROP);

	key.reason = (__u8)-DROP_NO_NODE_ID;
	key.dir = METRIC_EGRESS;
	entry = map_lookup_elem(&METRICS_MAP, &key);
	if (!entry)
		test_fatal("metrics entry not found");
	assert(entry->count == 1);

	test_finish();
}

PKTGEN("tc", "02_ipv4_from_lxc_encrypt")
int ipv4_from_lxc_encrypt_pktgen(struct __ctx_buff *ctx)
{
	return pktgen_from_lxc(ctx);
}

SETUP("tc", "02_ipv4_from_lxc_encrypt")
int ipv4_from_lxc_encrypt_setup(struct __ctx_buff *ctx)
{
	struct node_key node_ip = {};
	__u32 node_id = NODE_ID;

	node_ip.family = ENDPOINT_KEY_IPV4;
	node_ip.ip4 = v4_node_two;
	map_update_elem(&NODE_MAP, &node_ip, &node_id, BPF_ANY);

	tail_call_static(ctx, &entry_call_map, FROM_CONTAINER);
	return TEST_ERROR;
}

CHECK("tc", "02_ipv4_from_lxc_encrypt")
int ipv4_from_lxc_encrypt_check(__maybe_unused const struct __ctx_buff *ctx)
{
	void *data;
	void *data_end;
	__u32 *status_code;
	struct ethhdr *l2;
	struct iphdr *l3;
	struct tcphdr *l4;
	__u8 *payload;

	test_init();

	data = (void *)(long)ctx->data;
	data_end = (void *)(long)ctx->data_end;

	if (data + sizeof(*status_code) > data_end)
		test_fatal("status code out of bounds");

	status_code = data;
	assert(*status_code == CTX_ACT_OK);
	assert(ctx->mark == (NODE_ID << 16 | ENCRYPT_KEY << 12 | MARK_MAGIC_ENCRYPT));
	assert(ctx_load_meta(ctx, CB_ENCRYPT_IDENTITY) == SECLABEL);

	l2 = data + sizeof(*status_code);

	if ((void *)l2 + sizeof(struct ethhdr) > data_end)
		test_fatal("l2 out of bounds");

	if (l2->h_proto != bpf_htons(ETH_P_IP))
		test_fatal("l2 proto hasn't been set to ETH_P_IP");

	if (memcmp(l2->h_source, (__u8 *)mac_one, ETH_ALEN) != 0)
		test_fatal("src mac hasn't been set to source ep's mac");

	if (memcmp(l2->h_dest, (__u8 *)mac_two, ETH_ALEN) != 0)
		test_fatal("dest mac hasn't been set to dest ep's mac");

	l3 = (void *)l2 + sizeof(struct ethhdr);

	if ((void *)l3 + sizeof(struct iphdr) > data_end)
		test_fatal("l3 out of bounds");

	if (l3->saddr != v4_pod_one)
		test_fatal("src IP was changed");

	if (l3->daddr != v4_pod_two)
		test_fatal("dest IP was changed");

	l4 = (void *)l3 + sizeof(struct iphdr);

	if ((void *)l4 + sizeof(struct tcphdr) > data_end)
		test_fatal("l4 out of bounds");

	if (l4->source != tcp_src_one)
		test_fatal("src TCP port was changed");

	if (l4->dest != tcp_svc_one)
		test_fatal("dst TCP port was changed");

	payload = (void *)l4 + sizeof(struct tcphdr);
	if ((void *)payload + sizeof(default_data) > data_end)
		test_fatal("paylaod out of bounds\n");

	if (memcmp(payload, default_data, sizeof(default_data)) != 0)
		test_fatal("tcp payload was changed");

	test_finish();
}

PKTGEN("tc", "03_ipv6_from_lxc_encrypt")
int ipv6_from_lxc_encrypt_pktgen(struct __ctx_buff *ctx)
{
	struct pktgen builder;
	struct ethhdr *l2;
	struct ipv6hdr *l3;
	struct tcphdr *l4;
	void *data;

	pktgen__init(&builder, ctx);

	l2 = pktgen__push_ethhdr(&builder);
	if (!l2)
		return TEST_ERROR;
	ethhdr__set_macs(l2, (__u8 *)mac_one, (__u8 *)mac_two);

	l3 = pktgen__push_default_ipv6hdr(&builder);
	if (!l3)
		return TEST_ERROR;
	ipv6hdr__set_addrs(l3, (__u8 *)v6_pod_one, (__u8 *)v6_pod_two);

	l4 = pktgen__push_default_tcphdr(&builder);
	if (!l4)
		return TEST_ERROR;
	l4->source = tcp_src_one;
	l4->dest = tcp_svc_one;

	data = pktgen__push_data(&builder, default_data, sizeof(default_data));
	if (!data)
		return TEST_ERROR;

	pktgen__finish(&builder);
	return 0;
}

SETUP("tc", "03_ipv6_from_lxc_encrypt")
int ipv6_from_lxc_encrypt_setup(struct __ctx_buff *ctx)
{
	struct policy_key policy_key = { .egress = 1 };
	struct policy_entry policy_value = {};

	map_update_elem(&POLICY_MAP, &policy_key, &policy_value, BPF_ANY);

	struct ipcache_key cache_key = {};
	struct remote_endpoint_info cache_value = {};

	cache_key.lpm_key.prefixlen = IPCACHE_PREFIX_LEN(128);
	cache_key.family = ENDPOINT_KEY_IPV6;
	memcpy(&cache_key.ip6, (__u8 *)v6_pod_two, 16);
	cache_value.sec_label = 233;
	cache_value.tunnel_endpoint = v4_node_two;
	cache_value.key = ENCRYPT_KEY;
	map_update_elem(&IPCACHE_MAP, &cache_key, &cache_value, BPF_ANY);

	__u32 encrypt_key = 0;
	struct encrypt_config encrypt_value = { .encrypt_key = 3 };

	map_update_elem(&ENCRYPT_MAP, &encrypt_key, &encrypt_value, BPF_ANY);

	struct node_key node_ip = {};
	__u32 node_id = NODE_ID;

	node_ip.family = ENDPOINT_KEY_IPV4;
	node_ip.ip4 = v4_node_two;
	map_update_elem(&NODE_MAP, &node_ip, &node_id, BPF_ANY);

	tail_call_static(ctx, &entry_call_map, FROM_CONTAINER);
	return TEST_ERROR;
}

CHECK("tc", "03_ipv6_from_lxc_encrypt")
int ipv6_from_lxc_encrypt_check(__maybe_unused const struct __ctx_buff *ctx)
{
	void *data;
	void *data_end;
	__u32 *status_code;
	struct ethhdr *l2;
	struct ipv6hdr *l3;
	struct tcphdr *l4;
	__u8 *payload;

	test_init();

	data = (void *)(long)ctx->data;
	data_end = (void *)(long)ctx->data_end;

	if (data + sizeof(*status_code) > data_end)
		test_fatal("status code out of bounds");

	status_code = data;
	assert(*status_code == CTX_ACT_OK);
	assert(ctx->mark == (NODE_ID << 16 | ENCRYPT_KEY << 12 | MARK_MAGIC_ENCRYPT));
	assert(ctx_load_meta(ctx, CB_ENCRYPT_IDENTITY) == SECLABEL);

	l2 = data + sizeof(*status_code);

	if ((void *)l2 + sizeof(struct ethhdr) > data_end)
		test_fatal("l2 out of bounds");

	if (l2->h_proto != bpf_htons(ETH_P_IPV6))
		test_fatal("l2 proto hasn't been set to ETH_P_IPV6");

	if (memcmp(l2->h_source, (__u8 *)mac_one, ETH_ALEN) != 0)
		test_fatal("src mac hasn't been set to source ep's mac");

	if (memcmp(l2->h_dest, (__u8 *)mac_two, ETH_ALEN) != 0)
		test_fatal("dest mac hasn't been set to dest ep's mac");

	l3 = (void *)l2 + sizeof(struct ethhdr);

	if ((void *)l3 + sizeof(struct ipv6hdr) > data_end)
		test_fatal("l3 out of bounds");

	if (memcmp((__u8 *)&l3->saddr, (__u8 *)v6_pod_one, 16) != 0)
		test_fatal("src IP was changed");

	if (memcmp((__u8 *)&l3->daddr, (__u8 *)v6_pod_two, 16) != 0)
		test_fatal("dest IP was changed");

	l4 = (void *)l3 + sizeof(struct ipv6hdr);

	if ((void *)l4 + sizeof(struct tcphdr) > data_end)
		test_fatal("l4 out of bounds");

	if (l4->source != tcp_src_one)
		test_fatal("src TCP port was changed");

	if (l4->dest != tcp_svc_one)
		test_fatal("dst TCP port was changed");

	payload = (void *)l4 + sizeof(struct tcphdr);
	if ((void *)payload + sizeof(default_data) > data_end)
		test_fatal("paylaod out of bounds\n");

	if (memcmp(payload, default_data, sizeof(default_data)) != 0)
		test_fatal("tcp payload was changed");
	test_finish();
}
back to top