#!/bin/bash
#
# L2TPv3 tunnel between 2 hosts
#
#            host-1          |   router   |     host-2
#                            |            |
#      lo          l2tp      |            |      l2tp           lo
#  fc00:101::1   fc00:1::1   |            |   fc00:1::2    fc00:101::2
#                  eth0      |            |     eth0
#              2001:db8:1::1 |            | 2001:db8:2::1

which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)

################################################################################
# create namespaces and interconnects

create_ns()
{
	local ns=$1
	local addr=$2
	local addr6=$3

	[ -z "${addr}" ] && addr="-"
	[ -z "${addr6}" ] && addr6="-"

	ip netns add ${ns}

	ip -netns ${ns} link set lo up
	if [ "${addr}" != "-" ]; then
		ip -netns ${ns} addr add dev lo ${addr}
	fi
	if [ "${addr6}" != "-" ]; then
		ip -netns ${ns} -6 addr add dev lo ${addr6}
	fi

	ip -netns ${ns} ro add unreachable default metric 8192
	ip -netns ${ns} -6 ro add unreachable default metric 8192

	ip netns exec ${ns} sysctl -qw net.ipv4.ip_forward=1
	ip netns exec ${ns} sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1
	ip netns exec ${ns} sysctl -qw net.ipv6.conf.all.forwarding=1
	ip netns exec ${ns} sysctl -qw net.ipv6.conf.default.forwarding=1
}

# create veth pair to connect namespaces and apply addresses.
connect_ns()
{
	local ns1=$1
	local ns1_dev=$2
	local ns1_addr=$3
	local ns1_addr6=$4
	local ns2=$5
	local ns2_dev=$6
	local ns2_addr=$7
	local ns2_addr6=$8

	ip -netns ${ns1} li add ${ns1_dev} type veth peer name tmp
	ip -netns ${ns1} li set ${ns1_dev} up
	ip -netns ${ns1} li set tmp netns ${ns2} name ${ns2_dev}
	ip -netns ${ns2} li set ${ns2_dev} up

	if [ "${ns1_addr}" != "-" ]; then
		ip -netns ${ns1} addr add dev ${ns1_dev} ${ns1_addr}
		ip -netns ${ns2} addr add dev ${ns2_dev} ${ns2_addr}
	fi

	if [ "${ns1_addr6}" != "-" ]; then
		ip -netns ${ns1} addr add dev ${ns1_dev} ${ns1_addr6}
		ip -netns ${ns2} addr add dev ${ns2_dev} ${ns2_addr6}
	fi
}

################################################################################
# test setup
setup()
{
	create_ns host-1
	create_ns host-2
	create_ns router

	connect_ns host-1 eth0 10.1.1.1/24 2001:db8:1::1/64 \
	           router eth1 10.1.1.2/24 2001:db8:1::2/64

	connect_ns host-2 eth0 10.1.2.1/24 2001:db8:2::1/64 \
	           router eth2 10.1.2.2/24 2001:db8:2::2/64

	ip -netns host-1 addr add dev lo fc00:101::1/128
	ip -netns host-2 addr add dev lo fc00:101::2/128
	sleep 5

	ip -netns host-1 -6 ro add 2001:db8:2::/64 via 2001:db8:1::2
	ip -netns host-2 -6 ro add 2001:db8:1::/64 via 2001:db8:2::2

	#
	# configure l2tpv3 tunnel on host-1
	#
	ip -netns host-1 l2tp add tunnel tunnel_id 1234 peer_tunnel_id 1235 \
			 encap ip local 2001:db8:1::1 remote 2001:db8:2::1
	ip -netns host-1 l2tp add session name l2tp1 tunnel_id 1234 \
			 session_id 1234 peer_session_id 1235
	ip -netns host-1 link set dev l2tp1 up
	ip -netns host-1 addr add dev l2tp1 fc00:1::1 peer fc00:1::2

	#
	# configure l2tpv3 tunnel on host-2
	#
	ip -netns host-2 l2tp add tunnel tunnel_id 1235 peer_tunnel_id 1234 \
			 encap ip local 2001:db8:2::1 remote 2001:db8:1::1
	ip -netns host-2 l2tp add session name l2tp2 tunnel_id 1235 \
			 session_id 1235 peer_session_id 1234
	ip -netns host-2 link set dev l2tp2 up
	ip -netns host-2 addr add dev l2tp2 fc00:1::2 peer fc00:1::1

	sleep 5

	#
	# add routes to loopback addresses
	#
	ip -netns host-1 -6 ro add fc00:101::2/128 via fc00:1::2
	ip -netns host-2 -6 ro add fc00:101::1/128 via fc00:1::1
}

################################################################################
# main

setup
ip netns exec host-1 ${ping6} -c1 -w1 fc00:1::2
ip netns exec host-1 ${ping6} -c1 -w1 fc00:101::2
