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 | |
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 | |
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 |
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 | |