1fa212bfbSJulian Elischer#!/bin/sh 2fa212bfbSJulian Elischer# 3fa212bfbSJulian Elischer# Copyright (c) 2010, Yavuz Gokirmak 4fa212bfbSJulian Elischer# 5fa212bfbSJulian Elischer# All rights reserved. 6fa212bfbSJulian Elischer# 7fa212bfbSJulian Elischer# This source code may be used, modified, copied, distributed, and 8fa212bfbSJulian Elischer# sold, in both source and binary form provided that the above 9fa212bfbSJulian Elischer# copyright and these terms are retained, verbatim, as the first 10fa212bfbSJulian Elischer# lines of this file. Under no circumstances is the author 11fa212bfbSJulian Elischer# responsible for the proper functioning of the software nor does 12fa212bfbSJulian Elischer# the author assume any responsibility for damages incurred with 13fa212bfbSJulian Elischer# its use. 14fa212bfbSJulian Elischer# 15fa212bfbSJulian Elischer# 16fa212bfbSJulian Elischer# This script creates and connects n router like nodes. Complex wide 17fa212bfbSJulian Elischer# area topologies can be created with the help of script. 18fa212bfbSJulian Elischer# 19fa212bfbSJulian Elischer# Virtual nodes are generated via jails and network connections are 20fa212bfbSJulian Elischer# established using ng_eiface(4) node types. 21fa212bfbSJulian Elischer# 22fa212bfbSJulian Elischer# To use this script: 23fa212bfbSJulian Elischer# 24fa212bfbSJulian Elischer# 0. Make your own copy of this example script. 25fa212bfbSJulian Elischer# 26fa212bfbSJulian Elischer# 1. Edit the definition of ${TARGET_TOPOLOGY} to define your virtual 27fa212bfbSJulian Elischer# nodes. Virtual topology definition includes node names and their 28*5665fe6bSUlrich Spörlein# IP address. Target top. syntax: ( name|ip<->name|ip ... ) 29fa212bfbSJulian Elischer# Example 1: ( n1|10.0.2.1/30<->n2|10.0.2.2/30 ...) 30fa212bfbSJulian Elischer# Example 2: ( n1|2001:b90::14a/125<->n1|2001:b90::14b/125 ...) 31fa212bfbSJulian Elischer# 32fa212bfbSJulian Elischer# 2. Run this script with "start" as the command line argument. 33fa212bfbSJulian Elischer# 34fa212bfbSJulian Elischer# 3. Add necessary static route commands for each virtual node. For 35fa212bfbSJulian Elischer# example assume you have three virtual nodes connected each other 36*5665fe6bSUlrich Spörlein# like a chain (n1 is connected to n2, n2 is connected to n3). 37*5665fe6bSUlrich Spörlein# In order to establish connectivity among these virtual nodes, 38fa212bfbSJulian Elischer# you have to add default routes to node n1 and node n3. Example 39fa212bfbSJulian Elischer# static route command is: 40fa212bfbSJulian Elischer# STATIC_ROUTE0="jexec n1 route add -inet default 10.0.2.2" 41fa212bfbSJulian Elischer# STATIC_ROUTE1="jexec n3 route add -inet default 10.0.2.5" 42fa212bfbSJulian Elischer# After defining default routes with above format you have to set 43fa212bfbSJulian Elischer# the total number of static route commands as: 44fa212bfbSJulian Elischer# STATIC_ROUTE_CNT=2 45fa212bfbSJulian Elischer# 46fa212bfbSJulian Elischer# 4. Stop bridging by running this script with "stop" as the 47fa212bfbSJulian Elischer# command line argument. 48fa212bfbSJulian Elischer# 49*5665fe6bSUlrich Spörlein# 5. This script uses a template file in order to carry information 50fa212bfbSJulian Elischer# between start and stop calls. 51fa212bfbSJulian Elischer# In the start call, the netgraph interfaces and jails are created. 52fa212bfbSJulian Elischer# At the stop phase, all created objects should be removed. 53fa212bfbSJulian Elischer# DO NOT delete the temporary file between the start and stop phases. 54fa212bfbSJulian Elischer# 55fa212bfbSJulian Elischer# Target Topology: 56fa212bfbSJulian Elischer# 57fa212bfbSJulian Elischer# +---------------+ +---------------------------------------------+ 58fa212bfbSJulian Elischer# | n1 (vimage) | | n2 (vimage) | 59fa212bfbSJulian Elischer# | | | | 60fa212bfbSJulian Elischer# | +-----------+ | | +-----------+ +-----------+ +-----------+ | 61fa212bfbSJulian Elischer# | | ngeth0 | | | | ngeth1 | | ngeth2 | | ngeth4 | | 62fa212bfbSJulian Elischer# | |(ng_eiface)| | | |(ng_eiface)| |(ng_eiface)| |(ng_eiface)| | 63fa212bfbSJulian Elischer# | +--+-----+--+ | | +--+-----+--+ +--+-----+--+ +--+-----+--+ | 64fa212bfbSJulian Elischer# | |ether| | | |ether| |ether| |ether| | 65fa212bfbSJulian Elischer# | +-X---+ | | +--X--+ +--X--+ +--X--+ | 66fa212bfbSJulian Elischer# +-------X-------+ +------X--------------X---------------X-------+ 67fa212bfbSJulian Elischer# X X X X 68fa212bfbSJulian Elischer# X X X X 69fa212bfbSJulian Elischer# XXXXXXXXXXXXXXX X X 70fa212bfbSJulian Elischer# X X 71fa212bfbSJulian Elischer# +--------X------+ +--------X------+ 72fa212bfbSJulian Elischer# | -+--X--+- | | -+--X--+- | 73fa212bfbSJulian Elischer# | |ether| | | |ether| | 74fa212bfbSJulian Elischer# | +--+-----+--+ | | +--+-----+--+ | 75fa212bfbSJulian Elischer# | | ngeth3 | | | | ngeth5 | | 76fa212bfbSJulian Elischer# | |(ng_eiface)| | | |(ng_eiface)| | 77fa212bfbSJulian Elischer# | +-----------+ | | +-----------+ | 78fa212bfbSJulian Elischer# | | | | 79fa212bfbSJulian Elischer# | n3 (vimage) | | n4 (vimage) | 80fa212bfbSJulian Elischer# +---------------+ +---------------+ 81fa212bfbSJulian Elischer# 82fa212bfbSJulian Elischer# 83fa212bfbSJulian Elischer# 84fa212bfbSJulian Elischer 85fa212bfbSJulian Elischer# List the names of virtual nodes and their IP addresses. Use ':' 86*5665fe6bSUlrich Spörlein# character to separate node name from node IP address and netmask. 87fa212bfbSJulian Elischer 88fa212bfbSJulian ElischerTARGET_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" 89fa212bfbSJulian ElischerSTATIC_ROUTE0="jexec n1 route add -inet default 10.0.2.2" 90fa212bfbSJulian ElischerSTATIC_ROUTE1="jexec n3 route add -inet default 10.0.2.5" 91fa212bfbSJulian ElischerSTATIC_ROUTE2="jexec n4 route add -inet default 10.0.2.9" 92fa212bfbSJulian ElischerSTATIC_ROUTE_CNT=3 93fa212bfbSJulian Elischer 94*5665fe6bSUlrich Spörlein# MAC manufacturer prefix. This can be modified according to needs. 95fa212bfbSJulian ElischerMAC_PREFIX="00:1d:92" 96fa212bfbSJulian Elischer 97fa212bfbSJulian Elischer# Temporary file is important for proper execution of script. 98fa212bfbSJulian ElischerTEMP_FILE="/var/tmp/.virtual.chain.tmp" 99fa212bfbSJulian Elischer 100fa212bfbSJulian Elischer# Set root directory for jails to be created. 101fa212bfbSJulian ElischerJAIL_PATH="/usr/jails/router" 102fa212bfbSJulian Elischer 103fa212bfbSJulian Elischer 104fa212bfbSJulian Elischer#################################################################### 105fa212bfbSJulian Elischer#### Nothing below this point should need to be modified. #### 106fa212bfbSJulian Elischer#################################################################### 107fa212bfbSJulian Elischer 108fa212bfbSJulian Elischer 109fa212bfbSJulian Elischer# Start/restart routine. 110fa212bfbSJulian Elischervirtual_chain_start() { 111fa212bfbSJulian Elischer 112fa212bfbSJulian Elischer # Load netgraph KLD's as necessary. 113fa212bfbSJulian Elischer 114fa212bfbSJulian Elischer for KLD in ng_ether ng_bridge ng_eiface; do 115fa212bfbSJulian Elischer if ! kldstat -v | grep -qw ${KLD}; then 116fa212bfbSJulian Elischer echo -n "Loading ${KLD}.ko... " 117fa212bfbSJulian Elischer kldload ${KLD} || exit 1 118fa212bfbSJulian Elischer echo "done" 119fa212bfbSJulian Elischer fi 120fa212bfbSJulian Elischer done 121fa212bfbSJulian Elischer 122fa212bfbSJulian Elischer # Reset all interfaces and jails. If temporary file can not be found 123fa212bfbSJulian Elischer # script assumes that there is no previous configuration. 124fa212bfbSJulian Elischer 125fa212bfbSJulian Elischer if [ ! -e ${TEMP_FILE} ]; then 126fa212bfbSJulian Elischer echo "No previous configuration(${TEMP_FILE}) found to clean-up." 127fa212bfbSJulian Elischer else 128fa212bfbSJulian Elischer echo -n "Cleaning previous configuration..." 129fa212bfbSJulian Elischer virtual_chain_stop 130fa212bfbSJulian Elischer echo "done" 131fa212bfbSJulian Elischer fi 132fa212bfbSJulian Elischer 133fa212bfbSJulian Elischer # Create temporary file for usage. This file includes generated 134fa212bfbSJulian Elischer # interface names and jail names. All bridges, interfaces and jails 135fa212bfbSJulian Elischer # are written to file while created. In clean-up process written 136*5665fe6bSUlrich Spörlein # objects are cleaned (i.e. removed) from system. 137fa212bfbSJulian Elischer 138fa212bfbSJulian Elischer if [ -e ${TEMP_FILE} ]; then 139fa212bfbSJulian Elischer touch ${TEMP_FILE} 140fa212bfbSJulian Elischer fi 141fa212bfbSJulian Elischer 142fa212bfbSJulian Elischer 143fa212bfbSJulian Elischer # Attach other interfaces as well. 144fa212bfbSJulian Elischer for CONNECTION in ${TARGET_TOPOLOGY}; do 145fa212bfbSJulian Elischer 146fa212bfbSJulian Elischer # Virtual connections are defined in TARGET_TOPOLOGY variable. 147fa212bfbSJulian Elischer # They have the form of 'nodeName|IPaddr'. Below two lines split 148fa212bfbSJulian Elischer 149fa212bfbSJulian Elischer PEER1=`echo ${CONNECTION} | awk -F"<->" '{print $1}'` 150fa212bfbSJulian Elischer PEER1_NAME=`echo ${PEER1} | awk -F"|" '{print $1}'` 151fa212bfbSJulian Elischer PEER1_IP=`echo ${PEER1} | awk -F"|" '{print $2}'` 152fa212bfbSJulian Elischer 153fa212bfbSJulian Elischer PEER2=`echo ${CONNECTION} | awk -F"<->" '{print $2}'` 154fa212bfbSJulian Elischer PEER2_NAME=`echo ${PEER2} | awk -F"|" '{print $1}'` 155fa212bfbSJulian Elischer PEER2_IP=`echo ${PEER2} | awk -F"|" '{print $2}'` 156fa212bfbSJulian Elischer 157fa212bfbSJulian Elischer # !!! if not created already.. 158fa212bfbSJulian Elischer # Create virtual node (jail) with given name and using 159fa212bfbSJulian Elischer # JAIL_PATH as root directory for jail. 160fa212bfbSJulian Elischer 161fa212bfbSJulian Elischer virtual_chain_create_peer_if_necessary ${PEER1_NAME} 162fa212bfbSJulian Elischer virtual_chain_create_peer_if_necessary ${PEER2_NAME} 163fa212bfbSJulian Elischer 164fa212bfbSJulian Elischer # create an interface for peer with the given peer IP. Get interface 165fa212bfbSJulian Elischer # for future use; you will connect this interface to the other 166fa212bfbSJulian Elischer # peers' (PEER2) interface. 167fa212bfbSJulian Elischer virtual_chain_create_interface_with_ip ${PEER1_NAME} ${PEER1_IP} 168fa212bfbSJulian Elischer PEER1_INTERFACE=${RET_INTERFACE} 169fa212bfbSJulian Elischer 170fa212bfbSJulian Elischer # create an interface for peer with the given peer IP. Get interface 171fa212bfbSJulian Elischer # for future use; you will connect this interface to the other 172fa212bfbSJulian Elischer # peers' (PEER2) interface. 173fa212bfbSJulian Elischer virtual_chain_create_interface_with_ip ${PEER2_NAME} ${PEER2_IP} 174fa212bfbSJulian Elischer PEER2_INTERFACE=${RET_INTERFACE} 175fa212bfbSJulian Elischer 176fa212bfbSJulian Elischer # Connect virtual interface to other interface. Syntax is : 177fa212bfbSJulian Elischer # ngctl connect INTERFACE1: INTERFACE2: ether ether. 178fa212bfbSJulian Elischer 179fa212bfbSJulian Elischer echo -n "Connecting ${PEER1_INTERFACE}:ether to ${PEER2_INTERFACE}:ether..." 180fa212bfbSJulian Elischer ngctl connect ${PEER1_INTERFACE}: ${PEER2_INTERFACE}: ether ether \ 181fa212bfbSJulian Elischer || exit 1 182fa212bfbSJulian Elischer echo "done" 183fa212bfbSJulian Elischer 184fa212bfbSJulian Elischer done 185fa212bfbSJulian Elischer 186fa212bfbSJulian Elischer # Executes static route add commands. 187fa212bfbSJulian Elischer i=0 188fa212bfbSJulian Elischer while [ $i != $STATIC_ROUTE_CNT ]; do 189fa212bfbSJulian Elischer eval ROUTE=\${STATIC_ROUTE${i}} 190fa212bfbSJulian Elischer ret=`${ROUTE}` 191fa212bfbSJulian Elischer i=`expr $i + 1` 192fa212bfbSJulian Elischer done 193fa212bfbSJulian Elischer 194*5665fe6bSUlrich Spörlein echo "Virtual WAN established successfully!" 195fa212bfbSJulian Elischer} 196fa212bfbSJulian Elischer 197fa212bfbSJulian Elischervirtual_chain_create_interface_with_ip() { 198fa212bfbSJulian Elischer 199fa212bfbSJulian Elischer NODE_NAME=$1 200fa212bfbSJulian Elischer NODE_IP=$2 201fa212bfbSJulian Elischer 202fa212bfbSJulian Elischer # Create a ng_eiface object for virtual node. ng_eiface 203fa212bfbSJulian Elischer # object has a hook that can be connected to one of bridge 204fa212bfbSJulian Elischer # links. After creating interface get its automatically 205fa212bfbSJulian Elischer # generated name for further usage. 206fa212bfbSJulian Elischer 207fa212bfbSJulian Elischer echo "Creating eiface interface for virtual node ${NODE_NAME}." 208fa212bfbSJulian Elischer ngctl mkpeer eiface ether ether 209fa212bfbSJulian Elischer EIFACE=`ngctl l | grep ngeth | tail -n 1| awk '{print $2}'` 210fa212bfbSJulian Elischer echo "Interface ${EIFACE} is created." 211fa212bfbSJulian Elischer 212fa212bfbSJulian Elischer # Write name of the interface to temp file. Clean-up procedure 213fa212bfbSJulian Elischer # will use this name to shutdown interface. 214fa212bfbSJulian Elischer 215fa212bfbSJulian Elischer echo "interface ${EIFACE}" >> ${TEMP_FILE} 216fa212bfbSJulian Elischer 217fa212bfbSJulian Elischer # Move virtual interface to virtual node. Note that Interface 218fa212bfbSJulian Elischer # name will not be changed at the end of this movement. Moved 219fa212bfbSJulian Elischer # interface can be seen at the output of ifconfig command in 220fa212bfbSJulian Elischer # jail: 'jexec jailname ifconfig' 221fa212bfbSJulian Elischer 222fa212bfbSJulian Elischer echo "Moving ${EIFACE} to ${NODE_NAME}" 223fa212bfbSJulian Elischer ifconfig ${EIFACE} vnet ${NODE_NAME} 224fa212bfbSJulian Elischer 225fa212bfbSJulian Elischer # Make lo0 interface localhost. 226fa212bfbSJulian Elischer jexec ${NODE_NAME} ifconfig lo0 localhost 227fa212bfbSJulian Elischer 228fa212bfbSJulian Elischer # Generate a random mac address for virtual interface. First 229fa212bfbSJulian Elischer # three octets can be changed by user. Last three octets are 230fa212bfbSJulian Elischer # generated randomly. 231fa212bfbSJulian Elischer M4=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ 232fa212bfbSJulian Elischer awk '{ print $1 % 256 }'` 233fa212bfbSJulian Elischer M5=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ 234fa212bfbSJulian Elischer awk '{ print $1 % 256 }'` 235fa212bfbSJulian Elischer M6=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ 236fa212bfbSJulian Elischer awk '{ print $1 % 256 }'` 237fa212bfbSJulian Elischer 238fa212bfbSJulian Elischer MAC=`printf ${MAC_PREFIX}:%02x:%02x:%02x ${M4} ${M5} ${M6}` 239fa212bfbSJulian Elischer 240fa212bfbSJulian Elischer # Set the link address (mac address) of virtual interface in 241fa212bfbSJulian Elischer # virtual node to randomly generated MAC. 242fa212bfbSJulian Elischer echo "Setting MAC address of ${EIFACE} to '${MAC}'" 243fa212bfbSJulian Elischer jexec ${NODE_NAME} ifconfig ${EIFACE} link $MAC 244fa212bfbSJulian Elischer 245fa212bfbSJulian Elischer # Either IPv4 or IPv6 can be used in this script. Ifconfig 246fa212bfbSJulian Elischer # IP setting syntax differs slightly for two IP versions. 247fa212bfbSJulian Elischer # For version 4 'inet' keyword is used whereas for version 6 248fa212bfbSJulian Elischer # 'inet6' is used. Below line tries to decide which IP version 249fa212bfbSJulian Elischer # is given and sets IPVER to 'inet' or 'inet6'. 250fa212bfbSJulian Elischer 251fa212bfbSJulian Elischer IPVER=`echo ${NODE_IP} | awk -F"." '{ split($4,last,"/"); \ 252fa212bfbSJulian Elischer if( NF==4 && $1>0 && $1<256 && $2<256 && $3<256 && \ 253fa212bfbSJulian Elischer last[1]<256) print "inet"; else print "inet6"}'` 254fa212bfbSJulian Elischer 255fa212bfbSJulian Elischer # Set IP address of virtual interface in virtual node. 256fa212bfbSJulian Elischer echo "Setting IP address of ${EIFACE} to '${NODE_IP}'" 257fa212bfbSJulian Elischer jexec ${NODE_NAME} ifconfig ${EIFACE} ${IPVER} ${NODE_IP} 258fa212bfbSJulian Elischer 259fa212bfbSJulian Elischer RET_INTERFACE=${EIFACE} 260fa212bfbSJulian Elischer} 261fa212bfbSJulian Elischer 262fa212bfbSJulian Elischervirtual_chain_create_peer_if_necessary() { 263fa212bfbSJulian Elischer 264fa212bfbSJulian Elischer if ! grep -q $1 ${TEMP_FILE} ; then 265fa212bfbSJulian Elischer 266fa212bfbSJulian Elischer echo -n "Creating virtual node (jail) ${1}..." 267fa212bfbSJulian Elischer jail -c vnet name=${1} host.hostname=${1} \ 268fa212bfbSJulian Elischer path=${JAIL_PATH} persist 269fa212bfbSJulian Elischer jexec ${1} sysctl -w net.inet.ip.forwarding=1 270fa212bfbSJulian Elischer jexec ${1} sysctl -w net.inet6.ip6.forwarding=1 271fa212bfbSJulian Elischer echo "done" 272fa212bfbSJulian Elischer 273fa212bfbSJulian Elischer # Write name of the jail to temp file. Clean-up 274fa212bfbSJulian Elischer # procedure will use this name to remove jail. 275fa212bfbSJulian Elischer 276fa212bfbSJulian Elischer echo "node ${1}" >> ${TEMP_FILE} 277fa212bfbSJulian Elischer fi 278fa212bfbSJulian Elischer 279fa212bfbSJulian Elischer} 280fa212bfbSJulian Elischer 281fa212bfbSJulian Elischer# Stop routine. 282fa212bfbSJulian Elischervirtual_chain_stop() { 283fa212bfbSJulian Elischer 284fa212bfbSJulian Elischer if [ ! -e ${TEMP_FILE} ]; then 285fa212bfbSJulian Elischer echo "Nothing to stop! ${TEMP_FILE}: temp file not found" 286fa212bfbSJulian Elischer else 287fa212bfbSJulian Elischer 288fa212bfbSJulian Elischer echo -n "Shutdown bridge interface.." 289fa212bfbSJulian Elischer OBJECTS=`cat ${TEMP_FILE} | grep bridge | awk '{print $2}'` 290fa212bfbSJulian Elischer for BRIDGE in ${OBJECTS}; do 291fa212bfbSJulian Elischer ngctl shutdown ${BRIDGE}: >/dev/null 2>&1 292fa212bfbSJulian Elischer done 293fa212bfbSJulian Elischer echo "done" 294fa212bfbSJulian Elischer 295fa212bfbSJulian Elischer echo -n "Shutdown all eiface interfaces..." 296fa212bfbSJulian Elischer OBJECTS=`cat ${TEMP_FILE} | grep interface | awk '{print $2}'` 297fa212bfbSJulian Elischer for INTERFACE in ${OBJECTS}; do 298fa212bfbSJulian Elischer ngctl shutdown ${INTERFACE}: >/dev/null 2>&1 299fa212bfbSJulian Elischer done 300fa212bfbSJulian Elischer echo "done" 301fa212bfbSJulian Elischer 302fa212bfbSJulian Elischer echo -n "Removing all jails..." 303fa212bfbSJulian Elischer OBJECTS=`cat ${TEMP_FILE} | grep node | awk '{print $2}'` 304fa212bfbSJulian Elischer for NODE in ${OBJECTS}; do 305fa212bfbSJulian Elischer jail -r ${NODE} 306fa212bfbSJulian Elischer done 307fa212bfbSJulian Elischer echo "done" 308fa212bfbSJulian Elischer 309fa212bfbSJulian Elischer echo "Removing tempfile ${TEMP_FILE}" 310fa212bfbSJulian Elischer rm ${TEMP_FILE} 311fa212bfbSJulian Elischer fi 312*5665fe6bSUlrich Spörlein echo "Virtual LAN objects removed successfully!" 313fa212bfbSJulian Elischer 314fa212bfbSJulian Elischer} 315fa212bfbSJulian Elischer 316fa212bfbSJulian Elischervirtual_chain_usage() { 317fa212bfbSJulian Elischer echo "usage: $0 start [target_topology]" 318fa212bfbSJulian Elischer echo " : $0 [ stop | help ]" 319fa212bfbSJulian Elischer} 320fa212bfbSJulian Elischer 321fa212bfbSJulian Elischer 322fa212bfbSJulian Elischer# Main entry point. 323fa212bfbSJulian Elischer 324fa212bfbSJulian Elischercase $# in 325fa212bfbSJulian Elischer 1) 326fa212bfbSJulian Elischer case $1 in 327fa212bfbSJulian Elischer start) 328fa212bfbSJulian Elischer echo -n "Creating default target topology:" 329fa212bfbSJulian Elischer echo " ${TARGET_TOPOLOGY}" 330fa212bfbSJulian Elischer virtual_chain_start 331fa212bfbSJulian Elischer ;; 332fa212bfbSJulian Elischer stop) 333fa212bfbSJulian Elischer 334fa212bfbSJulian Elischer if [ ! -e ${TEMP_FILE} ]; then 335fa212bfbSJulian Elischer echo -n "Noting to stop! ${TEMP_FILE}:" 336fa212bfbSJulian Elischer echo " temp file not found" 337fa212bfbSJulian Elischer else 338fa212bfbSJulian Elischer virtual_chain_stop 339fa212bfbSJulian Elischer fi 340fa212bfbSJulian Elischer ;; 341fa212bfbSJulian Elischer help) 342fa212bfbSJulian Elischer virtual_chain_usage 343fa212bfbSJulian Elischer exit 1 344fa212bfbSJulian Elischer ;; 345fa212bfbSJulian Elischer *) 346fa212bfbSJulian Elischer virtual_chain_usage 347fa212bfbSJulian Elischer exit 1 348fa212bfbSJulian Elischer 349fa212bfbSJulian Elischer esac 350fa212bfbSJulian Elischer ;; 351fa212bfbSJulian Elischer 2) 352fa212bfbSJulian Elischer case $1 in 353fa212bfbSJulian Elischer start) 354fa212bfbSJulian Elischer TARGET_TOPOLOGY=$2 355fa212bfbSJulian Elischer echo -n "Creating target topology:" 356fa212bfbSJulian Elischer echo "${TARGET_TOPOLOGY}" 357fa212bfbSJulian Elischer virtual_chain_start 358fa212bfbSJulian Elischer ;; 359fa212bfbSJulian Elischer *) 360fa212bfbSJulian Elischer virtual_chain_usage 361fa212bfbSJulian Elischer exit 1 362fa212bfbSJulian Elischer esac 363fa212bfbSJulian Elischer ;; 364fa212bfbSJulian Elischer 365fa212bfbSJulian Elischer *) 366fa212bfbSJulian Elischer virtual_chain_usage 367fa212bfbSJulian Elischer exit 1 368fa212bfbSJulian Elischeresac 369fa212bfbSJulian Elischer 370