github.com/cilium/cilium@v1.16.2/bpf/tests/skip_tunnel_nodeport_masq.c (about) 1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright Authors of Cilium */ 3 #include "common.h" 4 #include <bpf/ctx/skb.h> 5 #include "pktgen.h" 6 7 /* 8 * Datapath configuration settings to setup tunneling with VXLan 9 * and nodeport 10 */ 11 #define ENCAP_IFINDEX 1 /* Set dummy ifindex for tunnel device */ 12 #define ENABLE_IPV4 1 13 #define ENABLE_IPV6 1 14 #define TUNNEL_MODE 1 15 #define ENABLE_NODEPORT 1 16 #define ENABLE_MASQUERADE_IPV4 1 17 #define ENABLE_MASQUERADE_IPV6 1 18 19 /* 20 * Now include testing defaults 21 */ 22 #define ROUTER_IP 23 #undef ROUTER_IP 24 #include "node_config.h" 25 26 /* 27 * Simulate sending traffic from pod_one on node_one directly to 28 * node_two. Tests are written from the perspective of node_one, 29 * allowing us access to nodeport_snat_fwd_ipv{4,6}. 30 */ 31 #define SRC_MAC mac_one 32 #define SRC_IPV4 v4_pod_one 33 #define SRC_IPV6 v6_pod_one 34 #define SRC_PORT tcp_src_one 35 #define DST_MAC mac_three 36 #define DST_IPV4 v4_node_two 37 #define DST_IPV6 v6_node_two 38 #define DST_PORT tcp_svc_one 39 40 /* 41 * Include entrypoint into host stack 42 */ 43 #include "bpf_host.c" 44 45 /* 46 * Include test helpers 47 */ 48 #include "lib/endpoint.h" 49 #include "lib/ipcache.h" 50 #include "lib/policy.h" 51 #include "lib/clear.h" 52 53 #define TO_NETDEV 0 54 struct { 55 __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 56 __uint(key_size, sizeof(__u32)); 57 __uint(max_entries, 1); 58 __array(values, int()); 59 } entry_call_map __section(".maps") = { 60 .values = { 61 [TO_NETDEV] = &cil_to_netdev, 62 }, 63 }; 64 65 static __always_inline int 66 pktgen(struct __ctx_buff *ctx, bool v4) 67 { 68 struct pktgen builder; 69 struct tcphdr *l4; 70 void *data; 71 72 pktgen__init(&builder, ctx); 73 74 if (v4) 75 l4 = pktgen__push_ipv4_tcp_packet(&builder, 76 (__u8 *)SRC_MAC, 77 (__u8 *)DST_MAC, 78 SRC_IPV4, DST_IPV4, 79 SRC_PORT, DST_PORT); 80 else 81 l4 = pktgen__push_ipv6_tcp_packet(&builder, 82 (__u8 *)SRC_MAC, (__u8 *)DST_MAC, 83 (__u8 *)SRC_IPV6, 84 (__u8 *)DST_IPV6, 85 SRC_PORT, DST_PORT); 86 87 if (!l4) 88 return TEST_ERROR; 89 90 data = pktgen__push_data(&builder, default_data, sizeof(default_data)); 91 if (!data) 92 return TEST_ERROR; 93 94 pktgen__finish(&builder); 95 return 0; 96 } 97 98 /* 99 * Setup scenario where pod with SRC_IP on node is sending traffic directly 100 * to a remote node with the address DST_IP. In the case of tunnel mode where 101 * flag_skip_tunnel=true, bpf masquerading should be skipped. 102 */ 103 static __always_inline int 104 setup(struct __ctx_buff *ctx, bool v4, bool flag_skip_tunnel) 105 { 106 /* 107 * Reset maps before the test. 108 * Otherwise, leftover state from previous tests will have an impact, 109 * as the tests and checks assume we have a fresh state every time. 110 */ 111 clear_map(&METRICS_MAP); 112 clear_map(&CT_MAP_TCP4); 113 clear_map(&CT_MAP_TCP6); 114 clear_map(get_cluster_snat_map_v4(0)); 115 clear_map(get_cluster_snat_map_v6(0)); 116 117 policy_add_egress_allow_all_entry(); 118 119 /* 120 * For this scenario, an endpoint for the source addresses needs 121 * to be created. Additionally, the destination's security identity in the ipcache 122 * must reflect that it is a remote node. This information is used by the SNAT stack to 123 * determine if SNAT needs to be performed for the given packet. See snat_v{4,6}_needs_masquerade. 124 */ 125 126 if (v4) { 127 endpoint_v4_add_entry(SRC_IPV4, 0, 0, 0, 0, (__u8 *)SRC_MAC, (__u8 *)SRC_MAC); 128 ipcache_v4_add_entry_with_flags(DST_IPV4, 129 0, REMOTE_NODE_ID, 0, 130 0, flag_skip_tunnel); 131 } else { 132 endpoint_v6_add_entry((union v6addr *)SRC_IPV6, 0, 0, 0, 0, 133 (__u8 *)SRC_MAC, (__u8 *)SRC_MAC); 134 ipcache_v6_add_entry_with_flags((union v6addr *)DST_IPV6, 135 0, REMOTE_NODE_ID, 0, 136 0, flag_skip_tunnel); 137 } 138 139 tail_call_static(ctx, entry_call_map, TO_NETDEV); 140 return TEST_ERROR; 141 } 142 143 static __always_inline int 144 check_ctx(const struct __ctx_buff *ctx, bool v4, bool snat) 145 { 146 void *data; 147 void *data_end; 148 __u32 *status_code; 149 struct ethhdr *l2; 150 struct tcphdr *l4; 151 __u8 *payload; 152 153 struct metrics_value *entry = NULL; 154 struct metrics_key key = {}; 155 156 test_init(); 157 158 data = (void *)(long)ctx->data; 159 data_end = (void *)(long)ctx->data_end; 160 161 if (data + sizeof(*status_code) > data_end) 162 test_fatal("status code out of bounds"); 163 164 status_code = data; 165 assert(*status_code == CTX_ACT_OK); 166 167 key.reason = REASON_FORWARDED; 168 key.dir = METRIC_EGRESS; 169 170 entry = map_lookup_elem(&METRICS_MAP, &key); 171 if (!entry) 172 test_fatal("metrics entry not found") 173 174 __u64 count = 1; 175 176 assert_metrics_count(key, count); 177 178 l2 = data + sizeof(*status_code); 179 180 if ((void *)l2 + sizeof(struct ethhdr) > data_end) 181 test_fatal("l2 out of bounds") 182 183 if (v4 && l2->h_proto != bpf_htons(ETH_P_IP)) 184 test_fatal("l2 proto hasn't been set to ETH_P_IP") 185 186 if (!v4 && l2->h_proto != bpf_htons(ETH_P_IPV6)) 187 test_fatal("l2 proto hasn't been set to ETH_P_IPV6") 188 189 if (memcmp(l2->h_source, (__u8 *)SRC_MAC, ETH_ALEN) != 0) 190 test_fatal("src mac was changed"); 191 192 if (memcmp(l2->h_dest, (__u8 *)DST_MAC, ETH_ALEN) != 0) 193 test_fatal("dst mac has changed") 194 195 if (v4) { 196 struct iphdr *l3; 197 198 l3 = (void *)l2 + sizeof(struct ethhdr); 199 200 if ((void *)l3 + sizeof(struct iphdr) > data_end) 201 test_fatal("l3 out of bounds"); 202 203 if (snat) { 204 if (l3->saddr != IPV4_MASQUERADE) 205 test_fatal("src IP was not snatted"); 206 } else { 207 if (l3->saddr != SRC_IPV4) 208 test_fatal("src IP was changed"); 209 } 210 211 if (l3->daddr != DST_IPV4) 212 test_fatal("dest IP was changed"); 213 214 l4 = (void *)l3 + sizeof(struct iphdr); 215 } else { 216 struct ipv6hdr *l3; 217 union v6addr masq_addr; 218 219 BPF_V6(masq_addr, IPV6_MASQUERADE); 220 221 l3 = (void *)l2 + sizeof(struct ethhdr); 222 223 if ((void *)l3 + sizeof(struct ipv6hdr) > data_end) 224 test_fatal("l3 out of bounds"); 225 226 if (snat) { 227 if (memcmp((__u8 *)&l3->saddr, (__u8 *)&masq_addr, 16) != 0) 228 test_fatal("src IP was not snatted"); 229 } else { 230 if (memcmp((__u8 *)&l3->saddr, (__u8 *)SRC_IPV6, 16) != 0) 231 test_fatal("src IP was changed"); 232 } 233 234 if (memcmp((__u8 *)&l3->daddr, (__u8 *)DST_IPV6, 16) != 0) 235 test_fatal("dest IP was changed"); 236 237 l4 = (void *)l3 + sizeof(struct ipv6hdr); 238 } 239 240 if ((void *)l4 + sizeof(struct tcphdr) > data_end) 241 test_fatal("l4 out of bounds"); 242 243 if (snat) { 244 __be16 p = bpf_ntohs(l4->source); 245 246 if (p < NODEPORT_PORT_MIN_NAT || p > NODEPORT_PORT_MAX_NAT) 247 test_fatal("src port was not snatted"); 248 } else { 249 if (l4->source != SRC_PORT) 250 test_fatal("src port was changed"); 251 } 252 253 if (l4->dest != DST_PORT) 254 test_fatal("dest port was changed"); 255 256 payload = (void *)l4 + sizeof(struct tcphdr); 257 if ((void *)payload + sizeof(default_data) > data_end) 258 test_fatal("payload out of bounds"); 259 260 if (memcmp(payload, default_data, sizeof(default_data)) != 0) 261 test_fatal("tcp payload was changed") 262 263 test_finish(); 264 } 265 266 PKTGEN("tc", "01_ipv4_nodeport_ingress_no_flags") 267 int ipv4_nodeport_ingress_no_flags_pktgen(struct __ctx_buff *ctx) 268 { 269 return pktgen(ctx, true); 270 } 271 272 SETUP("tc", "01_ipv4_nodeport_ingress_no_flags") 273 int ipv4_nodeport_ingress_no_flags_setup(struct __ctx_buff *ctx) 274 { 275 return setup(ctx, true, false); 276 } 277 278 CHECK("tc", "01_ipv4_nodeport_ingress_no_flags") 279 int ipv4_nodeport_ingress_no_flags_check(__maybe_unused const struct __ctx_buff *ctx) 280 { 281 return check_ctx(ctx, true, true); 282 } 283 284 PKTGEN("tc", "02_ipv4_nodeport_ingress_skip_tunnel") 285 int ipv4_nodeport_ingress_skip_tunnel_pktgen(struct __ctx_buff *ctx) 286 { 287 return pktgen(ctx, true); 288 } 289 290 SETUP("tc", "02_ipv4_nodeport_ingress_skip_tunnel") 291 int ipv4_nodeport_ingress_skip_tunnel_setup(struct __ctx_buff *ctx) 292 { 293 return setup(ctx, true, true); 294 } 295 296 CHECK("tc", "02_ipv4_nodeport_ingress_skip_tunnel") 297 int ipv4_nodeport_ingress_skip_tunnel_check(__maybe_unused const struct __ctx_buff *ctx) 298 { 299 return check_ctx(ctx, true, false); 300 } 301 302 PKTGEN("tc", "03_ipv6_nodeport_ingress_no_flags") 303 int ipv6_nodeport_ingress_no_flags_pktgen(struct __ctx_buff *ctx) 304 { 305 return pktgen(ctx, false); 306 } 307 308 SETUP("tc", "03_ipv6_nodeport_ingress_no_flags") 309 int ipv6_nodeport_ingress_no_flags_setup(struct __ctx_buff *ctx) 310 { 311 return setup(ctx, false, false); 312 } 313 314 CHECK("tc", "03_ipv6_nodeport_ingress_no_flags") 315 int ipv6_nodeport_ingress_no_flags_check(__maybe_unused const struct __ctx_buff *ctx) 316 { 317 return check_ctx(ctx, false, true); 318 } 319 320 PKTGEN("tc", "04_ipv6_nodeport_ingress_skip_tunnel") 321 int ipv6_nodeport_ingress_skip_tunnel_pktgen(struct __ctx_buff *ctx) 322 { 323 return pktgen(ctx, false); 324 } 325 326 SETUP("tc", "04_ipv6_nodeport_ingress_skip_tunnel") 327 int ipv6_nodeport_ingress_skip_tunnel_setup(struct __ctx_buff *ctx) 328 { 329 return setup(ctx, false, true); 330 } 331 332 CHECK("tc", "04_ipv6_nodeport_ingress_skip_tunnel") 333 int ipv6_nodeport_ingress_skip_tunnel_check(__maybe_unused const struct __ctx_buff *ctx) 334 { 335 return check_ctx(ctx, false, false); 336 }