github.com/cilium/cilium@v1.16.2/bpf/tests/skip_tunnel_nodeport_masq.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   * and nodeport
    10   */
    11  #define ENCAP_IFINDEX 1  /* Set dummy ifindex for tunnel device */
    12  #define ENABLE_IPV4 1
    13  #define ENABLE_IPV6 1
    14  #define TUNNEL_MODE 1
    15  #define ENABLE_NODEPORT 1
    16  #define ENABLE_MASQUERADE_IPV4 1
    17  #define ENABLE_MASQUERADE_IPV6 1
    18  
    19  /*
    20   * Now include testing defaults
    21   */
    22  #define ROUTER_IP
    23  #undef ROUTER_IP
    24  #include "node_config.h"
    25  
    26  /*
    27   * Simulate sending traffic from pod_one on node_one directly to
    28   * node_two. Tests are written from the perspective of node_one,
    29   * allowing us access to nodeport_snat_fwd_ipv{4,6}.
    30   */
    31  #define SRC_MAC mac_one
    32  #define SRC_IPV4 v4_pod_one
    33  #define SRC_IPV6 v6_pod_one
    34  #define SRC_PORT tcp_src_one
    35  #define DST_MAC mac_three
    36  #define DST_IPV4 v4_node_two
    37  #define DST_IPV6 v6_node_two
    38  #define DST_PORT tcp_svc_one
    39  
    40  /*
    41   * Include entrypoint into host stack
    42   */
    43  #include "bpf_host.c"
    44  
    45  /*
    46   * Include test helpers
    47   */
    48  #include "lib/endpoint.h"
    49  #include "lib/ipcache.h"
    50  #include "lib/policy.h"
    51  #include "lib/clear.h"
    52  
    53  #define TO_NETDEV 0
    54  struct {
    55  	__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
    56  	__uint(key_size, sizeof(__u32));
    57  	__uint(max_entries, 1);
    58  	__array(values, int());
    59  } entry_call_map __section(".maps") = {
    60  	.values = {
    61  		[TO_NETDEV] = &cil_to_netdev,
    62  	},
    63  };
    64  
    65  static __always_inline int
    66  pktgen(struct __ctx_buff *ctx, bool v4)
    67  {
    68  	struct pktgen builder;
    69  	struct tcphdr *l4;
    70  	void *data;
    71  
    72  	pktgen__init(&builder, ctx);
    73  
    74  	if (v4)
    75  		l4 = pktgen__push_ipv4_tcp_packet(&builder,
    76  						  (__u8 *)SRC_MAC,
    77  						  (__u8 *)DST_MAC,
    78  						  SRC_IPV4, DST_IPV4,
    79  						  SRC_PORT, DST_PORT);
    80  	else
    81  		l4 = pktgen__push_ipv6_tcp_packet(&builder,
    82  						  (__u8 *)SRC_MAC, (__u8 *)DST_MAC,
    83  						  (__u8 *)SRC_IPV6,
    84  						  (__u8 *)DST_IPV6,
    85  						  SRC_PORT, DST_PORT);
    86  
    87  	if (!l4)
    88  		return TEST_ERROR;
    89  
    90  	data = pktgen__push_data(&builder, default_data, sizeof(default_data));
    91  	if (!data)
    92  		return TEST_ERROR;
    93  
    94  	pktgen__finish(&builder);
    95  	return 0;
    96  }
    97  
    98  /*
    99   * Setup scenario where pod with SRC_IP on node is sending traffic directly
   100   * to a remote node with the address DST_IP. In the case of tunnel mode where
   101   * flag_skip_tunnel=true, bpf masquerading should be skipped.
   102   */
   103  static __always_inline int
   104  setup(struct __ctx_buff *ctx, bool v4, bool flag_skip_tunnel)
   105  {
   106  	/*
   107  	 * Reset maps before the test.
   108  	 * Otherwise, leftover state from previous tests will have an impact,
   109  	 * as the tests and checks assume we have a fresh state every time.
   110  	 */
   111  	clear_map(&METRICS_MAP);
   112  	clear_map(&CT_MAP_TCP4);
   113  	clear_map(&CT_MAP_TCP6);
   114  	clear_map(get_cluster_snat_map_v4(0));
   115  	clear_map(get_cluster_snat_map_v6(0));
   116  
   117  	policy_add_egress_allow_all_entry();
   118  
   119  	/*
   120  	 * For this scenario, an endpoint for the source addresses needs
   121  	 * to be created. Additionally, the destination's security identity in the ipcache
   122  	 * must reflect that it is a remote node. This information is used by the SNAT stack to
   123  	 * determine if SNAT needs to be performed for the given packet. See snat_v{4,6}_needs_masquerade.
   124  	 */
   125  
   126  	if (v4) {
   127  		endpoint_v4_add_entry(SRC_IPV4, 0, 0, 0, 0, (__u8 *)SRC_MAC, (__u8 *)SRC_MAC);
   128  		ipcache_v4_add_entry_with_flags(DST_IPV4,
   129  						0, REMOTE_NODE_ID, 0,
   130  						0, flag_skip_tunnel);
   131  	} else {
   132  		endpoint_v6_add_entry((union v6addr *)SRC_IPV6, 0, 0, 0, 0,
   133  				      (__u8 *)SRC_MAC, (__u8 *)SRC_MAC);
   134  		ipcache_v6_add_entry_with_flags((union v6addr *)DST_IPV6,
   135  						0, REMOTE_NODE_ID, 0,
   136  						0, flag_skip_tunnel);
   137  	}
   138  
   139  	tail_call_static(ctx, entry_call_map, TO_NETDEV);
   140  	return TEST_ERROR;
   141  }
   142  
   143  static __always_inline int
   144  check_ctx(const struct __ctx_buff *ctx, bool v4, bool snat)
   145  {
   146  	void *data;
   147  	void *data_end;
   148  	__u32 *status_code;
   149  	struct ethhdr *l2;
   150  	struct tcphdr *l4;
   151  	__u8 *payload;
   152  
   153  	struct metrics_value *entry = NULL;
   154  	struct metrics_key key = {};
   155  
   156  	test_init();
   157  
   158  	data = (void *)(long)ctx->data;
   159  	data_end = (void *)(long)ctx->data_end;
   160  
   161  	if (data + sizeof(*status_code) > data_end)
   162  		test_fatal("status code out of bounds");
   163  
   164  	status_code = data;
   165  	assert(*status_code == CTX_ACT_OK);
   166  
   167  	key.reason = REASON_FORWARDED;
   168  	key.dir = METRIC_EGRESS;
   169  
   170  	entry = map_lookup_elem(&METRICS_MAP, &key);
   171  	if (!entry)
   172  		test_fatal("metrics entry not found")
   173  
   174  	__u64 count = 1;
   175  
   176  	assert_metrics_count(key, count);
   177  
   178  	l2 = data + sizeof(*status_code);
   179  
   180  	if ((void *)l2 + sizeof(struct ethhdr) > data_end)
   181  		test_fatal("l2 out of bounds")
   182  
   183  	if (v4 && l2->h_proto != bpf_htons(ETH_P_IP))
   184  		test_fatal("l2 proto hasn't been set to ETH_P_IP")
   185  
   186  	if (!v4 && l2->h_proto != bpf_htons(ETH_P_IPV6))
   187  		test_fatal("l2 proto hasn't been set to ETH_P_IPV6")
   188  
   189  	if (memcmp(l2->h_source, (__u8 *)SRC_MAC, ETH_ALEN) != 0)
   190  		test_fatal("src mac was changed");
   191  
   192  	if (memcmp(l2->h_dest, (__u8 *)DST_MAC, ETH_ALEN) != 0)
   193  		test_fatal("dst mac has changed")
   194  
   195  	if (v4) {
   196  		struct iphdr *l3;
   197  
   198  		l3 = (void *)l2 + sizeof(struct ethhdr);
   199  
   200  		if ((void *)l3 + sizeof(struct iphdr) > data_end)
   201  			test_fatal("l3 out of bounds");
   202  
   203  		if (snat) {
   204  			if (l3->saddr != IPV4_MASQUERADE)
   205  				test_fatal("src IP was not snatted");
   206  		} else {
   207  			if (l3->saddr != SRC_IPV4)
   208  				test_fatal("src IP was changed");
   209  		}
   210  
   211  		if (l3->daddr != DST_IPV4)
   212  			test_fatal("dest IP was changed");
   213  
   214  		l4 = (void *)l3 + sizeof(struct iphdr);
   215  	} else {
   216  		struct ipv6hdr *l3;
   217  		union v6addr masq_addr;
   218  
   219  		BPF_V6(masq_addr, IPV6_MASQUERADE);
   220  
   221  		l3 = (void *)l2 + sizeof(struct ethhdr);
   222  
   223  		if ((void *)l3 + sizeof(struct ipv6hdr) > data_end)
   224  			test_fatal("l3 out of bounds");
   225  
   226  		if (snat) {
   227  			if (memcmp((__u8 *)&l3->saddr, (__u8 *)&masq_addr, 16) != 0)
   228  				test_fatal("src IP was not snatted");
   229  		} else {
   230  			if (memcmp((__u8 *)&l3->saddr, (__u8 *)SRC_IPV6, 16) != 0)
   231  				test_fatal("src IP was changed");
   232  		}
   233  
   234  		if (memcmp((__u8 *)&l3->daddr, (__u8 *)DST_IPV6, 16) != 0)
   235  			test_fatal("dest IP was changed");
   236  
   237  		l4 = (void *)l3 + sizeof(struct ipv6hdr);
   238  	}
   239  
   240  	if ((void *)l4 + sizeof(struct tcphdr) > data_end)
   241  		test_fatal("l4 out of bounds");
   242  
   243  	if (snat) {
   244  		__be16 p = bpf_ntohs(l4->source);
   245  
   246  		if (p < NODEPORT_PORT_MIN_NAT || p > NODEPORT_PORT_MAX_NAT)
   247  			test_fatal("src port was not snatted");
   248  	} else {
   249  		if (l4->source != SRC_PORT)
   250  			test_fatal("src port was changed");
   251  	}
   252  
   253  	if (l4->dest != DST_PORT)
   254  		test_fatal("dest port was changed");
   255  
   256  	payload = (void *)l4 + sizeof(struct tcphdr);
   257  	if ((void *)payload + sizeof(default_data) > data_end)
   258  		test_fatal("payload out of bounds");
   259  
   260  	if (memcmp(payload, default_data, sizeof(default_data)) != 0)
   261  		test_fatal("tcp payload was changed")
   262  
   263  	test_finish();
   264  }
   265  
   266  PKTGEN("tc", "01_ipv4_nodeport_ingress_no_flags")
   267  int ipv4_nodeport_ingress_no_flags_pktgen(struct __ctx_buff *ctx)
   268  {
   269  	return pktgen(ctx, true);
   270  }
   271  
   272  SETUP("tc", "01_ipv4_nodeport_ingress_no_flags")
   273  int ipv4_nodeport_ingress_no_flags_setup(struct __ctx_buff *ctx)
   274  {
   275  	return setup(ctx, true, false);
   276  }
   277  
   278  CHECK("tc", "01_ipv4_nodeport_ingress_no_flags")
   279  int ipv4_nodeport_ingress_no_flags_check(__maybe_unused const struct __ctx_buff *ctx)
   280  {
   281  	return check_ctx(ctx, true, true);
   282  }
   283  
   284  PKTGEN("tc", "02_ipv4_nodeport_ingress_skip_tunnel")
   285  int ipv4_nodeport_ingress_skip_tunnel_pktgen(struct __ctx_buff *ctx)
   286  {
   287  	return pktgen(ctx, true);
   288  }
   289  
   290  SETUP("tc", "02_ipv4_nodeport_ingress_skip_tunnel")
   291  int ipv4_nodeport_ingress_skip_tunnel_setup(struct __ctx_buff *ctx)
   292  {
   293  	return setup(ctx, true, true);
   294  }
   295  
   296  CHECK("tc", "02_ipv4_nodeport_ingress_skip_tunnel")
   297  int ipv4_nodeport_ingress_skip_tunnel_check(__maybe_unused const struct __ctx_buff *ctx)
   298  {
   299  	return check_ctx(ctx, true, false);
   300  }
   301  
   302  PKTGEN("tc", "03_ipv6_nodeport_ingress_no_flags")
   303  int ipv6_nodeport_ingress_no_flags_pktgen(struct __ctx_buff *ctx)
   304  {
   305  	return pktgen(ctx, false);
   306  }
   307  
   308  SETUP("tc", "03_ipv6_nodeport_ingress_no_flags")
   309  int ipv6_nodeport_ingress_no_flags_setup(struct __ctx_buff *ctx)
   310  {
   311  	return setup(ctx, false, false);
   312  }
   313  
   314  CHECK("tc", "03_ipv6_nodeport_ingress_no_flags")
   315  int ipv6_nodeport_ingress_no_flags_check(__maybe_unused const struct __ctx_buff *ctx)
   316  {
   317  	return check_ctx(ctx, false, true);
   318  }
   319  
   320  PKTGEN("tc", "04_ipv6_nodeport_ingress_skip_tunnel")
   321  int ipv6_nodeport_ingress_skip_tunnel_pktgen(struct __ctx_buff *ctx)
   322  {
   323  	return pktgen(ctx, false);
   324  }
   325  
   326  SETUP("tc", "04_ipv6_nodeport_ingress_skip_tunnel")
   327  int ipv6_nodeport_ingress_skip_tunnel_setup(struct __ctx_buff *ctx)
   328  {
   329  	return setup(ctx, false, true);
   330  }
   331  
   332  CHECK("tc", "04_ipv6_nodeport_ingress_skip_tunnel")
   333  int ipv6_nodeport_ingress_skip_tunnel_check(__maybe_unused const struct __ctx_buff *ctx)
   334  {
   335  	return check_ctx(ctx, false, false);
   336  }