github.com/cilium/cilium@v1.16.2/bpf/tests/hairpin_sctp_flow.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  /* Set the LXC source address to be the address of pod one */
     7  #define LXC_IPV4 (__be32)v4_pod_one
     8  
     9  /* Enable CT debug output */
    10  #undef QUIET_CT
    11  
    12  #include <bpf/ctx/skb.h>
    13  #include "pktgen.h"
    14  
    15  /* Set ETH_HLEN to 14 to indicate that the packet has a 14 byte ethernet header */
    16  #define ETH_HLEN 14
    17  
    18  /* Enable code paths under test*/
    19  #define ENABLE_IPV4
    20  #define ENABLE_SCTP
    21  
    22  /* Use to-container for ingress policy: */
    23  #define USE_BPF_PROG_FOR_INGRESS_POLICY
    24  #undef FORCE_LOCAL_POLICY_EVAL_AT_SOURCE
    25  
    26  #define ctx_redirect_peer mock_ctx_redirect_peer
    27  static __always_inline __maybe_unused int
    28  mock_ctx_redirect_peer(const struct __sk_buff *ctx __maybe_unused, int ifindex __maybe_unused,
    29  		       __u32 flags __maybe_unused)
    30  {
    31  	return TC_ACT_REDIRECT;
    32  }
    33  
    34  #include <bpf_lxc.c>
    35  
    36  #include "lib/endpoint.h"
    37  #include "lib/ipcache.h"
    38  #include "lib/lb.h"
    39  
    40  struct {
    41  	__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
    42  	__uint(key_size, sizeof(__u32));
    43  	__uint(max_entries, 2);
    44  	__array(values, int());
    45  } entry_call_map __section(".maps") = {
    46  	.values = {
    47  		[0] = &cil_from_container,
    48  		[1] = &cil_to_container,
    49  	},
    50  };
    51  
    52  /* Setup for this test:
    53   * +-------ClusterIP--------+    +----------Pod 1---------+
    54   * | v4_svc_one:tcp_svc_one | -> | v4_pod_one:tcp_svc_one |
    55   * +------------------------+    +------------------------+
    56   *            ^                            |
    57   *            \---------------------------/
    58   */
    59  
    60  /* Test that sending a packet from a pod to its own service gets source nat-ed
    61   * and that it is forwarded to the correct veth.
    62   */
    63  SETUP("tc", "hairpin_sctp_flow_1_forward_v4")
    64  int hairpin_flow_forward_setup(struct __ctx_buff *ctx)
    65  {
    66  	struct pktgen builder;
    67  	volatile const __u8 *src = mac_one;
    68  	volatile const __u8 *dst = mac_two;
    69  	struct iphdr *l3;
    70  	struct sctphdr *l4;
    71  	__u16 revnat_id = 1;
    72  
    73  	/* Init packet builder */
    74  	pktgen__init(&builder, ctx);
    75  
    76  	l3 = pktgen__push_ipv4_packet(&builder, (__u8 *)src, (__u8 *)dst,
    77  				      v4_pod_one, v4_svc_one);
    78  	if (!l3)
    79  		return TEST_ERROR;
    80  
    81  	/* Push SCTP header */
    82  	l4 = pktgen__push_sctphdr(&builder);
    83  
    84  	if (!l4)
    85  		return TEST_ERROR;
    86  	if ((void *)l4 + sizeof(struct sctphdr) > ctx_data_end(ctx))
    87  		return TEST_ERROR;
    88  
    89  	l4->source = tcp_src_one;
    90  	l4->dest = tcp_svc_one;
    91  
    92  	/* Calc lengths, set protocol fields and calc checksums */
    93  	pktgen__finish(&builder);
    94  
    95  	lb_v4_add_service(v4_svc_one, tcp_svc_one, 1, revnat_id);
    96  	lb_v4_add_backend(v4_svc_one, tcp_svc_one, 1, 124,
    97  			  v4_pod_one, tcp_svc_one, IPPROTO_SCTP, 0);
    98  
    99  	/* Add an IPCache entry for pod 1 */
   100  	ipcache_v4_add_entry(v4_pod_one, 0, 112233, 0, 0);
   101  
   102  	endpoint_v4_add_entry(v4_pod_one, 0, 0, 0, 0, NULL, NULL);
   103  
   104  	/* Jump into the entrypoint */
   105  	tail_call_static(ctx, entry_call_map, 0);
   106  	/* Fail if we didn't jump */
   107  	return TEST_ERROR;
   108  }
   109  
   110  CHECK("tc", "hairpin_sctp_flow_1_forward_v4")
   111  int hairpin_flow_forward_check(__maybe_unused const struct __ctx_buff *ctx)
   112  {
   113  	void *data;
   114  	void *data_end;
   115  	__u32 *status_code;
   116  	struct iphdr *l3;
   117  	struct sctphdr *l4;
   118  
   119  	test_init();
   120  
   121  	data = (void *)(long)ctx->data;
   122  	data_end = (void *)(long)ctx->data_end;
   123  
   124  	if (data + sizeof(__u32) > data_end)
   125  		test_fatal("status code out of bounds");
   126  
   127  	status_code = data;
   128  
   129  	assert(*status_code == TC_ACT_REDIRECT);
   130  
   131  	l3 = data + sizeof(__u32) + sizeof(struct ethhdr);
   132  
   133  	if ((void *)l3 + sizeof(struct iphdr) > data_end)
   134  		test_fatal("l3 out of bounds");
   135  
   136  	if (l3->saddr != IPV4_LOOPBACK)
   137  		test_fatal("src IP was not SNAT'ed");
   138  
   139  	if (l3->daddr != v4_pod_one)
   140  		test_fatal("dest IP hasn't been changed to the pod IP");
   141  
   142  	if (l3->check != bpf_htons(0xb09c))
   143  		test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check));
   144  
   145  	l4 = (void *)l3 + sizeof(struct iphdr);
   146  
   147  	if ((void *)l4 + sizeof(struct sctphdr) > data_end)
   148  		test_fatal("l4 out of bounds");
   149  
   150  	if (l4->source != tcp_src_one)
   151  		test_fatal("src SCTP port was changed");
   152  
   153  	if (l4->dest != tcp_svc_one)
   154  		test_fatal("dst SCTP port incorrect");
   155  
   156  	test_finish();
   157  }
   158  
   159  /* Let backend's ingress path create its CT own entry: */
   160  PKTGEN("tc", "hairpin_sctp_flow_2_forward_ingress_v4")
   161  int hairpin_flow_forward_ingress_pktgen(struct __ctx_buff *ctx)
   162  {
   163  	struct pktgen builder;
   164  	volatile const __u8 *src = mac_one;
   165  	volatile const __u8 *dst = mac_two;
   166  	struct iphdr *l3;
   167  	struct sctphdr *l4;
   168  
   169  	/* Init packet builder */
   170  	pktgen__init(&builder, ctx);
   171  
   172  	l3 = pktgen__push_ipv4_packet(&builder, (__u8 *)src, (__u8 *)dst,
   173  				      IPV4_LOOPBACK, v4_pod_one);
   174  	if (!l3)
   175  		return TEST_ERROR;
   176  
   177  	/* Push SCTP header */
   178  	l4 = pktgen__push_sctphdr(&builder);
   179  
   180  	if (!l4)
   181  		return TEST_ERROR;
   182  
   183  	l4->source = tcp_src_one;
   184  	l4->dest = tcp_svc_one;
   185  
   186  	/* Calc lengths, set protocol fields and calc checksums */
   187  	pktgen__finish(&builder);
   188  
   189  	return 0;
   190  }
   191  
   192  SETUP("tc", "hairpin_sctp_flow_2_forward_ingress_v4")
   193  int hairpin_flow_forward_ingress_setup(struct __ctx_buff *ctx)
   194  {
   195  	/* Jump into the entrypoint */
   196  	tail_call_static(ctx, entry_call_map, 1);
   197  	/* Fail if we didn't jump */
   198  	return TEST_ERROR;
   199  }
   200  
   201  CHECK("tc", "hairpin_sctp_flow_2_forward_ingress_v4")
   202  int hairpin_flow_forward_ingress_check(__maybe_unused const struct __ctx_buff *ctx)
   203  {
   204  	void *data;
   205  	void *data_end;
   206  	__u32 *status_code;
   207  	struct iphdr *l3;
   208  	struct sctphdr *l4;
   209  
   210  	test_init();
   211  
   212  	data = (void *)(long)ctx->data;
   213  	data_end = (void *)(long)ctx->data_end;
   214  
   215  	if (data + sizeof(__u32) > data_end)
   216  		test_fatal("status code out of bounds");
   217  
   218  	status_code = data;
   219  
   220  	assert(*status_code == TC_ACT_OK);
   221  
   222  	l3 = data + sizeof(__u32) + sizeof(struct ethhdr);
   223  
   224  	if ((void *)l3 + sizeof(struct iphdr) > data_end)
   225  		test_fatal("l3 out of bounds");
   226  
   227  	if (l3->saddr != IPV4_LOOPBACK)
   228  		test_fatal("src IP changed");
   229  
   230  	if (l3->daddr != v4_pod_one)
   231  		test_fatal("dest IP changed");
   232  
   233  	if (l3->check != bpf_htons(0xaf9c))
   234  		test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check));
   235  
   236  	l4 = (void *)l3 + sizeof(struct iphdr);
   237  
   238  	if ((void *)l4 + sizeof(struct sctphdr) > data_end)
   239  		test_fatal("l4 out of bounds");
   240  
   241  	if (l4->source != tcp_src_one)
   242  		test_fatal("src SCTP port changed");
   243  
   244  	if (l4->dest != tcp_svc_one)
   245  		test_fatal("dst SCTP port changed");
   246  
   247  	test_finish();
   248  }
   249  
   250  /* Test that a packet in the reverse direction gets translated back. */
   251  SETUP("tc", "hairpin_sctp_flow_3_reverse_v4")
   252  int hairpin_flow_rev_setup(struct __ctx_buff *ctx)
   253  {
   254  	struct pktgen builder;
   255  	volatile const __u8 *src = mac_one;
   256  	volatile const __u8 *dst = mac_two;
   257  	struct iphdr *l3;
   258  	struct sctphdr *l4;
   259  
   260  	/* Init packet builder */
   261  	pktgen__init(&builder, ctx);
   262  
   263  	l3 = pktgen__push_ipv4_packet(&builder, (__u8 *)src, (__u8 *)dst,
   264  				      v4_pod_one, IPV4_LOOPBACK);
   265  	if (!l3)
   266  		return TEST_ERROR;
   267  
   268  	/* Push SCTP header */
   269  	l4 = pktgen__push_sctphdr(&builder);
   270  
   271  	if (!l4)
   272  		return TEST_ERROR;
   273  
   274  	l4->source = tcp_svc_one;
   275  	l4->dest = tcp_src_one;
   276  
   277  	/* Calc lengths, set protocol fields and calc checksums */
   278  	pktgen__finish(&builder);
   279  
   280  	/* Jump into the entrypoint */
   281  	tail_call_static(ctx, entry_call_map, 0);
   282  	/* Fail if we didn't jump */
   283  	return TEST_ERROR;
   284  }
   285  
   286  CHECK("tc", "hairpin_sctp_flow_3_reverse_v4")
   287  int hairpin_flow_rev_check(__maybe_unused const struct __ctx_buff *ctx)
   288  {
   289  	void *data;
   290  	void *data_end;
   291  	__u32 *status_code;
   292  	struct iphdr *l3;
   293  	struct sctphdr *l4;
   294  
   295  	test_init();
   296  
   297  	data = (void *)(long)ctx->data;
   298  	data_end = (void *)(long)ctx->data_end;
   299  
   300  	if (data + sizeof(__u32) > data_end)
   301  		test_fatal("status code out of bounds");
   302  
   303  	status_code = data;
   304  
   305  	assert(*status_code == TC_ACT_REDIRECT);
   306  
   307  	l3 = data + sizeof(__u32) + sizeof(struct ethhdr);
   308  
   309  	if ((void *)l3 + sizeof(struct iphdr) > data_end)
   310  		test_fatal("l3 out of bounds");
   311  
   312  	if (l3->saddr != v4_pod_one)
   313  		test_fatal("src IP changed");
   314  
   315  	if (l3->daddr != IPV4_LOOPBACK)
   316  		test_fatal("dest IP changed");
   317  
   318  	l4 = (void *)l3 + sizeof(struct iphdr);
   319  
   320  	if ((void *)l4 + sizeof(struct sctphdr) > data_end)
   321  		test_fatal("l4 out of bounds");
   322  
   323  	if (l4->source != tcp_svc_one)
   324  		test_fatal("src SCTP port changed");
   325  
   326  	if (l4->dest != tcp_src_one)
   327  		test_fatal("dst SCTP port changed");
   328  
   329  	test_finish();
   330  }
   331  
   332  PKTGEN("tc", "hairpin_sctp_flow_4_reverse_ingress_v4")
   333  int hairpin_sctp_flow_4_reverse_ingress_v4_pktgen(struct __ctx_buff *ctx)
   334  {
   335  	struct pktgen builder;
   336  	volatile const __u8 *src = mac_one;
   337  	volatile const __u8 *dst = mac_two;
   338  	struct iphdr *l3;
   339  	struct sctphdr *l4;
   340  
   341  	/* Init packet builder */
   342  	pktgen__init(&builder, ctx);
   343  
   344  	l3 = pktgen__push_ipv4_packet(&builder, (__u8 *)src, (__u8 *)dst,
   345  				      v4_pod_one, IPV4_LOOPBACK);
   346  	if (!l3)
   347  		return TEST_ERROR;
   348  
   349  	/* Push SCTP header */
   350  	l4 = pktgen__push_sctphdr(&builder);
   351  
   352  	if (!l4)
   353  		return TEST_ERROR;
   354  
   355  	l4->source = tcp_svc_one;
   356  	l4->dest = tcp_src_one;
   357  
   358  	/* Calc lengths, set protocol fields and calc checksums */
   359  	pktgen__finish(&builder);
   360  
   361  	return 0;
   362  }
   363  
   364  SETUP("tc", "hairpin_sctp_flow_4_reverse_ingress_v4")
   365  int hairpin_sctp_flow_4_reverse_ingress_v4_setup(struct __ctx_buff *ctx)
   366  {
   367  	/* Jump into the entrypoint */
   368  	tail_call_static(ctx, entry_call_map, 1);
   369  	/* Fail if we didn't jump */
   370  	return TEST_ERROR;
   371  }
   372  
   373  CHECK("tc", "hairpin_sctp_flow_4_reverse_ingress_v4")
   374  int hairpin_sctp_flow_4_reverse_ingress_v4_check(const struct __ctx_buff *ctx)
   375  {
   376  	void *data;
   377  	void *data_end;
   378  	__u32 *status_code;
   379  	struct iphdr *l3;
   380  	struct sctphdr *l4;
   381  
   382  	test_init();
   383  
   384  	data = (void *)(long)ctx->data;
   385  	data_end = (void *)(long)ctx->data_end;
   386  
   387  	if (data + sizeof(__u32) > data_end)
   388  		test_fatal("status code out of bounds");
   389  
   390  	status_code = data;
   391  
   392  	assert(*status_code == CTX_ACT_OK);
   393  
   394  	l3 = data + sizeof(__u32) + sizeof(struct ethhdr);
   395  
   396  	if ((void *)l3 + sizeof(struct iphdr) > data_end)
   397  		test_fatal("l3 out of bounds");
   398  
   399  	if (l3->saddr != v4_svc_one)
   400  		test_fatal("src IP was not NAT'ed back to the svc IP");
   401  
   402  	if (l3->daddr != v4_pod_one)
   403  		test_fatal("dest IP hasn't been NAT'ed to the original source IP");
   404  
   405  	if (l3->check != bpf_htons(0x3a0))
   406  		test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check));
   407  
   408  	l4 = (void *)l3 + sizeof(struct iphdr);
   409  
   410  	if ((void *)l4 + sizeof(struct sctphdr) > data_end)
   411  		test_fatal("l4 out of bounds");
   412  
   413  	if (l4->source != tcp_svc_one)
   414  		test_fatal("src TCP port was changed");
   415  
   416  	if (l4->dest != tcp_src_one)
   417  		test_fatal("dst TCP port incorrect");
   418  
   419  	test_finish();
   420  }