xen/network-multinet

678 lines
24 KiB
Bash

#!/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:
#
# <virtual network device>,<mac address>,<IP address/CIDR NetMask>,<nat|hostonly|routed>
#
# 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 <virtual net device> <MAC Addr> <IP Addr>
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