github.com/cilium/cilium@v1.16.2/bpf/tests/tc_nodeport_lb6_no_backend.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 "pktgen.h"
     8  
     9  /* Set ETH_HLEN to 14 to indicate that the packet has a 14 byte ethernet header */
    10  #define ETH_HLEN 14
    11  
    12  /* Enable code paths under test */
    13  #define ENABLE_IPV6
    14  #define ENABLE_NODEPORT
    15  #define SERVICE_NO_BACKEND_RESPONSE
    16  
    17  #define DISABLE_LOOPBACK_LB
    18  
    19  #define CLIENT_IP		v6_pod_one
    20  #define CLIENT_PORT		__bpf_htons(111)
    21  
    22  #define FRONTEND_IP		v6_pod_two
    23  #define FRONTEND_PORT		tcp_svc_one
    24  
    25  #define BACKEND_IP		v6_node_two
    26  #define BACKEND_PORT		__bpf_htons(8080)
    27  
    28  static volatile const __u8 *client_mac = mac_one;
    29  /* this matches the default node_config.h: */
    30  static volatile const __u8 lb_mac[ETH_ALEN] = { 0xce, 0x72, 0xa7, 0x03, 0x88, 0x56 };
    31  
    32  #include <bpf_host.c>
    33  
    34  #include "lib/ipcache.h"
    35  #include "lib/lb.h"
    36  
    37  #define FROM_NETDEV	0
    38  #define TO_NETDEV	1
    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  		[FROM_NETDEV] = &cil_from_netdev,
    48  		[TO_NETDEV] = &cil_to_netdev,
    49  	},
    50  };
    51  
    52  /* Test that a SVC without backends returns a TCP RST or ICMP error */
    53  PKTGEN("tc", "tc_nodeport_no_backend")
    54  int nodeport_no_backend_pktgen(struct __ctx_buff *ctx)
    55  {
    56  struct pktgen builder;
    57  	struct tcphdr *l4;
    58  	void *data;
    59  
    60  	/* Init packet builder */
    61  	pktgen__init(&builder, ctx);
    62  
    63  	l4 = pktgen__push_ipv6_tcp_packet(&builder,
    64  					  (__u8 *)client_mac, (__u8 *)lb_mac,
    65  					  (__u8 *)CLIENT_IP,
    66  					  (__u8 *)FRONTEND_IP,
    67  					  tcp_src_one, tcp_svc_one);
    68  	if (!l4)
    69  		return TEST_ERROR;
    70  
    71  	data = pktgen__push_data(&builder, default_data, sizeof(default_data));
    72  	if (!data)
    73  		return TEST_ERROR;
    74  
    75  	/* Calc lengths, set protocol fields and calc checksums */
    76  	pktgen__finish(&builder);
    77  
    78  	return 0;
    79  }
    80  
    81  SETUP("tc", "tc_nodeport_no_backend")
    82  int nodeport_no_backend_setup(struct __ctx_buff *ctx)
    83  {
    84  	__u16 revnat_id = 1;
    85  
    86  	union v6addr frontend_ip = {};
    87  
    88  	memcpy(frontend_ip.addr, (void *)FRONTEND_IP, 16);
    89  
    90  	lb_v6_add_service(&frontend_ip, FRONTEND_PORT, 1, revnat_id);
    91  
    92  	union v6addr backend_ip = {};
    93  
    94  	memcpy(backend_ip.addr, (void *)BACKEND_IP, 16);
    95  
    96  	ipcache_v6_add_entry(&backend_ip, 0, 112233, 0, 0);
    97  
    98  	/* Jump into the entrypoint */
    99  	tail_call_static(ctx, entry_call_map, FROM_NETDEV);
   100  
   101  	/* Fail if we didn't jump */
   102  	return TEST_ERROR;
   103  }
   104  
   105  CHECK("tc", "tc_nodeport_no_backend")
   106  int nodeport_no_backend_check(__maybe_unused const struct __ctx_buff *ctx)
   107  {
   108  	void *data, *data_end;
   109  	__u32 *status_code;
   110  	struct ethhdr *l2;
   111  	struct ipv6hdr *l3;
   112  	struct icmp6hdr *l4;
   113  	struct ratelimit_value *value;
   114  
   115  	test_init();
   116  
   117  	data = (void *)(long)ctx_data(ctx);
   118  	data_end = (void *)(long)ctx->data_end;
   119  
   120  	if (data + sizeof(__u32) > data_end)
   121  		test_fatal("status code out of bounds");
   122  
   123  	status_code = data;
   124  
   125  	test_log("Status code: %d", *status_code);
   126  	assert(*status_code == CTX_ACT_REDIRECT);
   127  
   128  	l2 = data + sizeof(__u32);
   129  	if ((void *)l2 + sizeof(struct ethhdr) > data_end)
   130  		test_fatal("l2 header out of bounds");
   131  
   132  	assert(memcmp(l2->h_dest, (__u8 *)client_mac, sizeof(lb_mac)) == 0);
   133  	assert(memcmp(l2->h_source, (__u8 *)lb_mac, sizeof(lb_mac)) == 0);
   134  	assert(l2->h_proto == __bpf_htons(ETH_P_IPV6));
   135  
   136  	l3 = data + sizeof(__u32) + sizeof(struct ethhdr);
   137  	if ((void *)l3 + sizeof(struct ipv6hdr) > data_end)
   138  		test_fatal("l3 header out of bounds");
   139  
   140  	assert(l3->hop_limit == 64);
   141  	assert(l3->version == 6);
   142  	assert(l3->nexthdr == IPPROTO_ICMPV6);
   143  
   144  	l4 = data + sizeof(__u32) + sizeof(struct ethhdr) + sizeof(struct ipv6hdr);
   145  	if ((void *) l4 + sizeof(struct icmp6hdr) > data_end)
   146  		test_fatal("l4 header out of bounds");
   147  
   148  	assert(l4->icmp6_type == ICMPV6_DEST_UNREACH);
   149  	assert(l4->icmp6_code == ICMPV6_PORT_UNREACH);
   150  
   151  	/* reference checksum is calculated with wireshark by dumping the
   152  	 * context with the runner option and importing the packet into
   153  	 * wireshark
   154  	 */
   155  	assert(l4->icmp6_cksum == bpf_htons(0x7da8));
   156  
   157  	struct ratelimit_key key = {
   158  		.netdev_idx = 1,
   159  	};
   160  
   161  	value = map_lookup_elem(&RATELIMIT_MAP, &key);
   162  	if (!value)
   163  		test_fatal("ratelimit map lookup failed");
   164  
   165  	assert(value->tokens > 0);
   166  
   167  	test_finish();
   168  }