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(¶ms->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 }