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();
}
|