github.com/cilium/cilium@v1.16.2/bpf/tests/tc_nodeport_lb4_dsr_lb.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 "pktgen.h" 8 9 /* Set ETH_HLEN to 14 to indicate that the packet has a 14 byte ethernet header */ 10 #define ETH_HLEN 14 11 12 /* Enable code paths under test */ 13 #define ENABLE_IPV4 14 #define ENABLE_NODEPORT 15 #define ENABLE_DSR 16 #define DSR_ENCAP_GENEVE 3 17 18 #define DISABLE_LOOPBACK_LB 19 20 /* Skip ingress policy checks, not needed to validate hairpin flow */ 21 #define USE_BPF_PROG_FOR_INGRESS_POLICY 22 #undef FORCE_LOCAL_POLICY_EVAL_AT_SOURCE 23 24 #define CLIENT_IP v4_ext_one 25 #define CLIENT_PORT __bpf_htons(111) 26 27 #define FRONTEND_IP v4_svc_two 28 #define FRONTEND_PORT tcp_svc_one 29 30 #define LB_IP v4_node_one 31 #define IPV4_DIRECT_ROUTING LB_IP 32 33 #define BACKEND_IP v4_pod_two 34 #define BACKEND_PORT __bpf_htons(8080) 35 36 #define fib_lookup mock_fib_lookup 37 38 static volatile const __u8 *client_mac = mac_one; 39 /* this matches the default node_config.h: */ 40 static volatile const __u8 lb_mac[ETH_ALEN] = { 0xce, 0x72, 0xa7, 0x03, 0x88, 0x56 }; 41 static volatile const __u8 *remote_backend_mac = mac_five; 42 43 long mock_fib_lookup(__maybe_unused void *ctx, struct bpf_fib_lookup *params, 44 __maybe_unused int plen, __maybe_unused __u32 flags) 45 { 46 params->ifindex = 0; 47 48 if (params->ipv4_dst == BACKEND_IP) { 49 __bpf_memcpy_builtin(params->smac, (__u8 *)lb_mac, ETH_ALEN); 50 __bpf_memcpy_builtin(params->dmac, (__u8 *)remote_backend_mac, ETH_ALEN); 51 } else { 52 __bpf_memcpy_builtin(params->smac, (__u8 *)lb_mac, ETH_ALEN); 53 __bpf_memcpy_builtin(params->dmac, (__u8 *)client_mac, ETH_ALEN); 54 } 55 56 return 0; 57 } 58 59 #define SECCTX_FROM_IPCACHE 1 60 61 #include <bpf_host.c> 62 63 #include "lib/ipcache.h" 64 #include "lib/lb.h" 65 66 #define FROM_NETDEV 0 67 #define TO_NETDEV 1 68 69 struct { 70 __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 71 __uint(key_size, sizeof(__u32)); 72 __uint(max_entries, 2); 73 __array(values, int()); 74 } entry_call_map __section(".maps") = { 75 .values = { 76 [FROM_NETDEV] = &cil_from_netdev, 77 [TO_NETDEV] = &cil_to_netdev, 78 }, 79 }; 80 81 /* Test that a SVC request that is LBed to a DSR remote backend 82 * - gets DNATed, 83 * - has IP Option inserted, 84 * - gets redirected back out by TC 85 */ 86 PKTGEN("tc", "tc_nodeport_dsr_fwd") 87 int nodeport_dsr_fwd_pktgen(struct __ctx_buff *ctx) 88 { 89 struct pktgen builder; 90 struct tcphdr *l4; 91 void *data; 92 93 /* Init packet builder */ 94 pktgen__init(&builder, ctx); 95 96 l4 = pktgen__push_ipv4_tcp_packet(&builder, 97 (__u8 *)client_mac, (__u8 *)lb_mac, 98 CLIENT_IP, FRONTEND_IP, 99 CLIENT_PORT, FRONTEND_PORT); 100 if (!l4) 101 return TEST_ERROR; 102 103 data = pktgen__push_data(&builder, default_data, sizeof(default_data)); 104 if (!data) 105 return TEST_ERROR; 106 107 /* Calc lengths, set protocol fields and calc checksums */ 108 pktgen__finish(&builder); 109 110 return 0; 111 } 112 113 SETUP("tc", "tc_nodeport_dsr_fwd") 114 int nodeport_dsr_fwd_setup(struct __ctx_buff *ctx) 115 { 116 __u16 revnat_id = 1; 117 118 lb_v4_add_service(FRONTEND_IP, FRONTEND_PORT, 1, revnat_id); 119 lb_v4_add_backend(FRONTEND_IP, FRONTEND_PORT, 1, 124, 120 BACKEND_IP, BACKEND_PORT, IPPROTO_TCP, 0); 121 122 ipcache_v4_add_entry(BACKEND_IP, 0, 112233, 0, 0); 123 124 /* Jump into the entrypoint */ 125 tail_call_static(ctx, entry_call_map, FROM_NETDEV); 126 /* Fail if we didn't jump */ 127 return TEST_ERROR; 128 } 129 130 CHECK("tc", "tc_nodeport_dsr_fwd") 131 int nodeport_dsr_fwd_check(__maybe_unused const struct __ctx_buff *ctx) 132 { 133 struct dsr_opt_v4 *opt; 134 void *data, *data_end; 135 __u32 *status_code; 136 struct tcphdr *l4; 137 struct ethhdr *l2; 138 struct iphdr *l3; 139 140 test_init(); 141 142 data = (void *)(long)ctx_data(ctx); 143 data_end = (void *)(long)ctx->data_end; 144 145 if (data + sizeof(__u32) > data_end) 146 test_fatal("status code out of bounds"); 147 148 status_code = data; 149 150 assert(*status_code == CTX_ACT_REDIRECT); 151 152 l2 = data + sizeof(__u32); 153 if ((void *)l2 + sizeof(struct ethhdr) > data_end) 154 test_fatal("l2 out of bounds"); 155 156 l3 = (void *)l2 + sizeof(struct ethhdr); 157 if ((void *)l3 + sizeof(struct iphdr) > data_end) 158 test_fatal("l3 out of bounds"); 159 160 opt = (void *)l3 + sizeof(struct iphdr); 161 if ((void *)opt + 2 * sizeof(__u32) > data_end) 162 test_fatal("l3 DSR option out of bounds"); 163 164 l4 = (void *)opt + sizeof(*opt); 165 if ((void *)l4 + sizeof(struct tcphdr) > data_end) 166 test_fatal("l4 out of bounds"); 167 168 if (memcmp(l2->h_source, (__u8 *)lb_mac, ETH_ALEN) != 0) 169 test_fatal("src MAC is not the LB MAC") 170 if (memcmp(l2->h_dest, (__u8 *)remote_backend_mac, ETH_ALEN) != 0) 171 test_fatal("dst MAC is not the backend MAC") 172 173 if (l3->saddr != CLIENT_IP) 174 test_fatal("src IP has changed"); 175 176 if (l3->daddr != BACKEND_IP) 177 test_fatal("dst IP hasn't been NATed to remote backend IP"); 178 179 if (l3->check != bpf_htons(0x434a)) 180 test_fatal("L3 checksum is invalid: %d", bpf_htons(l3->check)); 181 182 if (opt->type != DSR_IPV4_OPT_TYPE) 183 test_fatal("type in DSR IP option is bad") 184 if (opt->len != 8) 185 test_fatal("length in DSR IP option is bad") 186 if (opt->port != __bpf_ntohs(FRONTEND_PORT)) 187 test_fatal("port in DSR IP option is bad") 188 if (opt->addr != __bpf_ntohl(FRONTEND_IP)) 189 test_fatal("addr in DSR IP option is bad") 190 191 if (l4->source != CLIENT_PORT) 192 test_fatal("src port has changed"); 193 194 if (l4->dest != BACKEND_PORT) 195 test_fatal("dst port hasn't been NATed to backend port"); 196 197 test_finish(); 198 }