348 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause2 3/*4 * Topology:5 * ---------6 * NS0 namespace | NS1 namespace | NS2 namespace7 * | |8 * +---------------+ | +---------------+ |9 * | ipsec0 |---------| ipsec0 | |10 * | 192.168.1.100 | | | 192.168.1.200 | |11 * | if_id: bpf | | +---------------+ |12 * +---------------+ | |13 * | | | +---------------+14 * | | | | ipsec0 |15 * \------------------------------------------| 192.168.1.200 |16 * | | +---------------+17 * | |18 * | | (overlay network)19 * ------------------------------------------------------20 * | | (underlay network)21 * +--------------+ | +--------------+ |22 * | veth01 |----------| veth10 | |23 * | 172.16.1.100 | | | 172.16.1.200 | |24 * ---------------+ | +--------------+ |25 * | |26 * +--------------+ | | +--------------+27 * | veth02 |-----------------------------------| veth20 |28 * | 172.16.2.100 | | | | 172.16.2.200 |29 * +--------------+ | | +--------------+30 *31 *32 * Test Packet flow33 * -----------34 * The tests perform 'ping 192.168.1.200' from the NS0 namespace:35 * 1) request is routed to NS0 ipsec036 * 2) NS0 ipsec0 tc egress BPF program is triggered and sets the if_id based37 * on the requested value. This makes the ipsec0 device in external mode38 * select the destination tunnel39 * 3) ping reaches the other namespace (NS1 or NS2 based on which if_id was40 * used) and response is sent41 * 4) response is received on NS0 ipsec0, tc ingress program is triggered and42 * records the response if_id43 * 5) requested if_id is compared with received if_id44 */45 46#include <net/if.h>47#include <linux/rtnetlink.h>48#include <linux/if_link.h>49 50#include "test_progs.h"51#include "network_helpers.h"52#include "xfrm_info.skel.h"53 54#define NS0 "xfrm_test_ns0"55#define NS1 "xfrm_test_ns1"56#define NS2 "xfrm_test_ns2"57 58#define IF_ID_0_TO_1 159#define IF_ID_0_TO_2 260#define IF_ID_1 361#define IF_ID_2 462 63#define IP4_ADDR_VETH01 "172.16.1.100"64#define IP4_ADDR_VETH10 "172.16.1.200"65#define IP4_ADDR_VETH02 "172.16.2.100"66#define IP4_ADDR_VETH20 "172.16.2.200"67 68#define ESP_DUMMY_PARAMS \69 "proto esp aead 'rfc4106(gcm(aes))' " \70 "0xe4d8f4b4da1df18a3510b3781496daa82488b713 128 mode tunnel "71 72static int attach_tc_prog(struct bpf_tc_hook *hook, int igr_fd, int egr_fd)73{74 LIBBPF_OPTS(bpf_tc_opts, opts1, .handle = 1, .priority = 1,75 .prog_fd = igr_fd);76 LIBBPF_OPTS(bpf_tc_opts, opts2, .handle = 1, .priority = 1,77 .prog_fd = egr_fd);78 int ret;79 80 ret = bpf_tc_hook_create(hook);81 if (!ASSERT_OK(ret, "create tc hook"))82 return ret;83 84 if (igr_fd >= 0) {85 hook->attach_point = BPF_TC_INGRESS;86 ret = bpf_tc_attach(hook, &opts1);87 if (!ASSERT_OK(ret, "bpf_tc_attach")) {88 bpf_tc_hook_destroy(hook);89 return ret;90 }91 }92 93 if (egr_fd >= 0) {94 hook->attach_point = BPF_TC_EGRESS;95 ret = bpf_tc_attach(hook, &opts2);96 if (!ASSERT_OK(ret, "bpf_tc_attach")) {97 bpf_tc_hook_destroy(hook);98 return ret;99 }100 }101 102 return 0;103}104 105static void cleanup(void)106{107 SYS_NOFAIL("test -f /var/run/netns/" NS0 " && ip netns delete " NS0);108 SYS_NOFAIL("test -f /var/run/netns/" NS1 " && ip netns delete " NS1);109 SYS_NOFAIL("test -f /var/run/netns/" NS2 " && ip netns delete " NS2);110}111 112static int config_underlay(void)113{114 SYS(fail, "ip netns add " NS0);115 SYS(fail, "ip netns add " NS1);116 SYS(fail, "ip netns add " NS2);117 118 /* NS0 <-> NS1 [veth01 <-> veth10] */119 SYS(fail, "ip link add veth01 netns " NS0 " type veth peer name veth10 netns " NS1);120 SYS(fail, "ip -net " NS0 " addr add " IP4_ADDR_VETH01 "/24 dev veth01");121 SYS(fail, "ip -net " NS0 " link set dev veth01 up");122 SYS(fail, "ip -net " NS1 " addr add " IP4_ADDR_VETH10 "/24 dev veth10");123 SYS(fail, "ip -net " NS1 " link set dev veth10 up");124 125 /* NS0 <-> NS2 [veth02 <-> veth20] */126 SYS(fail, "ip link add veth02 netns " NS0 " type veth peer name veth20 netns " NS2);127 SYS(fail, "ip -net " NS0 " addr add " IP4_ADDR_VETH02 "/24 dev veth02");128 SYS(fail, "ip -net " NS0 " link set dev veth02 up");129 SYS(fail, "ip -net " NS2 " addr add " IP4_ADDR_VETH20 "/24 dev veth20");130 SYS(fail, "ip -net " NS2 " link set dev veth20 up");131 132 return 0;133fail:134 return -1;135}136 137static int setup_xfrm_tunnel_ns(const char *ns, const char *ipv4_local,138 const char *ipv4_remote, int if_id)139{140 /* State: local -> remote */141 SYS(fail, "ip -net %s xfrm state add src %s dst %s spi 1 "142 ESP_DUMMY_PARAMS "if_id %d", ns, ipv4_local, ipv4_remote, if_id);143 144 /* State: local <- remote */145 SYS(fail, "ip -net %s xfrm state add src %s dst %s spi 1 "146 ESP_DUMMY_PARAMS "if_id %d", ns, ipv4_remote, ipv4_local, if_id);147 148 /* Policy: local -> remote */149 SYS(fail, "ip -net %s xfrm policy add dir out src 0.0.0.0/0 dst 0.0.0.0/0 "150 "if_id %d tmpl src %s dst %s proto esp mode tunnel if_id %d", ns,151 if_id, ipv4_local, ipv4_remote, if_id);152 153 /* Policy: local <- remote */154 SYS(fail, "ip -net %s xfrm policy add dir in src 0.0.0.0/0 dst 0.0.0.0/0 "155 "if_id %d tmpl src %s dst %s proto esp mode tunnel if_id %d", ns,156 if_id, ipv4_remote, ipv4_local, if_id);157 158 return 0;159fail:160 return -1;161}162 163static int setup_xfrm_tunnel(const char *ns_a, const char *ns_b,164 const char *ipv4_a, const char *ipv4_b,165 int if_id_a, int if_id_b)166{167 return setup_xfrm_tunnel_ns(ns_a, ipv4_a, ipv4_b, if_id_a) ||168 setup_xfrm_tunnel_ns(ns_b, ipv4_b, ipv4_a, if_id_b);169}170 171static struct rtattr *rtattr_add(struct nlmsghdr *nh, unsigned short type,172 unsigned short len)173{174 struct rtattr *rta =175 (struct rtattr *)((uint8_t *)nh + RTA_ALIGN(nh->nlmsg_len));176 rta->rta_type = type;177 rta->rta_len = RTA_LENGTH(len);178 nh->nlmsg_len = RTA_ALIGN(nh->nlmsg_len) + RTA_ALIGN(rta->rta_len);179 return rta;180}181 182static struct rtattr *rtattr_add_str(struct nlmsghdr *nh, unsigned short type,183 const char *s)184{185 struct rtattr *rta = rtattr_add(nh, type, strlen(s));186 187 memcpy(RTA_DATA(rta), s, strlen(s));188 return rta;189}190 191static struct rtattr *rtattr_begin(struct nlmsghdr *nh, unsigned short type)192{193 return rtattr_add(nh, type, 0);194}195 196static void rtattr_end(struct nlmsghdr *nh, struct rtattr *attr)197{198 uint8_t *end = (uint8_t *)nh + nh->nlmsg_len;199 200 attr->rta_len = end - (uint8_t *)attr;201}202 203static int setup_xfrmi_external_dev(const char *ns)204{205 struct {206 struct nlmsghdr nh;207 struct ifinfomsg info;208 unsigned char data[128];209 } req;210 struct rtattr *link_info, *info_data;211 struct nstoken *nstoken;212 int ret = -1, sock = -1;213 struct nlmsghdr *nh;214 215 memset(&req, 0, sizeof(req));216 nh = &req.nh;217 nh->nlmsg_len = NLMSG_LENGTH(sizeof(req.info));218 nh->nlmsg_type = RTM_NEWLINK;219 nh->nlmsg_flags |= NLM_F_CREATE | NLM_F_REQUEST;220 221 rtattr_add_str(nh, IFLA_IFNAME, "ipsec0");222 link_info = rtattr_begin(nh, IFLA_LINKINFO);223 rtattr_add_str(nh, IFLA_INFO_KIND, "xfrm");224 info_data = rtattr_begin(nh, IFLA_INFO_DATA);225 rtattr_add(nh, IFLA_XFRM_COLLECT_METADATA, 0);226 rtattr_end(nh, info_data);227 rtattr_end(nh, link_info);228 229 nstoken = open_netns(ns);230 if (!ASSERT_OK_PTR(nstoken, "setns"))231 goto done;232 233 sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);234 if (!ASSERT_GE(sock, 0, "netlink socket"))235 goto done;236 ret = send(sock, nh, nh->nlmsg_len, 0);237 if (!ASSERT_EQ(ret, nh->nlmsg_len, "netlink send length"))238 goto done;239 240 ret = 0;241done:242 if (sock != -1)243 close(sock);244 if (nstoken)245 close_netns(nstoken);246 return ret;247}248 249static int config_overlay(void)250{251 if (setup_xfrm_tunnel(NS0, NS1, IP4_ADDR_VETH01, IP4_ADDR_VETH10,252 IF_ID_0_TO_1, IF_ID_1))253 goto fail;254 if (setup_xfrm_tunnel(NS0, NS2, IP4_ADDR_VETH02, IP4_ADDR_VETH20,255 IF_ID_0_TO_2, IF_ID_2))256 goto fail;257 258 /* Older iproute2 doesn't support this option */259 if (!ASSERT_OK(setup_xfrmi_external_dev(NS0), "xfrmi"))260 goto fail;261 262 SYS(fail, "ip -net " NS0 " addr add 192.168.1.100/24 dev ipsec0");263 SYS(fail, "ip -net " NS0 " link set dev ipsec0 up");264 265 SYS(fail, "ip -net " NS1 " link add ipsec0 type xfrm if_id %d", IF_ID_1);266 SYS(fail, "ip -net " NS1 " addr add 192.168.1.200/24 dev ipsec0");267 SYS(fail, "ip -net " NS1 " link set dev ipsec0 up");268 269 SYS(fail, "ip -net " NS2 " link add ipsec0 type xfrm if_id %d", IF_ID_2);270 SYS(fail, "ip -net " NS2 " addr add 192.168.1.200/24 dev ipsec0");271 SYS(fail, "ip -net " NS2 " link set dev ipsec0 up");272 273 return 0;274fail:275 return -1;276}277 278static int test_xfrm_ping(struct xfrm_info *skel, u32 if_id)279{280 skel->bss->req_if_id = if_id;281 282 SYS(fail, "ping -i 0.01 -c 3 -w 10 -q 192.168.1.200 > /dev/null");283 284 if (!ASSERT_EQ(skel->bss->resp_if_id, if_id, "if_id"))285 goto fail;286 287 return 0;288fail:289 return -1;290}291 292static void _test_xfrm_info(void)293{294 LIBBPF_OPTS(bpf_tc_hook, tc_hook, .attach_point = BPF_TC_INGRESS);295 int get_xfrm_info_prog_fd, set_xfrm_info_prog_fd;296 struct nstoken *nstoken = NULL;297 struct xfrm_info *skel;298 int ifindex;299 300 /* load and attach bpf progs to ipsec dev tc hook point */301 skel = xfrm_info__open_and_load();302 if (!ASSERT_OK_PTR(skel, "xfrm_info__open_and_load"))303 goto done;304 nstoken = open_netns(NS0);305 if (!ASSERT_OK_PTR(nstoken, "setns " NS0))306 goto done;307 ifindex = if_nametoindex("ipsec0");308 if (!ASSERT_NEQ(ifindex, 0, "ipsec0 ifindex"))309 goto done;310 tc_hook.ifindex = ifindex;311 set_xfrm_info_prog_fd = bpf_program__fd(skel->progs.set_xfrm_info);312 get_xfrm_info_prog_fd = bpf_program__fd(skel->progs.get_xfrm_info);313 if (!ASSERT_GE(set_xfrm_info_prog_fd, 0, "bpf_program__fd"))314 goto done;315 if (!ASSERT_GE(get_xfrm_info_prog_fd, 0, "bpf_program__fd"))316 goto done;317 if (attach_tc_prog(&tc_hook, get_xfrm_info_prog_fd,318 set_xfrm_info_prog_fd))319 goto done;320 321 /* perform test */322 if (!ASSERT_EQ(test_xfrm_ping(skel, IF_ID_0_TO_1), 0, "ping " NS1))323 goto done;324 if (!ASSERT_EQ(test_xfrm_ping(skel, IF_ID_0_TO_2), 0, "ping " NS2))325 goto done;326 327done:328 if (nstoken)329 close_netns(nstoken);330 xfrm_info__destroy(skel);331}332 333void test_xfrm_info(void)334{335 cleanup();336 337 if (!ASSERT_OK(config_underlay(), "config_underlay"))338 goto done;339 if (!ASSERT_OK(config_overlay(), "config_overlay"))340 goto done;341 342 if (test__start_subtest("xfrm_info"))343 _test_xfrm_info();344 345done:346 cleanup();347}348