github.com/cilium/cilium@v1.16.2/bpf/tests/tc_host_encrypted_overlay.c (about)

     1  // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
     2  /* Copyright Authors of Cilium */
     3  
     4  #include "common.h"
     5  
     6  #include <bpf/ctx/skb.h>
     7  #include "pktgen.h"
     8  
     9  /* Set ETH_HLEN to 14 to indicate that the packet has a 14 byte ethernet header */
    10  #define ETH_HLEN 14
    11  
    12  /* Enable code paths under test */
    13  #define ENABLE_IPV4			1
    14  #define ENABLE_IPSEC			1
    15  #define ENABLE_ENCRYPTED_OVERLAY	1
    16  
    17  #define TUNNEL_MODE			1
    18  #define TUNNEL_PROTOCOL			TUNNEL_PROTOCOL_VXLAN
    19  #define TUNNEL_PORT			8472
    20  #define ENCAP_IFINDEX			25
    21  
    22  #define NODE1_IP			v4_ext_one
    23  #define NODE1_TUNNEL_SPORT		1337
    24  
    25  #define NODE2_IP			v4_ext_two
    26  #define NODE1_SPI			5
    27  #define NODE2_ID			123
    28  #define NODE2_SPI			6
    29  
    30  #define POD1_IP				v4_pod_one
    31  #define POD1_IFACE			100
    32  #define POD2_IP				v4_pod_two
    33  
    34  #define POD1_SEC_IDENTITY		112233
    35  
    36  static volatile const __u8 *node1_mac = mac_one;
    37  static volatile const __u8 *node2_mac = mac_two;
    38  
    39  static volatile const __u8 *pod1_mac = mac_three;
    40  static volatile const __u8 *pod2_mac = mac_four;
    41  
    42  #define ctx_redirect mock_ctx_redirect
    43  
    44  static __always_inline __maybe_unused int
    45  mock_ctx_redirect(const struct __sk_buff *ctx __maybe_unused,
    46  		  int ifindex __maybe_unused, __u32 flags __maybe_unused)
    47  {
    48  	if ((__u32)ifindex != ctx->ifindex)
    49  		return CTX_ACT_DROP;
    50  	if (flags != BPF_F_INGRESS)
    51  		return CTX_ACT_DROP;
    52  
    53  	return CTX_ACT_REDIRECT;
    54  }
    55  
    56  #define SECCTX_FROM_IPCACHE 1
    57  
    58  #include "bpf_host.c"
    59  
    60  #include "lib/endpoint.h"
    61  #include "lib/node.h"
    62  
    63  #define TO_NETDEV	0
    64  
    65  struct {
    66  	__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
    67  	__uint(key_size, sizeof(__u32));
    68  	__uint(max_entries, 1);
    69  	__array(values, int());
    70  } entry_call_map __section(".maps") = {
    71  	.values = {
    72  		[TO_NETDEV] = &cil_to_netdev,
    73  	},
    74  };
    75  
    76  PKTGEN("tc", "tc_host_encrypted_overlay_01")
    77  int host_encrypted_overlay_01_pktgen(struct __ctx_buff *ctx)
    78  {
    79  	struct vxlanhdr *vxlan;
    80  	struct iphdr *inner_l3;
    81  	struct pktgen builder;
    82  
    83  	/* Init packet builder */
    84  	pktgen__init(&builder, ctx);
    85  
    86  	vxlan = pktgen__push_ipv4_vxlan_packet(&builder,
    87  					       (__u8 *)node1_mac, (__u8 *)node2_mac,
    88  					       NODE1_IP, NODE2_IP,
    89  					       NODE1_TUNNEL_SPORT, TUNNEL_PORT);
    90  	if (!vxlan)
    91  		return TEST_ERROR;
    92  
    93  	vxlan->vx_vni = sec_identity_to_tunnel_vni(ENCRYPTED_OVERLAY_ID);
    94  
    95  	inner_l3 = pktgen__push_ipv4_packet(&builder,
    96  					    (__u8 *)pod1_mac, (__u8 *)pod2_mac,
    97  					    POD1_IP, POD2_IP);
    98  	if (!inner_l3)
    99  		return TEST_ERROR;
   100  
   101  	/* Calc lengths, set protocol fields and calc checksums */
   102  	pktgen__finish(&builder);
   103  
   104  	return 0;
   105  }
   106  
   107  SETUP("tc", "tc_host_encrypted_overlay_01")
   108  int tc_host_encrypted_overlay_01_setup(struct __ctx_buff *ctx)
   109  {
   110  	struct encrypt_config encrypt_value = { .encrypt_key = NODE1_SPI };
   111  	__u32 encrypt_key = 0;
   112  
   113  	endpoint_v4_add_entry(POD1_IP, POD1_IFACE, 0, 0, POD1_SEC_IDENTITY,
   114  			      (__u8 *)pod1_mac, (__u8 *)node1_mac);
   115  	node_v4_add_entry(NODE2_IP, NODE2_ID, NODE2_SPI);
   116  	map_update_elem(&ENCRYPT_MAP, &encrypt_key, &encrypt_value, BPF_ANY);
   117  
   118  	set_identity_mark(ctx, ENCRYPTED_OVERLAY_ID, MARK_MAGIC_OVERLAY);
   119  
   120  	/* Jump into the entrypoint */
   121  	tail_call_static(ctx, entry_call_map, TO_NETDEV);
   122  	/* Fail if we didn't jump */
   123  	return TEST_ERROR;
   124  }
   125  
   126  CHECK("tc", "tc_host_encrypted_overlay_01")
   127  int tc_host_encrypted_overlay_01_check(const struct __ctx_buff *ctx)
   128  {
   129  	struct vxlanhdr *vxlan;
   130  	void *data, *data_end;
   131  	__u32 *status_code;
   132  	struct udphdr *l4;
   133  	struct ethhdr *l2;
   134  	struct iphdr *l3;
   135  
   136  	test_init();
   137  
   138  	data = (void *)(long)ctx_data(ctx);
   139  	data_end = (void *)(long)ctx->data_end;
   140  
   141  	if (data + sizeof(__u32) > data_end)
   142  		test_fatal("status code out of bounds");
   143  
   144  	status_code = data;
   145  
   146  	assert(*status_code == CTX_ACT_REDIRECT);
   147  
   148  	l2 = data + sizeof(__u32);
   149  	if ((void *)l2 + sizeof(*l2) > data_end)
   150  		test_fatal("l2 out of bounds");
   151  
   152  	l3 = (void *)l2 + sizeof(*l2);
   153  	if ((void *)l3 + sizeof(*l3) > data_end)
   154  		test_fatal("l3 out of bounds");
   155  
   156  	l4 = (void *)l3 + sizeof(*l3);
   157  	if ((void *)l4 + sizeof(*l4) > data_end)
   158  		test_fatal("l4 out of bounds");
   159  
   160  	vxlan = (void *)l4 + sizeof(*l4);
   161  	if ((void *)vxlan + sizeof(*vxlan) > data_end)
   162  		test_fatal("vxlan out of bounds");
   163  
   164  	if (memcmp(l2->h_source, (__u8 *)node1_mac, ETH_ALEN) != 0)
   165  		test_fatal("src MAC is not the node MAC")
   166  	if (memcmp(l2->h_dest, (__u8 *)node1_mac, ETH_ALEN) != 0)
   167  		test_fatal("dst MAC has not been updated")
   168  
   169  	if (l3->saddr != NODE1_IP)
   170  		test_fatal("src IP has changed");
   171  
   172  	if (l3->daddr != NODE2_IP)
   173  		test_fatal("dst IP has changed");
   174  
   175  	if (l3->check != bpf_htons(0x7da4))
   176  		test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check));
   177  
   178  	if (l4->source != NODE1_TUNNEL_SPORT)
   179  		test_fatal("src port has changed");
   180  
   181  	if (l4->dest != TUNNEL_PORT)
   182  		test_fatal("dst port has changed");
   183  
   184  	if (tunnel_vni_to_sec_identity(vxlan->vx_vni) != POD1_SEC_IDENTITY)
   185  		test_fatal("VNI has not been updated");
   186  
   187  	assert(ctx->mark == (or_encrypt_key(NODE1_SPI) | (NODE2_ID << 16)));
   188  	assert(ctx_load_meta(ctx, CB_ENCRYPT_IDENTITY) == POD1_SEC_IDENTITY);
   189  
   190  	test_finish();
   191  }