github.com/cilium/cilium@v1.16.2/bpf/tests/inter_cluster_snat_clusterip_backend_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/ctx/skb.h> 7 #include "linux/if_ether.h" 8 #include "pktgen.h" 9 #include "mock_skb_metadata.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 BACKEND_IFINDEX 12345 54 #define BACKEND_MAC mac_one 55 #define BACKEND_ROUTER_MAC mac_two 56 #define CLIENT_ROUTER_MAC mac_three 57 #define BACKEND_IP v4_pod_one 58 #define CLIENT_NODE_IP v4_ext_one 59 #define BACKEND_NODE_IP v4_ext_two 60 #define BACKEND_PORT tcp_svc_one 61 #define CLIENT_CLUSTER_ID 1 62 #define CLIENT_IDENTITY (0x00000000 | (CLIENT_CLUSTER_ID << 16) | 0xff01) 63 64 #undef IPV4_INTER_CLUSTER_SNAT 65 #define IPV4_INTER_CLUSTER_SNAT BACKEND_NODE_IP 66 67 /* SNAT should always select NODEPORT_PORT_MIN_NAT as a source */ 68 #define CLIENT_INTER_CLUSTER_SNAT_PORT __bpf_htons(NODEPORT_PORT_MIN_NAT) 69 70 /* Mock out get_tunnel_key to emulate input from tunnel device */ 71 #define skb_get_tunnel_key mock_skb_get_tunnel_key 72 73 int mock_skb_get_tunnel_key(struct __ctx_buff *ctx __maybe_unused, struct bpf_tunnel_key *to, 74 __u32 size __maybe_unused, __u32 flags __maybe_unused) 75 { 76 to->remote_ipv4 = CLIENT_NODE_IP; 77 to->tunnel_id = CLIENT_IDENTITY; 78 return 0; 79 } 80 81 /* 82 * Mock out send_drop_notify. This is because it uses ctx_store_meta internally 83 * and breaks the skb->cb test. 84 */ 85 86 #define DEBUG 87 #include <lib/drop.h> 88 89 #define _send_drop_notify mock_send_drop_notify 90 91 static __always_inline 92 int mock_send_drop_notify(__u8 file __maybe_unused, __u16 line __maybe_unused, 93 struct __ctx_buff *ctx, __u32 src __maybe_unused, 94 __u32 dst __maybe_unused, __u32 dst_id __maybe_unused, 95 __u32 reason, __u32 exitcode, enum metric_dir direction) 96 { 97 cilium_dbg3(ctx, DBG_GENERIC, reason, exitcode, direction); 98 return exitcode; 99 } 100 101 /* Include an actual datapath code */ 102 #include <bpf_overlay.c> 103 104 #include "lib/endpoint.h" 105 106 /* 107 * Tests 108 */ 109 110 #define TO_OVERLAY 0 111 #define FROM_OVERLAY 1 112 113 struct { 114 __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 115 __uint(key_size, sizeof(__u32)); 116 __uint(max_entries, 2); 117 __array(values, int()); 118 } entry_call_map __section(".maps") = { 119 .values = { 120 [TO_OVERLAY] = &cil_to_overlay, 121 [FROM_OVERLAY] = &cil_from_overlay, 122 }, 123 }; 124 125 static __always_inline int 126 pktgen_to_overlay(struct __ctx_buff *ctx, bool syn, bool ack) 127 { 128 struct pktgen builder; 129 struct tcphdr *l4; 130 void *data; 131 132 pktgen__init(&builder, ctx); 133 134 l4 = pktgen__push_ipv4_tcp_packet(&builder, 135 (__u8 *)BACKEND_MAC, 136 (__u8 *)BACKEND_ROUTER_MAC, 137 BACKEND_IP, CLIENT_NODE_IP, 138 BACKEND_PORT, CLIENT_INTER_CLUSTER_SNAT_PORT); 139 if (!l4) 140 return TEST_ERROR; 141 142 l4->syn = syn ? 1 : 0; 143 l4->ack = ack ? 1 : 0; 144 145 data = pktgen__push_data(&builder, default_data, sizeof(default_data)); 146 if (!data) 147 return TEST_ERROR; 148 149 pktgen__finish(&builder); 150 151 return 0; 152 } 153 154 static __always_inline int 155 pktgen_from_overlay(struct __ctx_buff *ctx, bool syn, bool ack) 156 { 157 struct pktgen builder; 158 struct tcphdr *l4; 159 void *data; 160 161 pktgen__init(&builder, ctx); 162 163 l4 = pktgen__push_ipv4_tcp_packet(&builder, 164 (__u8 *)CLIENT_ROUTER_MAC, 165 (__u8 *)BACKEND_ROUTER_MAC, 166 CLIENT_NODE_IP, BACKEND_IP, 167 CLIENT_INTER_CLUSTER_SNAT_PORT, BACKEND_PORT); 168 if (!l4) 169 return TEST_ERROR; 170 171 l4->syn = syn ? 1 : 0; 172 l4->ack = ack ? 1 : 0; 173 174 data = pktgen__push_data(&builder, default_data, sizeof(default_data)); 175 if (!data) 176 return TEST_ERROR; 177 178 pktgen__finish(&builder); 179 180 return 0; 181 } 182 183 PKTGEN("tc", "01_from_overlay_syn") 184 int from_overlay_syn_pktgen(struct __ctx_buff *ctx) 185 { 186 /* Emulate input from bpf_lxc */ 187 ctx_set_cluster_id_mark(ctx, 0); 188 189 return pktgen_from_overlay(ctx, true, false); 190 } 191 192 SETUP("tc", "01_from_overlay_syn") 193 int from_overlay_syn_setup(struct __ctx_buff *ctx) 194 { 195 endpoint_v4_add_entry(BACKEND_IP, BACKEND_IFINDEX, 0, 0, 0, 196 (__u8 *)BACKEND_MAC, (__u8 *)BACKEND_ROUTER_MAC); 197 198 tail_call_static(ctx, entry_call_map, FROM_OVERLAY); 199 return TEST_ERROR; 200 } 201 202 CHECK("tc", "01_from_overlay_syn") 203 int from_overlay_syn_check(struct __ctx_buff *ctx) 204 { 205 void *data, *data_end; 206 __s32 *status_code; 207 struct tcphdr *l4; 208 struct ethhdr *l2; 209 struct iphdr *l3; 210 __u32 meta; 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 /* The packet should go to ipv4_local_delivery and dropped with 223 * missed tail call since the POLICY_CALL_MAP should be empty. 224 */ 225 if (*status_code != CTX_ACT_DROP) 226 test_fatal("unexpected status code %d, want %d", *status_code, CTX_ACT_OK); 227 228 l2 = data + sizeof(__u32); 229 if ((void *)l2 + sizeof(struct ethhdr) > data_end) 230 test_fatal("l2 out of bounds"); 231 232 l3 = (void *)l2 + sizeof(struct ethhdr); 233 if ((void *)l3 + sizeof(struct iphdr) > data_end) 234 test_fatal("l3 out of bounds"); 235 236 l4 = (void *)l3 + sizeof(struct iphdr); 237 if ((void *)l4 + sizeof(struct tcphdr) > data_end) 238 test_fatal("l4 out of bounds"); 239 240 if (memcmp(l2->h_source, (__u8 *)BACKEND_ROUTER_MAC, ETH_ALEN) != 0) 241 test_fatal("src MAC is not the backend router MAC") 242 243 if (memcmp(l2->h_dest, (__u8 *)BACKEND_MAC, ETH_ALEN) != 0) 244 test_fatal("dst MAC is not the backend MAC") 245 246 if (l3->saddr != CLIENT_NODE_IP) 247 test_fatal("src IP has changed"); 248 249 if (l3->daddr != BACKEND_IP) 250 test_fatal("dst IP has changed"); 251 252 if (l3->check != bpf_htons(0x4212)) 253 test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check)); 254 255 if (l4->source != CLIENT_INTER_CLUSTER_SNAT_PORT) 256 test_fatal("src port has changed"); 257 258 if (l4->dest != BACKEND_PORT) 259 test_fatal("dst port has changed"); 260 261 meta = ctx_load_meta(ctx, CB_IFINDEX); 262 if (meta != BACKEND_IFINDEX) 263 test_fatal("skb->cb[CB_IFINDEX] should be %d, got %d", BACKEND_IFINDEX, meta); 264 265 meta = ctx_load_meta(ctx, CB_SRC_LABEL); 266 if (meta != CLIENT_IDENTITY) 267 test_fatal("skb->cb[CB_SRC_LABEL] should be %d, got %d", CLIENT_IDENTITY, meta); 268 269 meta = ctx_load_meta(ctx, CB_FROM_TUNNEL); 270 if (meta != 1) 271 test_fatal("skb->cb[CB_FROM_TUNNEL] should be 1, got %d", meta); 272 273 meta = ctx_load_meta(ctx, CB_FROM_HOST); 274 if (meta != 0) 275 test_fatal("skb->cb[CB_FROM_HOST] should be 0, got %d", meta); 276 277 meta = ctx_load_meta(ctx, CB_CLUSTER_ID_INGRESS); 278 if (meta != 0) 279 test_fatal("skb->cb[CB_CLUSTER_ID_INGRESS] should be 0, got %d", meta); 280 281 test_finish(); 282 } 283 284 PKTGEN("tc", "02_to_overlay_synack") 285 int to_overlay_synack_pktgen(struct __ctx_buff *ctx) 286 { 287 return pktgen_to_overlay(ctx, true, true); 288 } 289 290 SETUP("tc", "02_to_overlay_synack") 291 int to_overlay_synack_setup(struct __ctx_buff *ctx) 292 { 293 tail_call_static(ctx, entry_call_map, TO_OVERLAY); 294 return TEST_ERROR; 295 } 296 297 CHECK("tc", "02_to_overlay_synack") 298 int to_overlay_synack_check(struct __ctx_buff *ctx) 299 { 300 void *data, *data_end; 301 __s32 *status_code; 302 struct tcphdr *l4; 303 struct ethhdr *l2; 304 struct iphdr *l3; 305 306 test_init(); 307 308 data = (void *)(long)ctx_data(ctx); 309 data_end = (void *)(long)ctx->data_end; 310 311 if (data + sizeof(__u32) > data_end) 312 test_fatal("status code out of bounds"); 313 314 status_code = data; 315 316 if (*status_code != CTX_ACT_OK) 317 test_fatal("unexpected status code %d, want %d", *status_code, CTX_ACT_OK); 318 319 l2 = data + sizeof(__u32); 320 if ((void *)l2 + sizeof(struct ethhdr) > data_end) 321 test_fatal("l2 out of bounds"); 322 323 l3 = (void *)l2 + sizeof(struct ethhdr); 324 if ((void *)l3 + sizeof(struct iphdr) > data_end) 325 test_fatal("l3 out of bounds"); 326 327 l4 = (void *)l3 + sizeof(struct iphdr); 328 if ((void *)l4 + sizeof(struct tcphdr) > data_end) 329 test_fatal("l4 out of bounds"); 330 331 if (memcmp(l2->h_source, (__u8 *)BACKEND_MAC, ETH_ALEN) != 0) 332 test_fatal("src MAC has changed") 333 334 if (memcmp(l2->h_dest, (__u8 *)BACKEND_ROUTER_MAC, ETH_ALEN) != 0) 335 test_fatal("dst MAC has changed") 336 337 if (l3->saddr != BACKEND_IP) 338 test_fatal("src IP has changed"); 339 340 if (l3->daddr != CLIENT_NODE_IP) 341 test_fatal("dst IP has changed"); 342 343 if (l3->check != bpf_htons(0x4112)) 344 test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check)); 345 346 if (l4->source != BACKEND_PORT) 347 test_fatal("src port has changed"); 348 349 if (l4->dest != CLIENT_INTER_CLUSTER_SNAT_PORT) 350 test_fatal("dst port has changed"); 351 352 test_finish(); 353 } 354 355 PKTGEN("tc", "03_from_overlay_ack") 356 int from_overlay_ack_pktgen(struct __ctx_buff *ctx) 357 { 358 return pktgen_from_overlay(ctx, false, true); 359 } 360 361 SETUP("tc", "03_from_overlay_ack") 362 int from_overlay_ack_setup(struct __ctx_buff *ctx) 363 { 364 tail_call_static(ctx, entry_call_map, FROM_OVERLAY); 365 return TEST_ERROR; 366 } 367 368 CHECK("tc", "03_from_overlay_ack") 369 int from_overlay_ack_check(struct __ctx_buff *ctx) 370 { 371 void *data, *data_end; 372 __s32 *status_code; 373 struct tcphdr *l4; 374 struct ethhdr *l2; 375 struct iphdr *l3; 376 __u32 meta; 377 378 test_init(); 379 380 data = (void *)(long)ctx_data(ctx); 381 data_end = (void *)(long)ctx->data_end; 382 383 if (data + sizeof(__u32) > data_end) 384 test_fatal("status code out of bounds"); 385 386 status_code = data; 387 388 if (*status_code != CTX_ACT_DROP) 389 test_fatal("unexpected status code %d, want %d", *status_code, CTX_ACT_DROP); 390 391 l2 = data + sizeof(__u32); 392 if ((void *)l2 + sizeof(struct ethhdr) > data_end) 393 test_fatal("l2 out of bounds"); 394 395 l3 = (void *)l2 + sizeof(struct ethhdr); 396 if ((void *)l3 + sizeof(struct iphdr) > data_end) 397 test_fatal("l3 out of bounds"); 398 399 l4 = (void *)l3 + sizeof(struct iphdr); 400 if ((void *)l4 + sizeof(struct tcphdr) > data_end) 401 test_fatal("l4 out of bounds"); 402 403 if (memcmp(l2->h_source, (__u8 *)BACKEND_ROUTER_MAC, ETH_ALEN) != 0) 404 test_fatal("src MAC is not the backend router MAC") 405 406 if (memcmp(l2->h_dest, (__u8 *)BACKEND_MAC, ETH_ALEN) != 0) 407 test_fatal("dst MAC is not the backend MAC") 408 409 if (l3->saddr != CLIENT_NODE_IP) 410 test_fatal("src IP has changed"); 411 412 if (l3->daddr != BACKEND_IP) 413 test_fatal("dst IP has changed"); 414 415 if (l3->check != bpf_htons(0x4212)) 416 test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check)); 417 418 if (l4->source != CLIENT_INTER_CLUSTER_SNAT_PORT) 419 test_fatal("src port has changed"); 420 421 if (l4->dest != BACKEND_PORT) 422 test_fatal("dst port has changed"); 423 424 meta = ctx_load_meta(ctx, CB_IFINDEX); 425 if (meta != BACKEND_IFINDEX) 426 test_fatal("skb->cb[CB_IFINDEX] should be %d, got %d", BACKEND_IFINDEX, meta); 427 428 meta = ctx_load_meta(ctx, CB_SRC_LABEL); 429 if (meta != CLIENT_IDENTITY) 430 test_fatal("skb->cb[CB_SRC_LABEL] should be %d, got %d", CLIENT_IDENTITY, meta); 431 432 meta = ctx_load_meta(ctx, CB_FROM_TUNNEL); 433 if (meta != 1) 434 test_fatal("skb->cb[CB_FROM_TUNNEL] should be 1, got %d", meta); 435 436 meta = ctx_load_meta(ctx, CB_FROM_HOST); 437 if (meta != 0) 438 test_fatal("skb->cb[CB_FROM_HOST] should be 0, got %d", meta); 439 440 meta = ctx_load_meta(ctx, CB_CLUSTER_ID_INGRESS); 441 if (meta != 0) 442 test_fatal("skb->cb[CB_CLUSTER_ID_INGRESS] should be 0, got %d", meta); 443 444 test_finish(); 445 }