Lightweight 4over6 B4 Client in Linux Namespace
RFC 7596 extends Dual-Stack Lite (RFC 6333) by moving the Network Address and Port Translation (NAPT) function from the centralized DS-Lite tunnel concentrator to the tunnel client located in the Customer Premises Equipment (CPE).
I needed a simple test setup to verify Juniper Networks vMX lw4over6 AFTR functionality. Originally I set up 2 virtual machines on a Linux server: one acting as a B4 client and another one as a reachable server, though it turns out, everything can be done nicely with Linux namespaces:
This setup verifies the operation of a single binding entry for client IPv6 address fc00:1:2:3:4:5:7:128 to public IP 193.5.1.100, using TCP/UDP port range 2048–3071. In lw4over6 “jargon”, that’s the actual numbers resulting from PSID length 6, PSOffset 0 and PSID 2.
lwaftr-server.sh
This rather simple shell script creates a network namespace called ‘public’, places the interface p2p2 in it, sets an IPv4 address and launches iperf in server mode:
#!/bin/bash
INT=p2p2
function cleanup {
trap - EXIT SIGINT SIGTERM
echo ""
echo "Cleaning up netns and interfaces"
ip netns exec public ip addr flush dev $INT
ip netns del public
exit 0
}
trap cleanup EXIT SIGINT SIGTERM
sh -c "echo -n 0000:04:00.1 > /sys/bus/pci/drivers/ixgbe/bind" 2>/dev/null
echo "Server IP set to 10.0.1.100/24 on $INT"
ip netns add public
ip link set $INT netns public
ip netns exec public ip link set dev $INT up
ip netns exec public ip link set dev lo up
ip netns exec public ip addr add 10.0.1.100/24 dev $INT
ip netns exec public ip route add default via 10.0.1.1
ip netns exec public iperf -s
Execute the script as root/sudo to have a minimal test server to be reached via the test setup:
$ sudo ./lwaftr-server.sh
Server IP set to 10.0.1.100/24 on p2p2
------------------------------------------------------------
Server listening on TCP port 5001
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
b4-client.sh
This shell script creates a network namespace called ‘b4’, places the specified interface (p2p1 in this case) in it, sets an IPv4 and IPv6 address, creates the IPIP tunnel and configures NAPT using iptables:
#!/bin/bash
INT=p2p1
IP="193.5.1.100"
PORTRANGE="2048-3071"
IPV6="fc00:1:2:3:4:5:7:128"
function cleanup {
trap - EXIT SIGINT SIGTERM
echo "cleaning up netns and interfaces"
ip netns exec b4 ip addr flush dev $INT
ip netns exec b4 ip -6 addr flush dev $INT
ip netns exec b4 ip -6 tunnel del mytun mode ipip6
ip netns del b4
exit 0
}
trap cleanup EXIT SIGINT SIGTERM
sh -c "echo -n 0000:04:00.0 > /sys/bus/pci/drivers/ixgbe/bind" 2>/dev/null
ip netns add b4
ip link set $INT netns b4
ip netns exec b4 ip link set dev lo up
ip netns exec b4 ip link set dev $INT up
ip netns exec b4 ip addr add $IP/24 dev $INT
ip netns exec b4 ip -6 addr add fc00::1/64 dev $INT
ip netns exec b4 ip -6 tunnel add mytun mode ipip6 remote fc00::100 local $IPV6 dev $INT
ip netns exec b4 ip link set dev mytun up
ip netns exec b4 ip -6 addr add $IPV6 dev mytun
ip netns exec b4 ip route add default dev mytun
ip netns exec b4 iptables -t nat --flush
ip netns exec b4 iptables -t nat -A POSTROUTING -p tcp -o mytun -j SNAT --to $IP:$PORTRANGE
ip netns exec b4 iptables -t nat -A POSTROUTING -p udp -o mytun -j SNAT --to $IP:$PORTRANGE
ip netns exec b4 iptables -t nat -A POSTROUTING -p icmp -o mytun -j SNAT --to $IP:$PORTRANGE
ip netns exec b4 /bin/bash --rcfile <(echo "PS1=\"B4 client $IPV6> \"")
Executing the script as root/sudo will launch a bash shell within the network namespace, allowing the operator to issue network commands like ping, telnet, ssh and iperf:
$ sudo ./b4-client.sh [sudo] password for mwiget: B4 client fc00:1:2:3:4:5:7:128> ping 10.0.1.100 PING 10.0.1.100 (10.0.1.100) 56(84) bytes of data. 64 bytes from 10.0.1.100: icmp_seq=1 ttl=63 time=1.33 ms 64 bytes from 10.0.1.100: icmp_seq=2 ttl=63 time=1.33 ms ^C --- 10.0.1.100 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 1.338/1.338/1.339/0.036 ms B4 client fc00:1:2:3:4:5:7:128> iperf -c 10.0.1.100 ------------------------------------------------------------ Client connecting to 10.0.1.100, TCP port 5001 TCP window size: 85.0 KByte (default) ------------------------------------------------------------ [ 3] local 193.5.1.100 port 49488 connected with 10.0.1.100 port 5001 [ ID] Interval Transfer Bandwidth [ 3] 0.0-10.0 sec 1.29 GBytes 1.10 Gbits/sec B4 client fc00:1:2:3:4:5:7:128>
tcpdump-netns.sh
#!/bin/bash if [ -z "$1" ]; then echo "Usage: $0 namespace [interface]" echo "Available namespaces:" sudo ip netns list exit 1 fi if [ -z "$2" ]; then INT=`sudo ip netns exec $1 ifconfig | grep Ethernet |cut -d' ' -f1` else INT=$2 fi echo "using interfave $INT in $1 ..." sudo ip netns exec $1 stdbuf -i0 -o0 -e0 tcpdump -n -s 1500 -i $INT $3 $4 $5 $6
This script launches tcpdump within a specified namespace on the first available interface of type Ethernet. Very handy for troubleshooting. The following output is shown for a single ping from the B4 client above:
$ ./tcpdump-netns.sh b4 using interfave p2p1 in b4 ... tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on p2p1, link-type EN10MB (Ethernet), capture size 1500 bytes 07:18:07.257019 IP6 fc00:1:2:3:4:5:7:128 > fc00::100: IP 193.5.1.100 > 10.0.1.100: ICMP echo request, id 2082, seq 1, length 64 07:18:07.258434 IP6 fc00::100 > fc00:1:2:3:4:5:7:128: IP 10.0.1.100 > 193.5.1.100: ICMP echo reply, id 2082, seq 1, length 64 07:18:12.273015 IP6 fe80::ec4:7aff:febc:bf08 > fc00::100: ICMP6, neighbor solicitation, who has fc00::100, length 32 07:18:12.273239 IP6 fc00::100 > fe80::ec4:7aff:febc:bf08: ICMP6, neighbor advertisement, tgt is fc00::100, length 32
Hi,
Thanks for your blog! It looks really interesting 🙂 I left you a comment in this post: https://marcelwiget.wordpress.com/2015/06/30/autoinstall-ubuntu-14-04-2-via-usb-stick-on-apu-board-from-pc-engines/ I’m just letting you know in case you don’t see it (it’s a old post). You can delete this post afterwards 🙂
Thank you!!!
LikeLike
Any chance you still have your vMX lw4o6 config? I’d love to see what’s involved on that end.
LikeLike
Have a look here: https://github.com/Juniper/vmx-docker-lwaftr, but it requires vMX plus snabb to function. Junos doesn’t provide lwaftr functionality.
LikeLike