1 // SPDX-License-Identifier: GPL-2.0-only
2
3 /* Connects 6 network namespaces through veths.
4 * Each NS may have different IPv6 global scope addresses :
5 *
6 * NS1 NS2 NS3 NS4 NS5 NS6
7 * lo veth1 <-> veth2 veth3 <-> veth4 veth5 <-> veth6 lo veth7 <-> veth8 veth9 <-> veth10 lo
8 * fb00 ::1 ::12 ::21 ::34 ::43 ::56 ::65 ::78 ::87 ::910 ::109 ::6
9 * fd00 ::4
10 * fc42 ::1
11 *
12 * All IPv6 packets going to fb00::/16 through NS2 will be encapsulated in a
13 * IPv6 header with a Segment Routing Header, with segments :
14 * fd00::1 -> fd00::2 -> fd00::3 -> fd00::4
15 *
16 * 3 fd00::/16 IPv6 addresses are binded to seg6local End.BPF actions :
17 * - fd00::1 : add a TLV, change the flags and apply a End.X action to fc42::1
18 * - fd00::2 : remove the TLV, change the flags, add a tag
19 * - fd00::3 : apply an End.T action to fd00::4, through routing table 117
20 *
21 * fd00::4 is a simple Segment Routing node decapsulating the inner IPv6 packet.
22 * Each End.BPF action will validate the operations applied on the SRH by the
23 * previous BPF program in the chain, otherwise the packet is dropped.
24 *
25 * An UDP datagram is sent from fb00::1 to fb00::6. The test succeeds if this
26 * datagram can be read on NS6 when binding to fb00::6.
27 */
28
29 #include "network_helpers.h"
30 #include "test_progs.h"
31
32 #define NETNS_BASE "lwt-seg6local-"
33 #define BPF_FILE "test_lwt_seg6local.bpf.o"
34
cleanup(void)35 static void cleanup(void)
36 {
37 int ns;
38
39 for (ns = 1; ns < 7; ns++)
40 SYS_NOFAIL("ip netns del %s%d", NETNS_BASE, ns);
41 }
42
setup(void)43 static int setup(void)
44 {
45 int ns;
46
47 for (ns = 1; ns < 7; ns++)
48 SYS(fail, "ip netns add %s%d", NETNS_BASE, ns);
49
50 SYS(fail, "ip -n %s6 link set dev lo up", NETNS_BASE);
51
52 for (ns = 1; ns < 6; ns++) {
53 int local_id = ns * 2 - 1;
54 int peer_id = ns * 2;
55 int next_ns = ns + 1;
56
57 SYS(fail, "ip -n %s%d link add veth%d type veth peer name veth%d netns %s%d",
58 NETNS_BASE, ns, local_id, peer_id, NETNS_BASE, next_ns);
59
60 SYS(fail, "ip -n %s%d link set dev veth%d up", NETNS_BASE, ns, local_id);
61 SYS(fail, "ip -n %s%d link set dev veth%d up", NETNS_BASE, next_ns, peer_id);
62
63 /* All link scope addresses to veths */
64 SYS(fail, "ip -n %s%d -6 addr add fb00::%d%d/16 dev veth%d scope link",
65 NETNS_BASE, ns, local_id, peer_id, local_id);
66 SYS(fail, "ip -n %s%d -6 addr add fb00::%d%d/16 dev veth%d scope link",
67 NETNS_BASE, next_ns, peer_id, local_id, peer_id);
68 }
69
70
71 SYS(fail, "ip -n %s5 -6 route add fb00::109 table 117 dev veth9 scope link", NETNS_BASE);
72
73 SYS(fail, "ip -n %s1 -6 addr add fb00::1/16 dev lo", NETNS_BASE);
74 SYS(fail, "ip -n %s1 -6 route add fb00::6 dev veth1 via fb00::21", NETNS_BASE);
75
76 SYS(fail, "ip -n %s2 -6 route add fb00::6 encap bpf in obj %s sec encap_srh dev veth2",
77 NETNS_BASE, BPF_FILE);
78 SYS(fail, "ip -n %s2 -6 route add fd00::1 dev veth3 via fb00::43 scope link", NETNS_BASE);
79
80 SYS(fail, "ip -n %s3 -6 route add fc42::1 dev veth5 via fb00::65", NETNS_BASE);
81 SYS(fail,
82 "ip -n %s3 -6 route add fd00::1 encap seg6local action End.BPF endpoint obj %s sec add_egr_x dev veth4",
83 NETNS_BASE, BPF_FILE);
84
85 SYS(fail,
86 "ip -n %s4 -6 route add fd00::2 encap seg6local action End.BPF endpoint obj %s sec pop_egr dev veth6",
87 NETNS_BASE, BPF_FILE);
88 SYS(fail, "ip -n %s4 -6 addr add fc42::1 dev lo", NETNS_BASE);
89 SYS(fail, "ip -n %s4 -6 route add fd00::3 dev veth7 via fb00::87", NETNS_BASE);
90
91 SYS(fail, "ip -n %s5 -6 route add fd00::4 table 117 dev veth9 via fb00::109", NETNS_BASE);
92 SYS(fail,
93 "ip -n %s5 -6 route add fd00::3 encap seg6local action End.BPF endpoint obj %s sec inspect_t dev veth8",
94 NETNS_BASE, BPF_FILE);
95
96 SYS(fail, "ip -n %s6 -6 addr add fb00::6/16 dev lo", NETNS_BASE);
97 SYS(fail, "ip -n %s6 -6 addr add fd00::4/16 dev lo", NETNS_BASE);
98
99 for (ns = 1; ns < 6; ns++)
100 SYS(fail, "ip netns exec %s%d sysctl -wq net.ipv6.conf.all.forwarding=1",
101 NETNS_BASE, ns);
102
103 SYS(fail, "ip netns exec %s6 sysctl -wq net.ipv6.conf.all.seg6_enabled=1", NETNS_BASE);
104 SYS(fail, "ip netns exec %s6 sysctl -wq net.ipv6.conf.lo.seg6_enabled=1", NETNS_BASE);
105 SYS(fail, "ip netns exec %s6 sysctl -wq net.ipv6.conf.veth10.seg6_enabled=1", NETNS_BASE);
106
107 return 0;
108 fail:
109 return -1;
110 }
111
112 #define SERVER_PORT 7330
113 #define CLIENT_PORT 2121
test_lwt_seg6local(void)114 void test_lwt_seg6local(void)
115 {
116 struct sockaddr_in6 server_addr = {};
117 const char *ns1 = NETNS_BASE "1";
118 const char *ns6 = NETNS_BASE "6";
119 struct nstoken *nstoken = NULL;
120 const char *foobar = "foobar";
121 ssize_t bytes;
122 int sfd, cfd;
123 char buf[7];
124
125 if (!ASSERT_OK(setup(), "setup"))
126 goto out;
127
128 nstoken = open_netns(ns6);
129 if (!ASSERT_OK_PTR(nstoken, "open ns6"))
130 goto out;
131
132 sfd = start_server_str(AF_INET6, SOCK_DGRAM, "fb00::6", SERVER_PORT, NULL);
133 if (!ASSERT_OK_FD(sfd, "start server"))
134 goto close_netns;
135
136 close_netns(nstoken);
137
138 nstoken = open_netns(ns1);
139 if (!ASSERT_OK_PTR(nstoken, "open ns1"))
140 goto close_server;
141
142 cfd = start_server_str(AF_INET6, SOCK_DGRAM, "fb00::1", CLIENT_PORT, NULL);
143 if (!ASSERT_OK_FD(cfd, "start client"))
144 goto close_server;
145
146 close_netns(nstoken);
147 nstoken = NULL;
148
149 /* Send a packet larger than MTU */
150 server_addr.sin6_family = AF_INET6;
151 server_addr.sin6_port = htons(SERVER_PORT);
152 if (!ASSERT_EQ(inet_pton(AF_INET6, "fb00::6", &server_addr.sin6_addr), 1,
153 "build target addr"))
154 goto close_client;
155
156 bytes = sendto(cfd, foobar, sizeof(foobar), 0,
157 (struct sockaddr *)&server_addr, sizeof(server_addr));
158 if (!ASSERT_EQ(bytes, sizeof(foobar), "send packet"))
159 goto close_client;
160
161 /* Verify we received all expected bytes */
162 bytes = read(sfd, buf, sizeof(buf));
163 if (!ASSERT_EQ(bytes, sizeof(buf), "receive packet"))
164 goto close_client;
165 ASSERT_STREQ(buf, foobar, "check udp packet");
166
167 close_client:
168 close(cfd);
169 close_server:
170 close(sfd);
171 close_netns:
172 close_netns(nstoken);
173
174 out:
175 cleanup();
176 }
177