|
| 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 | +} |
0 commit comments