454 lines
14 KiB
Bash
454 lines
14 KiB
Bash
# dragonflow.sh - Devstack extras script to install Dragonflow
|
|
|
|
# The git repo to use
|
|
OVS_REPO=${OVS_REPO:-http://github.com/openvswitch/ovs.git}
|
|
OVS_REPO_NAME=$(basename ${OVS_REPO} | cut -f1 -d'.')
|
|
|
|
# The branch to use from $OVS_REPO
|
|
# TODO(gsagie) Currently take branch-2.5 branch as master is not stable
|
|
OVS_BRANCH=${OVS_BRANCH:-origin/branch-2.5}
|
|
|
|
DEFAULT_NB_DRIVER_CLASS="dragonflow.db.drivers.etcd_db_driver.EtcdDbDriver"
|
|
DEFAULT_TUNNEL_TYPE="geneve"
|
|
DEFAULT_APPS_LIST="l2_app.L2App,l3_app.L3App,dhcp_app.DHCPApp"
|
|
|
|
# How to connect to the database storing the virtual topology.
|
|
REMOTE_DB_IP=${REMOTE_DB_IP:-$HOST_IP}
|
|
REMOTE_DB_PORT=${REMOTE_DB_PORT:-4001}
|
|
REMOTE_DB_HOSTS=${REMOTE_DB_HOSTS:-"$REMOTE_DB_IP:$REMOTE_DB_PORT"}
|
|
NB_DRIVER_CLASS=${NB_DRIVER_CLASS:-$DEFAULT_NB_DRIVER_CLASS}
|
|
TUNNEL_TYPE=${TUNNEL_TYPE:-$DEFAULT_TUNNEL_TYPE}
|
|
DF_APPS_LIST=${DF_APPS_LIST:-$DEFAULT_APPS_LIST}
|
|
|
|
#ovs related pid files
|
|
OVS_DB_SERVICE="ovsdb-server"
|
|
OVS_VSWITCHD_SERVICE="ovs-vswitchd"
|
|
OVS_DIR="/usr/local/var/run/openvswitch"
|
|
OVS_DB_PID=$OVS_DIR"/"$OVS_DB_SERVICE".pid"
|
|
OVS_VSWITCHD_PID=$OVS_DIR"/"$OVS_VSWITCHD_SERVICE".pid"
|
|
|
|
# Pluggable DB drivers
|
|
#----------------------
|
|
if is_service_enabled df-etcd ; then
|
|
source $DEST/dragonflow/devstack/etcd_driver
|
|
NB_DRIVER_CLASS="dragonflow.db.drivers.etcd_db_driver.EtcdDbDriver"
|
|
fi
|
|
if is_service_enabled df-ramcloud ; then
|
|
source $DEST/dragonflow/devstack/ramcloud_driver
|
|
NB_DRIVER_CLASS="dragonflow.db.drivers.ramcloud_db_driver.RamCloudDbDriver"
|
|
fi
|
|
if is_service_enabled df-zookeeper ; then
|
|
source $DEST/dragonflow/devstack/zookeeper_driver
|
|
NB_DRIVER_CLASS="dragonflow.db.drivers.zookeeper_db_driver.ZookeeperDbDriver"
|
|
fi
|
|
|
|
# Dragonflow installation uses functions from these files
|
|
source $TOP_DIR/lib/neutron_plugins/ovs_base
|
|
source $TOP_DIR/lib/neutron_plugins/openvswitch_agent
|
|
|
|
# Entry Points
|
|
# ------------
|
|
|
|
function cleanup_ovs {
|
|
# Remove the patch ports
|
|
for port in $(sudo ovs-vsctl show | grep Port | awk '{print $2}' | cut -d '"' -f 2 | grep patch); do
|
|
sudo ovs-vsctl del-port ${port}
|
|
done
|
|
|
|
# remove all OVS ports that look like Neutron created ports
|
|
for port in $(sudo ovs-vsctl list port | grep -o -e tap[0-9a-f\-]* -e q[rg]-[0-9a-f\-]*); do
|
|
sudo ovs-vsctl del-port ${port}
|
|
done
|
|
|
|
# Remove all the vxlan ports
|
|
for port in $(sudo ovs-vsctl list port | grep name | grep vxlan | awk '{print $3}' | cut -d '"' -f 2); do
|
|
sudo ovs-vsctl del-port ${port}
|
|
done
|
|
|
|
local _pwd=$(pwd)
|
|
cd $DEST/$OVS_REPO_NAME
|
|
sudo make uninstall
|
|
cd $_pwd
|
|
}
|
|
|
|
function configure_df_plugin {
|
|
echo "Configuring Neutron for Dragonflow"
|
|
|
|
if is_service_enabled q-svc ; then
|
|
export NETWORK_API_EXTENSIONS='binding,quotas,agent,dhcp_agent_scheduler,external-net,router'
|
|
Q_PLUGIN_CLASS="dragonflow.neutron.plugin.DFPlugin"
|
|
|
|
NEUTRON_CONF=/etc/neutron/neutron.conf
|
|
iniset $NEUTRON_CONF df remote_db_ip "$REMOTE_DB_IP"
|
|
iniset $NEUTRON_CONF df remote_db_port $REMOTE_DB_PORT
|
|
iniset $NEUTRON_CONF df remote_db_hosts "$REMOTE_DB_HOSTS"
|
|
iniset $NEUTRON_CONF df nb_db_class "$NB_DRIVER_CLASS"
|
|
iniset $NEUTRON_CONF df local_ip "$HOST_IP"
|
|
iniset $NEUTRON_CONF df tunnel_type "$TUNNEL_TYPE"
|
|
iniset $NEUTRON_CONF df apps_list "$DF_APPS_LIST"
|
|
iniset $NEUTRON_CONF DEFAULT advertise_mtu "True"
|
|
iniset $NEUTRON_CONF DEFAULT core_plugin "$Q_PLUGIN_CLASS"
|
|
iniset $NEUTRON_CONF DEFAULT service_plugins ""
|
|
|
|
if is_service_enabled q-dhcp ; then
|
|
iniset $NEUTRON_CONF df use_centralized_ipv6_DHCP "True"
|
|
else
|
|
iniset $NEUTRON_CONF DEFAULT dhcp_agent_notification "False"
|
|
fi
|
|
else
|
|
_create_neutron_conf_dir
|
|
# NOTE: We need to manually generate the neutron.conf file here. This
|
|
# is normally done by a call to _configure_neutron_common in
|
|
# neutron-lib, but we don't call that for compute nodes here.
|
|
# Uses oslo config generator to generate core sample configuration files
|
|
local _pwd=$(pwd)
|
|
NEUTRON_CONF=/etc/neutron/neutron.conf
|
|
(cd $NEUTRON_DIR && exec ./tools/generate_config_file_samples.sh)
|
|
cd $_pwd
|
|
|
|
cp $NEUTRON_DIR/etc/neutron.conf.sample $NEUTRON_CONF
|
|
|
|
iniset $NEUTRON_CONF df remote_db_ip "$REMOTE_DB_IP"
|
|
iniset $NEUTRON_CONF df remote_db_port $REMOTE_DB_PORT
|
|
iniset $NEUTRON_CONF df remote_db_hosts "$REMOTE_DB_HOSTS"
|
|
iniset $NEUTRON_CONF df nb_db_class "$NB_DRIVER_CLASS"
|
|
iniset $NEUTRON_CONF df local_ip "$HOST_IP"
|
|
iniset $NEUTRON_CONF df tunnel_type "$TUNNEL_TYPE"
|
|
iniset $NEUTRON_CONF df apps_list "$DF_APPS_LIST"
|
|
fi
|
|
}
|
|
|
|
# init_ovs() - Initialize databases, etc.
|
|
function init_ovs {
|
|
# clean up from previous (possibly aborted) runs
|
|
# create required data files
|
|
|
|
# Assumption: this is a dedicated test system and there is nothing important
|
|
# ovs databases. We're going to trash them and
|
|
# create new ones on each devstack run.
|
|
|
|
base_dir=$DATA_DIR/ovs
|
|
mkdir -p $base_dir
|
|
|
|
for db in conf.db ; do
|
|
if [ -f $base_dir/$db ] ; then
|
|
rm -f $base_dir/$db
|
|
fi
|
|
done
|
|
rm -f $base_dir/.*.db.~lock~
|
|
|
|
echo "Creating OVS Database"
|
|
ovsdb-tool create $base_dir/conf.db $DEST/$OVS_REPO_NAME/vswitchd/vswitch.ovsschema
|
|
}
|
|
|
|
function install_zeromq {
|
|
if is_fedora; then
|
|
install_package zeromq python-zmq
|
|
elif is_ubuntu; then
|
|
install_package libzmq1 python-zmq
|
|
elif is_suse; then
|
|
install_package libzmq1 python-pyzmq
|
|
fi
|
|
# Necessary directory for socket location.
|
|
sudo mkdir -p /var/run/openstack
|
|
sudo chown $STACK_USER /var/run/openstack
|
|
}
|
|
|
|
function install_df {
|
|
|
|
# Obtain devstack directory for df-ext-services.sh
|
|
sed -i "/^TOP_DIR=/cTOP_DIR=$TOP_DIR" $DEST/dragonflow/devstack/df-ext-services.sh
|
|
|
|
install_zeromq
|
|
|
|
nb_db_driver_install_server
|
|
|
|
nb_db_driver_install_client
|
|
|
|
#echo_summary "Installing DragonFlow"
|
|
#git clone $DRAGONFLOW_REPO $DRAGONFLOW_DIR $DRAGONFLOW_BRANCH
|
|
setup_package $DRAGONFLOW_DIR
|
|
|
|
if [ ! -d $RYU_DIR ] ; then
|
|
echo "Cloning and installing Ryu"
|
|
git clone $RYU_REPO $RYU_DIR
|
|
pushd $RYU_DIR
|
|
setup_package ./ -e
|
|
popd
|
|
echo "Finished installing Ryu"
|
|
fi
|
|
}
|
|
|
|
# install_ovs() - Collect source and prepare
|
|
function install_ovs {
|
|
local _pwd=$(pwd)
|
|
echo "Installing OVS and dependent packages"
|
|
|
|
# If OVS is already installed, remove it, because we're about to re-install
|
|
# it from source.
|
|
for package in openvswitch openvswitch-switch openvswitch-common; do
|
|
if is_package_installed $package ; then
|
|
uninstall_package $package
|
|
fi
|
|
done
|
|
|
|
if ! is_neutron_enabled ; then
|
|
install_neutron
|
|
fi
|
|
|
|
cd $DEST
|
|
if [ ! -d $OVS_REPO_NAME ] ; then
|
|
git clone $OVS_REPO
|
|
cd $OVS_REPO_NAME
|
|
git checkout $OVS_BRANCH
|
|
else
|
|
cd $OVS_REPO_NAME
|
|
fi
|
|
|
|
install_package python-openvswitch
|
|
|
|
# TODO: Can you create package list files like you can inside devstack?
|
|
install_package autoconf automake libtool gcc patch make
|
|
|
|
if [ ! -f configure ] ; then
|
|
./boot.sh
|
|
fi
|
|
if [ ! -f config.status ] || [ configure -nt config.status ] ; then
|
|
./configure --with-linux=/lib/modules/`uname -r`/build
|
|
fi
|
|
make -j$[$(nproc) + 1]
|
|
sudo make install
|
|
|
|
sudo make INSTALL_MOD_DIR=kernel/net/openvswitch modules_install
|
|
sudo modprobe -r vport_geneve
|
|
sudo modprobe -r openvswitch
|
|
|
|
sudo modprobe openvswitch || (dmesg && die $LINENO "FAILED TO LOAD openvswitch")
|
|
sudo modprobe vport-geneve || (echo "FAILED TO LOAD vport_geneve" && dmesg)
|
|
dmesg | tail
|
|
|
|
sudo chown $(whoami) $OVS_DIR
|
|
sudo chown $(whoami) /usr/local/var/log/openvswitch
|
|
|
|
cd $_pwd
|
|
}
|
|
|
|
function stop_ovs
|
|
{
|
|
# Stop ovs db
|
|
ovs_service_stop $OVS_DB_SERVICE
|
|
# Stop ovs vswitch
|
|
ovs_service_stop $OVS_VSWITCHD_SERVICE
|
|
|
|
while ovs_service_status $OVS_DB_SERVICE; do
|
|
echo "Waiting for the $OVS_DB_SERVICE to be stopped..."
|
|
sleep 1
|
|
ovs_service_stop $OVS_DB_SERVICE
|
|
done
|
|
|
|
while ovs_service_status $OVS_VSWITCHD_SERVICE; do
|
|
echo "Waiting for the ovsdb-vswitchd to be stopped..."
|
|
sleep 1
|
|
ovs_service_stop $OVS_VSWITCHD_SERVICE
|
|
done
|
|
}
|
|
|
|
# The following returns "0" when service is live.
|
|
# Zero (0) is considered a TRUE value in bash.
|
|
function ovs_service_status
|
|
{
|
|
TEMP_PID=$OVS_DIR"/"$1".pid"
|
|
if [ -e $TEMP_PID ]
|
|
then
|
|
TEMP_PID_VALUE=$(cat $TEMP_PID 2>/dev/null)
|
|
if [ -e /proc/$TEMP_PID_VALUE ]
|
|
then
|
|
return 0
|
|
fi
|
|
fi
|
|
# service is dead
|
|
return 1
|
|
}
|
|
|
|
# Kills a service
|
|
function ovs_service_stop
|
|
{
|
|
TEMP_PID=$OVS_DIR"/"$1".pid"
|
|
if [ -e $TEMP_PID ]
|
|
then
|
|
TEMP_PID_VALUE=$(cat $TEMP_PID 2>/dev/null)
|
|
if [ -e /proc/$TEMP_PID_VALUE ]
|
|
then
|
|
sudo kill $TEMP_PID_VALUE
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function start_ovs {
|
|
echo "Starting OVS"
|
|
|
|
local _pwd=$(pwd)
|
|
cd $DATA_DIR/ovs
|
|
|
|
EXTRA_DBS=""
|
|
OVSDB_REMOTE="--remote=ptcp:6640:$HOST_IP"
|
|
|
|
if ! ovs_service_status $OVS_DB_SERVICE; then
|
|
#echo "Going to start $OVS_DB_SERVICE"
|
|
$OVS_DB_SERVICE --remote=punix:$OVS_DIR"/db.sock" \
|
|
--remote=db:Open_vSwitch,Open_vSwitch,manager_options \
|
|
--pidfile=$OVS_DB_PID --detach -vconsole:off --log-file $OVSDB_REMOTE \
|
|
conf.db ${EXTRA_DBS}
|
|
|
|
echo -n "Waiting for $OVS_DB_SERVICE to start ... "
|
|
while ! test -e $OVS_DIR"/db.sock" ; do
|
|
sleep 1
|
|
done
|
|
echo "done."
|
|
ovs-vsctl --no-wait init
|
|
fi
|
|
|
|
if is_service_enabled df-controller ; then
|
|
if ! ovs_service_status $OVS_VSWITCHD_SERVICE; then
|
|
#echo "Going to start $OVS_VSWITCHD_SERVICE"
|
|
sudo modprobe openvswitch || die $LINENO "Failed to load openvswitch module"
|
|
# TODO This needs to be a fatal error when doing multi-node testing, but
|
|
# breaks testing in OpenStack CI where geneve isn't available.
|
|
#sudo modprobe geneve || die $LINENO "Failed to load geneve module"
|
|
sudo modprobe geneve || true
|
|
#sudo modprobe vport_geneve || die $LINENO "Failed to load vport_geneve module"
|
|
sudo modprobe vport_geneve || true
|
|
|
|
_neutron_ovs_base_setup_bridge br-int
|
|
ovs-vsctl --no-wait set bridge br-int fail-mode=secure other-config:disable-in-band=true
|
|
|
|
sudo $OVS_VSWITCHD_SERVICE --pidfile=$OVS_VSWITCHD_PID --detach -vconsole:off --log-file
|
|
fi
|
|
fi
|
|
|
|
cd $_pwd
|
|
}
|
|
|
|
# start_df() - Start running processes, including screen
|
|
function start_df {
|
|
echo "Starting Dragonflow"
|
|
|
|
if is_service_enabled df-controller ; then
|
|
ovs-vsctl --no-wait set-controller br-int tcp:$HOST_IP:6633
|
|
run_process df-controller "python $DF_LOCAL_CONTROLLER --config-file $NEUTRON_CONF"
|
|
run_process df-ext-services "bash $DEST/dragonflow/devstack/df-ext-services.sh"
|
|
fi
|
|
}
|
|
|
|
# stop_df() - Stop running processes (non-screen)
|
|
function stop_df {
|
|
if is_service_enabled df-controller ; then
|
|
stop_process df-controller
|
|
ovs_service_stop $OVS_VSWITCHD_SERVICE
|
|
fi
|
|
|
|
nb_db_driver_stop_server
|
|
|
|
ovs_service_stop $OVS_DB_SERVICE
|
|
}
|
|
|
|
function disable_libvirt_apparmor {
|
|
if ! sudo aa-status --enabled ; then
|
|
return 0
|
|
fi
|
|
# NOTE(arosen): This is used as a work around to allow newer versions
|
|
# of libvirt to work with ovs configured ports. See LP#1466631.
|
|
# requires the apparmor-utils
|
|
install_package apparmor-utils
|
|
# disables apparmor for libvirtd
|
|
sudo aa-complain /etc/apparmor.d/usr.sbin.libvirtd
|
|
}
|
|
|
|
# main loop
|
|
if [[ "$Q_ENABLE_DRAGONFLOW_LOCAL_CONTROLLER" == "True" ]]; then
|
|
if [[ "$1" == "stack" && "$2" == "install" ]]; then
|
|
if [[ "$OFFLINE" != "True" ]]; then
|
|
install_df
|
|
install_ovs
|
|
fi
|
|
echo export PYTHONPATH=\$PYTHONPATH:$DRAGONFLOW_DIR:$RYU_DIR >> $RC_DIR/.localrc.auto
|
|
init_ovs
|
|
# We have to start at install time, because Neutron's post-config
|
|
# phase runs ovs-vsctl.
|
|
nb_db_driver_start_server
|
|
start_ovs
|
|
disable_libvirt_apparmor
|
|
elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
|
|
configure_df_plugin
|
|
|
|
if is_service_enabled nova; then
|
|
create_nova_conf_neutron
|
|
fi
|
|
|
|
start_df
|
|
fi
|
|
|
|
if [[ "$1" == "unstack" ]]; then
|
|
stop_df
|
|
cleanup_ovs
|
|
fi
|
|
fi
|
|
|
|
if [[ "$Q_ENABLE_DRAGONFLOW" == "True" ]]; then
|
|
if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then
|
|
echo summary "DragonFlow pre-install"
|
|
elif [[ "$1" == "stack" && "$2" == "install" ]]; then
|
|
echo_summary "Installing DragonFlow"
|
|
|
|
git_clone $DRAGONFLOW_REPO $DRAGONFLOW_DIR $DRAGONFLOW_BRANCH
|
|
|
|
if is_service_enabled q-df-l3; then
|
|
echo "Cloning and installing Ryu"
|
|
git_clone $RYU_REPO $RYU_DIR $RYU_BRANCH
|
|
# Don't use setup_develop, which is for openstack global requirement
|
|
# compatible projects, and Ryu is not.
|
|
pushd $RYU_DIR
|
|
setup_package ./ -e
|
|
popd
|
|
echo "Finished installing Ryu"
|
|
fi
|
|
|
|
elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
|
|
echo_summary "Configure DragonFlow"
|
|
|
|
if is_service_enabled q-df-l3; then
|
|
_configure_neutron_l3_agent
|
|
fi
|
|
|
|
iniset $NEUTRON_CONF DEFAULT L3controller_ip_list $Q_DF_CONTROLLER_IP
|
|
iniset /$Q_PLUGIN_CONF_FILE agent enable_l3_controller "True"
|
|
iniset /$Q_PLUGIN_CONF_FILE agent L3controller_ip_list $Q_DF_CONTROLLER_IP
|
|
|
|
echo export PYTHONPATH=\$PYTHONPATH:$DRAGONFLOW_DIR:$RYU_DIR >> $RC_DIR/.localrc.auto
|
|
|
|
OVS_VERSION=`ovs-vsctl --version | head -n 1 | grep -E -o "[0-9]+\.[0-9]+\.[0-9]"`
|
|
if [ `vercmp_numbers "$OVS_VERSION" "2.3.1"` -lt "0" ] && is_service_enabled q-agt ; then
|
|
die $LINENO "You are running OVS version $OVS_VERSION. OVS 2.3.1+ is required for Dragonflow."
|
|
fi
|
|
|
|
echo summary "Dragonflow OVS version validated, version is $OVS_VERSION"
|
|
|
|
echo summary "Setting L2 Agent to use Dragonflow Agent"
|
|
AGENT_BINARY="$DF_L2_AGENT"
|
|
|
|
elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
|
|
echo_summary "Initializing DragonFlow"
|
|
|
|
if is_service_enabled q-df-l3; then
|
|
run_process q-df-l3 "python $DF_L3_AGENT --config-file $NEUTRON_CONF --config-file=$Q_L3_CONF_FILE"
|
|
fi
|
|
fi
|
|
|
|
if [[ "$1" == "unstack" ]]; then
|
|
|
|
if is_service_enabled q-df-l3; then
|
|
stop_process q-df-l3
|
|
fi
|
|
fi
|
|
fi
|