github.com/cilium/cilium@v1.16.2/bpf/tests/hairpin_sctp_flow.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 /* Set the LXC source address to be the address of pod one */ 7 #define LXC_IPV4 (__be32)v4_pod_one 8 9 /* Enable CT debug output */ 10 #undef QUIET_CT 11 12 #include <bpf/ctx/skb.h> 13 #include "pktgen.h" 14 15 /* Set ETH_HLEN to 14 to indicate that the packet has a 14 byte ethernet header */ 16 #define ETH_HLEN 14 17 18 /* Enable code paths under test*/ 19 #define ENABLE_IPV4 20 #define ENABLE_SCTP 21 22 /* Use to-container for ingress policy: */ 23 #define USE_BPF_PROG_FOR_INGRESS_POLICY 24 #undef FORCE_LOCAL_POLICY_EVAL_AT_SOURCE 25 26 #define ctx_redirect_peer mock_ctx_redirect_peer 27 static __always_inline __maybe_unused int 28 mock_ctx_redirect_peer(const struct __sk_buff *ctx __maybe_unused, int ifindex __maybe_unused, 29 __u32 flags __maybe_unused) 30 { 31 return TC_ACT_REDIRECT; 32 } 33 34 #include <bpf_lxc.c> 35 36 #include "lib/endpoint.h" 37 #include "lib/ipcache.h" 38 #include "lib/lb.h" 39 40 struct { 41 __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 42 __uint(key_size, sizeof(__u32)); 43 __uint(max_entries, 2); 44 __array(values, int()); 45 } entry_call_map __section(".maps") = { 46 .values = { 47 [0] = &cil_from_container, 48 [1] = &cil_to_container, 49 }, 50 }; 51 52 /* Setup for this test: 53 * +-------ClusterIP--------+ +----------Pod 1---------+ 54 * | v4_svc_one:tcp_svc_one | -> | v4_pod_one:tcp_svc_one | 55 * +------------------------+ +------------------------+ 56 * ^ | 57 * \---------------------------/ 58 */ 59 60 /* Test that sending a packet from a pod to its own service gets source nat-ed 61 * and that it is forwarded to the correct veth. 62 */ 63 SETUP("tc", "hairpin_sctp_flow_1_forward_v4") 64 int hairpin_flow_forward_setup(struct __ctx_buff *ctx) 65 { 66 struct pktgen builder; 67 volatile const __u8 *src = mac_one; 68 volatile const __u8 *dst = mac_two; 69 struct iphdr *l3; 70 struct sctphdr *l4; 71 __u16 revnat_id = 1; 72 73 /* Init packet builder */ 74 pktgen__init(&builder, ctx); 75 76 l3 = pktgen__push_ipv4_packet(&builder, (__u8 *)src, (__u8 *)dst, 77 v4_pod_one, v4_svc_one); 78 if (!l3) 79 return TEST_ERROR; 80 81 /* Push SCTP header */ 82 l4 = pktgen__push_sctphdr(&builder); 83 84 if (!l4) 85 return TEST_ERROR; 86 if ((void *)l4 + sizeof(struct sctphdr) > ctx_data_end(ctx)) 87 return TEST_ERROR; 88 89 l4->source = tcp_src_one; 90 l4->dest = tcp_svc_one; 91 92 /* Calc lengths, set protocol fields and calc checksums */ 93 pktgen__finish(&builder); 94 95 lb_v4_add_service(v4_svc_one, tcp_svc_one, 1, revnat_id); 96 lb_v4_add_backend(v4_svc_one, tcp_svc_one, 1, 124, 97 v4_pod_one, tcp_svc_one, IPPROTO_SCTP, 0); 98 99 /* Add an IPCache entry for pod 1 */ 100 ipcache_v4_add_entry(v4_pod_one, 0, 112233, 0, 0); 101 102 endpoint_v4_add_entry(v4_pod_one, 0, 0, 0, 0, NULL, NULL); 103 104 /* Jump into the entrypoint */ 105 tail_call_static(ctx, entry_call_map, 0); 106 /* Fail if we didn't jump */ 107 return TEST_ERROR; 108 } 109 110 CHECK("tc", "hairpin_sctp_flow_1_forward_v4") 111 int hairpin_flow_forward_check(__maybe_unused const struct __ctx_buff *ctx) 112 { 113 void *data; 114 void *data_end; 115 __u32 *status_code; 116 struct iphdr *l3; 117 struct sctphdr *l4; 118 119 test_init(); 120 121 data = (void *)(long)ctx->data; 122 data_end = (void *)(long)ctx->data_end; 123 124 if (data + sizeof(__u32) > data_end) 125 test_fatal("status code out of bounds"); 126 127 status_code = data; 128 129 assert(*status_code == TC_ACT_REDIRECT); 130 131 l3 = data + sizeof(__u32) + sizeof(struct ethhdr); 132 133 if ((void *)l3 + sizeof(struct iphdr) > data_end) 134 test_fatal("l3 out of bounds"); 135 136 if (l3->saddr != IPV4_LOOPBACK) 137 test_fatal("src IP was not SNAT'ed"); 138 139 if (l3->daddr != v4_pod_one) 140 test_fatal("dest IP hasn't been changed to the pod IP"); 141 142 if (l3->check != bpf_htons(0xb09c)) 143 test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check)); 144 145 l4 = (void *)l3 + sizeof(struct iphdr); 146 147 if ((void *)l4 + sizeof(struct sctphdr) > data_end) 148 test_fatal("l4 out of bounds"); 149 150 if (l4->source != tcp_src_one) 151 test_fatal("src SCTP port was changed"); 152 153 if (l4->dest != tcp_svc_one) 154 test_fatal("dst SCTP port incorrect"); 155 156 test_finish(); 157 } 158 159 /* Let backend's ingress path create its CT own entry: */ 160 PKTGEN("tc", "hairpin_sctp_flow_2_forward_ingress_v4") 161 int hairpin_flow_forward_ingress_pktgen(struct __ctx_buff *ctx) 162 { 163 struct pktgen builder; 164 volatile const __u8 *src = mac_one; 165 volatile const __u8 *dst = mac_two; 166 struct iphdr *l3; 167 struct sctphdr *l4; 168 169 /* Init packet builder */ 170 pktgen__init(&builder, ctx); 171 172 l3 = pktgen__push_ipv4_packet(&builder, (__u8 *)src, (__u8 *)dst, 173 IPV4_LOOPBACK, v4_pod_one); 174 if (!l3) 175 return TEST_ERROR; 176 177 /* Push SCTP header */ 178 l4 = pktgen__push_sctphdr(&builder); 179 180 if (!l4) 181 return TEST_ERROR; 182 183 l4->source = tcp_src_one; 184 l4->dest = tcp_svc_one; 185 186 /* Calc lengths, set protocol fields and calc checksums */ 187 pktgen__finish(&builder); 188 189 return 0; 190 } 191 192 SETUP("tc", "hairpin_sctp_flow_2_forward_ingress_v4") 193 int hairpin_flow_forward_ingress_setup(struct __ctx_buff *ctx) 194 { 195 /* Jump into the entrypoint */ 196 tail_call_static(ctx, entry_call_map, 1); 197 /* Fail if we didn't jump */ 198 return TEST_ERROR; 199 } 200 201 CHECK("tc", "hairpin_sctp_flow_2_forward_ingress_v4") 202 int hairpin_flow_forward_ingress_check(__maybe_unused const struct __ctx_buff *ctx) 203 { 204 void *data; 205 void *data_end; 206 __u32 *status_code; 207 struct iphdr *l3; 208 struct sctphdr *l4; 209 210 test_init(); 211 212 data = (void *)(long)ctx->data; 213 data_end = (void *)(long)ctx->data_end; 214 215 if (data + sizeof(__u32) > data_end) 216 test_fatal("status code out of bounds"); 217 218 status_code = data; 219 220 assert(*status_code == TC_ACT_OK); 221 222 l3 = data + sizeof(__u32) + sizeof(struct ethhdr); 223 224 if ((void *)l3 + sizeof(struct iphdr) > data_end) 225 test_fatal("l3 out of bounds"); 226 227 if (l3->saddr != IPV4_LOOPBACK) 228 test_fatal("src IP changed"); 229 230 if (l3->daddr != v4_pod_one) 231 test_fatal("dest IP changed"); 232 233 if (l3->check != bpf_htons(0xaf9c)) 234 test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check)); 235 236 l4 = (void *)l3 + sizeof(struct iphdr); 237 238 if ((void *)l4 + sizeof(struct sctphdr) > data_end) 239 test_fatal("l4 out of bounds"); 240 241 if (l4->source != tcp_src_one) 242 test_fatal("src SCTP port changed"); 243 244 if (l4->dest != tcp_svc_one) 245 test_fatal("dst SCTP port changed"); 246 247 test_finish(); 248 } 249 250 /* Test that a packet in the reverse direction gets translated back. */ 251 SETUP("tc", "hairpin_sctp_flow_3_reverse_v4") 252 int hairpin_flow_rev_setup(struct __ctx_buff *ctx) 253 { 254 struct pktgen builder; 255 volatile const __u8 *src = mac_one; 256 volatile const __u8 *dst = mac_two; 257 struct iphdr *l3; 258 struct sctphdr *l4; 259 260 /* Init packet builder */ 261 pktgen__init(&builder, ctx); 262 263 l3 = pktgen__push_ipv4_packet(&builder, (__u8 *)src, (__u8 *)dst, 264 v4_pod_one, IPV4_LOOPBACK); 265 if (!l3) 266 return TEST_ERROR; 267 268 /* Push SCTP header */ 269 l4 = pktgen__push_sctphdr(&builder); 270 271 if (!l4) 272 return TEST_ERROR; 273 274 l4->source = tcp_svc_one; 275 l4->dest = tcp_src_one; 276 277 /* Calc lengths, set protocol fields and calc checksums */ 278 pktgen__finish(&builder); 279 280 /* Jump into the entrypoint */ 281 tail_call_static(ctx, entry_call_map, 0); 282 /* Fail if we didn't jump */ 283 return TEST_ERROR; 284 } 285 286 CHECK("tc", "hairpin_sctp_flow_3_reverse_v4") 287 int hairpin_flow_rev_check(__maybe_unused const struct __ctx_buff *ctx) 288 { 289 void *data; 290 void *data_end; 291 __u32 *status_code; 292 struct iphdr *l3; 293 struct sctphdr *l4; 294 295 test_init(); 296 297 data = (void *)(long)ctx->data; 298 data_end = (void *)(long)ctx->data_end; 299 300 if (data + sizeof(__u32) > data_end) 301 test_fatal("status code out of bounds"); 302 303 status_code = data; 304 305 assert(*status_code == TC_ACT_REDIRECT); 306 307 l3 = data + sizeof(__u32) + sizeof(struct ethhdr); 308 309 if ((void *)l3 + sizeof(struct iphdr) > data_end) 310 test_fatal("l3 out of bounds"); 311 312 if (l3->saddr != v4_pod_one) 313 test_fatal("src IP changed"); 314 315 if (l3->daddr != IPV4_LOOPBACK) 316 test_fatal("dest IP changed"); 317 318 l4 = (void *)l3 + sizeof(struct iphdr); 319 320 if ((void *)l4 + sizeof(struct sctphdr) > data_end) 321 test_fatal("l4 out of bounds"); 322 323 if (l4->source != tcp_svc_one) 324 test_fatal("src SCTP port changed"); 325 326 if (l4->dest != tcp_src_one) 327 test_fatal("dst SCTP port changed"); 328 329 test_finish(); 330 } 331 332 PKTGEN("tc", "hairpin_sctp_flow_4_reverse_ingress_v4") 333 int hairpin_sctp_flow_4_reverse_ingress_v4_pktgen(struct __ctx_buff *ctx) 334 { 335 struct pktgen builder; 336 volatile const __u8 *src = mac_one; 337 volatile const __u8 *dst = mac_two; 338 struct iphdr *l3; 339 struct sctphdr *l4; 340 341 /* Init packet builder */ 342 pktgen__init(&builder, ctx); 343 344 l3 = pktgen__push_ipv4_packet(&builder, (__u8 *)src, (__u8 *)dst, 345 v4_pod_one, IPV4_LOOPBACK); 346 if (!l3) 347 return TEST_ERROR; 348 349 /* Push SCTP header */ 350 l4 = pktgen__push_sctphdr(&builder); 351 352 if (!l4) 353 return TEST_ERROR; 354 355 l4->source = tcp_svc_one; 356 l4->dest = tcp_src_one; 357 358 /* Calc lengths, set protocol fields and calc checksums */ 359 pktgen__finish(&builder); 360 361 return 0; 362 } 363 364 SETUP("tc", "hairpin_sctp_flow_4_reverse_ingress_v4") 365 int hairpin_sctp_flow_4_reverse_ingress_v4_setup(struct __ctx_buff *ctx) 366 { 367 /* Jump into the entrypoint */ 368 tail_call_static(ctx, entry_call_map, 1); 369 /* Fail if we didn't jump */ 370 return TEST_ERROR; 371 } 372 373 CHECK("tc", "hairpin_sctp_flow_4_reverse_ingress_v4") 374 int hairpin_sctp_flow_4_reverse_ingress_v4_check(const struct __ctx_buff *ctx) 375 { 376 void *data; 377 void *data_end; 378 __u32 *status_code; 379 struct iphdr *l3; 380 struct sctphdr *l4; 381 382 test_init(); 383 384 data = (void *)(long)ctx->data; 385 data_end = (void *)(long)ctx->data_end; 386 387 if (data + sizeof(__u32) > data_end) 388 test_fatal("status code out of bounds"); 389 390 status_code = data; 391 392 assert(*status_code == CTX_ACT_OK); 393 394 l3 = data + sizeof(__u32) + sizeof(struct ethhdr); 395 396 if ((void *)l3 + sizeof(struct iphdr) > data_end) 397 test_fatal("l3 out of bounds"); 398 399 if (l3->saddr != v4_svc_one) 400 test_fatal("src IP was not NAT'ed back to the svc IP"); 401 402 if (l3->daddr != v4_pod_one) 403 test_fatal("dest IP hasn't been NAT'ed to the original source IP"); 404 405 if (l3->check != bpf_htons(0x3a0)) 406 test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check)); 407 408 l4 = (void *)l3 + sizeof(struct iphdr); 409 410 if ((void *)l4 + sizeof(struct sctphdr) > data_end) 411 test_fatal("l4 out of bounds"); 412 413 if (l4->source != tcp_svc_one) 414 test_fatal("src TCP port was changed"); 415 416 if (l4->dest != tcp_src_one) 417 test_fatal("dst TCP port incorrect"); 418 419 test_finish(); 420 }