github.com/cilium/cilium@v1.16.2/bpf/tests/xdp_nodeport_lb4_test.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/xdp.h" 7 8 #define ENABLE_IPV4 9 #define ENABLE_NODEPORT 10 #define ENABLE_NODEPORT_ACCELERATION 11 12 #define fib_lookup mock_fib_lookup 13 14 static const char fib_smac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x02}; 15 static const char fib_dmac[6] = {0x13, 0x37, 0x13, 0x37, 0x13, 0x37}; 16 17 long mock_fib_lookup(__maybe_unused void *ctx, struct bpf_fib_lookup *params, 18 __maybe_unused int plen, __maybe_unused __u32 flags) 19 { 20 __bpf_memcpy_builtin(params->smac, fib_smac, ETH_ALEN); 21 __bpf_memcpy_builtin(params->dmac, fib_dmac, ETH_ALEN); 22 return 0; 23 } 24 25 #include "bpf_xdp.c" 26 #include "lib/nodeport.h" 27 28 #include "lib/lb.h" 29 30 struct { 31 __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 32 __uint(key_size, sizeof(__u32)); 33 __uint(max_entries, 2); 34 __array(values, int()); 35 } entry_call_map __section(".maps") = { 36 .values = { 37 [0] = &cil_xdp_entry, 38 }, 39 }; 40 41 #define FRONTEND_IP 0x0F00010A /* 10.0.1.15 */ 42 #define FRONTEND_PORT 80 43 #define BACKEND_IP 0x0F00020A /* 10.2.0.15 */ 44 #define BACKEND_PORT 8080 45 46 static long (*bpf_xdp_adjust_tail)(struct xdp_md *xdp_md, int delta) = (void *)65; 47 48 static __always_inline int build_packet(struct __ctx_buff *ctx) 49 { 50 /* Create room for our packet to be crafted */ 51 unsigned int data_len = ctx->data_end - ctx->data; 52 53 int offset = offset = 4096 - 256 - 320 - data_len; 54 55 bpf_xdp_adjust_tail(ctx, offset); 56 57 void *data = (void *)(long)ctx->data; 58 void *data_end = (void *)(long)ctx->data_end; 59 60 if (data + sizeof(struct ethhdr) > data_end) 61 return TEST_ERROR; 62 63 struct ethhdr l2 = { 64 .h_source = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, 65 .h_dest = {0x12, 0x23, 0x34, 0x45, 0x56, 0x67}, 66 .h_proto = bpf_htons(ETH_P_IP) 67 }; 68 memcpy(data, &l2, sizeof(struct ethhdr)); 69 data += sizeof(struct ethhdr); 70 71 if (data + sizeof(struct iphdr) > data_end) 72 return TEST_ERROR; 73 74 struct iphdr l3 = { 75 .version = 4, 76 .ihl = 5, 77 .tot_len = 40, /* 20 bytes l3 + 20 bytes l4 + 20 bytes data */ 78 .id = 0x5438, 79 .frag_off = bpf_htons(IP_DF), 80 .ttl = 64, 81 .protocol = IPPROTO_TCP, 82 .saddr = 0x0F00000A, /* 10.0.0.15 */ 83 .daddr = FRONTEND_IP, 84 }; 85 memcpy(data, &l3, sizeof(struct iphdr)); 86 data += sizeof(struct iphdr); 87 88 char tcp_data[20] = "Should not change!!"; 89 90 /* TCP header + data */ 91 if (data + (sizeof(struct tcphdr) + sizeof(tcp_data)) > data_end) 92 return TEST_ERROR; 93 94 struct tcphdr l4 = { 95 .source = 23445, 96 .dest = FRONTEND_PORT, 97 .seq = 2922048129, 98 .doff = 0, /* no options */ 99 .syn = 1, 100 .window = 64240, 101 }; 102 memcpy(data, &l4, sizeof(struct tcphdr)); 103 104 char *tcp_data_ptr = data + sizeof(tcp_data); 105 106 memcpy(tcp_data_ptr, tcp_data, sizeof(tcp_data)); 107 108 data += sizeof(struct tcphdr) + sizeof(tcp_data); 109 110 /* Shrink ctx to the exact size we used */ 111 offset = (long)data - (long)ctx->data_end; 112 bpf_xdp_adjust_tail(ctx, offset); 113 114 return 0; 115 } 116 117 SETUP("xdp", "xdp_lb4_forward_to_other_node") 118 int test1_setup(struct __ctx_buff *ctx) 119 { 120 int ret; 121 122 ret = build_packet(ctx); 123 if (ret) 124 return ret; 125 126 lb_v4_add_service(FRONTEND_IP, FRONTEND_PORT, 1, 1); 127 lb_v4_add_backend(FRONTEND_IP, FRONTEND_PORT, 1, 124, 128 BACKEND_IP, BACKEND_PORT, IPPROTO_TCP, 0); 129 130 /* Jump into the entrypoint */ 131 tail_call_static(ctx, entry_call_map, 0); 132 /* Fail if we didn't jump */ 133 return TEST_ERROR; 134 } 135 136 CHECK("xdp", "xdp_lb4_forward_to_other_node") 137 int test1_check(__maybe_unused const struct __ctx_buff *ctx) 138 { 139 test_init(); 140 141 void *data = (void *)(long)ctx->data; 142 void *data_end = (void *)(long)ctx->data_end; 143 144 if (data + sizeof(__u32) > data_end) 145 test_fatal("status code out of bounds"); 146 147 __u32 *status_code = data; 148 149 if (*status_code != XDP_TX) 150 test_fatal("status code != XDP_TX"); 151 152 data += sizeof(__u32); 153 154 if (data + sizeof(struct ethhdr) > data_end) 155 test_fatal("ctx doesn't fit ethhdr"); 156 157 struct ethhdr *l2 = data; 158 159 data += sizeof(struct ethhdr); 160 161 if (memcmp(l2->h_source, fib_smac, sizeof(fib_smac)) != 0) 162 test_fatal("l2->h_source != fib_smac"); 163 164 if (memcmp(l2->h_dest, fib_dmac, sizeof(fib_dmac)) != 0) 165 test_fatal("l2->h_dest != fib_dmac"); 166 167 if (data + sizeof(struct iphdr) > data_end) 168 test_fatal("ctx doesn't fit iphdr"); 169 170 struct iphdr *l3 = data; 171 172 data += sizeof(struct iphdr); 173 174 if (l3->daddr != BACKEND_IP) 175 test_fatal("dst ip != backend IP"); 176 177 if (data + sizeof(struct tcphdr) > data_end) 178 test_fatal("ctx doesn't fit tcphdr"); 179 180 struct tcphdr *l4 = data; 181 182 data += sizeof(struct tcphdr); 183 184 if (l4->dest != BACKEND_PORT) 185 test_fatal("dst port != backend port"); 186 187 char msg[20] = "Should not change!!"; 188 189 if (data + sizeof(msg) > data_end) 190 test_fatal("ctx doesn't fit tcp body"); 191 192 char *body = data; 193 194 if (memcmp(body, msg, sizeof(msg)) != 0) 195 test_fatal("body changed"); 196 197 test_finish(); 198 } 199 200 SETUP("xdp", "xdp_lb4_drop_no_backend") 201 int test2_setup(struct __ctx_buff *ctx) 202 { 203 int ret; 204 205 ret = build_packet(ctx); 206 if (ret) 207 return ret; 208 209 lb_v4_add_service(FRONTEND_IP, FRONTEND_PORT, 0, 1); 210 211 /* Jump into the entrypoint */ 212 tail_call_static(ctx, entry_call_map, 0); 213 /* Fail if we didn't jump */ 214 return TEST_ERROR; 215 } 216 217 CHECK("xdp", "xdp_lb4_drop_no_backend") 218 int test2_check(__maybe_unused const struct __ctx_buff *ctx) 219 { 220 void *data_end = (void *)(long)ctx->data_end; 221 void *data = (void *)(long)ctx->data; 222 __u32 expected_status = XDP_DROP; 223 __u32 *status_code; 224 225 test_init(); 226 227 if (data + sizeof(__u32) > data_end) 228 test_fatal("status code out of bounds"); 229 230 status_code = data; 231 232 if (*status_code != expected_status) 233 test_fatal("status code is %lu, expected %lu", *status_code, expected_status); 234 235 test_finish(); 236 }