#!/bin/sh #============================================================================ # network-multi_net # # Version = 1.1.2 # Date = 2007-07-11 # # Maintainer(s) = Ron Terry - ron (at) pronetworkconsulting (dot) com # # The latest version can be found at: # # http://pronetworkconsulting.com/linux/scripts/network-multi_net.html # # Description: # # Replacement for the xen network-bridge, network-nat and network-route # scripts. This script allows for the creation of multiple bridges. # # This script can create 3 types of bridges: # # traditional bridges: -Bridges that contain both a physical network # device (ethX) and a virtual network device (vethX) # from Dom0. # -This is the traditional type of network bridge # created in xen by the network-bridge script. # # local bridges: -Bridges that contain only a virtual network # device (vethX) from Dom0. # -These bridges can be configured in the # following ways: # # -hostonly: This type of bridge will allow # VMs connected to these networks # to access only Dom0 and other # VMs connected to the bridge. # This type of bridge is similiar to # a VMware "HOST ONLY" network. # # -nat: This type of bridge will allow # VMs connected to these networks # to access the "outside world" # via NAT and other VMs connected # to the bridge. # This type of bridge is similiar to # a VMware "NAT" network. # # -routed: This type of bridge will allow # to access the "outside world" # via routing through Dom0 and # other VMs connected to the # bridge. # # empty bridges: -Bridges that do not contain any physical or # virtual network devices from Dom0. # -These can be used to allow VMs in DomUs to # communicate only with other DomUs and not Dom0. # # This script accepts the (start|stop|restart|status) parameters. # # This script depends on an unmodified version of the network-bridge script # because it uses it to create the traditional bridges. It passes the # (start|stop|status) parameters into the network-bridge script allowing # the user to disassemble the traditional bridges containg physical network # devices so that they may change the network configuration of the Physical # network interfaces. # # This script requires that the vif-bridge script be used as the vif # creation script (as opposed to vif-nat/vif-route). # # Local bridges do not need to be disassembled to change the IP address # of the virtual interfaces because they do not contain interfaces that # have been renamed like the traditional briges (created by the # network-bridge script) do. The stop parameter does however cause them # to be disassembled and removed. If these bridges are NATed or Routed # networks the default gateway of the VMs connected to them will also need # to be changed for them to continue accessing the "outside world". # # The Empty bridges do not contain interfaces from Dom0 so are not # affected by IP address changes. The stop parameter does cause them # to be removed as well. # # This script will test for the presence of the physical interfaces # configured to be connected to traditional bridges and only attempt to # create bridges on the ones that are present and up. It will also test # for the presence of virtual interfaces configured to be connected to # local bridges and only create bridges for the ones that exist and # are not already connected to an existing bridge. # # Edit the BRIDGE_NETDEV_LIST variable to define which physical interfaces # you wish to create traditional bridges on. The default is to create a # traditional bridge on only the first interface (eth0). # # Edit the LOCAL_BRIDGE_LIST variable to define which virtual interfaces # you wish to create local bridges on. The default is the 3rd and 4th # virtual interfaces (veth2, veth3). The first local bridge (on veth2) # is configured as a NAT network and the second host bridge (on veth3) # is configured as a hostonly network. # # Edit the EMPTY_BRIDGE_LIST variable to define which empty bridges to # create. This list should contain the numbers of the bridges to # create (4 5 6 7) # # To enable this script edit the network-script field in the # /etc/xen/xen-config.sxp file. # # Example: (network-script network-multi_net) # # Depends on: /etc/xen/scripts/xen-network-common.sh # /etc/xen/scripts/network-bridge # # Config file: /etc/sysconfig/xendconfig # # Usage: network-multi_net (start|stop|restart|status) # # Vars: # # SCRIPT_PATH -Path to the directory conaining the xen network-bridge # script (typically /etc/xen/scripts) # # BRIDGE_NETDEV_LIST -Space delimited list of physical network devices to # create traditional bridges on # # LOCAL_BRIDGE_LIST -Space delimited list of virtual network devices to # create local bridges on using the following format: # # ,,, # # Example with 2 virtual devices: # # "veth2,00:16:3E:01:00:02,172.22.0.1/16,nat veth3,00:16:3E:01:00:03,172.23.0.1/16,hostonly" # # EMPTY_BRIDGE_LIST -Space delimited list of bridge numbers to create as # empty bridges. # # BRIDGE_NAME -Name of bridge to create (example: xenbr) # # NAT_EXTERNAL_INTERFACE -Network interface to use as the external interface # for NATed and Routed networks # #============================================================================ #### Read config files and set variables ################################## . /etc/xen/scripts/xen-network-common.sh # Source the configuration File . /etc/sysconfig/xendconfig SCRIPT_PATH="/etc/xen/scripts" NETWORK_SAVE_PATH="/var/lib/xend/network_save" IPTABLES_SAVE_FILE="$NETWORK_SAVE_PATH/iptables-save" #### Script Functions ##################################################### usage() { # Gives hlep about usage parameters echo "Usage: $0 {start|stop|restart|status}" exit 1 } get_option() { # Determine which option was passed from the command line. case "$1" in start|stop|restart|status) CMD_OPT="$1" ;; *) usage ;; esac } make_save_dir() { # Create temporary storage directory if needed. if ! [ -d "$NETWORK_SAVE_PATH" ] then mkdir $NETWORK_SAVE_PATH fi } manage_routing() { # Saves and restores the ip forward and Network Address Translation state # that exist before the script runs # # This function reads the start,stop parameter from the $CMD_OPT # variable and responds respectively. case $CMD_OPT in start) #------------------------------------------------------------------ # Determine the initial state of the ip_forward parameter #------------------------------------------------------------------ case `cat /proc/sys/net/ipv4/ip_forward` in 0) INIT_IP_FWD="off" echo "0" > $NETWORK_SAVE_PATH/init_ip_fwd_state ;; 1) INIT_IP_FWD="on" echo "1" > $NETWORK_SAVE_PATH/init_ip_fwd_state ;; esac #------------------------------------------------------------------ # Determine if we need to enable ip_forward #------------------------------------------------------------------ if echo $LOCAL_BRIDGE_LIST | grep -qE "(nat|NAT|route|ROUTE)" then IP_FWD="on" echo "" echo "============================================================" echo "Enabling IP Forwarding" echo "============================================================" echo 1 > /proc/sys/net/ipv4/ip_forward else IP_FWD="off" echo "" echo "============================================================" echo "Disabling IP Forwarding" echo "============================================================" echo 0 > /proc/sys/net/ipv4/ip_forward fi #------------------------------------------------------------------ # Determine if we need to enable NAT #------------------------------------------------------------------ if echo $LOCAL_BRIDGE_LIST | grep -qE "(nat|NAT)" then echo "" echo "============================================================" echo "Enabling Network Adress Translation" echo "============================================================" iptables -t nat -A POSTROUTING -o $NAT_EXTERNAL_INTERFACE -j MASQUERADE sysctl -q -w net.bridge.bridge-nf-call-iptables="0" NAT_DONE="yes" fi ;; stop) #------------------------------------------------------------------ # Set the ip_forward value back to its original state #------------------------------------------------------------------ echo "" echo "============================================================" echo "Restoring IP Forwarding to its original state" echo "============================================================" case `cat $NETWORK_SAVE_PATH/init_ip_fwd_state` in 0) echo "ip_forward = 0" echo "0" > /proc/sys/net/ipv4/ip_forward ;; 1) echo "ip_forward = 0" echo "1" > /proc/sys/net/ipv4/ip_forward ;; *) echo "Original state unknown. Using default value." echo "ip_forward = 0" echo "0" > /proc/sys/net/ipv4/ip_forward ;; esac #------------------------------------------------------------------ # Clean up init_ip_fwd_state file #------------------------------------------------------------------ rm $NETWORK_SAVE_PATH/init_ip_fwd_state ;; esac } manage_susefirewall2() { case $CMD_OPT in start) if [ -e /etc/init.d/SuSEfirewall2_setup ] && /etc/init.d/SuSEfirewall2_setup status | grep -iwq "running" then echo "" echo "============================================================" echo "Stopping SuSEfirewall2" echo "============================================================" /etc/init.d/SuSEfirewall2_setup stop > /dev/null echo "0" > $NETWORK_SAVE_PATH/sf2 return 0 else return 1 fi ;; stop) if [ -e $NETWORK_SAVE_PATH/sf2 ] && grep "0" $NETWORK_SAVE_PATH/sf2 then echo "" echo "============================================================" echo "Starting SuSEfirewall2" echo "============================================================" /etc/init.d/SuSEfirewall2_setup start > /dev/null rm -rf $NETWORK_SAVE_PATH/sf2 return 0 else return 1 fi ;; esac } manage_iptables() { # Saves and restores the iptables rules that exist before the script runs # # This function reads the start,stop parameter from the $CMD_OPT # variable and responds respectively. case $CMD_OPT in start) echo "" echo "============================================================" echo "Saving iptables rules" echo "============================================================" #---------------------------------------------------------------- # Saving iptables rules for $TABLE to a file #---------------------------------------------------------------- for TABLE in `iptables-save |grep '*'|cut -d '*' -f 2` do echo "Saving table: $TABLE" iptables-save -t $TABLE > $IPTABLES_SAVE_FILE@$TABLE echo "Flushing table: $TABLE" iptables -F -t $TABLE echo "-----------------------" done #---------------------------------------------------------------- # Deleting any custom chain #---------------------------------------------------------------- for CHAIN in `iptables-save |grep ^:|cut -d ":" -f 2|cut -d " " -f 1` do case $CHAIN in INPUT|OUTPUT|FORWARD|PREROUTING|POSTROUTING) #do nothing ;; *) echo "Deteting chain: $CHAIN" iptables -X $CHAIN ;; esac done ;; stop) echo "" echo "============================================================" echo "Restoring iptables rules" echo "============================================================" #---------------------------------------------------------------- # Restoring iptables rules for $TABLE #---------------------------------------------------------------- for TABLE in `ls $IPTABLES_SAVE_FILE*|cut -d "@" -f 2` do echo "Restoring table: $TABLE" iptables-restore < $IPTABLES_SAVE_FILE@$TABLE rm $IPTABLES_SAVE_FILE@$TABLE echo "-----------------------" done ;; esac } setup_host_interface() { # Configure the MAC and IP address of a virtual device. # # This function is called by other fuctions. # # usage: setup_host_interface local DEV="$1" local MAC="$2" local IPADDR="$3" case $CMD_OPT in start) # take the interface down ip link set $DEV down # ... and configure it ip link set $DEV addr $MAC ip addr flush $DEV ip addr add $IPADDR brd + dev $DEV # bring it back up ip link set $DEV up ;; stop) # take the interface down ip link set $DEV down # unconfigure it ip link set $DEV addr fe:ff:ff:ff:ff:ff ip addr flush $DEV ;; status) ip addr show $DEV ;; esac } create_traditional_bridges() { # Uses the network-bridge script to create bridges on physical devices in Dom0. # # This fuction passes the start,stop,status parameters on to the network-bridge # script. for NETDEVICE in $BRIDGE_NETDEV_LIST do local BRIDGE_NUM=${NETDEVICE##${NETDEVICE%%[0-9]*}} if /sbin/ip link show $NETDEVICE | grep -qw UP then echo "" echo "============================================================" echo "Configuring Virtual Bridge: $BRIDGE_NAME$BRIDGE_NUM" echo "using- Physical Interface: $NETDEVICE" echo " Virtual Interface: vif$BRIDGE_NUM" echo "============================================================" echo "" $SCRIPT_PATH/network-bridge $CMD_OPT netdev=$NETDEVICE bridge=$BRIDGE_NAME$BRIDGE_NUM vifnum=$BRIDGE_NUM echo "" else echo " Physical Interface $NETDEVICE is not up. Skipping $BRIDGE_NAME$BRIDGE_NUM" fi done } create_local_bridges() { # Creates bridges attached to virtual devices in Dom0 and enables nat or routing # on the bridges if specified. # # This fuction reads the start,stop,status parameter from the $CMD_OPT variable # and responds respectively. for IFACE in $LOCAL_BRIDGE_LIST do # Set local function variables local DEV=`echo $IFACE|cut -d "," -f 1` local MAC=`echo $IFACE|cut -d "," -f 2` local IPADDR=`echo $IFACE|cut -d "," -f 3` local BRIDGE_TYPE=`echo $IFACE|cut -d "," -f 4` local NAT_GW_IP=`echo $IFACE|cut -d "," -f 3|cut -d "/" -f 1` local NAT_INTIF=$DEV local ROUTE_INTIF=$DEV local BRIDGE_NUM=${NAT_INTIF##${NAT_INTIF%%[0-9]*}} local BR_NAME=$BRIDGE_NAME$BRIDGE_NUM local VIF=vif0.$BRIDGE_NUM case $CMD_OPT in start) if ! brctl show | grep -qw $DEV && /sbin/ip address show $DEV > /dev/null then #------------------------------------------------------------------ # Create the bridge #------------------------------------------------------------------ echo "" echo "============================================================" echo "Configuring Virtual Host Bridge: $BR_NAME" echo " As a network of type: $BRIDGE_TYPE" echo "" echo " using- Virtual Interface: $VIF" echo " Virtual Device: $DEV" create_bridge $BR_NAME > /dev/null 2>&1 setup_bridge_port $VIF > /dev/null 2>&1 add_to_bridge $BR_NAME $VIF > /dev/null 2>&1 setup_host_interface $DEV $MAC $IPADDR > /dev/null 2>&1 #------------------------------------------------------------------ # Set up the bridge as a hostonly / NAT / Routed network #------------------------------------------------------------------ case $BRIDGE_TYPE in NAT|nat) # Set up the bridge as NATed network echo " Gateway: $NAT_GW_IP" echo " External Interface: $NAT_EXTERNAL_INTERFACE" ;; ROUTE|route) # Set up the bridge as Routed network echo " Gateway: $NAT_GW_IP" echo " External Interface: $NAT_EXTERNAL_INTERFACE" iptables -t nat -A PREROUTING -i $ROUTE_INTIF -j ACCEPT #iptables -t filter -A FORWARD -i $NAT_INTIF -j ACCEPT #iptables -t filter -A FORWARD -i $NAT_INTIF -j ACCEPT ;; HOSTONLY|hostonly) # Set up the bridge as hostonly network if [ "$IP_FWD" = "on" ] then iptables -t nat -A PREROUTING -i $NAT_INTIF -j DROP fi ;; esac echo "============================================================" else #------------------------------------------------------------------ # Skip this bridge #------------------------------------------------------------------ echo " Virtual Interface $DEV is already attached to a bridge or it does not exist." echo " Skipping $BR_NAME" fi ;; stop) #------------------------------------------------------------------ # Remove the bridge #------------------------------------------------------------------ echo "" echo "============================================================" echo "Removing Virtual Host Bridge: $BR_NAME" echo " As a network of type: $BRIDGE_TYPE" echo "" echo " using- Virtual Interface: $VIF" echo " Virtual Device: $DEV" #------------------------------------------------------------------ # First remove the hostonly / NAT / Routed configuration #------------------------------------------------------------------ case $BRIDGE_TYPE in NAT|nat) ;; ROUTE|route) # Clean out the bridge specific routing iptables rule iptables -t nat -D PREROUTING -i $ROUTE_INTIF -j ACCEPT #iptables -t filter -D FORWARD -i $DEV -j ACCEPT #iptables -t filter -D FORWARD -i $NAT_INTIF -j ACCEPT ;; HOSTONLY|hostonly) # Clean out the bridge specific nat iptables rule iptables -t nat -D PREROUTING -i $NAT_INTIF -j DROP ;; esac echo "============================================================" #------------------------------------------------------------------ # Then unconfigure the veth #------------------------------------------------------------------ setup_host_interface $DEV $MAC $IPADDR > /dev/null 2>&1 #------------------------------------------------------------------ # remove vif from the bridge #------------------------------------------------------------------ brctl delif $BR_NAME $VIF #------------------------------------------------------------------ # unconfigure the vif #------------------------------------------------------------------ ip link set $VIF down ip link set $VIF addr fe:ff:ff:ff:ff:ff ip link set $VIF multicast on ip link set $VIF arp on ip addr flush $VIF #------------------------------------------------------------------ # and finaly unconfigure the bridge #------------------------------------------------------------------ ip link set $BR_NAME down brctl delbr $BR_NAME ;; status) #------------------------------------------------------------------ # Show the status of the bridge #------------------------------------------------------------------ echo "" echo "============================================================" echo "Status of Virtual Host Bridge: $BR_NAME" echo " using- Virtual Interface: $VIF" echo " Virtual Device: $DEV" echo "------------------------------------------------------------" echo "This Network is: $BRIDGE_TYPE" echo "============================================================" brctl show | grep -w "^$BR_NAME" echo "" ip addr show $DEV echo "============================================================" ;; esac done } create_empty_bridges() { # Creates bridges attached to no devices in Dom0. # # This function reads the start,stop,status parameter from the $CMD_OPT # variable and responds respectively. echo "" echo "============================================================" for BRIDGE in $EMPTY_BRIDGE_LIST do local BRIDGE_NUM=$BRIDGE local BR_NAME=$BRIDGE_NAME$BRIDGE_NUM case $CMD_OPT in start) if ! brctl show | grep -qw "^$BR_NAME" then echo "Configuring Virtual Empty Bridge: $BR_NAME" create_bridge $BR_NAME fi ;; stop) if brctl show | grep -qw "^$BR_NAME" then echo "Unconfiguring Virtual Empty Bridge: $BR_NAME" ip link set $BR_NAME down brctl delbr $BR_NAME fi ;; status) brctl show $BR_NAME | grep -w "^$BR_NAME" ;; esac done echo "============================================================" } #### Start, Stop, Status Functions ######################################## start_xend_network() { echo "" echo "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" echo " Starting the xend network environment" echo "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" make_save_dir manage_susefirewall2 || manage_iptables create_traditional_bridges manage_routing create_local_bridges create_empty_bridges } stop_xend_network() { echo "" echo "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" echo " Stopping the xend network environment" echo "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" create_traditional_bridges create_local_bridges create_empty_bridges manage_routing manage_susefirewall2 || manage_iptables } show_xend_network_status() { create_traditional_bridges create_local_bridges create_empty_bridges } #### Maid Code Body ####################################################### get_option "$1" case $CMD_OPT in start) start_xend_network ;; stop) stop_xend_network ;; restart) CMD_OPT="stop" stop_xend_network CMD_OPT="start" start_xend_network ;; status) show_xend_network_status ;; esac exit 0