061dbf8161
Found by: codespell
371 lines
12 KiB
Bash
371 lines
12 KiB
Bash
#!/bin/sh
|
|
#
|
|
# Copyright (c) 2010, Yavuz Gokirmak
|
|
#
|
|
# All rights reserved.
|
|
#
|
|
# This source code may be used, modified, copied, distributed, and
|
|
# sold, in both source and binary form provided that the above
|
|
# copyright and these terms are retained, verbatim, as the first
|
|
# lines of this file. Under no circumstances is the author
|
|
# responsible for the proper functioning of the software nor does
|
|
# the author assume any responsibility for damages incurred with
|
|
# its use.
|
|
#
|
|
# $FreeBSD$
|
|
#
|
|
# This script creates and connects n router like nodes. Complex wide
|
|
# area topologies can be created with the help of script.
|
|
#
|
|
# Virtual nodes are generated via jails and network connections are
|
|
# established using ng_eiface(4) node types.
|
|
#
|
|
# To use this script:
|
|
#
|
|
# 0. Make your own copy of this example script.
|
|
#
|
|
# 1. Edit the definition of ${TARGET_TOPOLOGY} to define your virtual
|
|
# nodes. Virtual topology definition includes node names and their
|
|
# IP address. Target top. syntax: ( name|ip<->name|ip ... )
|
|
# Example 1: ( n1|10.0.2.1/30<->n2|10.0.2.2/30 ...)
|
|
# Example 2: ( n1|2001:b90::14a/125<->n1|2001:b90::14b/125 ...)
|
|
#
|
|
# 2. Run this script with "start" as the command line argument.
|
|
#
|
|
# 3. Add necessary static route commands for each virtual node. For
|
|
# example assume you have three virtual nodes connected each other
|
|
# like a chain (n1 is connected to n2, n2 is connected to n3).
|
|
# In order to establish connectivity among these virtual nodes,
|
|
# you have to add default routes to node n1 and node n3. Example
|
|
# static route command is:
|
|
# STATIC_ROUTE0="jexec n1 route add -inet default 10.0.2.2"
|
|
# STATIC_ROUTE1="jexec n3 route add -inet default 10.0.2.5"
|
|
# After defining default routes with above format you have to set
|
|
# the total number of static route commands as:
|
|
# STATIC_ROUTE_CNT=2
|
|
#
|
|
# 4. Stop bridging by running this script with "stop" as the
|
|
# command line argument.
|
|
#
|
|
# 5. This script uses a template file in order to carry information
|
|
# between start and stop calls.
|
|
# In the start call, the netgraph interfaces and jails are created.
|
|
# At the stop phase, all created objects should be removed.
|
|
# DO NOT delete the temporary file between the start and stop phases.
|
|
#
|
|
# Target Topology:
|
|
#
|
|
# +---------------+ +---------------------------------------------+
|
|
# | n1 (vimage) | | n2 (vimage) |
|
|
# | | | |
|
|
# | +-----------+ | | +-----------+ +-----------+ +-----------+ |
|
|
# | | ngeth0 | | | | ngeth1 | | ngeth2 | | ngeth4 | |
|
|
# | |(ng_eiface)| | | |(ng_eiface)| |(ng_eiface)| |(ng_eiface)| |
|
|
# | +--+-----+--+ | | +--+-----+--+ +--+-----+--+ +--+-----+--+ |
|
|
# | |ether| | | |ether| |ether| |ether| |
|
|
# | +-X---+ | | +--X--+ +--X--+ +--X--+ |
|
|
# +-------X-------+ +------X--------------X---------------X-------+
|
|
# X X X X
|
|
# X X X X
|
|
# XXXXXXXXXXXXXXX X X
|
|
# X X
|
|
# +--------X------+ +--------X------+
|
|
# | -+--X--+- | | -+--X--+- |
|
|
# | |ether| | | |ether| |
|
|
# | +--+-----+--+ | | +--+-----+--+ |
|
|
# | | ngeth3 | | | | ngeth5 | |
|
|
# | |(ng_eiface)| | | |(ng_eiface)| |
|
|
# | +-----------+ | | +-----------+ |
|
|
# | | | |
|
|
# | n3 (vimage) | | n4 (vimage) |
|
|
# +---------------+ +---------------+
|
|
#
|
|
#
|
|
#
|
|
|
|
# List the names of virtual nodes and their IP addresses. Use ':'
|
|
# character to separate node name from node IP address and netmask.
|
|
|
|
TARGET_TOPOLOGY="n1|10.0.2.1/30<->n2|10.0.2.2/30 n2|10.0.2.5/30<->n3|10.0.2.6/30 n2|10.0.2.9/30<->n4|10.0.2.10/30"
|
|
STATIC_ROUTE0="jexec n1 route add -inet default 10.0.2.2"
|
|
STATIC_ROUTE1="jexec n3 route add -inet default 10.0.2.5"
|
|
STATIC_ROUTE2="jexec n4 route add -inet default 10.0.2.9"
|
|
STATIC_ROUTE_CNT=3
|
|
|
|
# MAC manufacturer prefix. This can be modified according to needs.
|
|
MAC_PREFIX="00:1d:92"
|
|
|
|
# Temporary file is important for proper execution of script.
|
|
TEMP_FILE="/var/tmp/.virtual.chain.tmp"
|
|
|
|
# Set root directory for jails to be created.
|
|
JAIL_PATH="/usr/jails/router"
|
|
|
|
|
|
####################################################################
|
|
#### Nothing below this point should need to be modified. ####
|
|
####################################################################
|
|
|
|
|
|
# Start/restart routine.
|
|
virtual_chain_start() {
|
|
|
|
# Load netgraph KLD's as necessary.
|
|
|
|
for KLD in ng_ether ng_bridge ng_eiface; do
|
|
if ! kldstat -v | grep -qw ${KLD}; then
|
|
echo -n "Loading ${KLD}.ko... "
|
|
kldload ${KLD} || exit 1
|
|
echo "done"
|
|
fi
|
|
done
|
|
|
|
# Reset all interfaces and jails. If temporary file can not be found
|
|
# script assumes that there is no previous configuration.
|
|
|
|
if [ ! -e ${TEMP_FILE} ]; then
|
|
echo "No previous configuration(${TEMP_FILE}) found to clean-up."
|
|
else
|
|
echo -n "Cleaning previous configuration..."
|
|
virtual_chain_stop
|
|
echo "done"
|
|
fi
|
|
|
|
# Create temporary file for usage. This file includes generated
|
|
# interface names and jail names. All bridges, interfaces and jails
|
|
# are written to file while created. In clean-up process written
|
|
# objects are cleaned (i.e. removed) from system.
|
|
|
|
if [ -e ${TEMP_FILE} ]; then
|
|
touch ${TEMP_FILE}
|
|
fi
|
|
|
|
|
|
# Attach other interfaces as well.
|
|
for CONNECTION in ${TARGET_TOPOLOGY}; do
|
|
|
|
# Virtual connections are defined in TARGET_TOPOLOGY variable.
|
|
# They have the form of 'nodeName|IPaddr'. Below two lines split
|
|
|
|
PEER1=`echo ${CONNECTION} | awk -F"<->" '{print $1}'`
|
|
PEER1_NAME=`echo ${PEER1} | awk -F"|" '{print $1}'`
|
|
PEER1_IP=`echo ${PEER1} | awk -F"|" '{print $2}'`
|
|
|
|
PEER2=`echo ${CONNECTION} | awk -F"<->" '{print $2}'`
|
|
PEER2_NAME=`echo ${PEER2} | awk -F"|" '{print $1}'`
|
|
PEER2_IP=`echo ${PEER2} | awk -F"|" '{print $2}'`
|
|
|
|
# !!! if not created already..
|
|
# Create virtual node (jail) with given name and using
|
|
# JAIL_PATH as root directory for jail.
|
|
|
|
virtual_chain_create_peer_if_necessary ${PEER1_NAME}
|
|
virtual_chain_create_peer_if_necessary ${PEER2_NAME}
|
|
|
|
# create an interface for peer with the given peer IP. Get interface
|
|
# for future use; you will connect this interface to the other
|
|
# peers' (PEER2) interface.
|
|
virtual_chain_create_interface_with_ip ${PEER1_NAME} ${PEER1_IP}
|
|
PEER1_INTERFACE=${RET_INTERFACE}
|
|
|
|
# create an interface for peer with the given peer IP. Get interface
|
|
# for future use; you will connect this interface to the other
|
|
# peers' (PEER2) interface.
|
|
virtual_chain_create_interface_with_ip ${PEER2_NAME} ${PEER2_IP}
|
|
PEER2_INTERFACE=${RET_INTERFACE}
|
|
|
|
# Connect virtual interface to other interface. Syntax is :
|
|
# ngctl connect INTERFACE1: INTERFACE2: ether ether.
|
|
|
|
echo -n "Connecting ${PEER1_INTERFACE}:ether to ${PEER2_INTERFACE}:ether..."
|
|
ngctl connect ${PEER1_INTERFACE}: ${PEER2_INTERFACE}: ether ether \
|
|
|| exit 1
|
|
echo "done"
|
|
|
|
done
|
|
|
|
# Executes static route add commands.
|
|
i=0
|
|
while [ $i != $STATIC_ROUTE_CNT ]; do
|
|
eval ROUTE=\${STATIC_ROUTE${i}}
|
|
ret=`${ROUTE}`
|
|
i=`expr $i + 1`
|
|
done
|
|
|
|
echo "Virtual WAN established successfully!"
|
|
}
|
|
|
|
virtual_chain_create_interface_with_ip() {
|
|
|
|
NODE_NAME=$1
|
|
NODE_IP=$2
|
|
|
|
# Create a ng_eiface object for virtual node. ng_eiface
|
|
# object has a hook that can be connected to one of bridge
|
|
# links. After creating interface get its automatically
|
|
# generated name for further usage.
|
|
|
|
echo "Creating eiface interface for virtual node ${NODE_NAME}."
|
|
ngctl mkpeer eiface ether ether
|
|
EIFACE=`ngctl l | grep ngeth | tail -n 1| awk '{print $2}'`
|
|
echo "Interface ${EIFACE} is created."
|
|
|
|
# Write name of the interface to temp file. Clean-up procedure
|
|
# will use this name to shutdown interface.
|
|
|
|
echo "interface ${EIFACE}" >> ${TEMP_FILE}
|
|
|
|
# Move virtual interface to virtual node. Note that Interface
|
|
# name will not be changed at the end of this movement. Moved
|
|
# interface can be seen at the output of ifconfig command in
|
|
# jail: 'jexec jailname ifconfig'
|
|
|
|
echo "Moving ${EIFACE} to ${NODE_NAME}"
|
|
ifconfig ${EIFACE} vnet ${NODE_NAME}
|
|
|
|
# Make lo0 interface localhost.
|
|
jexec ${NODE_NAME} ifconfig lo0 localhost
|
|
|
|
# Generate a random mac address for virtual interface. First
|
|
# three octets can be changed by user. Last three octets are
|
|
# generated randomly.
|
|
M4=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
|
|
awk '{ print $1 % 256 }'`
|
|
M5=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
|
|
awk '{ print $1 % 256 }'`
|
|
M6=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
|
|
awk '{ print $1 % 256 }'`
|
|
|
|
MAC=`printf ${MAC_PREFIX}:%02x:%02x:%02x ${M4} ${M5} ${M6}`
|
|
|
|
# Set the link address (mac address) of virtual interface in
|
|
# virtual node to randomly generated MAC.
|
|
echo "Setting MAC address of ${EIFACE} to '${MAC}'"
|
|
jexec ${NODE_NAME} ifconfig ${EIFACE} link $MAC
|
|
|
|
# Either IPv4 or IPv6 can be used in this script. Ifconfig
|
|
# IP setting syntax differs slightly for two IP versions.
|
|
# For version 4 'inet' keyword is used whereas for version 6
|
|
# 'inet6' is used. Below line tries to decide which IP version
|
|
# is given and sets IPVER to 'inet' or 'inet6'.
|
|
|
|
IPVER=`echo ${NODE_IP} | awk -F"." '{ split($4,last,"/"); \
|
|
if( NF==4 && $1>0 && $1<256 && $2<256 && $3<256 && \
|
|
last[1]<256) print "inet"; else print "inet6"}'`
|
|
|
|
# Set IP address of virtual interface in virtual node.
|
|
echo "Setting IP address of ${EIFACE} to '${NODE_IP}'"
|
|
jexec ${NODE_NAME} ifconfig ${EIFACE} ${IPVER} ${NODE_IP}
|
|
|
|
RET_INTERFACE=${EIFACE}
|
|
}
|
|
|
|
virtual_chain_create_peer_if_necessary() {
|
|
|
|
if ! grep -q $1 ${TEMP_FILE} ; then
|
|
|
|
echo -n "Creating virtual node (jail) ${1}..."
|
|
jail -c vnet name=${1} host.hostname=${1} \
|
|
path=${JAIL_PATH} persist
|
|
jexec ${1} sysctl -w net.inet.ip.forwarding=1
|
|
jexec ${1} sysctl -w net.inet6.ip6.forwarding=1
|
|
echo "done"
|
|
|
|
# Write name of the jail to temp file. Clean-up
|
|
# procedure will use this name to remove jail.
|
|
|
|
echo "node ${1}" >> ${TEMP_FILE}
|
|
fi
|
|
|
|
}
|
|
|
|
# Stop routine.
|
|
virtual_chain_stop() {
|
|
|
|
if [ ! -e ${TEMP_FILE} ]; then
|
|
echo "Nothing to stop! ${TEMP_FILE}: temp file not found"
|
|
else
|
|
|
|
echo -n "Shutdown bridge interface.."
|
|
OBJECTS=`cat ${TEMP_FILE} | grep bridge | awk '{print $2}'`
|
|
for BRIDGE in ${OBJECTS}; do
|
|
ngctl shutdown ${BRIDGE}: >/dev/null 2>&1
|
|
done
|
|
echo "done"
|
|
|
|
echo -n "Shutdown all eiface interfaces..."
|
|
OBJECTS=`cat ${TEMP_FILE} | grep interface | awk '{print $2}'`
|
|
for INTERFACE in ${OBJECTS}; do
|
|
ngctl shutdown ${INTERFACE}: >/dev/null 2>&1
|
|
done
|
|
echo "done"
|
|
|
|
echo -n "Removing all jails..."
|
|
OBJECTS=`cat ${TEMP_FILE} | grep node | awk '{print $2}'`
|
|
for NODE in ${OBJECTS}; do
|
|
jail -r ${NODE}
|
|
done
|
|
echo "done"
|
|
|
|
echo "Removing tempfile ${TEMP_FILE}"
|
|
rm ${TEMP_FILE}
|
|
fi
|
|
echo "Virtual LAN objects removed successfully!"
|
|
|
|
}
|
|
|
|
virtual_chain_usage() {
|
|
echo "usage: $0 start [target_topology]"
|
|
echo " : $0 [ stop | help ]"
|
|
}
|
|
|
|
|
|
# Main entry point.
|
|
|
|
case $# in
|
|
1)
|
|
case $1 in
|
|
start)
|
|
echo -n "Creating default target topology:"
|
|
echo " ${TARGET_TOPOLOGY}"
|
|
virtual_chain_start
|
|
;;
|
|
stop)
|
|
|
|
if [ ! -e ${TEMP_FILE} ]; then
|
|
echo -n "Noting to stop! ${TEMP_FILE}:"
|
|
echo " temp file not found"
|
|
else
|
|
virtual_chain_stop
|
|
fi
|
|
;;
|
|
help)
|
|
virtual_chain_usage
|
|
exit 1
|
|
;;
|
|
*)
|
|
virtual_chain_usage
|
|
exit 1
|
|
|
|
esac
|
|
;;
|
|
2)
|
|
case $1 in
|
|
start)
|
|
TARGET_TOPOLOGY=$2
|
|
echo -n "Creating target topology:"
|
|
echo "${TARGET_TOPOLOGY}"
|
|
virtual_chain_start
|
|
;;
|
|
*)
|
|
virtual_chain_usage
|
|
exit 1
|
|
esac
|
|
;;
|
|
|
|
*)
|
|
virtual_chain_usage
|
|
exit 1
|
|
esac
|
|
|