Overhaul quantum networking for non-seed clouds.

The networking setup was inappropriate for non-seed clouds - it
depended on two network interfaces, forced NAT that we don't need and
could not be turned off. Additionally there wasn't much clarity
between idempotent machine config and non-idempotent service config.

Key changes in this patch:
* No longer write persistent device files, instead update
  idempotently.
* NAT rules are now setup idempotently on each o-r-c run.
* New definitions for the meaning of various config keys to suit
  working with different cloud layers.

Change-Id: Ie86be0fc884b4c4f655d73da345bdee45fcde473
This commit is contained in:
Robert Collins 2013-07-01 16:25:45 +12:00
parent 04a3c267a2
commit d9a4ea36e1
11 changed files with 160 additions and 139 deletions

View File

@ -1,125 +1,40 @@
#!/bin/bash
# Initialise the quantum server configuration.
#
# This creates initial networks for quantum based on heat metadata and local
# network configuration.
#
# It is not idempotent.
set -eux
set -o pipefail
PATH=/usr/local/bin:$PATH
source /root/stackrc
PUBLIC_INTERFACE=$(os-config-applier --key quantum.ovs.public_interface --key-default '')
OVS_PHYSICAL_BRIDGE=$(os-config-applier --type raw --key quantum.ovs.physical_bridge --key-default '')
OVS_RANGE=$(os-config-applier --type raw --key quantum.ovs.ovs_range --key-default '')
PHYSICAL_NETWORK=$(os-config-applier --type raw --key quantum.ovs.physical_network --key-default '')
FIXED_RANGE=$(os-config-applier --type raw --key quantum.ovs.fixed_range --key-default '')
ALLOCATION_START=$(os-config-applier --type netaddress --key quantum.ovs.fixed_range.start --key-default '')
ALLOCATION_END=$(os-config-applier --type netaddress --key quantum.ovs.fixed_range.end --key-default '')
NETWORK=$(os-config-applier --type netaddress --key quantum.ovs.ovs_range --key-default 'unset')
NETWORK_GATEWAY=`python -c 'import netaddr, sys; print netaddr.IPNetwork(sys.argv[1])[1]' $FIXED_RANGE`
OVS_FIXED_ADDRESS=${NETWORK_GATEWAY}/${FIXED_RANGE##*/}
FIXED_RANGE_START=`python -c 'import netaddr, sys; print netaddr.IPNetwork(sys.argv[1])[2]' $FIXED_RANGE`
FIXED_RANGE_END=`python -c 'import netaddr, sys; print netaddr.IPNetwork(sys.argv[1])[-2]' $FIXED_RANGE`
ALLOCATION_POOL="start=${FIXED_RANGE_START},end=${FIXED_RANGE_END}"
if [ "$NETWORK" == "unset" ] ; then
# undercloud / seed cloud - lookup the network device
BRIDGE=$(os-config-applier --type raw --key quantum.ovs.physical_bridge)
# NB: assumes only one network on the device
NETWORK=$(ip addr show dev $BRIDGE | grep ' inet ' | awk '{print $2}')
# Route traffic to this machine
NETWORK_GATEWAY=`python -c 'import netaddr, sys; print netaddr.IPNetwork(sys.argv[1]).ip' $NETWORK`
fi
NETWORK_CIDR=`python -c 'import netaddr, sys; print netaddr.IPNetwork(sys.argv[1]).cidr' $NETWORK`
DISTRO=`lsb_release -si`
add_bootstack_network_scripts() {
# Create $OVS_PHYSICAL_BRIDGE ifcfg file
IFCFG_FILE=/etc/sysconfig/network-scripts/ifcfg-$OVS_PHYSICAL_BRIDGE
if ! grep -q boot-stack $IFCFG_FILE; then
cat >> $IFCFG_FILE <<eof
# This interface was installed by the diskimage-builder boot-stack element.
DEVICE=$OVS_PHYSICAL_BRIDGE
BOOTPROTO=static
IPADDR=$OVS_ADDRESS
NETMASK=$OVS_NETMASK
ONBOOT=yes
eof
fi
# Create $PUBLIC_INTERFACE ifcfg file
IFCFG_FILE=/etc/sysconfig/network-scripts/ifcfg-$PUBLIC_INTERFACE
if ! grep -q boot-stack $IFCFG_FILE; then
cat >> $IFCFG_FILE <<eof
# This interface was installed by the diskimage-builder boot-stack element.
DEVICE=$PUBLIC_INTERFACE
BOOTPROTO=manual
ONBOOT=yes
eof
fi
# IFUP Configuration
IFUP_FILE=/sbin/ifup-local
if ! grep -q boot-stack $IFUP_FILE; then
cat >> $IFUP_FILE <<eof
# This script was installed by the diskimage-builder boot-stack element.
if [ \${1} = "$OVS_PHYSICAL_BRIDGE" ]; then
iptables -t nat -A PREROUTING -d 169.254.169.254 -p tcp -m tcp --dport 80 -j REDIRECT --to-port 8775
iptables -t nat -A POSTROUTING -s $OVS_RANGE ! -d 192.168.122.1/32 -o eth0 -j MASQUERADE
ip addr add $OVS_FIXED_ADDRESS dev \${1}
if [ -n "$ALLOCATION_START" -a -n "$ALLOCATION_END" ] ; then
ALLOCATION_POOL="start=${ALLOCATION_START},end=${ALLOCATION_END}"
fi
if [ \${1} = "$PUBLIC_INTERFACE" ]; then
ifconfig \${1} 0.0.0.0 up
fi
eof
fi
chmod +x $IFUP_FILE
}
add_bootstack_interfaces() {
if ! grep -q boot-stack /etc/network/interfaces && ! grep -q "iface $PUBLIC_INTERFACE" /etc/network/interfaces; then
cat >> /etc/network/interfaces <<eof
# This interface was installed by the diskimage-builder boot-stack element.
auto $OVS_PHYSICAL_BRIDGE
iface $OVS_PHYSICAL_BRIDGE inet static
address $OVS_ADDRESS
netmask $OVS_NETMASK
pre-up service openvswitch-switch restart
up iptables -t nat -A PREROUTING -d 169.254.169.254 -p tcp -m tcp --dport 80 -j REDIRECT --to-port 8775
up iptables -t nat -A POSTROUTING -s $OVS_RANGE -o eth0 -j MASQUERADE
up ip addr add $OVS_FIXED_ADDRESS dev \$IFACE
auto $PUBLIC_INTERFACE
iface $PUBLIC_INTERFACE inet manual
up ifconfig \$IFACE 0.0.0.0 up
# Public Bridge
# auto eth2
# iface eth2 inet manual
# up ifconfig \$IFACE 0.0.0.0 up
# up ip link set \$IFACE promisc on
# down ifconfig \$IFACE down
eof
elif ! grep -q '# may need to add' /etc/network/interfaces ; then
echo "# may need to add 192.0.2.1 to $OVS_PHYSICAL_BRIDGE, see $0" >> /etc/network/interfaces
fi
}
if [ -n "$PUBLIC_INTERFACE" ] && [ -n "$OVS_PHYSICAL_BRIDGE" ] ; then
OVS_ADDRESS=`python -c 'import netaddr, sys; print netaddr.IPNetwork(sys.argv[1])[1]' $OVS_RANGE`
OVS_NETMASK=`python -c 'import netaddr, sys; print netaddr.IPNetwork(sys.argv[1]).netmask' $OVS_RANGE`
if [[ "Fedora RedHatEnterpriseServer" =~ "$DISTRO" ]]; then
add_bootstack_network_scripts
elif [[ "Debian Ubuntu" =~ "$DISTRO" ]]; then
add_bootstack_interfaces
fi
fi
init-quantum-ovs
if [[ "Fedora RedHatEnterpriseServer" =~ "$DISTRO" ]]; then
service network restart
elif [[ "Debian Ubuntu" =~ "$DISTRO" ]]; then
service networking restart
fi
service nova-bm-dnsmasq restart
# Hackish: ensure the server is running. XXX: Test without this.
service quantum-server restart
# TODO: configurable
TENANT_ID=$(keystone tenant-list | grep ' admin ' | awk '{print $2}')
NET_EXTRA="--shared"
@ -143,8 +58,4 @@ while ! NET_ID=$(quantum net-create $NET_NAME $NET_EXTRA | grep ' id ' | awk '{p
sleep 1
done
SUBNET_ID=$(quantum subnet-create $SUBNET_EXTRA --ip_version 4 ${ALLOCATION_POOL:+--allocation-pool $ALLOCATION_POOL} --gateway $NETWORK_GATEWAY $NET_ID $FIXED_RANGE | grep ' id ' | awk '{print $4}')
if [ -n "$OVS_PHYSICAL_BRIDGE" ] ; then
ifconfig $OVS_PHYSICAL_BRIDGE up
fi
SUBNET_ID=$(quantum subnet-create $SUBNET_EXTRA --ip_version 4 ${ALLOCATION_POOL:+--allocation-pool $ALLOCATION_POOL} ${NETWORK_GATEWAY:+--gateway $NETWORK_GATEWAY} $NET_ID $NETWORK_CIDR | grep ' id ' | awk '{print $4}')

View File

@ -12,6 +12,6 @@ service glance-reg restart
service nova-api restart
init-nova
os-refresh-config
init-quantum
os-refresh-config

View File

@ -13,11 +13,18 @@ configured via Heat Metadata. For example:
physical_network: ctlplane
network_vlan_ranges: ctlplane
bridge_mappings: ctlplane:br-ctlplane
fixed_range: 192.0.2.32/29
ovs_range: 192.0.2.0/24
fixed_range:
start: 192.0.2.2
end: 192.0.2.3
ovs_range: 198.51.100.0/24
If public\_interface and physical\_bridge are not set, no bridges will be
connected directly. This is normal for quantum hosting virtual machines
as the l3 agent is responsible for making this connection. Some of the
when using an overlay network (e.g. GRE tunnelling). Some of the
other fields will be ignored in this case. Most of them map 1:1 with their
counterparts in the OVS section of ovs\_quantum\_plugin.ini
fixed\_range is used to create an allocation pool on the tenants network, and
ovs\_range is used to create the tenants subnet, if set. If not set the subnet
from the physical\_bridge is used, and the gateway is set to the
physical\_bridge address.

View File

@ -0,0 +1,3 @@
#!/bin/bash
set -eux
init-quantum-ovs

View File

@ -1,4 +1,3 @@
#!/bin/bash
set -eux
init-quantum-ovs
service quantum-openvswitch-agent restart

View File

@ -1,30 +1,82 @@
#!/bin/bash
# This script should remain idempotent as it may be called several times
# Idempotent script to apply heat configuration to the running network
# environment.
#
# If a bootstrap public_interface_ip is defined in metadata and not attached to
# any device then it will be added to the public_interface device if one is
# defined.
#
# An integration bridge for quantum-ovs-agent is created.
#
# If no physical bridge is defined in metadata, the script will have no
# further effect.
#
# If the defined physical_bridge is not present on the system, one will be
# defined via ovs-vsctl.
#
# The physical bridge will be brought up.
#
# If a public_interface is defined in metadata:
# - it will be made a member of the physical_bridge.
# - an ip addresses on public_interface are moved onto physical_bridge.
#
# An iptables rule to redirect incoming metadata server requests on the public
# bridge device is inserted if not present.
#
# Note that no persistent config file is written to the OS : ovs-vsctl modifies
# a persistent database so the bridge device will persist across reboots, but
# [on Ubuntu at least] early boot does not bring up ovs-vswitch early enough,
# and metadata access will fail.
set -eux
PATH=/usr/local/bin:$PATH
OVS_PHYSICAL_BRIDGE=$(os-config-applier --key quantum.ovs.physical_bridge --type raw --key-default '')
PUBLIC_INTERFACE=$(os-config-applier --key quantum.ovs.public_interface --type raw --key-default '')
EXTERNAL_BRIDGE=$(os-config-applier --key quantum.ovs.physical_bridge --type raw --key-default '')
PHYSICAL_INTERFACE=$(os-config-applier --key quantum.ovs.public_interface --type raw --key-default '')
PHYSICAL_INTERFACE_IP=$(os-config-applier --key bootstack.public_interface_ip --type netaddress --key-default '')
if [ -n "$PHYSICAL_INTERFACE_IP" -a -n "$PHYSICAL_INTERFACE" ] ; then
if ! (ip addr show | grep -q $PHYSICAL_INTERFACE_IP) ; then
ip addr add $PHYSICAL_INTERFACE_IP dev $PHYSICAL_INTERFACE
fi
fi
# Hacky: ensure the switch is running : we should instead arrange for this
# script to not be run before it's started.
service openvswitch-switch restart || service openvswitch restart
ovs-vsctl --no-wait -- --may-exist add-br br-int
ovs-vsctl --no-wait br-set-external-id br-int bridge-id br-int
if [ -n "$OVS_PHYSICAL_BRIDGE" ] && [ -n "$PUBLIC_INTERFACE" ]; then
ovs-vsctl --no-wait -- --may-exist add-br $OVS_PHYSICAL_BRIDGE
ovs-vsctl add-port $OVS_PHYSICAL_BRIDGE $PUBLIC_INTERFACE || echo "port already added?"
if [ -z "$EXTERNAL_BRIDGE" ] ; then
exit 0
fi
if [ -n "$OVS_PHYSICAL_BRIDGE" ] && [ -n "$PUBLIC_INTERFACE" ] ; then
ovs-vsctl -- --may-exist add-br $EXTERNAL_BRIDGE
ip link set dev $EXTERNAL_BRIDGE up
if [ -n "$PHYSICAL_INTERFACE" ] ; then
if ovs-vsctl port-to-br $PHYSICAL_INTERFACE ; then
EXISTING_PORT=$(ovs-vsctl port-to-br $PHYSICAL_INTERFACE)
if [ "$EXISTING_PORT" != "$PHYSICAL_INTERFACE" ] ; then
ovs-vsctl del-port $EXTERNAL_BRIDGE $PHYSICAL_INTERFACE
fi
fi
ovs-vsctl add-port $EXTERNAL_BRIDGE $PHYSICAL_INTERFACE
ip link set dev $PHYSICAL_INTERFACE up
fi
if [ -n "$PHYSICAL_INTERFACE" ] ; then
# Right now we probably are disconnected, need to move all IPs from public interface to bridge
for IP in $(ip addr show dev $PUBLIC_INTERFACE | grep ' inet ' | awk '{print $2}'); do
ip addr del $IP dev $PUBLIC_INTERFACE
if ! ip addr show $OVS_PHYSICAL_BRIDGE | grep $IP; then
ip addr add $IP dev $OVS_PHYSICAL_BRIDGE
for IP in $(ip addr show dev $PHYSICAL_INTERFACE | grep ' inet ' | awk '{print $2}'); do
if ! ip addr show $EXTERNAL_BRIDGE | grep $IP; then
ip addr add $IP dev $EXTERNAL_BRIDGE
fi
ip addr del $IP dev $PHYSICAL_INTERFACE
done
ifconfig $OVS_PHYSICAL_BRIDGE up
fi
service openvswitch-switch restart || service openvswitch restart
iptables -t nat -C PREROUTING -d 169.254.169.254/32 -i $EXTERNAL_BRIDGE -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8775 || iptables -t nat -I PREROUTING -d 169.254.169.254/32 -i $EXTERNAL_BRIDGE -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8775

View File

@ -16,3 +16,15 @@ Edit config.json to customise it for your deployment environment. The default
is configured for nova-baremetal operation in a seed VM. The configuration
options are documented in the actual elements that use the configuration - e.g.
nova, quantum etc.
Configuration keys
------------------
bootstack:
public\_interface\_ip: 192.0.2.1/24
- What IP address to place on the ovs public interface. Only intended for
use when the interface will not be otherwise configured.
masquerade\_networks: [192.0.2.0]
- What networks, if any, to masquerade. When set, all traffic being
output from each network to other networks is masqueraded. Traffic
to 192.168.122.1 is never masqueraded.

View File

@ -40,6 +40,10 @@
},
"metadata-proxy": "false"
},
"bootstack": {
"public_interface_ip": "192.0.2.1/24",
"masquerade_networks": ["192.0.2.0"]
},
"cinder": {
"db": "mysql://cinder:unset@localhost/cinder",
"volume_size_mb": "5000"
@ -48,15 +52,18 @@
"host": "127.0.0.1",
"ovs_db": "mysql://quantum:unset@localhost/ovs_quantum?charset=utf8",
"ovs": {
"public_interface": "eth1",
"bridge_mappings": "ctlplane:br-ctlplane",
"dnsmasq_range": ["192.0.2.4", "192.0.2.4"],
"enable_tunneling": "False",
"fixed_range": {
"start": "192.0.2.2",
"end": "192.0.2.3"
},
"network_vlan_ranges": "ctlplane",
"physical_bridge": "br-ctlplane",
"physical_network": "ctlplane",
"network_vlan_ranges": "ctlplane",
"bridge_mappings": "ctlplane:br-ctlplane",
"fixed_range": "192.0.2.32/29",
"ovs_range": "192.0.2.0/24",
"tenant_network_type": "vlan",
"enable_tunneling": "False"
"public_interface": "eth1",
"tenant_network_type": "vlan"
}
},
"heat": {

View File

@ -0,0 +1,2 @@
os-apply-config
os-refresh-config

View File

@ -0,0 +1,22 @@
# In case this script crashed or was interrupted earlier, flush, unlink and
# delete the temp chain.
iptables -t nat -F BOOTSTACK_MASQ_NEW || true
iptables -t nat -D POSTROUTING -j BOOTSTACK_MASQ_NEW || true
iptables -t nat -X BOOTSTACK_MASQ_NEW || true
iptables -t nat -N BOOTSTACK_MASQ_NEW
# Build the chain we want.
{{#bootstack.masquerade_networks}}
NETWORK={{.}}
# Workaround iptables not permitting two -d parameters in one call.
iptables -t nat -A BOOTSTACK_MASQ_NEW -s $NETWORK -d 192.168.122.1 -j RETURN
iptables -t nat -A BOOTSTACK_MASQ_NEW -s $NETWORK ! -d $NETWORK -j MASQUERADE
{{/bootstack.masquerade_networks}}
# Link it in.
iptables -t nat -I POSTROUTING -j BOOTSTACK_MASQ_NEW
# Delete the old chain if present.
iptables -t nat -F BOOTSTACK_MASQ || true
iptables -t nat -D POSTROUTING -j BOOTSTACK_MASQ || true
iptables -t nat -X BOOTSTACK_MASQ || true
# Rename the new chain into permanence.
iptables -t nat -E BOOTSTACK_MASQ_NEW BOOTSTACK_MASQ

View File

@ -0,0 +1,6 @@
#!/bin/bash
set -eux
RULES_SCRIPT=/var/opt/seed-stack/masquerade
. $RULES_SCRIPT