github.com/cilium/cilium@v1.16.2/bpf/tests/tc_nodeport_lb6_dsr_lb.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 ENABLE_DSR
    16  #define DSR_ENCAP_GENEVE	3
    17  
    18  #define DISABLE_LOOPBACK_LB
    19  
    20  /* Skip ingress policy checks, not needed to validate hairpin flow */
    21  #define USE_BPF_PROG_FOR_INGRESS_POLICY
    22  #undef FORCE_LOCAL_POLICY_EVAL_AT_SOURCE
    23  
    24  #define CLIENT_IP		{ .addr = { 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 } }
    25  #define CLIENT_PORT		__bpf_htons(111)
    26  
    27  #define FRONTEND_IP		{ .addr = { 0x2, 0x0, 0x0, 0x0, 0x0, 0x0 } }
    28  #define FRONTEND_PORT		tcp_svc_one
    29  
    30  #define LB_IP			{ .addr = { 0x5, 0x0, 0x0, 0x0, 0x0, 0x0 } }
    31  #define IPV6_DIRECT_ROUTING	LB_IP
    32  
    33  #define BACKEND_IP		{ .addr = { 0x3, 0x0, 0x0, 0x0, 0x0, 0x0 } }
    34  #define BACKEND_PORT		__bpf_htons(8080)
    35  
    36  #define fib_lookup mock_fib_lookup
    37  
    38  static volatile const __u8 *client_mac = mac_one;
    39  /* this matches the default node_config.h: */
    40  static volatile const __u8 lb_mac[ETH_ALEN] = { 0xce, 0x72, 0xa7, 0x03, 0x88, 0x56 };
    41  static volatile const __u8 *remote_backend_mac = mac_five;
    42  
    43  long mock_fib_lookup(__maybe_unused void *ctx, struct bpf_fib_lookup *params,
    44  		     __maybe_unused int plen, __maybe_unused __u32 flags)
    45  {
    46  	params->ifindex = 0;
    47  
    48  	if (1 /*memcmp(&params->ipv6_dst, BACKEND_IP)*/) {
    49  		__bpf_memcpy_builtin(params->smac, (__u8 *)lb_mac, ETH_ALEN);
    50  		__bpf_memcpy_builtin(params->dmac, (__u8 *)remote_backend_mac, ETH_ALEN);
    51  	} else {
    52  		__bpf_memcpy_builtin(params->smac, (__u8 *)lb_mac, ETH_ALEN);
    53  		__bpf_memcpy_builtin(params->dmac, (__u8 *)client_mac, ETH_ALEN);
    54  	}
    55  
    56  	return BPF_FIB_LKUP_RET_SUCCESS;
    57  }
    58  
    59  #define SECCTX_FROM_IPCACHE 1
    60  
    61  #include <bpf_host.c>
    62  
    63  #include "lib/ipcache.h"
    64  #include "lib/lb.h"
    65  
    66  #define FROM_NETDEV	0
    67  #define TO_NETDEV	1
    68  
    69  struct {
    70  	__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
    71  	__uint(key_size, sizeof(__u32));
    72  	__uint(max_entries, 2);
    73  	__array(values, int());
    74  } entry_call_map __section(".maps") = {
    75  	.values = {
    76  		[FROM_NETDEV] = &cil_from_netdev,
    77  		[TO_NETDEV] = &cil_to_netdev,
    78  	},
    79  };
    80  
    81  /* Test that a SVC request that is LBed to a DSR remote backend
    82   * - gets DNATed,
    83   * - has IPv6 Extension inserted,
    84   * - gets redirected back out by TC
    85   */
    86  PKTGEN("tc", "tc_nodeport_dsr_fwd")
    87  int nodeport_dsr_fwd_pktgen(struct __ctx_buff *ctx)
    88  {
    89  	union v6addr frontend_ip = FRONTEND_IP;
    90  	union v6addr client_ip = CLIENT_IP;
    91  	struct pktgen builder;
    92  	struct tcphdr *l4;
    93  	void *data;
    94  
    95  	/* Init packet builder */
    96  	pktgen__init(&builder, ctx);
    97  
    98  	l4 = pktgen__push_ipv6_tcp_packet(&builder,
    99  					  (__u8 *)client_mac, (__u8 *)lb_mac,
   100  					  (__u8 *)&client_ip, (__u8 *)&frontend_ip,
   101  					  CLIENT_PORT, FRONTEND_PORT);
   102  	if (!l4)
   103  		return TEST_ERROR;
   104  
   105  	data = pktgen__push_data(&builder, default_data, sizeof(default_data));
   106  	if (!data)
   107  		return TEST_ERROR;
   108  
   109  	/* Calc lengths, set protocol fields and calc checksums */
   110  	pktgen__finish(&builder);
   111  
   112  	return 0;
   113  }
   114  
   115  SETUP("tc", "tc_nodeport_dsr_fwd")
   116  int nodeport_dsr_fwd_setup(struct __ctx_buff *ctx)
   117  {
   118  	union v6addr frontend_ip = FRONTEND_IP;
   119  	union v6addr backend_ip = BACKEND_IP;
   120  	__u16 revnat_id = 1;
   121  
   122  	lb_v6_add_service(&frontend_ip, FRONTEND_PORT, 1, revnat_id);
   123  	lb_v6_add_backend(&frontend_ip, FRONTEND_PORT, 1, 124,
   124  			  &backend_ip, BACKEND_PORT, IPPROTO_TCP, 0);
   125  
   126  	ipcache_v6_add_entry(&backend_ip, 0, 112233, 0, 0);
   127  
   128  	/* Jump into the entrypoint */
   129  	tail_call_static(ctx, entry_call_map, FROM_NETDEV);
   130  	/* Fail if we didn't jump */
   131  	return TEST_ERROR;
   132  }
   133  
   134  CHECK("tc", "tc_nodeport_dsr_fwd")
   135  int nodeport_dsr_fwd_check(__maybe_unused const struct __ctx_buff *ctx)
   136  {
   137  	union v6addr frontend_ip = FRONTEND_IP;
   138  	union v6addr backend_ip = BACKEND_IP;
   139  	union v6addr client_ip = CLIENT_IP;
   140  	struct dsr_opt_v6 *opt;
   141  	void *data, *data_end;
   142  	__u32 *status_code;
   143  	struct ipv6hdr *l3;
   144  	struct tcphdr *l4;
   145  	struct ethhdr *l2;
   146  
   147  	test_init();
   148  
   149  	data = (void *)(long)ctx_data(ctx);
   150  	data_end = (void *)(long)ctx->data_end;
   151  
   152  	if (data + sizeof(__u32) > data_end)
   153  		test_fatal("status code out of bounds");
   154  
   155  	status_code = data;
   156  
   157  	assert(*status_code == CTX_ACT_REDIRECT);
   158  
   159  	l2 = data + sizeof(__u32);
   160  	if ((void *)l2 + sizeof(struct ethhdr) > data_end)
   161  		test_fatal("l2 out of bounds");
   162  
   163  	l3 = (void *)l2 + sizeof(struct ethhdr);
   164  	if ((void *)l3 + sizeof(struct ipv6hdr) > data_end)
   165  		test_fatal("l3 out of bounds");
   166  
   167  	opt = (void *)l3 + sizeof(struct ipv6hdr);
   168  	if ((void *)opt + sizeof(*opt) > data_end)
   169  		test_fatal("l3 DSR extension out of bounds");
   170  
   171  	l4 = (void *)opt + sizeof(*opt);
   172  	if ((void *)l4 + sizeof(struct tcphdr) > data_end)
   173  		test_fatal("l4 out of bounds");
   174  
   175  	if (memcmp(l2->h_source, (__u8 *)lb_mac, ETH_ALEN) != 0)
   176  		test_fatal("src MAC is not the LB MAC")
   177  	if (memcmp(l2->h_dest, (__u8 *)remote_backend_mac, ETH_ALEN) != 0)
   178  		test_fatal("dst MAC is not the backend MAC")
   179  
   180  	if (l3->nexthdr != NEXTHDR_DEST)
   181  		test_fatal("l3 header doesn't indicate DSR extension");
   182  
   183  	if (!ipv6_addr_equals((union v6addr *)&l3->saddr, &client_ip))
   184  		test_fatal("src IP has changed");
   185  	if (!ipv6_addr_equals((union v6addr *)&l3->daddr, &backend_ip))
   186  		test_fatal("dst IP hasn't been NATed to remote backend IP");
   187  
   188  	if (opt->hdr.nexthdr != IPPROTO_TCP)
   189  		test_fatal("nexthdr in DSR extension is bad")
   190  	if (opt->hdr.hdrlen != DSR_IPV6_EXT_LEN)
   191  		test_fatal("length in DSR extension is bad")
   192  	if (opt->opt_type != DSR_IPV6_OPT_TYPE)
   193  		test_fatal("opt_type in DSR extension is bad")
   194  	if (opt->opt_len != DSR_IPV6_OPT_LEN)
   195  		test_fatal("opt_len in DSR extension is bad")
   196  
   197  	if (opt->port != FRONTEND_PORT)
   198  		test_fatal("port in DSR extension is bad")
   199  	if (!ipv6_addr_equals((union v6addr *)&opt->addr, &frontend_ip))
   200  		test_fatal("addr in DSR extension is bad")
   201  
   202  	if (l4->source != CLIENT_PORT)
   203  		test_fatal("src port has changed");
   204  
   205  	if (l4->dest != BACKEND_PORT)
   206  		test_fatal("dst port hasn't been NATed to backend port");
   207  
   208  	test_finish();
   209  }