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

     1  // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
     2  /* Copyright Authors of Cilium */
     3  #include "common.h"
     4  #include <bpf/ctx/skb.h>
     5  #include "pktgen.h"
     6  
     7  /*
     8   * Datapath configuration settings to setup tunneling with VXLan
     9   */
    10  #define ENCAP_IFINDEX 1  /* Set dummy ifindex for tunnel device */
    11  #define ENABLE_IPV4
    12  #define ENABLE_IPV6
    13  #define TUNNEL_MODE
    14  
    15  /*
    16   * Now include testing defaults
    17   */
    18  #define ROUTER_IP
    19  #undef ROUTER_IP
    20  #include "node_config.h"
    21  
    22  /*
    23   * Test Configuration Settings
    24   * Simulate sending traffic from node_one to pod_two.
    25   *
    26   * cil_from_host will lead us to handle_ipv{4,6}_cont,
    27   * which rewrites the destination mac address to
    28   * CIILUM_NET_MAC to send the packet to the
    29   * cilium_net interface.
    30   *
    31   * CILIUM_NET_MAC is set in node_config.h, so below we pull
    32   * it into a format that pktgen can use.
    33   */
    34  #define SRC_MAC mac_one
    35  #define SRC_IPV4 v4_node_one
    36  #define SRC_IPV6 v6_node_one
    37  #define SRC_TCP_PORT tcp_src_one
    38  #define DST_IPV4 v4_pod_two
    39  #define DST_IPV6 v6_pod_two
    40  #define DST_TCP_PORT tcp_svc_one
    41  #define TUNNEL_IPV4 v4_node_two
    42  #define TUNNEL_IPV6 v6_node_two
    43  
    44  #include "lib/eth.h"
    45  static volatile const union macaddr __cilium_net_mac = CILIUM_NET_MAC;
    46  #define DST_MAC __cilium_net_mac.addr
    47  
    48  /*
    49   * Include entrypoint into host stack.
    50   */
    51  #include "bpf_host.c"
    52  
    53  /*
    54   * Include test helpers
    55   */
    56  #include "lib/ipcache.h"
    57  #include "lib/policy.h"
    58  
    59  #define FROM_HOST 0
    60  struct {
    61  	__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
    62  	__uint(key_size, sizeof(__u32));
    63  	__uint(max_entries, 1);
    64  	__array(values, int());
    65  } entry_call_map __section(".maps") = {
    66  	.values = {
    67  		[FROM_HOST] = &cil_from_host,
    68  	},
    69  };
    70  
    71  static __always_inline int
    72  pktgen_from_host(struct __ctx_buff *ctx, bool v4)
    73  {
    74  	struct pktgen builder;
    75  	struct tcphdr *l4;
    76  	void *data;
    77  
    78  	pktgen__init(&builder, ctx);
    79  
    80  	if (v4)
    81  		l4 = pktgen__push_ipv4_tcp_packet(&builder,
    82  						  (__u8 *)SRC_MAC,
    83  						  (__u8 *)DST_MAC,
    84  						  SRC_IPV4, DST_IPV4,
    85  						  SRC_TCP_PORT, DST_TCP_PORT);
    86  	else
    87  		l4 = pktgen__push_ipv6_tcp_packet(&builder,
    88  						  (__u8 *)SRC_MAC, (__u8 *)DST_MAC,
    89  						  (__u8 *)SRC_IPV6, (__u8 *)DST_IPV6,
    90  						  SRC_TCP_PORT, DST_TCP_PORT);
    91  
    92  	if (!l4)
    93  		return TEST_ERROR;
    94  
    95  	data = pktgen__push_data(&builder, default_data, sizeof(default_data));
    96  	if (!data)
    97  		return TEST_ERROR;
    98  
    99  	pktgen__finish(&builder);
   100  	return 0;
   101  }
   102  
   103  static __always_inline int
   104  setup(struct __ctx_buff *ctx, bool flag_skip_tunnel, bool v4)
   105  {
   106  	/*
   107  	 * Reset metric values before the test, if applicable.
   108  	 * Otherwise, the metric we want to check would increase by one
   109  	 * after each test.
   110  	 */
   111  	struct metrics_key key = {};
   112  
   113  	key.reason = REASON_FORWARDED;
   114  	key.dir = METRIC_EGRESS;
   115  
   116  	map_delete_elem(&METRICS_MAP, &key);
   117  
   118  	policy_add_egress_allow_all_entry();
   119  
   120  	if (v4)
   121  		ipcache_v4_add_entry_with_flags(DST_IPV4,
   122  						0, 1230, v4_node_two, 0, flag_skip_tunnel);
   123  	else
   124  		ipcache_v6_add_entry_with_flags((union v6addr *)DST_IPV6,
   125  						0, 1230, v4_node_two, 0, flag_skip_tunnel);
   126  
   127  	tail_call_static(ctx, entry_call_map, FROM_HOST);
   128  	return TEST_ERROR;
   129  }
   130  
   131  static __always_inline int
   132  check_ctx(const struct __ctx_buff *ctx, __u32 expected_result, bool v4)
   133  {
   134  	void *data;
   135  	void *data_end;
   136  	__u32 *status_code;
   137  	struct ethhdr *l2;
   138  	struct tcphdr *l4;
   139  	__u8 *payload;
   140  
   141  	struct metrics_value *entry = NULL;
   142  	struct metrics_key key = {};
   143  
   144  	test_init();
   145  
   146  	data = (void *)(long)ctx->data;
   147  	data_end = (void *)(long)ctx->data_end;
   148  
   149  	/*
   150  	 * Check the returned status is correct.
   151  	 * The appropriate value for "expected_result" should be set
   152  	 * by the caller.
   153  	 * If flag_skip_tunnel=false, then we need CTX_ACT_REDIRECT
   154  	 * If flag_skip_tunnel=true, then we need CTX_ACT_OK
   155  	 */
   156  	if (data + sizeof(*status_code) > data_end)
   157  		test_fatal("status code out of bounds");
   158  
   159  	status_code = data;
   160  	assert(*status_code == expected_result);
   161  
   162  	/*
   163  	 * Check that the packet was recorded in the metrics.
   164  	 * This only needs to be done if the packet was encapsulated,
   165  	 * as there is no unique metric recorded when the packet is
   166  	 * not encapsulated.
   167  	 */
   168  	if (expected_result == CTX_ACT_REDIRECT) {
   169  		key.reason = REASON_FORWARDED;
   170  		key.dir = METRIC_EGRESS;
   171  
   172  		entry = map_lookup_elem(&METRICS_MAP, &key);
   173  		if (!entry)
   174  			test_fatal("metrics entry not found")
   175  
   176  		__u64 count = 1;
   177  
   178  		assert_metrics_count(key, count);
   179  	}
   180  
   181  	/* Sanity checks on packet integrity. */
   182  	l2 = data + sizeof(*status_code);
   183  
   184  	if ((void *)l2 + sizeof(struct ethhdr) > data_end)
   185  		test_fatal("l2 out of bounds")
   186  
   187  	if (v4 && l2->h_proto != bpf_htons(ETH_P_IP))
   188  		test_fatal("l2 proto hasn't been set to ETH_P_IP")
   189  
   190  	if (!v4 && l2->h_proto != bpf_htons(ETH_P_IPV6))
   191  		test_fatal("l2 proto hasn't been set to ETH_P_IPV6")
   192  
   193  	if (memcmp(l2->h_source, (__u8 *)SRC_MAC, ETH_ALEN) != 0)
   194  		test_fatal("src mac hasn't been set to source ep's mac");
   195  
   196  	if (memcmp(l2->h_dest, (__u8 *)DST_MAC, ETH_ALEN) != 0)
   197  		test_fatal("dst mac hasn't been set to dest ep's mac")
   198  
   199  	if (v4) {
   200  		struct iphdr *l3;
   201  
   202  		l3 = (void *)l2 + sizeof(struct ethhdr);
   203  
   204  		if ((void *)l3 + sizeof(struct iphdr) > data_end)
   205  			test_fatal("l3 out of bounds");
   206  
   207  		if (l3->saddr != SRC_IPV4)
   208  			test_fatal("src IP was changed");
   209  
   210  		if (l3->daddr != DST_IPV4)
   211  			test_fatal("dest IP was changed");
   212  
   213  		if (l3->check != bpf_htons(0xa611))
   214  			test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check));
   215  
   216  		l4 = (void *)l3 + sizeof(struct iphdr);
   217  	} else {
   218  		struct ipv6hdr *l3;
   219  
   220  		l3 = (void *)l2 + sizeof(struct ethhdr);
   221  
   222  		if ((void *)l3 + sizeof(struct ipv6hdr) > data_end)
   223  			test_fatal("l3 out of bounds");
   224  
   225  		if (memcmp((__u8 *)&l3->saddr, (__u8 *)SRC_IPV6, 16) != 0)
   226  			test_fatal("src IP was changed");
   227  
   228  		if (memcmp((__u8 *)&l3->daddr, (__u8 *)DST_IPV6, 16) != 0)
   229  			test_fatal("dest IP was changed");
   230  
   231  		l4 = (void *)l3 + sizeof(struct ipv6hdr);
   232  	}
   233  
   234  	if ((void *)l4 + sizeof(struct tcphdr) > data_end)
   235  		test_fatal("l4 out of bounds");
   236  
   237  	if (l4->source != SRC_TCP_PORT)
   238  		test_fatal("src TCP port was changed");
   239  
   240  	if (l4->dest != DST_TCP_PORT)
   241  		test_fatal("dest TCP port was changed");
   242  
   243  	payload = (void *)l4 + sizeof(struct tcphdr);
   244  	if ((void *)payload + sizeof(default_data) > data_end)
   245  		test_fatal("payload out of bounds");
   246  
   247  	if (memcmp(payload, default_data, sizeof(default_data)) != 0)
   248  		test_fatal("tcp payload was changed")
   249  
   250  	test_finish();
   251  }
   252  
   253  PKTGEN("tc", "01_ipv4_from_host_no_flags")
   254  int ipv4_from_host_no_flags_pktgen(struct __ctx_buff *ctx)
   255  {
   256  	return pktgen_from_host(ctx, true);
   257  }
   258  
   259  SETUP("tc", "01_ipv4_from_host_no_flags")
   260  int ipv4_from_host_no_flags_setup(struct __ctx_buff *ctx)
   261  {
   262  	return setup(ctx, false, true);
   263  }
   264  
   265  CHECK("tc", "01_ipv4_from_host_no_flags")
   266  int ipv4_from_host_no_flags_check(__maybe_unused const struct __ctx_buff *ctx)
   267  {
   268  	return check_ctx(ctx, CTX_ACT_REDIRECT, true);
   269  }
   270  
   271  PKTGEN("tc", "02_ipv4_from_host_skip_tunnel")
   272  int ipv4_from_host_skip_tunnel_pktgen(struct __ctx_buff *ctx)
   273  {
   274  	return pktgen_from_host(ctx, true);
   275  }
   276  
   277  SETUP("tc", "02_ipv4_from_host_skip_tunnel")
   278  int ipv4_from_host_skip_tunnel_setup(struct __ctx_buff *ctx)
   279  {
   280  	return setup(ctx, true, true);
   281  }
   282  
   283  CHECK("tc", "02_ipv4_from_host_skip_tunnel")
   284  int ipv4_from_host_skip_tunnel_check(__maybe_unused const struct __ctx_buff *ctx)
   285  {
   286  	return check_ctx(ctx, CTX_ACT_OK, true);
   287  }
   288  
   289  PKTGEN("tc", "03_ipv6_from_host_no_flags")
   290  int ipv6_from_host_no_flags_pktgen(struct __ctx_buff *ctx)
   291  {
   292  	return pktgen_from_host(ctx, false);
   293  }
   294  
   295  SETUP("tc", "03_ipv6_from_host_no_flags")
   296  int ipv6_from_host_no_flags_setup(struct __ctx_buff *ctx)
   297  {
   298  	return setup(ctx, false, false);
   299  }
   300  
   301  CHECK("tc", "03_ipv6_from_host_no_flags")
   302  int ipv6_from_host_no_flags_check(__maybe_unused const struct __ctx_buff *ctx)
   303  {
   304  	return check_ctx(ctx, CTX_ACT_REDIRECT, false);
   305  }
   306  
   307  PKTGEN("tc", "04_ipv6_from_host_skip_tunnel")
   308  int ipv6_from_host_skip_tunnel_pktgen(struct __ctx_buff *ctx)
   309  {
   310  	return pktgen_from_host(ctx, false);
   311  }
   312  
   313  SETUP("tc", "04_ipv6_from_host_skip_tunnel")
   314  int ipv6_from_host_skip_tunnel_setup(struct __ctx_buff *ctx)
   315  {
   316  	return setup(ctx, true, false);
   317  }
   318  
   319  CHECK("tc", "04_ipv6_from_host_skip_tunnel")
   320  int ipv6_from_host_skip_tunnel_check(__maybe_unused const struct __ctx_buff *ctx)
   321  {
   322  	return check_ctx(ctx, CTX_ACT_OK, false);
   323  }