github.com/cilium/cilium@v1.16.2/bpf/tests/nodeport_geneve_dsr_lb_xdp.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  #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_IPV4
    14  #define ENABLE_NODEPORT
    15  #define ENABLE_NODEPORT_ACCELERATION
    16  #define ENABLE_DSR		1
    17  
    18  #define DSR_ENCAP_IPIP		2
    19  #define DSR_ENCAP_GENEVE	3
    20  #define DSR_ENCAP_MODE		DSR_ENCAP_GENEVE
    21  
    22  #define TUNNEL_PROTOCOL		TUNNEL_PROTOCOL_GENEVE
    23  #define ENCAP_IFINDEX		42
    24  #define TUNNEL_MODE
    25  
    26  #define DISABLE_LOOPBACK_LB
    27  
    28  /* Skip ingress policy checks, not needed to validate hairpin flow */
    29  #define USE_BPF_PROG_FOR_INGRESS_POLICY
    30  #undef FORCE_LOCAL_POLICY_EVAL_AT_SOURCE
    31  
    32  #define CLIENT_IP		v4_ext_one
    33  #define CLIENT_PORT		__bpf_htons(111)
    34  
    35  #define FRONTEND_IP_LOCAL	v4_svc_one
    36  #define FRONTEND_IP_REMOTE	v4_svc_two
    37  #define FRONTEND_PORT		tcp_svc_one
    38  
    39  #define LB_IP			v4_node_one
    40  #define IPV4_DIRECT_ROUTING	LB_IP
    41  #define BACKEND_NODE_IP		v4_node_two
    42  
    43  #define DIRECT_ROUTING_IFINDEX	25
    44  
    45  #define BACKEND_IP_LOCAL	v4_pod_one
    46  #define BACKEND_IP_REMOTE	v4_pod_two
    47  #define BACKEND_PORT		__bpf_htons(8080)
    48  
    49  #define fib_lookup mock_fib_lookup
    50  
    51  static volatile const __u8 *client_mac = mac_one;
    52  /* this matches the default node_config.h: */
    53  static volatile const __u8 lb_mac[ETH_ALEN]	= { 0xce, 0x72, 0xa7, 0x03, 0x88, 0x56 };
    54  static volatile const __u8 *node_mac = mac_three;
    55  static volatile const __u8 *local_backend_mac = mac_four;
    56  static volatile const __u8 *backend_node_mac = mac_six;
    57  
    58  static bool fail_fib;
    59  
    60  #define ctx_redirect mock_ctx_redirect
    61  static __always_inline __maybe_unused int
    62  mock_ctx_redirect(const struct __ctx_buff *ctx __maybe_unused, int ifindex __maybe_unused,
    63  		  __u32 flags __maybe_unused)
    64  {
    65  	if (ifindex != DIRECT_ROUTING_IFINDEX)
    66  		return CTX_ACT_DROP;
    67  
    68  	return CTX_ACT_REDIRECT;
    69  }
    70  
    71  long mock_fib_lookup(__maybe_unused void *ctx, struct bpf_fib_lookup *params,
    72  		     __maybe_unused int plen, __maybe_unused __u32 flags)
    73  {
    74  	if (fail_fib)
    75  		return BPF_FIB_LKUP_RET_NO_NEIGH;
    76  
    77  	params->ifindex = DIRECT_ROUTING_IFINDEX;
    78  
    79  	if (params->ipv4_dst == BACKEND_NODE_IP) {
    80  		__bpf_memcpy_builtin(params->smac, (__u8 *)lb_mac, ETH_ALEN);
    81  		__bpf_memcpy_builtin(params->dmac, (__u8 *)backend_node_mac, ETH_ALEN);
    82  	} else {
    83  		return CTX_ACT_DROP;
    84  	}
    85  
    86  	return 0;
    87  }
    88  
    89  #include <bpf_xdp.c>
    90  
    91  #include "lib/endpoint.h"
    92  #include "lib/ipcache.h"
    93  #include "lib/lb.h"
    94  
    95  #define FROM_NETDEV	0
    96  
    97  struct {
    98  	__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
    99  	__uint(key_size, sizeof(__u32));
   100  	__uint(max_entries, 1);
   101  	__array(values, int());
   102  } entry_call_map __section(".maps") = {
   103  	.values = {
   104  		[FROM_NETDEV] = &cil_xdp_entry,
   105  	},
   106  };
   107  
   108  /* Test that a SVC request to a local backend
   109   * - gets DNATed (but not SNATed)
   110   * - gets passed up from XDP to TC
   111   */
   112  PKTGEN("xdp", "nodeport_geneve_dsr_lb_xdp1_local_backend")
   113  int nodeport_geneve_dsr_lb_xdp1_local_backend_pktgen(struct __ctx_buff *ctx)
   114  {
   115  	struct pktgen builder;
   116  	struct tcphdr *l4;
   117  	void *data;
   118  
   119  	/* Init packet builder */
   120  	pktgen__init(&builder, ctx);
   121  
   122  	l4 = pktgen__push_ipv4_tcp_packet(&builder,
   123  					  (__u8 *)client_mac, (__u8 *)lb_mac,
   124  					  CLIENT_IP, FRONTEND_IP_LOCAL,
   125  					  CLIENT_PORT, FRONTEND_PORT);
   126  	if (!l4)
   127  		return TEST_ERROR;
   128  
   129  	data = pktgen__push_data(&builder, default_data, sizeof(default_data));
   130  	if (!data)
   131  		return TEST_ERROR;
   132  
   133  	/* Calc lengths, set protocol fields and calc checksums */
   134  	pktgen__finish(&builder);
   135  
   136  	return 0;
   137  }
   138  
   139  SETUP("xdp", "nodeport_geneve_dsr_lb_xdp1_local_backend")
   140  int nodeport_geneve_dsr_lb_xdp1_local_backend_setup(struct __ctx_buff *ctx)
   141  {
   142  	__u16 revnat_id = 1;
   143  
   144  	lb_v4_add_service(FRONTEND_IP_LOCAL, FRONTEND_PORT, 1, revnat_id);
   145  	lb_v4_add_backend(FRONTEND_IP_LOCAL, FRONTEND_PORT, 1, 124,
   146  			  BACKEND_IP_LOCAL, BACKEND_PORT, IPPROTO_TCP, 0);
   147  
   148  	/* add local backend */
   149  	endpoint_v4_add_entry(BACKEND_IP_LOCAL, 0, 0, 0, 0,
   150  			      (__u8 *)local_backend_mac, (__u8 *)node_mac);
   151  
   152  	ipcache_v4_add_entry(BACKEND_IP_LOCAL, 0, 112233, 0, 0);
   153  
   154  	/* Jump into the entrypoint */
   155  	tail_call_static(ctx, entry_call_map, FROM_NETDEV);
   156  	/* Fail if we didn't jump */
   157  	return TEST_ERROR;
   158  }
   159  
   160  CHECK("xdp", "nodeport_geneve_dsr_lb_xdp1_local_backend")
   161  int nodeport_geneve_dsr_lb_xdp1_local_backend_check(const struct __ctx_buff *ctx)
   162  {
   163  	void *data, *data_end;
   164  	__u32 *status_code;
   165  	struct tcphdr *l4;
   166  	struct ethhdr *l2;
   167  	struct iphdr *l3;
   168  	__u32 *meta;
   169  
   170  	test_init();
   171  
   172  	data = (void *)(long)ctx_data(ctx);
   173  	data_end = (void *)(long)ctx->data_end;
   174  
   175  	status_code = data;
   176  	if (data + sizeof(__u32) > data_end)
   177  		test_fatal("status code out of bounds");
   178  
   179  	meta = (void *)status_code + sizeof(__u32);
   180  	if ((void *)meta + sizeof(__u32) > data_end)
   181  		test_fatal("meta out of bounds");
   182  
   183  	l2 = (void *)meta + sizeof(__u32);
   184  	if ((void *)l2 + sizeof(struct ethhdr) > data_end)
   185  		test_fatal("l2 out of bounds");
   186  
   187  	l3 = (void *)l2 + sizeof(struct ethhdr);
   188  	if ((void *)l3 + sizeof(struct iphdr) > data_end)
   189  		test_fatal("l3 out of bounds");
   190  
   191  	l4 = (void *)l3 + sizeof(struct iphdr);
   192  	if ((void *)l4 + sizeof(struct tcphdr) > data_end)
   193  		test_fatal("l4 out of bounds");
   194  
   195  	assert(*status_code == CTX_ACT_OK);
   196  
   197  	assert((*meta & XFER_PKT_NO_SVC) == XFER_PKT_NO_SVC);
   198  
   199  	if (memcmp(l2->h_source, (__u8 *)client_mac, ETH_ALEN) != 0)
   200  		test_fatal("src MAC is not the client MAC");
   201  	if (memcmp(l2->h_dest, (__u8 *)lb_mac, ETH_ALEN) != 0)
   202  		test_fatal("dst MAC is not the LB MAC");
   203  
   204  	if (l3->saddr != CLIENT_IP)
   205  		test_fatal("src IP has changed");
   206  
   207  	if (l3->daddr != BACKEND_IP_LOCAL)
   208  		test_fatal("dst IP hasn't been NATed to local backend IP");
   209  
   210  	if (l3->check != bpf_htons(0x4112))
   211  		test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check));
   212  
   213  	if (l4->source != CLIENT_PORT)
   214  		test_fatal("src port has changed");
   215  
   216  	if (l4->dest != BACKEND_PORT)
   217  		test_fatal("dst TCP port hasn't been NATed to backend port");
   218  
   219  	test_finish();
   220  }
   221  
   222  /* Test that a SVC request that is LBed to a DSR remote backend
   223   * - gets DNATed,
   224   * - has tunnel encapsulation header added,
   225   * - has DSR option inserted
   226   */
   227  PKTGEN("xdp", "nodeport_geneve_dsr_lb_xdp2_fwd")
   228  int nodeport_geneve_dsr_lb_xdp2_fwd_pktgen(struct __ctx_buff *ctx)
   229  {
   230  	struct pktgen builder;
   231  	struct tcphdr *l4;
   232  	void *data;
   233  
   234  	/* Init packet builder */
   235  	pktgen__init(&builder, ctx);
   236  
   237  	l4 = pktgen__push_ipv4_tcp_packet(&builder,
   238  					  (__u8 *)client_mac, (__u8 *)lb_mac,
   239  					  CLIENT_IP, FRONTEND_IP_REMOTE,
   240  					  CLIENT_PORT, FRONTEND_PORT);
   241  	if (!l4)
   242  		return TEST_ERROR;
   243  
   244  	data = pktgen__push_data(&builder, default_data, sizeof(default_data));
   245  	if (!data)
   246  		return TEST_ERROR;
   247  
   248  	/* Calc lengths, set protocol fields and calc checksums */
   249  	pktgen__finish(&builder);
   250  
   251  	return 0;
   252  }
   253  
   254  SETUP("xdp", "nodeport_geneve_dsr_lb_xdp2_fwd")
   255  int nodeport_geneve_dsr_lb_xdp2_fwd_setup(struct __ctx_buff *ctx)
   256  {
   257  	__u32 backend_id = 125;
   258  	__u16 revnat_id = 2;
   259  
   260  	lb_v4_add_service(FRONTEND_IP_REMOTE, FRONTEND_PORT, 1, revnat_id);
   261  	lb_v4_add_backend(FRONTEND_IP_REMOTE, FRONTEND_PORT, 1, backend_id,
   262  			  BACKEND_IP_REMOTE, BACKEND_PORT, IPPROTO_TCP, 0);
   263  
   264  	ipcache_v4_add_entry(BACKEND_IP_REMOTE, 0, 112233, BACKEND_NODE_IP, 0);
   265  
   266  	/* Jump into the entrypoint */
   267  	tail_call_static(ctx, entry_call_map, FROM_NETDEV);
   268  	/* Fail if we didn't jump */
   269  	return TEST_ERROR;
   270  }
   271  
   272  CHECK("xdp", "nodeport_geneve_dsr_lb_xdp2_fwd")
   273  int nodeport_geneve_dsr_lb_xdp_fwd_check(__maybe_unused const struct __ctx_buff *ctx)
   274  {
   275  	struct geneve_dsr_opt4 *dsr_opt;
   276  	struct ethhdr *l2, *inner_l2;
   277  	struct iphdr *l3, *inner_l3;
   278  	struct tcphdr *tcp_inner;
   279  	struct genevehdr *geneve;
   280  	void *data, *data_end;
   281  	__u32 *status_code;
   282  	struct udphdr *udp;
   283  
   284  	test_init();
   285  
   286  	data = (void *)(long)ctx_data(ctx);
   287  	data_end = (void *)(long)ctx->data_end;
   288  
   289  	if (data + sizeof(__u32) > data_end)
   290  		test_fatal("status code out of bounds");
   291  
   292  	status_code = data;
   293  
   294  	assert(*status_code == CTX_ACT_REDIRECT);
   295  
   296  	l2 = data + sizeof(__u32);
   297  	if ((void *)l2 + sizeof(*l2) > data_end)
   298  		test_fatal("l2 out of bounds");
   299  
   300  	l3 = (void *)l2 + sizeof(*l2);
   301  	if ((void *)l3 + sizeof(*l3) > data_end)
   302  		test_fatal("l3 out of bounds");
   303  
   304  	udp = (void *)l3 + sizeof(*l3);
   305  	if ((void *)udp + sizeof(*udp) > data_end)
   306  		test_fatal("udp out of bounds");
   307  
   308  	geneve = (void *)udp + sizeof(*udp);
   309  	if ((void *)geneve + sizeof(*geneve) > data_end)
   310  		test_fatal("geneve out of bounds");
   311  
   312  	dsr_opt = (void *)geneve + sizeof(*geneve);
   313  	if ((void *)dsr_opt + sizeof(*dsr_opt) > data_end)
   314  		test_fatal("dsr opt out of bounds");
   315  	if ((void *)dsr_opt + geneve->opt_len * 4 > data_end)
   316  		test_fatal("geneve opts out of bounds");
   317  
   318  	inner_l2 = (void *)dsr_opt + geneve->opt_len * 4;
   319  	if ((void *)inner_l2 + sizeof(*inner_l2) > data_end)
   320  		test_fatal("l2 out of bounds");
   321  
   322  	inner_l3 = (void *)inner_l2 + sizeof(*inner_l2);
   323  	if ((void *)inner_l3 + sizeof(*inner_l3) > data_end)
   324  		test_fatal("l3 out of bounds");
   325  
   326  	tcp_inner = (void *)inner_l3 + sizeof(*inner_l3);
   327  	if ((void *)tcp_inner + sizeof(*tcp_inner) > data_end)
   328  		test_fatal("tcp out of bounds");
   329  
   330  	if (memcmp(l2->h_source, (__u8 *)lb_mac, ETH_ALEN) != 0)
   331  		test_fatal("src MAC is not the LB MAC");
   332  	if (memcmp(l2->h_dest, (__u8 *)backend_node_mac, ETH_ALEN) != 0)
   333  		test_fatal("dst MAC is not the backend node MAC");
   334  
   335  	if (l2->h_proto != bpf_htons(ETH_P_IP))
   336  		test_fatal("l2 doesn't have correct proto type");
   337  
   338  	if (l3->protocol != IPPROTO_UDP)
   339  		test_fatal("outer IP doesn't have correct L4 protocol");
   340  
   341  	if (l3->saddr != IPV4_DIRECT_ROUTING)
   342  		test_fatal("outerSrcIP is not correct");
   343  
   344  	if (l3->daddr != BACKEND_NODE_IP)
   345  		test_fatal("outerDstIP is not correct");
   346  
   347  	if (l3->check != bpf_htons(0x5371))
   348  		test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check));
   349  
   350  	if (udp->dest != bpf_htons(TUNNEL_PORT))
   351  		test_fatal("outerDstPort is not tunnel port");
   352  
   353  	__be32 sec_id;
   354  
   355  	memcpy(&sec_id, &geneve->vni, 4);
   356  	if (tunnel_vni_to_sec_identity(sec_id) != WORLD_ID)
   357  		test_fatal("geneve has unexpected SrcSecID");
   358  
   359  	if (geneve->opt_len * 4 != sizeof(*dsr_opt))
   360  		test_fatal("geneve has unexpected opt length");
   361  
   362  	if (dsr_opt->hdr.opt_class != bpf_htons(DSR_GENEVE_OPT_CLASS))
   363  		test_fatal("geneve opt has unexpected class");
   364  	if (dsr_opt->hdr.type != DSR_GENEVE_OPT_TYPE)
   365  		test_fatal("geneve opt has unexpected type");
   366  	if (dsr_opt->hdr.length != DSR_IPV4_GENEVE_OPT_LEN)
   367  		test_fatal("geneve opt has unexpected length");
   368  	if (dsr_opt->addr != FRONTEND_IP_REMOTE)
   369  		test_fatal("geneve opt has unexpected svc IP");
   370  	if (dsr_opt->port != FRONTEND_PORT)
   371  		test_fatal("geneve opt has unexpected svc port");
   372  
   373  	if (inner_l2->h_proto != bpf_htons(ETH_P_IP))
   374  		test_fatal("inner l2 doesn't have correct proto type");
   375  
   376  	if (inner_l3->protocol != IPPROTO_TCP)
   377  		test_fatal("inner IP doesn't have correct L4 protocol");
   378  
   379  	if (inner_l3->saddr != CLIENT_IP)
   380  		test_fatal("innerSrcIP has changed");
   381  
   382  	if (inner_l3->daddr != BACKEND_IP_REMOTE)
   383  		test_fatal("innerDstIP hasn't been NATed to remote backend IP");
   384  
   385  	if (inner_l3->check != bpf_htons(0x4111))
   386  		test_fatal("L3 checksum is invalid: %d", bpf_htons(inner_l3->check));
   387  
   388  	if (tcp_inner->source != CLIENT_PORT)
   389  		test_fatal("innerSrcPort has changed");
   390  
   391  	if (tcp_inner->dest != BACKEND_PORT)
   392  		test_fatal("innerDstPort hasn't been NATed to backend port");
   393  
   394  	test_finish();
   395  }