From 192a0a3c886f1ad2308dbd182783d0cb40a7ea15 Mon Sep 17 00:00:00 2001 From: Max Rottenkolber Date: Fri, 29 Jul 2022 15:10:16 +0000 Subject: [PATCH] lwaftr: tutorial wip --- src/program/lwaftr/doc/tutorial/README.md | 165 ++++++++++++++++++ .../doc/tutorial/lwaftr-start.conf.yang | 117 +++++++++++++ .../lwaftr/doc/tutorial/lwaftr-veth-env.sh | 136 +++++++++++++++ 3 files changed, 418 insertions(+) create mode 100644 src/program/lwaftr/doc/tutorial/README.md create mode 100644 src/program/lwaftr/doc/tutorial/lwaftr-start.conf.yang create mode 100755 src/program/lwaftr/doc/tutorial/lwaftr-veth-env.sh diff --git a/src/program/lwaftr/doc/tutorial/README.md b/src/program/lwaftr/doc/tutorial/README.md new file mode 100644 index 0000000000..3b237ef452 --- /dev/null +++ b/src/program/lwaftr/doc/tutorial/README.md @@ -0,0 +1,165 @@ +# Getting Started with Snabb lwAFTR + +## Installation + +Clone the Snabb repository to get the latest [release](https://github.com/snabbco/snabb/releases/): + +``` +$ git clone https://github.com/snabbco/snabb.git +``` + +If you don’t have `git` you can also download a Zip archive or Tarball of the latest release and unpack that. + +Next compile Snabb by running + +``` +$ cd snabb # where you cloned or unpacked Snabb +$ git checkout lwaftr-tutorial # XXX: bug fixes applying to this guide +$ make +... # a bunch of output that you should be able to safely ignore +BINARY 5.4M snabb # this should be the second-last line of output and indicates success +``` + +The result should be a Snabb executable located at `src/snabb`. +You can copy this binary to any location of your choosing, or execute from there as it is. + +## Configuring lwAFTR + +To run Snabb lwAFTR you need an initial configuration file. +You can find a minimal, commented example configuration to adapt to your needs here: +[src/program/lwaftr/doc/tutorial/lwaftr-start.conf.yang](lwaftr-start.conf.yang) + +For a complete documentation of Snabb lwAFTR configuration refer to its [YANG schema](https://github.com/snabbco/snabb/blob/master/src/lib/yang/snabb-softwire-v3.yang). + +## Running Snabb lwAFTR + +You can test the Snabb executable you compiled by running +``` +$ sudo src/snabb lwaftr run --help +``` +which should print a listing of available command line options for Snabb lwAFTR. + +> Note that Snabb always needs to be run with superuser privileges, hence we use "sudo". +> This is because Snabb directly accesses network hardware, bypassing the Linux OS. + +To run Snabb lwAFTR for real, download the example configuration and save it as `lwaftr-start.conf.yang`. +You probably need to edit at least the `device` and `external-device` statements for the configuration to apply +to your system. + +You can then run Snabb lwAFTR like so: + +``` +$ sudo src/snabb lwaftr run --name "my-lwaftr" --cpu 12-23 --conf lwaftr-start.conf.yang +``` + +The command line options mean: + + - `--name`: a name for this lwAFTR process used to refer to it in supporting programs: `snabb config get/set/get-state` + - `--cpu`: a CPU core range used by lwAFTR + - `--conf`: file from which to read the initial configuration + +## Supporting programs: snabb config get/set/get-state + +> XXX: TODO + +## Example: testing Snabb lwAFTR within a virtual Linux network namespace + +You can try out Snabb lwAFTR on virtual Linux interfaces. +There is an example setup described in [src/program/lwaftr/doc/tutorial/lwaftr-veth-env.sh](lwaftr-veth-env.sh) + +``` +$ sudo src/snabb lwaftr run --name testaftr --v6 aftrv6 --v4 aftrv4 --conf lwaftr-start.conf.yang & +lwaftr-start.conf.yang: loading source configuration +lwaftr-start.conf.yang: wrote compiled configuration lwaftr-start.conf.yang.o +Migrating instance '0000:85:00.0' to 'aftrv6' +No CPUs available; not binding to any NUMA node. +Warning: No assignable CPUs declared; leaving data-plane PID 1581617 without assigned CPU. +NDP: Resolving 'fd10::10' +ARP: Resolving '10.77.0.10' +NDP: 'fd10::10' resolved (76:6c:8a:be:20:27) +ARP: '10.77.0.10' resolved (42:06:59:b2:3c:6d) +``` + +``` +$ sudo ip netns exec aftrint ping -c 1 fd10::1 +PING fd10::1(fd10::1) 56 data bytes +64 bytes from fd10::1: icmp_seq=1 ttl=64 time=0.164 ms + +--- fd10::1 ping statistics --- +1 packets transmitted, 1 received, 0% packet loss, time 0ms +rtt min/avg/max/mdev = 0.164/0.164/0.164/0.000 ms +``` + +``` +$ sudo ip netns exec aftrext ping -c 1 10.77.0.1 +PING 10.77.0.1 (10.77.0.1) 56(84) bytes of data. +64 bytes from 10.77.0.1: icmp_seq=1 ttl=64 time=0.207 ms + +--- 10.77.0.1 ping statistics --- +1 packets transmitted, 1 received, 0% packet loss, time 0ms +rtt min/avg/max/mdev = 0.207/0.207/0.207/0.000 ms +``` + +``` + $ sudo ip netns exec aftrint tcpdump -nn -i internal -l --immediate-mode & +[2] 1797194 +tcpdump: verbose output suppressed, use -v or -vv for full protocol decode +listening on internal, link-type EN10MB (Ethernet), capture size 262144 bytes + +$ sudo ip netns exec aftrext ping -c 1 -W 1 198.18.0.1 +PING 198.18.0.1 (198.18.0.1) 56(84) bytes of data. +15:53:05.495202 IP6 2003:1b0b:fff9:ffff::4001 > 2003:1c09:ffe0:100::1: IP 10.77.0.10 > 198.18.0.1: ICMP echo request, id 29506, seq 1, length 64 + + +--- 198.18.0.1 ping statistics --- +1 packets transmitted, 0 received, 100% packet loss, time 0ms +``` + +``` +$ sudo src/snabb config get-state -s snabb-softwire-v3 testaftr /softwire-state | grep -v ' 0;' +discontinuity-time 2022-07-28T14:37:04Z; +drop-all-ipv6-iface-bytes 3648; +drop-all-ipv6-iface-packets 24; +drop-unknown-protocol-ipv6-bytes 3648; +drop-unknown-protocol-ipv6-packets 24; +in-arp-reply-bytes 42; +in-arp-reply-packets 1; +in-arp-request-bytes 210; +in-arp-request-packets 5; +in-icmpv4-echo-bytes 588; +in-icmpv4-echo-packets 6; +in-icmpv6-echo-bytes 472; +in-icmpv6-echo-packets 4; +in-ipv4-bytes 2646; +in-ipv4-frag-reassembly-unneeded 39; +in-ipv4-packets 27; +in-ipv6-bytes 4050; +in-ipv6-frag-reassembly-unneeded 49; +in-ipv6-packets 27; +in-ndp-na-bytes 554; +in-ndp-na-packets 7; +in-ndp-ns-bytes 774; +in-ndp-ns-packets 9; +memuse-ipv4-frag-reassembly-buffer 728203264; +memuse-ipv6-frag-reassembly-buffer 11378176; +out-arp-reply-bytes 210; +out-arp-reply-packets 5; +out-arp-request-bytes 42; +out-arp-request-packets 1; +out-icmpv4-echo-bytes 588; +out-icmpv4-echo-packets 6; +out-icmpv4-error-bytes 222; +out-icmpv4-error-packets 3; +out-icmpv6-echo-bytes 472; +out-icmpv6-echo-packets 4; +out-ipv4-bytes 222; +out-ipv4-frag-not 15; +out-ipv4-packets 3; +out-ipv6-bytes 3726; +out-ipv6-frag-not 35; +out-ipv6-packets 27; +out-ndp-na-bytes 258; +out-ndp-na-packets 3; +out-ndp-ns-bytes 86; +out-ndp-ns-packets 1; +``` diff --git a/src/program/lwaftr/doc/tutorial/lwaftr-start.conf.yang b/src/program/lwaftr/doc/tutorial/lwaftr-start.conf.yang new file mode 100644 index 0000000000..3833011ae0 --- /dev/null +++ b/src/program/lwaftr/doc/tutorial/lwaftr-start.conf.yang @@ -0,0 +1,117 @@ +// Minimal example Snabb lwAFTR configuration +// For more details consult the schema: src/lib/yang/snabb-spftwire-v3.yang + +softwire-config { + + instance { + + // These are the network devices used by Snabb lwAFTR. + // The external-device is optional, and if omitted lwAFTR + // will run in on-a-stick mode using a single interface. + // If both device and external-device are configured then + // lwAFTR will run in bump-in-the-wire mode where IPv6 traffic + // from 'device' is forwarded as IPv4 traffic to 'external-device' + // and vice-versa. + // Typically devices are specified as PCI-e bus addresses, but + // we also support Linux interface names for testing puproses. + + device "0000:85:00.0"; + external-device "0000:85:00.1"; + + // Snabb lwAFTR processes traffic in one or more queues. + // Each queue typically uses one dedicated CPU core of + // the host system. + // Traffic is distributed across the queues via RSS. + + queue { + id 0; + + // Each queue must specify the IP and MAC addresses used + // by its internal and external interfaces, as well as their + // respective next hop addresses. + // You can skip ARP/ND lookup by specifying a next hop + // MAC address instead of an IP address. + // These settings are usually identical for all queues, + // but do not have to be. + + // IPv6 interface + internal-interface { + ip "fd10::1"; + mac "02:00:00:00:00:02"; + next-hop { + ip "fd10::10"; + // or: mac "aa:bb:cc:dd:ee:ff"; + } + } + + // IPv4 interface + external-interface { + ip "10.77.0.1"; + mac "02:00:00:00:00:01"; + next-hop { + ip "10.77.0.10"; + // or: mac "aa:bb:cc:dd:ee:ff"; + } + } + + } + } + + // There are also important global interface settings. + // The most important ones are showcased below: + + // IPv6 interface + internal-interface { + mtu 1540; // MTU of the IPv6 interface (note: IPv6 encapsulation overhead!) + flow-label 42; // Flow label used for IPv6 encapsulation + } + + // IPv4 interface. + external-interface { + mtu 1500; // MTU of the IPv4 interface + } + + // Finally, we have to configure the binding table that + // describes how flows are encapsulated. + // The binding table below has just one entry (or 'softwire'), + // but typically a binding table consists of many tens of + // thousands of softwires. + + binding-table { + + // This binding table entry describes the following + // address translation: + // + // Packets originating from 198.18.0.1 arrive at the + // internal (IPv6) interface encapsulated in IPv6 with + // 2003:1c09:ffe0:100::1 (B4) as the source address and + // 2003:1b0b:fff9:ffff::4001 (BR) as the destination address, + // the encapsulation is stripped and the contained IPv4 frame + // is forwarded via the external interface. + // + // Packets destined to 198.18.0.1 arriving at the + // external (IPv4) interface are encapsulated in an IPv6 frame + // with 2003:1b0b:fff9:ffff::4001 (BR) as the source address and + // 2003:1c09:ffe0:100::1 (B4) as the destination address, and + // the resulting IPv6 frame is forwarded via the internal interface. + // + // It is further possible to share an IPv4 address among + // multiple B4 addresses by assigning a PSID. The entry below + // binds the address 198.18.0.1 exclusively. For information + // of how to use PSIDs refer to: + // https://github.com/snabbco/snabb/blob/master/src/apps/lwaftr/binding_table.lua#L14-L59 + + softwire { + ipv4 198.18.0.1; + psid 0; + b4-ipv6 2003:1c09:ffe0:100::1; + br-address 2003:1b0b:fff9:ffff::4001; + port-set { + psid-length 0; + } + } + + // Further binding table entries follow... + + } +} \ No newline at end of file diff --git a/src/program/lwaftr/doc/tutorial/lwaftr-veth-env.sh b/src/program/lwaftr/doc/tutorial/lwaftr-veth-env.sh new file mode 100755 index 0000000000..d4f2015e6e --- /dev/null +++ b/src/program/lwaftr/doc/tutorial/lwaftr-veth-env.sh @@ -0,0 +1,136 @@ +# Use of this source code is governed by the Apache 2.0 license; see COPYING. +#!/usr/bin/env bash + +# Example and test environment for Snabb lwAFTR +# +# Use with: lwaftr-start.conf.yang +# +# This script creates two network namespaces, 'aftrint' and 'aftrext', +# that simulate the external network (public internet) and the internal, +# IPv6-only network (operator network) respectively. +# +# Snabb lwAFTR sits between the two networks and routes packets between +# the external IPv4 network and the internal IPv6-only network. +# +# In the external network is a node with the public address: 10.77.0.10 +# In the internal network is a node with the private address: 198.18.0.1 +# In the internal network flows towards 198.18.0.1 are encapsulated in IPv6, +# and the IPv4 address is mapped to 2003:1c09:ffe0:100::1. +# +# The address of Snabb lwAFTR in the external network is 10.77.0.1 and +# its address in the internal network is fd10::1. + +set -e + +create() { set -x + # Create two veth pairs for the internal and external Snabb lwAFTR interfaces + + ip link add aftrv6 type veth peer name internal + ip link set aftrv6 address 02:00:00:00:00:02 + ip link set aftrv6 up + + ip link add aftrv4 type veth peer name external + ip link set aftrv4 address 02:00:00:00:00:01 + ip link set aftrv4 up + + # Configure internal network namespace + + ip netns add aftrint + ip netns exec aftrint ip link set lo up + ip link set internal netns aftrint + + # Configure internal interface + + ip netns exec aftrint ethtool --offload internal rx off tx off + ip netns exec aftrint ip address add dev internal local fd10::10/16 + ip netns exec aftrint ip link set internal mtu 1540 + ip netns exec aftrint ip link set internal up + sleep 3 + ip netns exec aftrint ip route add 2003::0/16 via fd10::1 src fd10::10 dev internal + ip netns exec aftrint ip route add default via fd10::1 dev internal + + # Configure external network namespace + + ip netns add aftrext + ip netns exec aftrext ip link set lo up + ip link set external netns aftrext + + # Configure external interface + + ip netns exec aftrext ethtool --offload external rx off tx off + ip netns exec aftrext ip address add dev external local 10.77.0.10/24 + ip netns exec aftrext ip link set external mtu 1500 + ip netns exec aftrext ip link set external up + sleep 3 + ip netns exec aftrext ip route add 198.18.0.0/16 via 10.77.0.1 src 10.77.0.10 dev external + ip netns exec aftrext ip route add default via 10.77.0.1 dev external + + # Configure tunneled endpoint in the internal network namespace + # + # Here we configure the softwire as defined in the binding table entry in + # lwaftr-start.conf.yang + # + # softwire { + # ipv4 198.18.0.1; + # psid 0; + # b4-ipv6 2003:1c09:ffe0:100::1; + # br-address 2003:1b0b:fff9:ffff::4001; + # port-set { + # psid-length 0; + # } + # } + # + # Note how ipv4, b4-ipv6, br-address relate to the Linux ip-tunnel and + # ip-route configuration. + + ip netns exec aftrint ip address add dev internal local 2003:1c09:ffe0:100::1 # b4-ipv6 + ip netns exec aftrint ip address add dev internal local 198.18.0.1/16 # ipv4 + # Here we create the ip-tunnel counterpart to our softwire + # between br-address and b4-ipv6. + ip netns exec aftrint ip -6 tunnel add name softwire0 \ + remote 2003:1b0b:fff9:ffff::4001 local 2003:1c09:ffe0:100::1 \ + mode ipip6 encaplimit none dev internal + ip netns exec aftrint ip link set softwire0 up + # Route from internal endpoint (ipv4) to public network (10.77.0.0/16) via softwire + ip netns exec aftrint ip route add 10.77.0.0/16 src 198.18.0.1 dev softwire0 +} + +destroy() { set -x + # Delete the network namespaces and the attached veth pairs + ip netns delete aftrint || true + ip link delete aftrv6 || true + ip netns delete aftrext || true + ip link delete aftrv4 || true +} + +if [ "$1" = "create" ]; then + create +elif [ "$1" = "destroy" ]; then + destroy +elif [ "$1" = "examples" ]; then + cat <