Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'selftests-bpf-migrate-test_xdp_redirect_multi-sh-to-test_progs'

Bastien Curutchet says:

====================
This patch series continues the work to migrate the *.sh tests into
prog_tests framework.

test_xdp_redirect_multi.sh tests the XDP redirections done through
bpf_redirect_map().

This is already partly covered by test_xdp_veth.c that already tests
map redirections at XDP level. What isn't covered yet by test_xdp_veth is
the use of the broadcast flags (BPF_F_BROADCAST or BPF_F_EXCLUDE_INGRESS)
and XDP egress programs.

This series is the prep work that will be followed up adding test cases
to eventually cover the tests done in test_xdp_redirect_multi.sh:
- PATCH 1 Add an helper to generate unique names
- PATCH 2 to 9 rework test_xdp_veth to make it more generic and allow to
configure different test cases
- PATCH 10 adds test cases for 'classic' bpf_redirect_map()
====================

Link: https://patch.msgid.link/20250131-redirect-multi-v4-0-970b33678512@bootlin.com
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Martin KaFai Lau and committed by
Alexei Starovoitov
03f3aa4a 12fdd29d

+231 -129
+17
tools/testing/selftests/bpf/network_helpers.c
··· 446 446 return "ping"; 447 447 } 448 448 449 + int append_tid(char *str, size_t sz) 450 + { 451 + size_t end; 452 + 453 + if (!str) 454 + return -1; 455 + 456 + end = strlen(str); 457 + if (end + 8 > sz) 458 + return -1; 459 + 460 + sprintf(&str[end], "%07d", gettid()); 461 + str[end + 7] = '\0'; 462 + 463 + return 0; 464 + } 465 + 449 466 int remove_netns(const char *name) 450 467 { 451 468 char *cmd;
+12
tools/testing/selftests/bpf/network_helpers.h
··· 98 98 int make_netns(const char *name); 99 99 int remove_netns(const char *name); 100 100 101 + /** 102 + * append_tid() - Append thread ID to the given string. 103 + * 104 + * @str: string to extend 105 + * @sz: string's size 106 + * 107 + * 8 characters are used to append the thread ID (7 digits + '\0') 108 + * 109 + * Returns -1 on errors, 0 otherwise 110 + */ 111 + int append_tid(char *str, size_t sz); 112 + 101 113 static __u16 csum_fold(__u32 csum) 102 114 { 103 115 csum = (csum & 0xffff) + (csum >> 16);
+202 -129
tools/testing/selftests/bpf/prog_tests/test_xdp_veth.c
··· 3 3 /* Create 3 namespaces with 3 veth peers, and forward packets in-between using 4 4 * native XDP 5 5 * 6 - * XDP_TX 7 - * NS1(veth11) NS2(veth22) NS3(veth33) 8 - * | | | 9 - * | | | 10 - * (veth1, (veth2, (veth3, 11 - * id:111) id:122) id:133) 12 - * ^ | ^ | ^ | 13 - * | | XDP_REDIRECT | | XDP_REDIRECT | | 14 - * | ------------------ ------------------ | 15 - * ----------------------------------------- 16 - * XDP_REDIRECT 6 + * Network topology: 7 + * ---------- ---------- ---------- 8 + * | NS1 | | NS2 | | NS3 | 9 + * | veth11 | | veth22 | | veth33 | 10 + * ----|----- -----|---- -----|---- 11 + * | | | 12 + * veth1 veth2 veth3 13 + * 14 + * Test cases: 15 + * - [test_xdp_veth_redirect] : ping veth33 from veth11 16 + * 17 + * veth11 veth22 veth33 18 + * (XDP_PASS) (XDP_TX) (XDP_PASS) 19 + * | | | 20 + * | | | 21 + * veth1 veth2 veth3 22 + * (XDP_REDIRECT) (XDP_REDIRECT) (XDP_REDIRECT) 23 + * ^ | ^ | ^ | 24 + * | | | | | | 25 + * | ------------------ ------------------ | 26 + * ----------------------------------------- 17 27 */ 18 28 19 29 #define _GNU_SOURCE ··· 33 23 #include "xdp_dummy.skel.h" 34 24 #include "xdp_redirect_map.skel.h" 35 25 #include "xdp_tx.skel.h" 26 + #include <uapi/linux/if_link.h> 36 27 37 28 #define VETH_PAIRS_COUNT 3 38 - #define NS_SUFFIX_LEN 6 39 - #define VETH_NAME_MAX_LEN 16 29 + #define VETH_NAME_MAX_LEN 32 30 + #define IP_MAX_LEN 16 40 31 #define IP_SRC "10.1.1.11" 41 32 #define IP_DST "10.1.1.33" 42 - #define IP_CMD_MAX_LEN 128 43 - 44 - struct skeletons { 45 - struct xdp_dummy *xdp_dummy; 46 - struct xdp_tx *xdp_tx; 47 - struct xdp_redirect_map *xdp_redirect_maps; 48 - }; 33 + #define PROG_NAME_MAX_LEN 128 34 + #define NS_NAME_MAX_LEN 32 49 35 50 36 struct veth_configuration { 51 37 char local_veth[VETH_NAME_MAX_LEN]; /* Interface in main namespace */ 52 38 char remote_veth[VETH_NAME_MAX_LEN]; /* Peer interface in dedicated namespace*/ 53 - const char *namespace; /* Namespace for the remote veth */ 54 - char next_veth[VETH_NAME_MAX_LEN]; /* Local interface to redirect traffic to */ 55 - char *remote_addr; /* IP address of the remote veth */ 39 + char namespace[NS_NAME_MAX_LEN]; /* Namespace for the remote veth */ 40 + int next_veth; /* Local interface to redirect traffic to */ 41 + char remote_addr[IP_MAX_LEN]; /* IP address of the remote veth */ 56 42 }; 57 43 58 - static struct veth_configuration config[VETH_PAIRS_COUNT] = { 44 + static const struct veth_configuration default_config[VETH_PAIRS_COUNT] = { 59 45 { 60 - .local_veth = "veth1", 46 + .local_veth = "veth1-", 61 47 .remote_veth = "veth11", 62 - .next_veth = "veth2", 48 + .next_veth = 1, 63 49 .remote_addr = IP_SRC, 64 - .namespace = "ns-veth11" 50 + .namespace = "ns-veth11-" 65 51 }, 66 52 { 67 - .local_veth = "veth2", 53 + .local_veth = "veth2-", 68 54 .remote_veth = "veth22", 69 - .next_veth = "veth3", 70 - .remote_addr = NULL, 71 - .namespace = "ns-veth22" 55 + .next_veth = 2, 56 + .remote_addr = "", 57 + .namespace = "ns-veth22-" 72 58 }, 73 59 { 74 - .local_veth = "veth3", 60 + .local_veth = "veth3-", 75 61 .remote_veth = "veth33", 76 - .next_veth = "veth1", 62 + .next_veth = 0, 77 63 .remote_addr = IP_DST, 78 - .namespace = "ns-veth33" 64 + .namespace = "ns-veth33-" 79 65 } 80 66 }; 81 67 82 - static int attach_programs_to_veth_pair(struct skeletons *skeletons, int index) 68 + struct prog_configuration { 69 + char local_name[PROG_NAME_MAX_LEN]; /* BPF prog to attach to local_veth */ 70 + char remote_name[PROG_NAME_MAX_LEN]; /* BPF prog to attach to remote_veth */ 71 + u32 local_flags; /* XDP flags to use on local_veth */ 72 + u32 remote_flags; /* XDP flags to use on remote_veth */ 73 + }; 74 + 75 + static int attach_programs_to_veth_pair(struct bpf_object **objs, size_t nb_obj, 76 + struct veth_configuration *net_config, 77 + struct prog_configuration *prog, int index) 83 78 { 84 79 struct bpf_program *local_prog, *remote_prog; 85 - struct bpf_link **local_link, **remote_link; 86 80 struct nstoken *nstoken; 87 - struct bpf_link *link; 88 - int interface; 81 + int interface, ret, i; 89 82 90 - switch (index) { 91 - case 0: 92 - local_prog = skeletons->xdp_redirect_maps->progs.xdp_redirect_map_0; 93 - local_link = &skeletons->xdp_redirect_maps->links.xdp_redirect_map_0; 94 - remote_prog = skeletons->xdp_dummy->progs.xdp_dummy_prog; 95 - remote_link = &skeletons->xdp_dummy->links.xdp_dummy_prog; 96 - break; 97 - case 1: 98 - local_prog = skeletons->xdp_redirect_maps->progs.xdp_redirect_map_1; 99 - local_link = &skeletons->xdp_redirect_maps->links.xdp_redirect_map_1; 100 - remote_prog = skeletons->xdp_tx->progs.xdp_tx; 101 - remote_link = &skeletons->xdp_tx->links.xdp_tx; 102 - break; 103 - case 2: 104 - local_prog = skeletons->xdp_redirect_maps->progs.xdp_redirect_map_2; 105 - local_link = &skeletons->xdp_redirect_maps->links.xdp_redirect_map_2; 106 - remote_prog = skeletons->xdp_dummy->progs.xdp_dummy_prog; 107 - remote_link = &skeletons->xdp_dummy->links.xdp_dummy_prog; 108 - break; 83 + for (i = 0; i < nb_obj; i++) { 84 + local_prog = bpf_object__find_program_by_name(objs[i], prog[index].local_name); 85 + if (local_prog) 86 + break; 109 87 } 110 - interface = if_nametoindex(config[index].local_veth); 88 + if (!ASSERT_OK_PTR(local_prog, "find local program")) 89 + return -1; 90 + 91 + for (i = 0; i < nb_obj; i++) { 92 + remote_prog = bpf_object__find_program_by_name(objs[i], prog[index].remote_name); 93 + if (remote_prog) 94 + break; 95 + } 96 + if (!ASSERT_OK_PTR(remote_prog, "find remote program")) 97 + return -1; 98 + 99 + interface = if_nametoindex(net_config[index].local_veth); 111 100 if (!ASSERT_NEQ(interface, 0, "non zero interface index")) 112 101 return -1; 113 - link = bpf_program__attach_xdp(local_prog, interface); 114 - if (!ASSERT_OK_PTR(link, "attach xdp program to local veth")) 102 + 103 + ret = bpf_xdp_attach(interface, bpf_program__fd(local_prog), 104 + prog[index].local_flags, NULL); 105 + if (!ASSERT_OK(ret, "attach xdp program to local veth")) 115 106 return -1; 116 - *local_link = link; 117 - nstoken = open_netns(config[index].namespace); 107 + 108 + nstoken = open_netns(net_config[index].namespace); 118 109 if (!ASSERT_OK_PTR(nstoken, "switch to remote veth namespace")) 119 110 return -1; 120 - interface = if_nametoindex(config[index].remote_veth); 111 + 112 + interface = if_nametoindex(net_config[index].remote_veth); 121 113 if (!ASSERT_NEQ(interface, 0, "non zero interface index")) { 122 114 close_netns(nstoken); 123 115 return -1; 124 116 } 125 - link = bpf_program__attach_xdp(remote_prog, interface); 126 - *remote_link = link; 127 - close_netns(nstoken); 128 - if (!ASSERT_OK_PTR(link, "attach xdp program to remote veth")) 129 - return -1; 130 117 118 + ret = bpf_xdp_attach(interface, bpf_program__fd(remote_prog), 119 + prog[index].remote_flags, NULL); 120 + if (!ASSERT_OK(ret, "attach xdp program to remote veth")) { 121 + close_netns(nstoken); 122 + return -1; 123 + } 124 + 125 + close_netns(nstoken); 131 126 return 0; 132 127 } 133 128 134 - static int configure_network(struct skeletons *skeletons) 129 + static int create_network(struct veth_configuration *net_config) 135 130 { 136 - int interface_id; 137 - int map_fd; 138 - int err; 139 - int i = 0; 131 + int i, err; 132 + 133 + memcpy(net_config, default_config, VETH_PAIRS_COUNT * sizeof(struct veth_configuration)); 140 134 141 135 /* First create and configure all interfaces */ 142 136 for (i = 0; i < VETH_PAIRS_COUNT; i++) { 143 - SYS(fail, "ip netns add %s", config[i].namespace); 144 - SYS(fail, "ip link add %s type veth peer name %s netns %s", 145 - config[i].local_veth, config[i].remote_veth, config[i].namespace); 146 - SYS(fail, "ip link set dev %s up", config[i].local_veth); 147 - if (config[i].remote_addr) 148 - SYS(fail, "ip -n %s addr add %s/24 dev %s", config[i].namespace, 149 - config[i].remote_addr, config[i].remote_veth); 150 - SYS(fail, "ip -n %s link set dev %s up", config[i].namespace, 151 - config[i].remote_veth); 152 - } 137 + err = append_tid(net_config[i].namespace, NS_NAME_MAX_LEN); 138 + if (!ASSERT_OK(err, "append TID to ns name")) 139 + return -1; 153 140 154 - /* Then configure the redirect map and attach programs to interfaces */ 155 - map_fd = bpf_map__fd(skeletons->xdp_redirect_maps->maps.tx_port); 156 - if (!ASSERT_GE(map_fd, 0, "open redirect map")) 157 - goto fail; 158 - for (i = 0; i < VETH_PAIRS_COUNT; i++) { 159 - interface_id = if_nametoindex(config[i].next_veth); 160 - if (!ASSERT_NEQ(interface_id, 0, "non zero interface index")) 161 - goto fail; 162 - err = bpf_map_update_elem(map_fd, &i, &interface_id, BPF_ANY); 163 - if (!ASSERT_OK(err, "configure interface redirection through map")) 164 - goto fail; 165 - if (attach_programs_to_veth_pair(skeletons, i)) 166 - goto fail; 141 + err = append_tid(net_config[i].local_veth, VETH_NAME_MAX_LEN); 142 + if (!ASSERT_OK(err, "append TID to local veth name")) 143 + return -1; 144 + 145 + SYS(fail, "ip netns add %s", net_config[i].namespace); 146 + SYS(fail, "ip link add %s type veth peer name %s netns %s", 147 + net_config[i].local_veth, net_config[i].remote_veth, net_config[i].namespace); 148 + SYS(fail, "ip link set dev %s up", net_config[i].local_veth); 149 + if (net_config[i].remote_addr[0]) 150 + SYS(fail, "ip -n %s addr add %s/24 dev %s", net_config[i].namespace, 151 + net_config[i].remote_addr, net_config[i].remote_veth); 152 + SYS(fail, "ip -n %s link set dev %s up", net_config[i].namespace, 153 + net_config[i].remote_veth); 167 154 } 168 155 169 156 return 0; ··· 169 162 return -1; 170 163 } 171 164 172 - static void cleanup_network(void) 165 + static void cleanup_network(struct veth_configuration *net_config) 173 166 { 167 + struct nstoken *nstoken; 174 168 int i; 175 169 176 - /* Deleting namespaces is enough to automatically remove veth pairs as well 177 - */ 178 - for (i = 0; i < VETH_PAIRS_COUNT; i++) 179 - SYS_NOFAIL("ip netns del %s", config[i].namespace); 170 + for (i = 0; i < VETH_PAIRS_COUNT; i++) { 171 + bpf_xdp_detach(if_nametoindex(net_config[i].local_veth), 0, NULL); 172 + nstoken = open_netns(net_config[i].namespace); 173 + if (nstoken) { 174 + bpf_xdp_detach(if_nametoindex(net_config[i].remote_veth), 0, NULL); 175 + close_netns(nstoken); 176 + } 177 + /* in case the detach failed */ 178 + SYS_NOFAIL("ip link del %s", net_config[i].local_veth); 179 + SYS_NOFAIL("ip netns del %s", net_config[i].namespace); 180 + } 180 181 } 181 182 182 - static int check_ping(struct skeletons *skeletons) 183 + #define VETH_REDIRECT_SKEL_NB 3 184 + static void xdp_veth_redirect(u32 flags) 183 185 { 186 + struct prog_configuration ping_config[VETH_PAIRS_COUNT] = { 187 + { 188 + .local_name = "xdp_redirect_map_0", 189 + .remote_name = "xdp_dummy_prog", 190 + .local_flags = flags, 191 + .remote_flags = flags, 192 + }, 193 + { 194 + .local_name = "xdp_redirect_map_1", 195 + .remote_name = "xdp_tx", 196 + .local_flags = flags, 197 + .remote_flags = flags, 198 + }, 199 + { 200 + .local_name = "xdp_redirect_map_2", 201 + .remote_name = "xdp_dummy_prog", 202 + .local_flags = flags, 203 + .remote_flags = flags, 204 + } 205 + }; 206 + struct veth_configuration net_config[VETH_PAIRS_COUNT]; 207 + struct bpf_object *bpf_objs[VETH_REDIRECT_SKEL_NB]; 208 + struct xdp_redirect_map *xdp_redirect_map; 209 + struct xdp_dummy *xdp_dummy; 210 + struct xdp_tx *xdp_tx; 211 + int map_fd; 212 + int i; 213 + 214 + xdp_dummy = xdp_dummy__open_and_load(); 215 + if (!ASSERT_OK_PTR(xdp_dummy, "xdp_dummy__open_and_load")) 216 + return; 217 + 218 + xdp_tx = xdp_tx__open_and_load(); 219 + if (!ASSERT_OK_PTR(xdp_tx, "xdp_tx__open_and_load")) 220 + goto destroy_xdp_dummy; 221 + 222 + xdp_redirect_map = xdp_redirect_map__open_and_load(); 223 + if (!ASSERT_OK_PTR(xdp_redirect_map, "xdp_redirect_map__open_and_load")) 224 + goto destroy_xdp_tx; 225 + 226 + if (!ASSERT_OK(create_network(net_config), "create network")) 227 + goto destroy_xdp_redirect_map; 228 + 229 + /* Then configure the redirect map and attach programs to interfaces */ 230 + map_fd = bpf_map__fd(xdp_redirect_map->maps.tx_port); 231 + if (!ASSERT_OK_FD(map_fd, "open redirect map")) 232 + goto destroy_xdp_redirect_map; 233 + 234 + bpf_objs[0] = xdp_dummy->obj; 235 + bpf_objs[1] = xdp_tx->obj; 236 + bpf_objs[2] = xdp_redirect_map->obj; 237 + for (i = 0; i < VETH_PAIRS_COUNT; i++) { 238 + int next_veth = net_config[i].next_veth; 239 + int interface_id; 240 + int err; 241 + 242 + interface_id = if_nametoindex(net_config[next_veth].local_veth); 243 + if (!ASSERT_NEQ(interface_id, 0, "non zero interface index")) 244 + goto destroy_xdp_redirect_map; 245 + err = bpf_map_update_elem(map_fd, &i, &interface_id, BPF_ANY); 246 + if (!ASSERT_OK(err, "configure interface redirection through map")) 247 + goto destroy_xdp_redirect_map; 248 + if (attach_programs_to_veth_pair(bpf_objs, VETH_REDIRECT_SKEL_NB, 249 + net_config, ping_config, i)) 250 + goto destroy_xdp_redirect_map; 251 + } 252 + 184 253 /* Test: if all interfaces are properly configured, we must be able to ping 185 254 * veth33 from veth11 186 255 */ 187 - return SYS_NOFAIL("ip netns exec %s ping -c 1 -W 1 %s > /dev/null", 188 - config[0].namespace, IP_DST); 256 + ASSERT_OK(SYS_NOFAIL("ip netns exec %s ping -c 1 -W 1 %s > /dev/null", 257 + net_config[0].namespace, IP_DST), "ping"); 258 + 259 + destroy_xdp_redirect_map: 260 + xdp_redirect_map__destroy(xdp_redirect_map); 261 + destroy_xdp_tx: 262 + xdp_tx__destroy(xdp_tx); 263 + destroy_xdp_dummy: 264 + xdp_dummy__destroy(xdp_dummy); 265 + 266 + cleanup_network(net_config); 189 267 } 190 268 191 269 void test_xdp_veth_redirect(void) 192 270 { 193 - struct skeletons skeletons = {}; 271 + if (test__start_subtest("0")) 272 + xdp_veth_redirect(0); 194 273 195 - skeletons.xdp_dummy = xdp_dummy__open_and_load(); 196 - if (!ASSERT_OK_PTR(skeletons.xdp_dummy, "xdp_dummy__open_and_load")) 197 - return; 274 + if (test__start_subtest("DRV_MODE")) 275 + xdp_veth_redirect(XDP_FLAGS_DRV_MODE); 198 276 199 - skeletons.xdp_tx = xdp_tx__open_and_load(); 200 - if (!ASSERT_OK_PTR(skeletons.xdp_tx, "xdp_tx__open_and_load")) 201 - goto destroy_xdp_dummy; 202 - 203 - skeletons.xdp_redirect_maps = xdp_redirect_map__open_and_load(); 204 - if (!ASSERT_OK_PTR(skeletons.xdp_redirect_maps, "xdp_redirect_map__open_and_load")) 205 - goto destroy_xdp_tx; 206 - 207 - if (configure_network(&skeletons)) 208 - goto destroy_xdp_redirect_map; 209 - 210 - ASSERT_OK(check_ping(&skeletons), "ping"); 211 - 212 - destroy_xdp_redirect_map: 213 - xdp_redirect_map__destroy(skeletons.xdp_redirect_maps); 214 - destroy_xdp_tx: 215 - xdp_tx__destroy(skeletons.xdp_tx); 216 - destroy_xdp_dummy: 217 - xdp_dummy__destroy(skeletons.xdp_dummy); 218 - 219 - cleanup_network(); 277 + if (test__start_subtest("SKB_MODE")) 278 + xdp_veth_redirect(XDP_FLAGS_SKB_MODE); 220 279 }