github.com/cilium/cilium@v1.16.2/bpf/tests/tc_l2_announcement.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 /* Enable debug output */ 7 #define DEBUG 8 9 /* Set THIS_INTERFACE_MAC equal to mac_two */ 10 #define THIS_INTERFACE_MAC { .addr = {0x13, 0x37, 0x13, 0x37, 0x13, 0x37} } 11 12 #define SECCTX_FROM_IPCACHE 1 13 14 /* Set the LXC source address to be the address of pod one */ 15 #define LXC_IPV4 (__be32)v4_pod_one 16 17 /* Enable CT debug output */ 18 #undef QUIET_CT 19 20 #include <bpf/ctx/skb.h> 21 #include "pktgen.h" 22 23 /* Set ETH_HLEN to 14 to indicate that the packet has a 14 byte ethernet header */ 24 #define ETH_HLEN 14 25 26 /* Enable code paths under test */ 27 #define ENABLE_IPV4 28 #define ENABLE_L2_ANNOUNCEMENTS 29 30 #include <bpf_host.c> 31 32 struct { 33 __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 34 __uint(key_size, sizeof(__u32)); 35 __uint(max_entries, 2); 36 __array(values, int()); 37 } entry_call_map __section(".maps") = { 38 .values = { 39 [0] = &cil_from_netdev, 40 }, 41 }; 42 43 /* Setup for this test: 44 * +-------------------------+ +--------------------------------------+ +--------------------------+ 45 * |L2:mac_one, L3:v4_ext_one|---| ARP Request broadcast for v4_svc_one |--->|L2:mac_two, L3:v4_node_one| 46 * +-------------------------+ +--------------------------------------+ +--------------------------+ 47 * ^ +-------------------------------------------------------------------+ | 48 * \---|ARP Reply, SHR:mac_two, SIP:v4_svc_one, DHR:mac_one, DIP:v4_ext_one|---/ 49 * +-------------------------------------------------------------------+ 50 */ 51 52 static volatile const __u8 mac_bcast[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 53 54 static __always_inline int build_packet(struct __ctx_buff *ctx) 55 { 56 struct pktgen builder; 57 volatile const __u8 *src = mac_one; 58 volatile const __u8 *dst = mac_bcast; 59 struct ethhdr *l2; 60 struct arphdreth *l3; 61 62 /* Init packet builder */ 63 pktgen__init(&builder, ctx); 64 65 /* Push ethernet header */ 66 l2 = pktgen__push_ethhdr(&builder); 67 68 if (!l2) 69 return TEST_ERROR; 70 71 ethhdr__set_macs(l2, (__u8 *)src, (__u8 *)dst); 72 73 /* Push ARP header */ 74 l3 = pktgen__push_default_arphdr_ethernet(&builder); 75 76 if (!l3) 77 return TEST_ERROR; 78 79 l3->ar_op = bpf_htons(ARPOP_REQUEST); 80 memcpy(l3->ar_sha, (__u8 *)mac_one, ETH_ALEN); 81 l3->ar_sip = v4_ext_one; 82 memcpy(l3->ar_tha, (__u8 *)mac_bcast, ETH_ALEN); 83 l3->ar_tip = v4_svc_one; 84 85 /* Calc lengths, set protocol fields and calc checksums */ 86 pktgen__finish(&builder); 87 88 return 0; 89 } 90 91 PKTGEN("tc", "0_no_entry") 92 int l2_announcement_arp_no_entry_pktgen(struct __ctx_buff *ctx) 93 { 94 return build_packet(ctx); 95 } 96 97 /* Test that sending a ARP broadcast request without entries in the map. 98 */ 99 SETUP("tc", "0_no_entry") 100 int l2_announcement_arp_no_entry_setup(struct __ctx_buff *ctx) 101 { 102 /* Jump into the entrypoint */ 103 tail_call_static(ctx, entry_call_map, 0); 104 /* Fail if we didn't jump */ 105 return TEST_ERROR; 106 } 107 108 CHECK("tc", "0_no_entry") 109 int l2_announcement_arp_no_entry_check(__maybe_unused const struct __ctx_buff *ctx) 110 { 111 void *data; 112 void *data_end; 113 __u32 *status_code; 114 struct ethhdr *l2; 115 struct arphdreth *l3; 116 117 test_init(); 118 119 data = ctx_data(ctx); 120 data_end = ctx_data_end(ctx); 121 122 if (data + sizeof(__u32) > data_end) 123 test_fatal("status code out of bounds"); 124 125 status_code = data; 126 127 /* The program should pass unknown ARP messages to the stack */ 128 assert(*status_code == TC_ACT_OK); 129 130 l2 = data + sizeof(__u32); 131 if ((void *)l2 + sizeof(struct ethhdr) > data_end) 132 test_fatal("l2 out of bounds"); 133 134 l3 = data + sizeof(__u32) + sizeof(struct ethhdr); 135 136 if ((void *)l3 + sizeof(struct arphdreth) > data_end) 137 test_fatal("l3 out of bounds"); 138 139 assert(memcmp(l2->h_source, (__u8 *)mac_one, ETH_ALEN) == 0); 140 assert(memcmp(l2->h_dest, (__u8 *)mac_bcast, ETH_ALEN) == 0); 141 assert(l3->ar_op == bpf_htons(ARPOP_REQUEST)); 142 assert(l3->ar_sip == v4_ext_one); 143 assert(l3->ar_tip == v4_svc_one); 144 assert(memcmp(l3->ar_sha, (__u8 *)mac_one, ETH_ALEN) == 0); 145 assert(memcmp(l3->ar_tha, (__u8 *)mac_bcast, ETH_ALEN) == 0); 146 147 test_finish(); 148 } 149 150 PKTGEN("tc", "1_happy_path") 151 int l2_announcement_arp_happy_path_pktgen(struct __ctx_buff *ctx) 152 { 153 return build_packet(ctx); 154 } 155 156 /* Test that sending a ARP broadcast request matching an entry in the 157 * L2_RESPONDER_MAP4 results in a valid ARP reply. 158 */ 159 SETUP("tc", "1_happy_path") 160 int l2_announcement_arp_happy_path_setup(struct __ctx_buff *ctx) 161 { 162 struct l2_responder_v4_key key; 163 struct l2_responder_v4_stats value = {0}; 164 __u32 index; 165 __u64 time; 166 167 key.ifindex = 0; 168 key.ip4 = v4_svc_one; 169 map_update_elem(&L2_RESPONDER_MAP4, &key, &value, BPF_ANY); 170 171 index = RUNTIME_CONFIG_AGENT_LIVENESS; 172 time = ktime_get_ns(); 173 map_update_elem(&CONFIG_MAP, &index, &time, BPF_ANY); 174 175 /* Jump into the entrypoint */ 176 tail_call_static(ctx, entry_call_map, 0); 177 /* Fail if we didn't jump */ 178 return TEST_ERROR; 179 } 180 181 CHECK("tc", "1_happy_path") 182 int l2_announcement_arp_happy_path_check(__maybe_unused const struct __ctx_buff *ctx) 183 { 184 void *data; 185 void *data_end; 186 __u32 *status_code; 187 struct ethhdr *l2; 188 struct arphdreth *l3; 189 190 test_init(); 191 192 data = (void *)(long)ctx->data; 193 data_end = (void *)(long)ctx->data_end; 194 195 if (data + sizeof(__u32) > data_end) 196 test_fatal("status code out of bounds"); 197 198 status_code = data; 199 200 assert(*status_code == TC_ACT_REDIRECT); 201 202 l2 = data + sizeof(__u32); 203 if ((void *)l2 + sizeof(struct ethhdr) > data_end) 204 test_fatal("l2 out of bounds"); 205 206 l3 = data + sizeof(__u32) + sizeof(struct ethhdr); 207 208 if ((void *)l3 + sizeof(struct arphdreth) > data_end) 209 test_fatal("l3 out of bounds"); 210 211 assert(memcmp(l2->h_source, (__u8 *)mac_two, ETH_ALEN) == 0); 212 assert(memcmp(l2->h_dest, (__u8 *)mac_one, ETH_ALEN) == 0); 213 assert(l3->ar_op == bpf_htons(ARPOP_REPLY)); 214 assert(l3->ar_sip == v4_svc_one); 215 assert(l3->ar_tip == v4_ext_one); 216 assert(memcmp(l3->ar_sha, (__u8 *)mac_two, ETH_ALEN) == 0); 217 assert(memcmp(l3->ar_tha, (__u8 *)mac_one, ETH_ALEN) == 0); 218 219 test_finish(); 220 }