summaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/bpf/prog_tests/lwt_seg6local.c
blob: 3bc730b7c7fa0c4809c7c4ed6e00e7a7d12cb555 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// SPDX-License-Identifier: GPL-2.0-only

/* Connects 6 network namespaces through veths.
 * Each NS may have different IPv6 global scope addresses :
 *
 *          NS1            NS2             NS3              NS4               NS5             NS6
 *      lo  veth1 <-> veth2 veth3 <-> veth4 veth5 <-> veth6 lo veth7 <-> veth8 veth9 <-> veth10 lo
 * fb00 ::1  ::12      ::21  ::34      ::43  ::56      ::65     ::78      ::87  ::910     ::109  ::6
 * fd00                                                                                          ::4
 * fc42                                                     ::1
 *
 * All IPv6 packets going to fb00::/16 through NS2 will be encapsulated in a
 * IPv6 header with a Segment Routing Header, with segments :
 *	fd00::1 -> fd00::2 -> fd00::3 -> fd00::4
 *
 * 3 fd00::/16 IPv6 addresses are binded to seg6local End.BPF actions :
 * - fd00::1 : add a TLV, change the flags and apply a End.X action to fc42::1
 * - fd00::2 : remove the TLV, change the flags, add a tag
 * - fd00::3 : apply an End.T action to fd00::4, through routing table 117
 *
 * fd00::4 is a simple Segment Routing node decapsulating the inner IPv6 packet.
 * Each End.BPF action will validate the operations applied on the SRH by the
 * previous BPF program in the chain, otherwise the packet is dropped.
 *
 * An UDP datagram is sent from fb00::1 to fb00::6. The test succeeds if this
 * datagram can be read on NS6 when binding to fb00::6.
 */

#include "network_helpers.h"
#include "test_progs.h"

#define NETNS_BASE "lwt-seg6local-"
#define BPF_FILE "test_lwt_seg6local.bpf.o"

static void cleanup(void)
{
	int ns;

	for (ns = 1; ns < 7; ns++)
		SYS_NOFAIL("ip netns del %s%d", NETNS_BASE, ns);
}

static int setup(void)
{
	int ns;

	for (ns = 1; ns < 7; ns++)
		SYS(fail, "ip netns add %s%d", NETNS_BASE, ns);

	SYS(fail, "ip -n %s6 link set dev lo up", NETNS_BASE);

	for (ns = 1; ns < 6; ns++) {
		int local_id = ns * 2 - 1;
		int peer_id = ns * 2;
		int next_ns = ns + 1;

		SYS(fail, "ip -n %s%d link add veth%d type veth peer name veth%d netns %s%d",
		    NETNS_BASE, ns, local_id, peer_id, NETNS_BASE, next_ns);

		SYS(fail, "ip -n %s%d link set dev veth%d up", NETNS_BASE, ns, local_id);
		SYS(fail, "ip -n %s%d link set dev veth%d up", NETNS_BASE, next_ns, peer_id);

		/* All link scope addresses to veths */
		SYS(fail, "ip -n %s%d -6 addr add fb00::%d%d/16 dev veth%d scope link",
		    NETNS_BASE, ns, local_id, peer_id, local_id);
		SYS(fail, "ip -n %s%d -6 addr add fb00::%d%d/16 dev veth%d scope link",
		    NETNS_BASE, next_ns, peer_id, local_id, peer_id);
	}


	SYS(fail, "ip -n %s5 -6 route add fb00::109 table 117 dev veth9 scope link", NETNS_BASE);

	SYS(fail, "ip -n %s1 -6 addr add fb00::1/16 dev lo", NETNS_BASE);
	SYS(fail, "ip -n %s1 -6 route add fb00::6 dev veth1 via fb00::21", NETNS_BASE);

	SYS(fail, "ip -n %s2 -6 route add fb00::6 encap bpf in obj %s sec encap_srh dev veth2",
	    NETNS_BASE, BPF_FILE);
	SYS(fail, "ip -n %s2 -6 route add fd00::1 dev veth3 via fb00::43 scope link", NETNS_BASE);

	SYS(fail, "ip -n %s3 -6 route add fc42::1 dev veth5 via fb00::65", NETNS_BASE);
	SYS(fail,
	    "ip -n %s3 -6 route add fd00::1 encap seg6local action End.BPF endpoint obj %s sec add_egr_x dev veth4",
	    NETNS_BASE, BPF_FILE);

	SYS(fail,
	    "ip -n %s4 -6 route add fd00::2 encap seg6local action End.BPF endpoint obj %s sec pop_egr dev veth6",
	    NETNS_BASE, BPF_FILE);
	SYS(fail, "ip -n %s4 -6 addr add fc42::1 dev lo", NETNS_BASE);
	SYS(fail, "ip -n %s4 -6 route add fd00::3 dev veth7 via fb00::87", NETNS_BASE);

	SYS(fail, "ip -n %s5 -6 route add fd00::4 table 117 dev veth9 via fb00::109", NETNS_BASE);
	SYS(fail,
	    "ip -n %s5 -6 route add fd00::3 encap seg6local action End.BPF endpoint obj %s sec inspect_t dev veth8",
	    NETNS_BASE, BPF_FILE);

	SYS(fail, "ip -n %s6 -6 addr add fb00::6/16 dev lo", NETNS_BASE);
	SYS(fail, "ip -n %s6 -6 addr add fd00::4/16 dev lo", NETNS_BASE);

	for (ns = 1; ns < 6; ns++)
		SYS(fail, "ip netns exec %s%d sysctl -wq net.ipv6.conf.all.forwarding=1",
		    NETNS_BASE, ns);

	SYS(fail, "ip netns exec %s6 sysctl -wq net.ipv6.conf.all.seg6_enabled=1", NETNS_BASE);
	SYS(fail, "ip netns exec %s6 sysctl -wq net.ipv6.conf.lo.seg6_enabled=1", NETNS_BASE);
	SYS(fail, "ip netns exec %s6 sysctl -wq net.ipv6.conf.veth10.seg6_enabled=1", NETNS_BASE);

	return 0;
fail:
	return -1;
}

#define SERVER_PORT 7330
#define CLIENT_PORT 2121
void test_lwt_seg6local(void)
{
	struct sockaddr_in6 server_addr = {};
	const char *ns1 = NETNS_BASE "1";
	const char *ns6 = NETNS_BASE "6";
	struct nstoken *nstoken = NULL;
	const char *foobar = "foobar";
	ssize_t bytes;
	int sfd, cfd;
	char buf[7];

	if (!ASSERT_OK(setup(), "setup"))
		goto out;

	nstoken = open_netns(ns6);
	if (!ASSERT_OK_PTR(nstoken, "open ns6"))
		goto out;

	sfd = start_server_str(AF_INET6, SOCK_DGRAM, "fb00::6", SERVER_PORT, NULL);
	if (!ASSERT_OK_FD(sfd, "start server"))
		goto close_netns;

	close_netns(nstoken);

	nstoken = open_netns(ns1);
	if (!ASSERT_OK_PTR(nstoken, "open ns1"))
		goto close_server;

	cfd = start_server_str(AF_INET6, SOCK_DGRAM, "fb00::1", CLIENT_PORT, NULL);
	if (!ASSERT_OK_FD(cfd, "start client"))
		goto close_server;

	close_netns(nstoken);
	nstoken = NULL;

	/* Send a packet larger than MTU */
	server_addr.sin6_family = AF_INET6;
	server_addr.sin6_port = htons(SERVER_PORT);
	if (!ASSERT_EQ(inet_pton(AF_INET6, "fb00::6", &server_addr.sin6_addr), 1,
		       "build target addr"))
		goto close_client;

	bytes = sendto(cfd, foobar, sizeof(foobar), 0,
		       (struct sockaddr *)&server_addr, sizeof(server_addr));
	if (!ASSERT_EQ(bytes, sizeof(foobar), "send packet"))
		goto close_client;

	/* Verify we received all expected bytes */
	bytes = read(sfd, buf, sizeof(buf));
	if (!ASSERT_EQ(bytes, sizeof(buf), "receive packet"))
		goto close_client;
	ASSERT_STREQ(buf, foobar, "check udp packet");

close_client:
	close(cfd);
close_server:
	close(sfd);
close_netns:
	close_netns(nstoken);

out:
	cleanup();
}