github.com/cilium/cilium@v1.16.2/bpf/tests/skip_tunnel_from_host.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 */ 10 #define ENCAP_IFINDEX 1 /* Set dummy ifindex for tunnel device */ 11 #define ENABLE_IPV4 12 #define ENABLE_IPV6 13 #define TUNNEL_MODE 14 15 /* 16 * Now include testing defaults 17 */ 18 #define ROUTER_IP 19 #undef ROUTER_IP 20 #include "node_config.h" 21 22 /* 23 * Test Configuration Settings 24 * Simulate sending traffic from node_one to pod_two. 25 * 26 * cil_from_host will lead us to handle_ipv{4,6}_cont, 27 * which rewrites the destination mac address to 28 * CIILUM_NET_MAC to send the packet to the 29 * cilium_net interface. 30 * 31 * CILIUM_NET_MAC is set in node_config.h, so below we pull 32 * it into a format that pktgen can use. 33 */ 34 #define SRC_MAC mac_one 35 #define SRC_IPV4 v4_node_one 36 #define SRC_IPV6 v6_node_one 37 #define SRC_TCP_PORT tcp_src_one 38 #define DST_IPV4 v4_pod_two 39 #define DST_IPV6 v6_pod_two 40 #define DST_TCP_PORT tcp_svc_one 41 #define TUNNEL_IPV4 v4_node_two 42 #define TUNNEL_IPV6 v6_node_two 43 44 #include "lib/eth.h" 45 static volatile const union macaddr __cilium_net_mac = CILIUM_NET_MAC; 46 #define DST_MAC __cilium_net_mac.addr 47 48 /* 49 * Include entrypoint into host stack. 50 */ 51 #include "bpf_host.c" 52 53 /* 54 * Include test helpers 55 */ 56 #include "lib/ipcache.h" 57 #include "lib/policy.h" 58 59 #define FROM_HOST 0 60 struct { 61 __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 62 __uint(key_size, sizeof(__u32)); 63 __uint(max_entries, 1); 64 __array(values, int()); 65 } entry_call_map __section(".maps") = { 66 .values = { 67 [FROM_HOST] = &cil_from_host, 68 }, 69 }; 70 71 static __always_inline int 72 pktgen_from_host(struct __ctx_buff *ctx, bool v4) 73 { 74 struct pktgen builder; 75 struct tcphdr *l4; 76 void *data; 77 78 pktgen__init(&builder, ctx); 79 80 if (v4) 81 l4 = pktgen__push_ipv4_tcp_packet(&builder, 82 (__u8 *)SRC_MAC, 83 (__u8 *)DST_MAC, 84 SRC_IPV4, DST_IPV4, 85 SRC_TCP_PORT, DST_TCP_PORT); 86 else 87 l4 = pktgen__push_ipv6_tcp_packet(&builder, 88 (__u8 *)SRC_MAC, (__u8 *)DST_MAC, 89 (__u8 *)SRC_IPV6, (__u8 *)DST_IPV6, 90 SRC_TCP_PORT, DST_TCP_PORT); 91 92 if (!l4) 93 return TEST_ERROR; 94 95 data = pktgen__push_data(&builder, default_data, sizeof(default_data)); 96 if (!data) 97 return TEST_ERROR; 98 99 pktgen__finish(&builder); 100 return 0; 101 } 102 103 static __always_inline int 104 setup(struct __ctx_buff *ctx, bool flag_skip_tunnel, bool v4) 105 { 106 /* 107 * Reset metric values before the test, if applicable. 108 * Otherwise, the metric we want to check would increase by one 109 * after each test. 110 */ 111 struct metrics_key key = {}; 112 113 key.reason = REASON_FORWARDED; 114 key.dir = METRIC_EGRESS; 115 116 map_delete_elem(&METRICS_MAP, &key); 117 118 policy_add_egress_allow_all_entry(); 119 120 if (v4) 121 ipcache_v4_add_entry_with_flags(DST_IPV4, 122 0, 1230, v4_node_two, 0, flag_skip_tunnel); 123 else 124 ipcache_v6_add_entry_with_flags((union v6addr *)DST_IPV6, 125 0, 1230, v4_node_two, 0, flag_skip_tunnel); 126 127 tail_call_static(ctx, entry_call_map, FROM_HOST); 128 return TEST_ERROR; 129 } 130 131 static __always_inline int 132 check_ctx(const struct __ctx_buff *ctx, __u32 expected_result, bool v4) 133 { 134 void *data; 135 void *data_end; 136 __u32 *status_code; 137 struct ethhdr *l2; 138 struct tcphdr *l4; 139 __u8 *payload; 140 141 struct metrics_value *entry = NULL; 142 struct metrics_key key = {}; 143 144 test_init(); 145 146 data = (void *)(long)ctx->data; 147 data_end = (void *)(long)ctx->data_end; 148 149 /* 150 * Check the returned status is correct. 151 * The appropriate value for "expected_result" should be set 152 * by the caller. 153 * If flag_skip_tunnel=false, then we need CTX_ACT_REDIRECT 154 * If flag_skip_tunnel=true, then we need CTX_ACT_OK 155 */ 156 if (data + sizeof(*status_code) > data_end) 157 test_fatal("status code out of bounds"); 158 159 status_code = data; 160 assert(*status_code == expected_result); 161 162 /* 163 * Check that the packet was recorded in the metrics. 164 * This only needs to be done if the packet was encapsulated, 165 * as there is no unique metric recorded when the packet is 166 * not encapsulated. 167 */ 168 if (expected_result == CTX_ACT_REDIRECT) { 169 key.reason = REASON_FORWARDED; 170 key.dir = METRIC_EGRESS; 171 172 entry = map_lookup_elem(&METRICS_MAP, &key); 173 if (!entry) 174 test_fatal("metrics entry not found") 175 176 __u64 count = 1; 177 178 assert_metrics_count(key, count); 179 } 180 181 /* Sanity checks on packet integrity. */ 182 l2 = data + sizeof(*status_code); 183 184 if ((void *)l2 + sizeof(struct ethhdr) > data_end) 185 test_fatal("l2 out of bounds") 186 187 if (v4 && l2->h_proto != bpf_htons(ETH_P_IP)) 188 test_fatal("l2 proto hasn't been set to ETH_P_IP") 189 190 if (!v4 && l2->h_proto != bpf_htons(ETH_P_IPV6)) 191 test_fatal("l2 proto hasn't been set to ETH_P_IPV6") 192 193 if (memcmp(l2->h_source, (__u8 *)SRC_MAC, ETH_ALEN) != 0) 194 test_fatal("src mac hasn't been set to source ep's mac"); 195 196 if (memcmp(l2->h_dest, (__u8 *)DST_MAC, ETH_ALEN) != 0) 197 test_fatal("dst mac hasn't been set to dest ep's mac") 198 199 if (v4) { 200 struct iphdr *l3; 201 202 l3 = (void *)l2 + sizeof(struct ethhdr); 203 204 if ((void *)l3 + sizeof(struct iphdr) > data_end) 205 test_fatal("l3 out of bounds"); 206 207 if (l3->saddr != SRC_IPV4) 208 test_fatal("src IP was changed"); 209 210 if (l3->daddr != DST_IPV4) 211 test_fatal("dest IP was changed"); 212 213 if (l3->check != bpf_htons(0xa611)) 214 test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check)); 215 216 l4 = (void *)l3 + sizeof(struct iphdr); 217 } else { 218 struct ipv6hdr *l3; 219 220 l3 = (void *)l2 + sizeof(struct ethhdr); 221 222 if ((void *)l3 + sizeof(struct ipv6hdr) > data_end) 223 test_fatal("l3 out of bounds"); 224 225 if (memcmp((__u8 *)&l3->saddr, (__u8 *)SRC_IPV6, 16) != 0) 226 test_fatal("src IP was changed"); 227 228 if (memcmp((__u8 *)&l3->daddr, (__u8 *)DST_IPV6, 16) != 0) 229 test_fatal("dest IP was changed"); 230 231 l4 = (void *)l3 + sizeof(struct ipv6hdr); 232 } 233 234 if ((void *)l4 + sizeof(struct tcphdr) > data_end) 235 test_fatal("l4 out of bounds"); 236 237 if (l4->source != SRC_TCP_PORT) 238 test_fatal("src TCP port was changed"); 239 240 if (l4->dest != DST_TCP_PORT) 241 test_fatal("dest TCP port was changed"); 242 243 payload = (void *)l4 + sizeof(struct tcphdr); 244 if ((void *)payload + sizeof(default_data) > data_end) 245 test_fatal("payload out of bounds"); 246 247 if (memcmp(payload, default_data, sizeof(default_data)) != 0) 248 test_fatal("tcp payload was changed") 249 250 test_finish(); 251 } 252 253 PKTGEN("tc", "01_ipv4_from_host_no_flags") 254 int ipv4_from_host_no_flags_pktgen(struct __ctx_buff *ctx) 255 { 256 return pktgen_from_host(ctx, true); 257 } 258 259 SETUP("tc", "01_ipv4_from_host_no_flags") 260 int ipv4_from_host_no_flags_setup(struct __ctx_buff *ctx) 261 { 262 return setup(ctx, false, true); 263 } 264 265 CHECK("tc", "01_ipv4_from_host_no_flags") 266 int ipv4_from_host_no_flags_check(__maybe_unused const struct __ctx_buff *ctx) 267 { 268 return check_ctx(ctx, CTX_ACT_REDIRECT, true); 269 } 270 271 PKTGEN("tc", "02_ipv4_from_host_skip_tunnel") 272 int ipv4_from_host_skip_tunnel_pktgen(struct __ctx_buff *ctx) 273 { 274 return pktgen_from_host(ctx, true); 275 } 276 277 SETUP("tc", "02_ipv4_from_host_skip_tunnel") 278 int ipv4_from_host_skip_tunnel_setup(struct __ctx_buff *ctx) 279 { 280 return setup(ctx, true, true); 281 } 282 283 CHECK("tc", "02_ipv4_from_host_skip_tunnel") 284 int ipv4_from_host_skip_tunnel_check(__maybe_unused const struct __ctx_buff *ctx) 285 { 286 return check_ctx(ctx, CTX_ACT_OK, true); 287 } 288 289 PKTGEN("tc", "03_ipv6_from_host_no_flags") 290 int ipv6_from_host_no_flags_pktgen(struct __ctx_buff *ctx) 291 { 292 return pktgen_from_host(ctx, false); 293 } 294 295 SETUP("tc", "03_ipv6_from_host_no_flags") 296 int ipv6_from_host_no_flags_setup(struct __ctx_buff *ctx) 297 { 298 return setup(ctx, false, false); 299 } 300 301 CHECK("tc", "03_ipv6_from_host_no_flags") 302 int ipv6_from_host_no_flags_check(__maybe_unused const struct __ctx_buff *ctx) 303 { 304 return check_ctx(ctx, CTX_ACT_REDIRECT, false); 305 } 306 307 PKTGEN("tc", "04_ipv6_from_host_skip_tunnel") 308 int ipv6_from_host_skip_tunnel_pktgen(struct __ctx_buff *ctx) 309 { 310 return pktgen_from_host(ctx, false); 311 } 312 313 SETUP("tc", "04_ipv6_from_host_skip_tunnel") 314 int ipv6_from_host_skip_tunnel_setup(struct __ctx_buff *ctx) 315 { 316 return setup(ctx, true, false); 317 } 318 319 CHECK("tc", "04_ipv6_from_host_skip_tunnel") 320 int ipv6_from_host_skip_tunnel_check(__maybe_unused const struct __ctx_buff *ctx) 321 { 322 return check_ctx(ctx, CTX_ACT_OK, false); 323 }