214 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/* Create 3 namespaces with 3 veth peers, and forward packets in-between using4 * native XDP5 *6 * XDP_TX7 * 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_REDIRECT17 */18 19#define _GNU_SOURCE20#include <net/if.h>21#include "test_progs.h"22#include "network_helpers.h"23#include "xdp_dummy.skel.h"24#include "xdp_redirect_map.skel.h"25#include "xdp_tx.skel.h"26 27#define VETH_PAIRS_COUNT 328#define NS_SUFFIX_LEN 629#define VETH_NAME_MAX_LEN 1630#define IP_SRC "10.1.1.11"31#define IP_DST "10.1.1.33"32#define IP_CMD_MAX_LEN 12833 34struct skeletons {35 struct xdp_dummy *xdp_dummy;36 struct xdp_tx *xdp_tx;37 struct xdp_redirect_map *xdp_redirect_maps;38};39 40struct veth_configuration {41 char local_veth[VETH_NAME_MAX_LEN]; /* Interface in main namespace */42 char remote_veth[VETH_NAME_MAX_LEN]; /* Peer interface in dedicated namespace*/43 const char *namespace; /* Namespace for the remote veth */44 char next_veth[VETH_NAME_MAX_LEN]; /* Local interface to redirect traffic to */45 char *remote_addr; /* IP address of the remote veth */46};47 48static struct veth_configuration config[VETH_PAIRS_COUNT] = {49 {50 .local_veth = "veth1",51 .remote_veth = "veth11",52 .next_veth = "veth2",53 .remote_addr = IP_SRC,54 .namespace = "ns-veth11"55 },56 {57 .local_veth = "veth2",58 .remote_veth = "veth22",59 .next_veth = "veth3",60 .remote_addr = NULL,61 .namespace = "ns-veth22"62 },63 {64 .local_veth = "veth3",65 .remote_veth = "veth33",66 .next_veth = "veth1",67 .remote_addr = IP_DST,68 .namespace = "ns-veth33"69 }70};71 72static int attach_programs_to_veth_pair(struct skeletons *skeletons, int index)73{74 struct bpf_program *local_prog, *remote_prog;75 struct bpf_link **local_link, **remote_link;76 struct nstoken *nstoken;77 struct bpf_link *link;78 int interface;79 80 switch (index) {81 case 0:82 local_prog = skeletons->xdp_redirect_maps->progs.xdp_redirect_map_0;83 local_link = &skeletons->xdp_redirect_maps->links.xdp_redirect_map_0;84 remote_prog = skeletons->xdp_dummy->progs.xdp_dummy_prog;85 remote_link = &skeletons->xdp_dummy->links.xdp_dummy_prog;86 break;87 case 1:88 local_prog = skeletons->xdp_redirect_maps->progs.xdp_redirect_map_1;89 local_link = &skeletons->xdp_redirect_maps->links.xdp_redirect_map_1;90 remote_prog = skeletons->xdp_tx->progs.xdp_tx;91 remote_link = &skeletons->xdp_tx->links.xdp_tx;92 break;93 case 2:94 local_prog = skeletons->xdp_redirect_maps->progs.xdp_redirect_map_2;95 local_link = &skeletons->xdp_redirect_maps->links.xdp_redirect_map_2;96 remote_prog = skeletons->xdp_dummy->progs.xdp_dummy_prog;97 remote_link = &skeletons->xdp_dummy->links.xdp_dummy_prog;98 break;99 }100 interface = if_nametoindex(config[index].local_veth);101 if (!ASSERT_NEQ(interface, 0, "non zero interface index"))102 return -1;103 link = bpf_program__attach_xdp(local_prog, interface);104 if (!ASSERT_OK_PTR(link, "attach xdp program to local veth"))105 return -1;106 *local_link = link;107 nstoken = open_netns(config[index].namespace);108 if (!ASSERT_OK_PTR(nstoken, "switch to remote veth namespace"))109 return -1;110 interface = if_nametoindex(config[index].remote_veth);111 if (!ASSERT_NEQ(interface, 0, "non zero interface index")) {112 close_netns(nstoken);113 return -1;114 }115 link = bpf_program__attach_xdp(remote_prog, interface);116 *remote_link = link;117 close_netns(nstoken);118 if (!ASSERT_OK_PTR(link, "attach xdp program to remote veth"))119 return -1;120 121 return 0;122}123 124static int configure_network(struct skeletons *skeletons)125{126 int interface_id;127 int map_fd;128 int err;129 int i = 0;130 131 /* First create and configure all interfaces */132 for (i = 0; i < VETH_PAIRS_COUNT; i++) {133 SYS(fail, "ip netns add %s", config[i].namespace);134 SYS(fail, "ip link add %s type veth peer name %s netns %s",135 config[i].local_veth, config[i].remote_veth, config[i].namespace);136 SYS(fail, "ip link set dev %s up", config[i].local_veth);137 if (config[i].remote_addr)138 SYS(fail, "ip -n %s addr add %s/24 dev %s", config[i].namespace,139 config[i].remote_addr, config[i].remote_veth);140 SYS(fail, "ip -n %s link set dev %s up", config[i].namespace,141 config[i].remote_veth);142 }143 144 /* Then configure the redirect map and attach programs to interfaces */145 map_fd = bpf_map__fd(skeletons->xdp_redirect_maps->maps.tx_port);146 if (!ASSERT_GE(map_fd, 0, "open redirect map"))147 goto fail;148 for (i = 0; i < VETH_PAIRS_COUNT; i++) {149 interface_id = if_nametoindex(config[i].next_veth);150 if (!ASSERT_NEQ(interface_id, 0, "non zero interface index"))151 goto fail;152 err = bpf_map_update_elem(map_fd, &i, &interface_id, BPF_ANY);153 if (!ASSERT_OK(err, "configure interface redirection through map"))154 goto fail;155 if (attach_programs_to_veth_pair(skeletons, i))156 goto fail;157 }158 159 return 0;160 161fail:162 return -1;163}164 165static void cleanup_network(void)166{167 int i;168 169 /* Deleting namespaces is enough to automatically remove veth pairs as well170 */171 for (i = 0; i < VETH_PAIRS_COUNT; i++)172 SYS_NOFAIL("ip netns del %s", config[i].namespace);173}174 175static int check_ping(struct skeletons *skeletons)176{177 /* Test: if all interfaces are properly configured, we must be able to ping178 * veth33 from veth11179 */180 return SYS_NOFAIL("ip netns exec %s ping -c 1 -W 1 %s > /dev/null",181 config[0].namespace, IP_DST);182}183 184void test_xdp_veth_redirect(void)185{186 struct skeletons skeletons = {};187 188 skeletons.xdp_dummy = xdp_dummy__open_and_load();189 if (!ASSERT_OK_PTR(skeletons.xdp_dummy, "xdp_dummy__open_and_load"))190 return;191 192 skeletons.xdp_tx = xdp_tx__open_and_load();193 if (!ASSERT_OK_PTR(skeletons.xdp_tx, "xdp_tx__open_and_load"))194 goto destroy_xdp_dummy;195 196 skeletons.xdp_redirect_maps = xdp_redirect_map__open_and_load();197 if (!ASSERT_OK_PTR(skeletons.xdp_redirect_maps, "xdp_redirect_map__open_and_load"))198 goto destroy_xdp_tx;199 200 if (configure_network(&skeletons))201 goto destroy_xdp_redirect_map;202 203 ASSERT_OK(check_ping(&skeletons), "ping");204 205destroy_xdp_redirect_map:206 xdp_redirect_map__destroy(skeletons.xdp_redirect_maps);207destroy_xdp_tx:208 xdp_tx__destroy(skeletons.xdp_tx);209destroy_xdp_dummy:210 xdp_dummy__destroy(skeletons.xdp_dummy);211 212 cleanup_network();213}214