github.com/cilium/cilium@v1.16.2/bpf/tests/xdp_nodeport_lb4_test.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/xdp.h"
     7  
     8  #define ENABLE_IPV4
     9  #define ENABLE_NODEPORT
    10  #define ENABLE_NODEPORT_ACCELERATION
    11  
    12  #define fib_lookup mock_fib_lookup
    13  
    14  static const char fib_smac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x02};
    15  static const char fib_dmac[6] = {0x13, 0x37, 0x13, 0x37, 0x13, 0x37};
    16  
    17  long mock_fib_lookup(__maybe_unused void *ctx, struct bpf_fib_lookup *params,
    18  		     __maybe_unused int plen, __maybe_unused __u32 flags)
    19  {
    20  	__bpf_memcpy_builtin(params->smac, fib_smac, ETH_ALEN);
    21  	__bpf_memcpy_builtin(params->dmac, fib_dmac, ETH_ALEN);
    22  	return 0;
    23  }
    24  
    25  #include "bpf_xdp.c"
    26  #include "lib/nodeport.h"
    27  
    28  #include "lib/lb.h"
    29  
    30  struct {
    31  	__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
    32  	__uint(key_size, sizeof(__u32));
    33  	__uint(max_entries, 2);
    34  	__array(values, int());
    35  } entry_call_map __section(".maps") = {
    36  	.values = {
    37  		[0] = &cil_xdp_entry,
    38  	},
    39  };
    40  
    41  #define FRONTEND_IP 0x0F00010A /* 10.0.1.15 */
    42  #define FRONTEND_PORT 80
    43  #define BACKEND_IP 0x0F00020A /* 10.2.0.15 */
    44  #define BACKEND_PORT 8080
    45  
    46  static long (*bpf_xdp_adjust_tail)(struct xdp_md *xdp_md, int delta) = (void *)65;
    47  
    48  static __always_inline int build_packet(struct __ctx_buff *ctx)
    49  {
    50  	/* Create room for our packet to be crafted */
    51  	unsigned int data_len = ctx->data_end - ctx->data;
    52  
    53  	int offset = offset = 4096 - 256 - 320 - data_len;
    54  
    55  	bpf_xdp_adjust_tail(ctx, offset);
    56  
    57  	void *data = (void *)(long)ctx->data;
    58  	void *data_end = (void *)(long)ctx->data_end;
    59  
    60  	if (data + sizeof(struct ethhdr) > data_end)
    61  		return TEST_ERROR;
    62  
    63  	struct ethhdr l2 = {
    64  		.h_source = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
    65  		.h_dest = {0x12, 0x23, 0x34, 0x45, 0x56, 0x67},
    66  		.h_proto = bpf_htons(ETH_P_IP)
    67  	};
    68  	memcpy(data, &l2, sizeof(struct ethhdr));
    69  	data += sizeof(struct ethhdr);
    70  
    71  	if (data + sizeof(struct iphdr) > data_end)
    72  		return TEST_ERROR;
    73  
    74  	struct iphdr l3 = {
    75  		.version = 4,
    76  		.ihl = 5,
    77  		.tot_len = 40, /* 20 bytes l3 + 20 bytes l4 + 20 bytes data */
    78  		.id = 0x5438,
    79  		.frag_off = bpf_htons(IP_DF),
    80  		.ttl = 64,
    81  		.protocol = IPPROTO_TCP,
    82  		.saddr = 0x0F00000A, /* 10.0.0.15 */
    83  		.daddr = FRONTEND_IP,
    84  	};
    85  	memcpy(data, &l3, sizeof(struct iphdr));
    86  	data += sizeof(struct iphdr);
    87  
    88  	char tcp_data[20] = "Should not change!!";
    89  
    90  	/* TCP header + data */
    91  	if (data + (sizeof(struct tcphdr) + sizeof(tcp_data)) > data_end)
    92  		return TEST_ERROR;
    93  
    94  	struct tcphdr l4 = {
    95  		.source = 23445,
    96  		.dest = FRONTEND_PORT,
    97  		.seq = 2922048129,
    98  		.doff = 0, /* no options */
    99  		.syn = 1,
   100  		.window = 64240,
   101  	};
   102  	memcpy(data, &l4, sizeof(struct tcphdr));
   103  
   104  	char *tcp_data_ptr = data + sizeof(tcp_data);
   105  
   106  	memcpy(tcp_data_ptr, tcp_data, sizeof(tcp_data));
   107  
   108  	data += sizeof(struct tcphdr) + sizeof(tcp_data);
   109  
   110  	/* Shrink ctx to the exact size we used */
   111  	offset = (long)data - (long)ctx->data_end;
   112  	bpf_xdp_adjust_tail(ctx, offset);
   113  
   114  	return 0;
   115  }
   116  
   117  SETUP("xdp", "xdp_lb4_forward_to_other_node")
   118  int test1_setup(struct __ctx_buff *ctx)
   119  {
   120  	int ret;
   121  
   122  	ret = build_packet(ctx);
   123  	if (ret)
   124  		return ret;
   125  
   126  	lb_v4_add_service(FRONTEND_IP, FRONTEND_PORT, 1, 1);
   127  	lb_v4_add_backend(FRONTEND_IP, FRONTEND_PORT, 1, 124,
   128  			  BACKEND_IP, BACKEND_PORT, IPPROTO_TCP, 0);
   129  
   130  	/* Jump into the entrypoint */
   131  	tail_call_static(ctx, entry_call_map, 0);
   132  	/* Fail if we didn't jump */
   133  	return TEST_ERROR;
   134  }
   135  
   136  CHECK("xdp", "xdp_lb4_forward_to_other_node")
   137  int test1_check(__maybe_unused const struct __ctx_buff *ctx)
   138  {
   139  	test_init();
   140  
   141  	void *data = (void *)(long)ctx->data;
   142  	void *data_end = (void *)(long)ctx->data_end;
   143  
   144  	if (data + sizeof(__u32) > data_end)
   145  		test_fatal("status code out of bounds");
   146  
   147  	__u32 *status_code = data;
   148  
   149  	if (*status_code != XDP_TX)
   150  		test_fatal("status code != XDP_TX");
   151  
   152  	data += sizeof(__u32);
   153  
   154  	if (data + sizeof(struct ethhdr) > data_end)
   155  		test_fatal("ctx doesn't fit ethhdr");
   156  
   157  	struct ethhdr *l2 = data;
   158  
   159  	data += sizeof(struct ethhdr);
   160  
   161  	if (memcmp(l2->h_source, fib_smac, sizeof(fib_smac)) != 0)
   162  		test_fatal("l2->h_source != fib_smac");
   163  
   164  	if (memcmp(l2->h_dest, fib_dmac, sizeof(fib_dmac)) != 0)
   165  		test_fatal("l2->h_dest != fib_dmac");
   166  
   167  	if (data + sizeof(struct iphdr) > data_end)
   168  		test_fatal("ctx doesn't fit iphdr");
   169  
   170  	struct iphdr *l3 = data;
   171  
   172  	data += sizeof(struct iphdr);
   173  
   174  	if (l3->daddr != BACKEND_IP)
   175  		test_fatal("dst ip != backend IP");
   176  
   177  	if (data + sizeof(struct tcphdr) > data_end)
   178  		test_fatal("ctx doesn't fit tcphdr");
   179  
   180  	struct tcphdr *l4 = data;
   181  
   182  	data += sizeof(struct tcphdr);
   183  
   184  	if (l4->dest != BACKEND_PORT)
   185  		test_fatal("dst port != backend port");
   186  
   187  	char msg[20] = "Should not change!!";
   188  
   189  	if (data + sizeof(msg) > data_end)
   190  		test_fatal("ctx doesn't fit tcp body");
   191  
   192  	char *body = data;
   193  
   194  	if (memcmp(body, msg, sizeof(msg)) != 0)
   195  		test_fatal("body changed");
   196  
   197  	test_finish();
   198  }
   199  
   200  SETUP("xdp", "xdp_lb4_drop_no_backend")
   201  int test2_setup(struct __ctx_buff *ctx)
   202  {
   203  	int ret;
   204  
   205  	ret = build_packet(ctx);
   206  	if (ret)
   207  		return ret;
   208  
   209  	lb_v4_add_service(FRONTEND_IP, FRONTEND_PORT, 0, 1);
   210  
   211  	/* Jump into the entrypoint */
   212  	tail_call_static(ctx, entry_call_map, 0);
   213  	/* Fail if we didn't jump */
   214  	return TEST_ERROR;
   215  }
   216  
   217  CHECK("xdp", "xdp_lb4_drop_no_backend")
   218  int test2_check(__maybe_unused const struct __ctx_buff *ctx)
   219  {
   220  	void *data_end = (void *)(long)ctx->data_end;
   221  	void *data = (void *)(long)ctx->data;
   222  	__u32 expected_status = XDP_DROP;
   223  	__u32 *status_code;
   224  
   225  	test_init();
   226  
   227  	if (data + sizeof(__u32) > data_end)
   228  		test_fatal("status code out of bounds");
   229  
   230  	status_code = data;
   231  
   232  	if (*status_code != expected_status)
   233  		test_fatal("status code is %lu, expected %lu", *status_code, expected_status);
   234  
   235  	test_finish();
   236  }