github.com/cilium/cilium@v1.16.2/bpf/tests/inter_cluster_snat_clusterip_client_overlay.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/compiler.h" 7 #include <bpf/ctx/skb.h> 8 #include "mock_skb_metadata.h" 9 #include "pktgen.h" 10 11 /* 12 * Datapath configurations 13 */ 14 15 /* Set dummy ifindex for tunnel device */ 16 #define ENCAP_IFINDEX 1 17 18 /* Overlapping PodCIDR is only supported for IPv4 for now */ 19 #define ENABLE_IPV4 20 21 /* Overlapping PodCIDR depends on tunnel */ 22 #define TUNNEL_MODE 23 24 /* Fully enable KPR since kubeproxy doesn't understand cluster aware addressing */ 25 #define ENABLE_NODEPORT 26 27 /* Cluster-aware addressing is mandatory for overlapping PodCIDR support */ 28 #define ENABLE_CLUSTER_AWARE_ADDRESSING 29 30 /* Inter-cluster SNAT is mandatory for overlapping PodCIDR support for now */ 31 #define ENABLE_INTER_CLUSTER_SNAT 32 33 /* Import map definitions and some default values */ 34 #include "node_config.h" 35 36 /* Overwrite the default port range defined in node_config.h 37 * to have deterministic source port selection. 38 */ 39 #undef NODEPORT_PORT_MAX 40 #undef NODEPORT_PORT_MIN_NAT 41 #undef NODEPORT_PORT_MAX_NAT 42 #define NODEPORT_PORT_MAX 32767 43 #define NODEPORT_PORT_MIN_NAT (NODEPORT_PORT_MAX + 1) 44 #define NODEPORT_PORT_MAX_NAT (NODEPORT_PORT_MIN_NAT + 1) 45 46 /* Overwrite (local) CLUSTER_ID defined in node_config.h */ 47 #undef CLUSTER_ID 48 #define CLUSTER_ID 1 49 50 /* 51 * Test configurations 52 */ 53 #define CLIENT_IFINDEX 12345 54 #define CLIENT_MAC mac_one 55 #define CLIENT_ROUTER_MAC mac_two 56 #define BACKEND_ROUTER_MAC mac_three 57 #define CLIENT_IP v4_pod_one 58 #define BACKEND_IP v4_pod_two 59 #define CLIENT_NODE_IP v4_ext_one 60 #define BACKEND_NODE_IP v4_ext_two 61 #define CLIENT_PORT __bpf_htons(NODEPORT_PORT_MAX_NAT + 1) 62 #define BACKEND_PORT tcp_svc_one 63 #define BACKEND_CLUSTER_ID 2 64 #define BACKEND_IDENTITY (0x00000000 | (BACKEND_CLUSTER_ID << 16) | 0xff01) 65 66 #undef IPV4_INTER_CLUSTER_SNAT 67 #define IPV4_INTER_CLUSTER_SNAT CLIENT_NODE_IP 68 69 /* SNAT should always select NODEPORT_PORT_MIN_NAT as a source */ 70 #define CLIENT_INTER_CLUSTER_SNAT_PORT __bpf_htons(NODEPORT_PORT_MIN_NAT) 71 72 /* Mock out get_tunnel_key to emulate input from tunnel device */ 73 #define skb_get_tunnel_key mock_skb_get_tunnel_key 74 75 static __always_inline 76 int mock_skb_get_tunnel_key(struct __ctx_buff *ctx __maybe_unused, struct bpf_tunnel_key *to, 77 __u32 size __maybe_unused, __u32 flags __maybe_unused) 78 { 79 to->remote_ipv4 = BACKEND_NODE_IP; 80 to->tunnel_id = BACKEND_IDENTITY; 81 return 0; 82 } 83 84 /* 85 * Mock out send_drop_notify. This is because it uses ctx_store_meta internally 86 * and breaks the skb->cb test. 87 */ 88 89 #define DEBUG 90 #include <lib/drop.h> 91 92 #define _send_drop_notify mock_send_drop_notify 93 94 static __always_inline 95 int mock_send_drop_notify(__u8 file __maybe_unused, __u16 line __maybe_unused, 96 struct __ctx_buff *ctx, __u32 src __maybe_unused, 97 __u32 dst __maybe_unused, __u32 dst_id __maybe_unused, 98 __u32 reason, __u32 exitcode, enum metric_dir direction) 99 { 100 cilium_dbg3(ctx, DBG_GENERIC, reason, exitcode, direction); 101 return exitcode; 102 } 103 104 /* Include an actual datapath code */ 105 #include <bpf_overlay.c> 106 107 #include "lib/endpoint.h" 108 109 /* 110 * Tests 111 */ 112 113 #define TO_OVERLAY 0 114 #define FROM_OVERLAY 1 115 116 struct { 117 __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 118 __uint(key_size, sizeof(__u32)); 119 __uint(max_entries, 2); 120 __array(values, int()); 121 } entry_call_map __section(".maps") = { 122 .values = { 123 [TO_OVERLAY] = &cil_to_overlay, 124 [FROM_OVERLAY] = &cil_from_overlay, 125 }, 126 }; 127 128 static __always_inline int 129 pktgen_to_overlay(struct __ctx_buff *ctx, bool syn, bool ack) 130 { 131 struct pktgen builder; 132 struct tcphdr *l4; 133 void *data; 134 135 pktgen__init(&builder, ctx); 136 137 l4 = pktgen__push_ipv4_tcp_packet(&builder, 138 (__u8 *)CLIENT_MAC, (__u8 *)CLIENT_ROUTER_MAC, 139 CLIENT_IP, BACKEND_IP, 140 CLIENT_PORT, BACKEND_PORT); 141 if (!l4) 142 return TEST_ERROR; 143 144 l4->syn = syn ? 1 : 0; 145 l4->ack = ack ? 1 : 0; 146 147 data = pktgen__push_data(&builder, default_data, sizeof(default_data)); 148 if (!data) 149 return TEST_ERROR; 150 151 pktgen__finish(&builder); 152 153 return 0; 154 } 155 156 static __always_inline int 157 pktgen_from_overlay(struct __ctx_buff *ctx, bool syn, bool ack) 158 { 159 struct pktgen builder; 160 struct tcphdr *l4; 161 void *data; 162 163 pktgen__init(&builder, ctx); 164 165 l4 = pktgen__push_ipv4_tcp_packet(&builder, 166 (__u8 *)BACKEND_ROUTER_MAC, 167 (__u8 *)CLIENT_ROUTER_MAC, 168 BACKEND_IP, IPV4_INTER_CLUSTER_SNAT, 169 BACKEND_PORT, CLIENT_INTER_CLUSTER_SNAT_PORT); 170 if (!l4) 171 return TEST_ERROR; 172 173 l4->syn = syn ? 1 : 0; 174 l4->ack = ack ? 1 : 0; 175 176 data = pktgen__push_data(&builder, default_data, sizeof(default_data)); 177 if (!data) 178 return TEST_ERROR; 179 180 pktgen__finish(&builder); 181 182 return 0; 183 } 184 185 PKTGEN("tc", "01_to_overlay_syn") 186 int to_overlay_syn_pktgen(struct __ctx_buff *ctx) 187 { 188 return pktgen_to_overlay(ctx, true, false); 189 } 190 191 SETUP("tc", "01_to_overlay_syn") 192 int to_overlay_syn_setup(struct __ctx_buff *ctx) 193 { 194 /* Emulate input from bpf_lxc */ 195 ctx_set_cluster_id_mark(ctx, 2); 196 197 tail_call_static(ctx, entry_call_map, TO_OVERLAY); 198 return TEST_ERROR; 199 } 200 201 CHECK("tc", "01_to_overlay_syn") 202 int to_overlay_syn_check(struct __ctx_buff *ctx) 203 { 204 void *data, *data_end; 205 __s32 *status_code; 206 struct tcphdr *l4; 207 struct ethhdr *l2; 208 struct iphdr *l3; 209 struct ipv4_ct_tuple tuple; 210 struct ipv4_nat_entry *entry; 211 212 test_init(); 213 214 data = (void *)(long)ctx_data(ctx); 215 data_end = (void *)(long)ctx->data_end; 216 217 if (data + sizeof(__u32) > data_end) 218 test_fatal("status code out of bounds"); 219 220 status_code = data; 221 222 if (*status_code != CTX_ACT_OK) 223 test_fatal("unexpected status code %d, want %d", *status_code, CTX_ACT_OK); 224 225 l2 = data + sizeof(__u32); 226 if ((void *)l2 + sizeof(struct ethhdr) > data_end) 227 test_fatal("l2 out of bounds"); 228 229 l3 = (void *)l2 + sizeof(struct ethhdr); 230 if ((void *)l3 + sizeof(struct iphdr) > data_end) 231 test_fatal("l3 out of bounds"); 232 233 l4 = (void *)l3 + sizeof(struct iphdr); 234 if ((void *)l4 + sizeof(struct tcphdr) > data_end) 235 test_fatal("l4 out of bounds"); 236 237 if (memcmp(l2->h_source, (__u8 *)CLIENT_MAC, ETH_ALEN) != 0) 238 test_fatal("src MAC has changed") 239 240 if (memcmp(l2->h_dest, (__u8 *)CLIENT_ROUTER_MAC, ETH_ALEN) != 0) 241 test_fatal("dst MAC has changed") 242 243 if (l3->saddr != IPV4_INTER_CLUSTER_SNAT) 244 test_fatal("src IP hasn't been SNATed for inter-cluster communication"); 245 246 if (l3->daddr != BACKEND_IP) 247 test_fatal("dst IP has changed"); 248 249 if (l3->check != bpf_htons(0x4111)) 250 test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check)); 251 252 if (l4->source != CLIENT_INTER_CLUSTER_SNAT_PORT) 253 test_fatal("src port hasn't been SNATed for inter-cluster communication"); 254 255 if (l4->dest != BACKEND_PORT) 256 test_fatal("dst port has changed"); 257 258 tuple.daddr = BACKEND_IP; 259 tuple.saddr = CLIENT_IP; 260 tuple.dport = BACKEND_PORT; 261 tuple.sport = CLIENT_PORT; 262 tuple.nexthdr = IPPROTO_TCP; 263 tuple.flags = TUPLE_F_OUT; 264 265 entry = map_lookup_elem(&per_cluster_snat_mapping_ipv4_2, &tuple); 266 if (!entry) 267 test_fatal("couldn't find egress SNAT mapping"); 268 269 tuple.daddr = IPV4_INTER_CLUSTER_SNAT; 270 tuple.saddr = BACKEND_IP; 271 tuple.dport = CLIENT_INTER_CLUSTER_SNAT_PORT; 272 tuple.sport = BACKEND_PORT; 273 tuple.nexthdr = IPPROTO_TCP; 274 tuple.flags = TUPLE_F_IN; 275 276 entry = map_lookup_elem(&per_cluster_snat_mapping_ipv4_2, &tuple); 277 if (!entry) 278 test_fatal("couldn't find ingress SNAT mapping"); 279 280 test_finish(); 281 } 282 283 PKTGEN("tc", "02_from_overlay_synack") 284 int from_overlay_synack_pktgen(struct __ctx_buff *ctx) 285 { 286 return pktgen_from_overlay(ctx, true, true); 287 } 288 289 SETUP("tc", "02_from_overlay_synack") 290 int from_overlay_synack_setup(struct __ctx_buff *ctx) 291 { 292 endpoint_v4_add_entry(CLIENT_IP, CLIENT_IFINDEX, 0, 0, 0, 293 (__u8 *)CLIENT_MAC, (__u8 *)CLIENT_ROUTER_MAC); 294 295 tail_call_static(ctx, entry_call_map, FROM_OVERLAY); 296 return TEST_ERROR; 297 } 298 299 CHECK("tc", "02_from_overlay_synack") 300 int from_overlay_synack_check(struct __ctx_buff *ctx) 301 { 302 void *data, *data_end; 303 __s32 *status_code; 304 struct tcphdr *l4; 305 struct ethhdr *l2; 306 struct iphdr *l3; 307 __u32 meta; 308 309 test_init(); 310 311 data = (void *)(long)ctx_data(ctx); 312 data_end = (void *)(long)ctx->data_end; 313 314 if (data + sizeof(__u32) > data_end) 315 test_fatal("status code out of bounds"); 316 317 status_code = data; 318 319 /* The packet should go to ipv4_local_delivery and dropped with 320 * missed tail call since the POLICY_CALL_MAP should be empty. 321 */ 322 if (*status_code != CTX_ACT_DROP) 323 test_fatal("unexpected status code %d, want %d", *status_code, CTX_ACT_DROP); 324 325 l2 = data + sizeof(__u32); 326 if ((void *)l2 + sizeof(struct ethhdr) > data_end) 327 test_fatal("l2 out of bounds"); 328 329 l3 = (void *)l2 + sizeof(struct ethhdr); 330 if ((void *)l3 + sizeof(struct iphdr) > data_end) 331 test_fatal("l3 out of bounds"); 332 333 l4 = (void *)l3 + sizeof(struct iphdr); 334 if ((void *)l4 + sizeof(struct tcphdr) > data_end) 335 test_fatal("l4 out of bounds"); 336 337 if (memcmp(l2->h_source, (__u8 *)CLIENT_ROUTER_MAC, ETH_ALEN) != 0) 338 test_fatal("src MAC is not client router MAC"); 339 340 if (memcmp(l2->h_dest, (__u8 *)CLIENT_MAC, ETH_ALEN) != 0) 341 test_fatal("dst MAC is not client MAC"); 342 343 if (l3->saddr != BACKEND_IP) 344 test_fatal("src IP has changed"); 345 346 if (l3->daddr != CLIENT_IP) 347 test_fatal("dst IP hasn't been RevSNATed to client IP"); 348 349 if (l3->check != bpf_htons(0xfa68)) 350 test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check)); 351 352 if (l4->source != BACKEND_PORT) 353 test_fatal("src port has changed"); 354 355 if (l4->dest != CLIENT_PORT) 356 test_fatal("dst port hasn't been RevSNATed to client port"); 357 358 meta = ctx_load_meta(ctx, CB_IFINDEX); 359 if (meta != CLIENT_IFINDEX) 360 test_fatal("skb->cb[CB_IFINDEX] should be %d, got %d", CLIENT_IFINDEX, meta); 361 362 meta = ctx_load_meta(ctx, CB_SRC_LABEL); 363 if (meta != BACKEND_IDENTITY) 364 test_fatal("skb->cb[CB_SRC_LABEL] should be %d, got %d", BACKEND_IDENTITY, meta); 365 366 meta = ctx_load_meta(ctx, CB_FROM_TUNNEL); 367 if (meta != 1) 368 test_fatal("skb->cb[CB_FROM_TUNNEL] should be 1, got %d", meta); 369 370 meta = ctx_load_meta(ctx, CB_FROM_HOST); 371 if (meta != 0) 372 test_fatal("skb->cb[CB_FROM_HOST] should be 0, got %d", meta); 373 374 meta = ctx_load_meta(ctx, CB_CLUSTER_ID_INGRESS); 375 if (meta != BACKEND_CLUSTER_ID) 376 test_fatal("skb->cb[CB_CLUSTER_ID_INGRESS] should be %u, got %d", 377 BACKEND_CLUSTER_ID, meta); 378 379 test_finish(); 380 } 381 382 PKTGEN("tc", "03_to_overlay_ack") 383 int to_overlay_ack_pktgen(struct __ctx_buff *ctx) 384 { 385 return pktgen_to_overlay(ctx, false, true); 386 } 387 388 SETUP("tc", "03_to_overlay_ack") 389 int to_overlay_ack_setup(struct __ctx_buff *ctx) 390 { 391 /* Emulate input from bpf_lxc */ 392 ctx_set_cluster_id_mark(ctx, 2); 393 394 tail_call_static(ctx, entry_call_map, TO_OVERLAY); 395 return TEST_ERROR; 396 } 397 398 CHECK("tc", "03_to_overlay_ack") 399 int to_overlay_ack_check(struct __ctx_buff *ctx) 400 { 401 void *data, *data_end; 402 __s32 *status_code; 403 struct tcphdr *l4; 404 struct ethhdr *l2; 405 struct iphdr *l3; 406 407 test_init(); 408 409 data = (void *)(long)ctx_data(ctx); 410 data_end = (void *)(long)ctx->data_end; 411 412 if (data + sizeof(__u32) > data_end) 413 test_fatal("status code out of bounds"); 414 415 status_code = data; 416 417 if (*status_code != CTX_ACT_OK) 418 test_fatal("unexpected status code %d, want %d", *status_code, CTX_ACT_OK); 419 420 l2 = data + sizeof(__u32); 421 if ((void *)l2 + sizeof(struct ethhdr) > data_end) 422 test_fatal("l2 out of bounds"); 423 424 l3 = (void *)l2 + sizeof(struct ethhdr); 425 if ((void *)l3 + sizeof(struct iphdr) > data_end) 426 test_fatal("l3 out of bounds"); 427 428 l4 = (void *)l3 + sizeof(struct iphdr); 429 if ((void *)l4 + sizeof(struct tcphdr) > data_end) 430 test_fatal("l4 out of bounds"); 431 432 if (memcmp(l2->h_source, (__u8 *)CLIENT_MAC, ETH_ALEN) != 0) 433 test_fatal("src MAC has changed"); 434 435 if (memcmp(l2->h_dest, (__u8 *)CLIENT_ROUTER_MAC, ETH_ALEN) != 0) 436 test_fatal("dst MAC has changed"); 437 438 if (l3->saddr != IPV4_INTER_CLUSTER_SNAT) 439 test_fatal("src IP hasn't been SNATed for inter-cluster communication"); 440 441 if (l3->daddr != BACKEND_IP) 442 test_fatal("dst IP has changed"); 443 444 if (l3->check != bpf_htons(0x4111)) 445 test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check)); 446 447 if (l4->source != CLIENT_INTER_CLUSTER_SNAT_PORT) 448 test_fatal("src port hasn't been SNATed for inter-cluster communication"); 449 450 if (l4->dest != BACKEND_PORT) 451 test_fatal("dst port has changed"); 452 453 test_finish(); 454 }