#!/bin/bash

#
# Customer connection schema
#
# +--------------+ vrtr1a vrtr1b +---------------------+
# | Host system  | /           \ |         CPE         |
# | (ISP router) +---------------+ (Customer's Router) |
# |              |::1         ::2|                     |
# +--------------+               +----------+----------+
#                    fe80::/64              |
#                                           | ::ffff
#                                      +----+----+
#                      Ethernet switch |  brlan  |   fd11::/64
#                                      +-+-+-+-+-+
#                          +-----+ ::1   | | | |   ::3 +-----+
#                          | PC1 +-------+ | | +-------+ PC3 |
#                          +-----+         | |         +-----+
#                          +-----+ ::2     | |     ::4 +-----+
#                          | PC2 +---------+ +---------+ PC4 |
#                          +-----+                     +-----+
#
#

# Check for superuser privileges
if [ "${UID}" -ne 0 ]; then
	echo "${0##*/}: must be superuser (root) to use this program" >&2
	exit 1
fi

# These tools are MUST
IP="$(type -p ip)" || exit
BRCTL="$(type -p brctl)" || exit
MTR="$(type -p mtr)" || exit
SYSCTL="$(type -p sysctl)" || exit

# Maximum number of PCs in customer LAN
declare -ri MAX_PCs=4

### Host system - ISP router ###

## Add/setup/configure virtual wire to connect with CPE
"$IP" link add dev vrtr1a type veth peer name vrtr1b
"$IP" link set up dev lo
"$IP" link set up dev vrtr1a
"$IP" -6 addr add fe80::1/64 dev vrtr1a
# route to customer prefix
"$IP" -6 route add fd11::/64 via fe80::2 dev vrtr1a

## Setup source address for "$MTR" packets
"$IP" link add dev lo255 type dummy
"$IP" link set up dev lo255
"$IP" -6 addr add fd22::1/64 dev lo255

### Virtual CPE - customer router with ethernet LAN switch ###

## Create Linux network namespace and configure it
"$IP" netns add vrtr1
vrtr1="$IP netns exec vrtr1"
$vrtr1 "$SYSCTL" -qw net/ipv6/conf/all/forwarding=1
$vrtr1 "$SYSCTL" -qw net/ipv6/conf/default/forwarding=1

## Create/setup/configure INET interface in vrtr1

# move from host system (create)
"$IP" link set netns vrtr1 dev vrtr1b
# setup
$vrtr1 "$IP" link set up dev vrtr1b
# configure
$vrtr1 "$IP" -6 addr add fe80::2/64 dev vrtr1b
$vrtr1 "$IP" -6 route add default via fe80::1 dev vrtr1b

## Create/setup/configure LAN switch in vrtr1

# create
$vrtr1 "$BRCTL" addbr brlan
$vrtr1 "$BRCTL" setfd brlan 0
$vrtr1 "$BRCTL" stp brlan off
# setup
$vrtr1 "$IP" link set up dev brlan
# configure
$vrtr1 "$IP" -6 addr add fd11::ffff/64 dev brlan

### Virtual customer hosts (PCs for example) ###

# Create/setup/configure customer hosts
for ((i = 0; i < MAX_PCs; i++)); do
	# Create VPC
	"$IP" netns add vpc${i}
	# Create virtual ethernet wire
	"$IP" link add dev vpc${i}a type veth peer name vpc${i}b
	# Assign/setup one end to vrtr1, brlan, and one to vpc${i}
	"$IP" link set netns vrtr1 dev vpc${i}a
	$vrtr1 "$BRCTL" addif brlan vpc${i}a
	$vrtr1 "$IP" link set up dev vpc${i}a
	"$IP" link set netns vpc${i} dev vpc${i}b
	# Configure and setup PCs network (vpc${i}b)
	eval "vpc${i}='"$IP" netns exec vpc${i}'"

	eval "
		\$vpc${i} "$IP" link set up dev lo
		\$vpc${i} "$IP" link set up dev vpc${i}b
		\$vpc${i} "$IP" -6 addr add fd11::$((i+1))/64 dev vpc${i}b
		\$vpc${i} "$IP" -6 route add default via fd11::ffff
	"
done

### Test it ###
for ((i = 1; i <= MAX_PCs; i++)); do
	# Workaround for non-netns aware inetpeer implementation in kernel:
	# ICMP Time Exceeded gets suppressed and looses are seen.
	# Fixed in recent kernels.
	sleep 1
	"$MTR" --address=fd22::1 --report --report-cycles=10 fd11::${i}
done

### Cleanup: destroy network namespaces ###
"$IP" link del dev lo255
"$IP" netns del vrtr1
for ((i = 0; i < MAX_PCs; i++)); do
	"$IP" netns del vpc${i}
done
