github.com/cilium/cilium@v1.16.2/bpf/tests/inter_cluster_snat_clusterip_backend_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 "linux/if_ether.h"
     8  #include "pktgen.h"
     9  #include "mock_skb_metadata.h"
    10  
    11  /*
    12   * Datapath configurations
    13   */
    14  
    15  /* Set dummy ifindex for tunnel device */
    16  #define ENCAP_IFINDEX 1
    17  
    18  /* Overlapping PodCIDR is only supported for IPv4 for now */
    19  #define ENABLE_IPV4
    20  
    21  /* Overlapping PodCIDR depends on tunnel */
    22  #define TUNNEL_MODE
    23  
    24  /* Fully enable KPR since kubeproxy doesn't understand cluster aware addressing */
    25  #define ENABLE_NODEPORT
    26  
    27  /* Cluster-aware addressing is mandatory for overlapping PodCIDR support */
    28  #define ENABLE_CLUSTER_AWARE_ADDRESSING
    29  
    30  /* Inter-cluster SNAT is mandatory for overlapping PodCIDR support for now */
    31  #define ENABLE_INTER_CLUSTER_SNAT
    32  
    33  /* Import map definitions and some default values */
    34  #include "node_config.h"
    35  
    36  /* Overwrite the default port range defined in node_config.h
    37   * to have deterministic source port selection.
    38   */
    39  #undef NODEPORT_PORT_MAX
    40  #undef NODEPORT_PORT_MIN_NAT
    41  #undef NODEPORT_PORT_MAX_NAT
    42  #define NODEPORT_PORT_MAX 32767
    43  #define NODEPORT_PORT_MIN_NAT (NODEPORT_PORT_MAX + 1)
    44  #define NODEPORT_PORT_MAX_NAT (NODEPORT_PORT_MIN_NAT + 1)
    45  
    46  /* Overwrite (local) CLUSTER_ID defined in node_config.h */
    47  #undef CLUSTER_ID
    48  #define CLUSTER_ID 1
    49  
    50  /*
    51   * Test configurations
    52   */
    53  #define BACKEND_IFINDEX		12345
    54  #define BACKEND_MAC		mac_one
    55  #define BACKEND_ROUTER_MAC	mac_two
    56  #define CLIENT_ROUTER_MAC	mac_three
    57  #define BACKEND_IP		v4_pod_one
    58  #define CLIENT_NODE_IP		v4_ext_one
    59  #define BACKEND_NODE_IP		v4_ext_two
    60  #define BACKEND_PORT		tcp_svc_one
    61  #define CLIENT_CLUSTER_ID	1
    62  #define CLIENT_IDENTITY		(0x00000000 | (CLIENT_CLUSTER_ID << 16) | 0xff01)
    63  
    64  #undef IPV4_INTER_CLUSTER_SNAT
    65  #define IPV4_INTER_CLUSTER_SNAT BACKEND_NODE_IP
    66  
    67  /* SNAT should always select NODEPORT_PORT_MIN_NAT as a source */
    68  #define CLIENT_INTER_CLUSTER_SNAT_PORT __bpf_htons(NODEPORT_PORT_MIN_NAT)
    69  
    70  /* Mock out get_tunnel_key to emulate input from tunnel device */
    71  #define skb_get_tunnel_key mock_skb_get_tunnel_key
    72  
    73  int mock_skb_get_tunnel_key(struct __ctx_buff *ctx __maybe_unused, struct bpf_tunnel_key *to,
    74  			    __u32 size __maybe_unused, __u32 flags __maybe_unused)
    75  {
    76  	to->remote_ipv4 = CLIENT_NODE_IP;
    77  	to->tunnel_id = CLIENT_IDENTITY;
    78  	return 0;
    79  }
    80  
    81  /*
    82   * Mock out send_drop_notify. This is because it uses ctx_store_meta internally
    83   * and breaks the skb->cb test.
    84   */
    85  
    86  #define DEBUG
    87  #include <lib/drop.h>
    88  
    89  #define _send_drop_notify mock_send_drop_notify
    90  
    91  static __always_inline
    92  int mock_send_drop_notify(__u8 file __maybe_unused, __u16 line __maybe_unused,
    93  			  struct __ctx_buff *ctx, __u32 src __maybe_unused,
    94  			  __u32 dst __maybe_unused, __u32 dst_id __maybe_unused,
    95  			  __u32 reason, __u32 exitcode, enum metric_dir direction)
    96  {
    97  	cilium_dbg3(ctx, DBG_GENERIC, reason, exitcode, direction);
    98  	return exitcode;
    99  }
   100  
   101  /* Include an actual datapath code */
   102  #include <bpf_overlay.c>
   103  
   104  #include "lib/endpoint.h"
   105  
   106  /*
   107   * Tests
   108   */
   109  
   110  #define TO_OVERLAY 0
   111  #define FROM_OVERLAY 1
   112  
   113  struct {
   114  	__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
   115  	__uint(key_size, sizeof(__u32));
   116  	__uint(max_entries, 2);
   117  	__array(values, int());
   118  } entry_call_map __section(".maps") = {
   119  	.values = {
   120  		[TO_OVERLAY] = &cil_to_overlay,
   121  		[FROM_OVERLAY] = &cil_from_overlay,
   122  	},
   123  };
   124  
   125  static __always_inline int
   126  pktgen_to_overlay(struct __ctx_buff *ctx, bool syn, bool ack)
   127  {
   128  	struct pktgen builder;
   129  	struct tcphdr *l4;
   130  	void *data;
   131  
   132  	pktgen__init(&builder, ctx);
   133  
   134  	l4 = pktgen__push_ipv4_tcp_packet(&builder,
   135  					  (__u8 *)BACKEND_MAC,
   136  					  (__u8 *)BACKEND_ROUTER_MAC,
   137  					  BACKEND_IP, CLIENT_NODE_IP,
   138  					  BACKEND_PORT, CLIENT_INTER_CLUSTER_SNAT_PORT);
   139  	if (!l4)
   140  		return TEST_ERROR;
   141  
   142  	l4->syn = syn ? 1 : 0;
   143  	l4->ack = ack ? 1 : 0;
   144  
   145  	data = pktgen__push_data(&builder, default_data, sizeof(default_data));
   146  	if (!data)
   147  		return TEST_ERROR;
   148  
   149  	pktgen__finish(&builder);
   150  
   151  	return 0;
   152  }
   153  
   154  static __always_inline int
   155  pktgen_from_overlay(struct __ctx_buff *ctx, bool syn, bool ack)
   156  {
   157  	struct pktgen builder;
   158  	struct tcphdr *l4;
   159  	void *data;
   160  
   161  	pktgen__init(&builder, ctx);
   162  
   163  	l4 = pktgen__push_ipv4_tcp_packet(&builder,
   164  					  (__u8 *)CLIENT_ROUTER_MAC,
   165  					  (__u8 *)BACKEND_ROUTER_MAC,
   166  					  CLIENT_NODE_IP, BACKEND_IP,
   167  					  CLIENT_INTER_CLUSTER_SNAT_PORT, BACKEND_PORT);
   168  	if (!l4)
   169  		return TEST_ERROR;
   170  
   171  	l4->syn = syn ? 1 : 0;
   172  	l4->ack = ack ? 1 : 0;
   173  
   174  	data = pktgen__push_data(&builder, default_data, sizeof(default_data));
   175  	if (!data)
   176  		return TEST_ERROR;
   177  
   178  	pktgen__finish(&builder);
   179  
   180  	return 0;
   181  }
   182  
   183  PKTGEN("tc", "01_from_overlay_syn")
   184  int from_overlay_syn_pktgen(struct __ctx_buff *ctx)
   185  {
   186  	/* Emulate input from bpf_lxc */
   187  	ctx_set_cluster_id_mark(ctx, 0);
   188  
   189  	return pktgen_from_overlay(ctx, true, false);
   190  }
   191  
   192  SETUP("tc", "01_from_overlay_syn")
   193  int from_overlay_syn_setup(struct __ctx_buff *ctx)
   194  {
   195  	endpoint_v4_add_entry(BACKEND_IP, BACKEND_IFINDEX, 0, 0, 0,
   196  			      (__u8 *)BACKEND_MAC, (__u8 *)BACKEND_ROUTER_MAC);
   197  
   198  	tail_call_static(ctx, entry_call_map, FROM_OVERLAY);
   199  	return TEST_ERROR;
   200  }
   201  
   202  CHECK("tc", "01_from_overlay_syn")
   203  int from_overlay_syn_check(struct __ctx_buff *ctx)
   204  {
   205  	void *data, *data_end;
   206  	__s32 *status_code;
   207  	struct tcphdr *l4;
   208  	struct ethhdr *l2;
   209  	struct iphdr *l3;
   210  	__u32 meta;
   211  
   212  	test_init();
   213  
   214  	data = (void *)(long)ctx_data(ctx);
   215  	data_end = (void *)(long)ctx->data_end;
   216  
   217  	if (data + sizeof(__u32) > data_end)
   218  		test_fatal("status code out of bounds");
   219  
   220  	status_code = data;
   221  
   222  	/* The packet should go to ipv4_local_delivery and dropped with
   223  	 * missed tail call since the POLICY_CALL_MAP should be empty.
   224  	 */
   225  	if (*status_code != CTX_ACT_DROP)
   226  		test_fatal("unexpected status code %d, want %d", *status_code, CTX_ACT_OK);
   227  
   228  	l2 = data + sizeof(__u32);
   229  	if ((void *)l2 + sizeof(struct ethhdr) > data_end)
   230  		test_fatal("l2 out of bounds");
   231  
   232  	l3 = (void *)l2 + sizeof(struct ethhdr);
   233  	if ((void *)l3 + sizeof(struct iphdr) > data_end)
   234  		test_fatal("l3 out of bounds");
   235  
   236  	l4 = (void *)l3 + sizeof(struct iphdr);
   237  	if ((void *)l4 + sizeof(struct tcphdr) > data_end)
   238  		test_fatal("l4 out of bounds");
   239  
   240  	if (memcmp(l2->h_source, (__u8 *)BACKEND_ROUTER_MAC, ETH_ALEN) != 0)
   241  		test_fatal("src MAC is not the backend router MAC")
   242  
   243  	if (memcmp(l2->h_dest, (__u8 *)BACKEND_MAC, ETH_ALEN) != 0)
   244  		test_fatal("dst MAC is not the backend MAC")
   245  
   246  	if (l3->saddr != CLIENT_NODE_IP)
   247  		test_fatal("src IP has changed");
   248  
   249  	if (l3->daddr != BACKEND_IP)
   250  		test_fatal("dst IP has changed");
   251  
   252  	if (l3->check != bpf_htons(0x4212))
   253  		test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check));
   254  
   255  	if (l4->source != CLIENT_INTER_CLUSTER_SNAT_PORT)
   256  		test_fatal("src port has changed");
   257  
   258  	if (l4->dest != BACKEND_PORT)
   259  		test_fatal("dst port has changed");
   260  
   261  	meta = ctx_load_meta(ctx, CB_IFINDEX);
   262  	if (meta != BACKEND_IFINDEX)
   263  		test_fatal("skb->cb[CB_IFINDEX] should be %d, got %d", BACKEND_IFINDEX, meta);
   264  
   265  	meta = ctx_load_meta(ctx, CB_SRC_LABEL);
   266  	if (meta != CLIENT_IDENTITY)
   267  		test_fatal("skb->cb[CB_SRC_LABEL] should be %d, got %d", CLIENT_IDENTITY, meta);
   268  
   269  	meta = ctx_load_meta(ctx, CB_FROM_TUNNEL);
   270  	if (meta != 1)
   271  		test_fatal("skb->cb[CB_FROM_TUNNEL] should be 1, got %d", meta);
   272  
   273  	meta = ctx_load_meta(ctx, CB_FROM_HOST);
   274  	if (meta != 0)
   275  		test_fatal("skb->cb[CB_FROM_HOST] should be 0, got %d", meta);
   276  
   277  	meta = ctx_load_meta(ctx, CB_CLUSTER_ID_INGRESS);
   278  	if (meta != 0)
   279  		test_fatal("skb->cb[CB_CLUSTER_ID_INGRESS] should be 0, got %d", meta);
   280  
   281  	test_finish();
   282  }
   283  
   284  PKTGEN("tc", "02_to_overlay_synack")
   285  int to_overlay_synack_pktgen(struct __ctx_buff *ctx)
   286  {
   287  	return pktgen_to_overlay(ctx, true, true);
   288  }
   289  
   290  SETUP("tc", "02_to_overlay_synack")
   291  int to_overlay_synack_setup(struct __ctx_buff *ctx)
   292  {
   293  	tail_call_static(ctx, entry_call_map, TO_OVERLAY);
   294  	return TEST_ERROR;
   295  }
   296  
   297  CHECK("tc", "02_to_overlay_synack")
   298  int to_overlay_synack_check(struct __ctx_buff *ctx)
   299  {
   300  	void *data, *data_end;
   301  	__s32 *status_code;
   302  	struct tcphdr *l4;
   303  	struct ethhdr *l2;
   304  	struct iphdr *l3;
   305  
   306  	test_init();
   307  
   308  	data = (void *)(long)ctx_data(ctx);
   309  	data_end = (void *)(long)ctx->data_end;
   310  
   311  	if (data + sizeof(__u32) > data_end)
   312  		test_fatal("status code out of bounds");
   313  
   314  	status_code = data;
   315  
   316  	if (*status_code != CTX_ACT_OK)
   317  		test_fatal("unexpected status code %d, want %d", *status_code, CTX_ACT_OK);
   318  
   319  	l2 = data + sizeof(__u32);
   320  	if ((void *)l2 + sizeof(struct ethhdr) > data_end)
   321  		test_fatal("l2 out of bounds");
   322  
   323  	l3 = (void *)l2 + sizeof(struct ethhdr);
   324  	if ((void *)l3 + sizeof(struct iphdr) > data_end)
   325  		test_fatal("l3 out of bounds");
   326  
   327  	l4 = (void *)l3 + sizeof(struct iphdr);
   328  	if ((void *)l4 + sizeof(struct tcphdr) > data_end)
   329  		test_fatal("l4 out of bounds");
   330  
   331  	if (memcmp(l2->h_source, (__u8 *)BACKEND_MAC, ETH_ALEN) != 0)
   332  		test_fatal("src MAC has changed")
   333  
   334  	if (memcmp(l2->h_dest, (__u8 *)BACKEND_ROUTER_MAC, ETH_ALEN) != 0)
   335  		test_fatal("dst MAC has changed")
   336  
   337  	if (l3->saddr != BACKEND_IP)
   338  		test_fatal("src IP has changed");
   339  
   340  	if (l3->daddr != CLIENT_NODE_IP)
   341  		test_fatal("dst IP has changed");
   342  
   343  	if (l3->check != bpf_htons(0x4112))
   344  		test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check));
   345  
   346  	if (l4->source != BACKEND_PORT)
   347  		test_fatal("src port has changed");
   348  
   349  	if (l4->dest != CLIENT_INTER_CLUSTER_SNAT_PORT)
   350  		test_fatal("dst port has changed");
   351  
   352  	test_finish();
   353  }
   354  
   355  PKTGEN("tc", "03_from_overlay_ack")
   356  int from_overlay_ack_pktgen(struct __ctx_buff *ctx)
   357  {
   358  	return pktgen_from_overlay(ctx, false, true);
   359  }
   360  
   361  SETUP("tc", "03_from_overlay_ack")
   362  int from_overlay_ack_setup(struct __ctx_buff *ctx)
   363  {
   364  	tail_call_static(ctx, entry_call_map, FROM_OVERLAY);
   365  	return TEST_ERROR;
   366  }
   367  
   368  CHECK("tc", "03_from_overlay_ack")
   369  int from_overlay_ack_check(struct __ctx_buff *ctx)
   370  {
   371  	void *data, *data_end;
   372  	__s32 *status_code;
   373  	struct tcphdr *l4;
   374  	struct ethhdr *l2;
   375  	struct iphdr *l3;
   376  	__u32 meta;
   377  
   378  	test_init();
   379  
   380  	data = (void *)(long)ctx_data(ctx);
   381  	data_end = (void *)(long)ctx->data_end;
   382  
   383  	if (data + sizeof(__u32) > data_end)
   384  		test_fatal("status code out of bounds");
   385  
   386  	status_code = data;
   387  
   388  	if (*status_code != CTX_ACT_DROP)
   389  		test_fatal("unexpected status code %d, want %d", *status_code, CTX_ACT_DROP);
   390  
   391  	l2 = data + sizeof(__u32);
   392  	if ((void *)l2 + sizeof(struct ethhdr) > data_end)
   393  		test_fatal("l2 out of bounds");
   394  
   395  	l3 = (void *)l2 + sizeof(struct ethhdr);
   396  	if ((void *)l3 + sizeof(struct iphdr) > data_end)
   397  		test_fatal("l3 out of bounds");
   398  
   399  	l4 = (void *)l3 + sizeof(struct iphdr);
   400  	if ((void *)l4 + sizeof(struct tcphdr) > data_end)
   401  		test_fatal("l4 out of bounds");
   402  
   403  	if (memcmp(l2->h_source, (__u8 *)BACKEND_ROUTER_MAC, ETH_ALEN) != 0)
   404  		test_fatal("src MAC is not the backend router MAC")
   405  
   406  	if (memcmp(l2->h_dest, (__u8 *)BACKEND_MAC, ETH_ALEN) != 0)
   407  		test_fatal("dst MAC is not the backend MAC")
   408  
   409  	if (l3->saddr != CLIENT_NODE_IP)
   410  		test_fatal("src IP has changed");
   411  
   412  	if (l3->daddr != BACKEND_IP)
   413  		test_fatal("dst IP has changed");
   414  
   415  	if (l3->check != bpf_htons(0x4212))
   416  		test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check));
   417  
   418  	if (l4->source != CLIENT_INTER_CLUSTER_SNAT_PORT)
   419  		test_fatal("src port has changed");
   420  
   421  	if (l4->dest != BACKEND_PORT)
   422  		test_fatal("dst port has changed");
   423  
   424  	meta = ctx_load_meta(ctx, CB_IFINDEX);
   425  	if (meta != BACKEND_IFINDEX)
   426  		test_fatal("skb->cb[CB_IFINDEX] should be %d, got %d", BACKEND_IFINDEX, meta);
   427  
   428  	meta = ctx_load_meta(ctx, CB_SRC_LABEL);
   429  	if (meta != CLIENT_IDENTITY)
   430  		test_fatal("skb->cb[CB_SRC_LABEL] should be %d, got %d", CLIENT_IDENTITY, meta);
   431  
   432  	meta = ctx_load_meta(ctx, CB_FROM_TUNNEL);
   433  	if (meta != 1)
   434  		test_fatal("skb->cb[CB_FROM_TUNNEL] should be 1, got %d", meta);
   435  
   436  	meta = ctx_load_meta(ctx, CB_FROM_HOST);
   437  	if (meta != 0)
   438  		test_fatal("skb->cb[CB_FROM_HOST] should be 0, got %d", meta);
   439  
   440  	meta = ctx_load_meta(ctx, CB_CLUSTER_ID_INGRESS);
   441  	if (meta != 0)
   442  		test_fatal("skb->cb[CB_CLUSTER_ID_INGRESS] should be 0, got %d", meta);
   443  
   444  	test_finish();
   445  }