
networking-spp has not been able to upgrade DPDK/SPP version from v18.08 because DPDK v18.11 and later have a problem that secondary processes can not use vhost PMD. Now the problem is fixed in DPDK v20.02, this patch makes Neutron SPP driver use DPDK/SPP v20.02. Change-Id: Ic51071c10bf8f7b954586c82bbf85421918be55e Blueprint: upgrade-dpdk-2002
360 lines
11 KiB
Bash
360 lines
11 KiB
Bash
function spp_pre_install(){
|
|
OFFLINE=$(trueorfalse False OFFLINE)
|
|
|
|
if [ "$OFFLINE" != True ]; then
|
|
if is_ubuntu; then
|
|
echo "TODO: install packages necessary for DPDK build"
|
|
sudo apt-get install -y libnuma-dev
|
|
sudo apt-get install -y liblz4-dev
|
|
sudo apt-get install -y python3
|
|
sudo apt-get install -y python3-pip
|
|
sudo apt-get install -y linux-modules-extra-$(uname -r) # for uio_pci_generic
|
|
#NOTE(oda): it is environment dependent.
|
|
fi
|
|
#TODO: other OS support (ex. CentOS)
|
|
fi
|
|
}
|
|
|
|
function clone_spp_dpdk(){
|
|
OFFLINE=$(trueorfalse False OFFLINE)
|
|
RECLONE=$(trueorfalse False RECLONE)
|
|
|
|
if [[ "$OFFLINE" != True ]]; then
|
|
if [ ! -d "${DPDK_DIR}" ] || [ "$RECLONE" == True ]; then
|
|
git_clone ${DPDK_GIT_REPO} ${DPDK_DIR} ${DPDK_GIT_TAG}
|
|
fi
|
|
if [ ! -d "${SPP_DIR}" ] || [ "$RECLONE" == True ]; then
|
|
git_clone ${SPP_GIT_REPO} ${SPP_DIR} ${SPP_GIT_TAG}
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function build_spp_dpdk(){
|
|
if [[ "$SPP_DPDK_BUILD_SKIP" != True ]]; then
|
|
pushd ${DPDK_DIR}
|
|
sudo make config T=${RTE_TARGET}
|
|
if [ -e "${RTE_TARGET}" ]; then
|
|
rm -rf $RTE_TARGET
|
|
fi
|
|
ln -s -f build ${RTE_TARGET}
|
|
sudo make
|
|
cd ${SPP_DIR}
|
|
sudo SPP_HOME=${SPP_DIR} RTE_TARGET=${RTE_TARGET} RTE_SDK=${RTE_SDK} make
|
|
# for spp-ctl
|
|
sudo -H pip3 install -r requirements.txt
|
|
sudo chmod +x ${SPP_DIR}/src/spp-ctl/spp-ctl
|
|
popd
|
|
fi
|
|
}
|
|
|
|
function free_hugepages(){
|
|
HUGEPAGE_SIZE=$(grep Hugepagesize /proc/meminfo | awk '{ print $2 }')
|
|
|
|
sudo rm -rf ${SPP_HUGEPAGE_MOUNT}/rtemap*
|
|
sudo umount ${SPP_HUGEPAGE_MOUNT}
|
|
|
|
if [ $SPP_ALLOCATE_HUGEPAGES == 'True' ]; then
|
|
for d in /sys/devices/system/node/node? ; do
|
|
echo 0 | sudo tee $d/hugepages/hugepages-${HUGEPAGE_SIZE}kB/nr_hugepages
|
|
done
|
|
fi
|
|
}
|
|
|
|
function alloc_hugepages(){
|
|
HUGEPAGE_SIZE=$(grep Hugepagesize /proc/meminfo | awk '{ print $2 }')
|
|
|
|
if [ $SPP_NUM_HUGEPAGES -eq 0 ]; then
|
|
die 6 $LINENO "SPP_NUM_HUGEPAGES not set"
|
|
fi
|
|
|
|
if grep -ws $SPP_HUGEPAGE_MOUNT /proc/mounts > /dev/null; then
|
|
free_hugepages
|
|
fi
|
|
|
|
if [ $SPP_ALLOCATE_HUGEPAGES == 'True' ]; then
|
|
for d in /sys/devices/system/node/node? ; do
|
|
echo $SPP_NUM_HUGEPAGES | sudo tee $d/hugepages/hugepages-${HUGEPAGE_SIZE}kB/nr_hugepages
|
|
done
|
|
fi
|
|
|
|
sudo mkdir -p $SPP_HUGEPAGE_MOUNT
|
|
sudo mount -t hugetlbfs nodev $SPP_HUGEPAGE_MOUNT
|
|
|
|
#TODO: restart libvirtd ?
|
|
}
|
|
|
|
function bind_nics() {
|
|
if [ -n "$DPDK_PORT_MAPPINGS" ]; then
|
|
sudo modprobe uio_pci_generic
|
|
|
|
MAPPINGS=${DPDK_PORT_MAPPINGS//,/ }
|
|
ARRAY=( $MAPPINGS )
|
|
NICS=""
|
|
for pair in "${ARRAY[@]}"; do
|
|
addr=`echo $pair | cut -f 1 -d "#"`
|
|
NICS="$NICS $addr"
|
|
done
|
|
sudo $DPDK_DIR/usertools/dpdk-devbind.py -b uio_pci_generic $NICS
|
|
fi
|
|
}
|
|
|
|
function unbind_nic() {
|
|
pci=$1
|
|
|
|
out=$(lspci -s $pci -k | grep 'Kernel modules:')
|
|
driver=${out##*:}
|
|
if [ -n "$driver" ]; then
|
|
sudo $DPDK_DIR/usertools/dpdk-devbind.py -b $driver $pci
|
|
else
|
|
sudo $DPDK_DIR/usertools/dpdk-devbind.py --force -u $pci
|
|
fi
|
|
}
|
|
|
|
function unbind_nics() {
|
|
if [ -n "$DPDK_PORT_MAPPINGS" ]; then
|
|
MAPPINGS=${DPDK_PORT_MAPPINGS//,/ }
|
|
ARRAY=( $MAPPINGS )
|
|
for pair in "${ARRAY[@]}"; do
|
|
addr=`echo $pair | cut -f 1 -d "#"`
|
|
unbind_nic $addr
|
|
done
|
|
fi
|
|
}
|
|
|
|
function prepare_spp_dpdk(){
|
|
alloc_hugepages
|
|
bind_nics
|
|
}
|
|
|
|
function cleanup_spp_dpdk(){
|
|
unbind_nics
|
|
if grep -ws $SPP_HUGEPAGE_MOUNT /proc/mounts > /dev/null; then
|
|
free_hugepages
|
|
fi
|
|
}
|
|
|
|
function configure_etcd() {
|
|
iniset /$Q_PLUGIN_CONF_FILE spp etcd_host $ETCD_HOST
|
|
iniset /$Q_PLUGIN_CONF_FILE spp etcd_port $ETCD_PORT
|
|
}
|
|
|
|
function configure_spp_agent() {
|
|
iniset /$Q_PLUGIN_CONF_FILE spp api_ip_addr $SPP_CTL_IP_ADDR
|
|
iniset /$Q_PLUGIN_CONF_FILE spp api_port $SPP_API_PORT
|
|
|
|
if [ -z "$SPP_HOST" ]; then
|
|
SPP_HOST=$(hostname -s)
|
|
fi
|
|
export DPDK_PORT_MAPPINGS SPP_HOST ETCD_HOST ETCD_PORT SPP_COMPONENT_CONF SPP_MIRROR
|
|
$PYTHON $NETWORKING_SPP_DIR/devstack/spp-config-build.py
|
|
}
|
|
|
|
function unconfigure_spp_agent() {
|
|
if [ -z "$SPP_HOST" ]; then
|
|
SPP_HOST=$(hostname -s)
|
|
fi
|
|
$PYTHON $NETWORKING_SPP_DIR/devstack/spp-config-destroy.py \
|
|
$SPP_HOST $ETCD_HOST $ETCD_PORT
|
|
}
|
|
|
|
function build_spp_ctl_service() {
|
|
local service="spp_ctl.service"
|
|
local unitfile="$SYSTEMD_DIR/$service"
|
|
|
|
CTL_CMD="$SPP_DIR/src/spp-ctl/spp-ctl -p $SPP_PRIMARY_SOCK_PORT -s $SPP_SECONDARY_SOCK_PORT -a $SPP_API_PORT -b $SPP_CTL_IP_ADDR"
|
|
|
|
iniset -sudo $unitfile "Unit" "Description" "Devstack $service"
|
|
iniset -sudo $unitfile "Service" "User" "$STACK_USER"
|
|
iniset -sudo $unitfile "Service" "ExecStart" "$CTL_CMD"
|
|
}
|
|
|
|
function build_spp_primary_service() {
|
|
local service="spp_primary.service"
|
|
local unitfile="$SYSTEMD_DIR/$service"
|
|
|
|
MAPPINGS=${DPDK_PORT_MAPPINGS//,/ }
|
|
ARRAY=( $MAPPINGS )
|
|
NUM_VHOST=0
|
|
for map in "${ARRAY[@]}"; do
|
|
num=`echo $map | cut -f 3 -d "#"`
|
|
NUM_VHOST=$(( $NUM_VHOST + $num ))
|
|
done
|
|
|
|
PORT_MASK=0
|
|
for ((i=0; i<${#ARRAY[@]}; i++)); do
|
|
PORT_MASK=$(( $PORT_MASK + (1 << $i) ))
|
|
done
|
|
|
|
NUM_MIRROR=0
|
|
if [[ -n "$SPP_MIRROR" ]]; then
|
|
NUM_MIRROR=`echo $SPP_MIRROR | cut -f 1 -d "#"`
|
|
fi
|
|
NUM_RING=$(( $NUM_VHOST * 2 + $NUM_MIRROR * 2 ))
|
|
|
|
# this is a workaround for https://bugs.launchpad.net/networking-spp/+bug/1814834.
|
|
# it is necessary for DPDK v18.08.
|
|
VIRTADDR_OPT=
|
|
if [[ -n "$BASE_VIRTADDR" ]]; then
|
|
VIRTADDR_OPT="--base-virtaddr $BASE_VIRTADDR"
|
|
fi
|
|
PRIMARY_BIN=$SPP_DIR/src/primary/${RTE_TARGET}/spp_primary
|
|
PRIMARY_CMD="$PRIMARY_BIN -c $SPP_PRIMARY_CORE_MASK -n 4 --socket-mem $SPP_PRIMARY_SOCKET_MEM --huge-dir $SPP_HUGEPAGE_MOUNT --proc-type primary $VIRTADDR_OPT -- -p $PORT_MASK -n $NUM_RING -s $SPP_CTL_IP_ADDR:$SPP_PRIMARY_SOCK_PORT"
|
|
|
|
iniset -sudo $unitfile "Unit" "Description" "Devstack $service"
|
|
iniset -sudo $unitfile "Service" "User" "root"
|
|
iniset -sudo $unitfile "Service" "ExecStart" "$PRIMARY_CMD"
|
|
}
|
|
|
|
function build_spp_vf_service() {
|
|
local sec_id=$1
|
|
local core_mask=$2
|
|
local service="spp_vf-$sec_id.service"
|
|
local unitfile="$SYSTEMD_DIR/$service"
|
|
|
|
SEC_BIN=$SPP_DIR/src/vf/${RTE_TARGET}/spp_vf
|
|
SEC_CMD="$SEC_BIN -c $core_mask -n 4 --proc-type secondary -- --client-id $sec_id -s $SPP_CTL_IP_ADDR:$SPP_SECONDARY_SOCK_PORT --vhost-client"
|
|
|
|
iniset -sudo $unitfile "Unit" "Description" "Devstack $service"
|
|
iniset -sudo $unitfile "Service" "User" "root"
|
|
iniset -sudo $unitfile "Service" "ExecStart" "$SEC_CMD"
|
|
}
|
|
|
|
function build_spp_mirror_service() {
|
|
local sec_id=$1
|
|
local core_mask=$2
|
|
local service="spp_mirror.service"
|
|
local unitfile="$SYSTEMD_DIR/$service"
|
|
|
|
SEC_BIN=$SPP_DIR/src/mirror/${RTE_TARGET}/spp_mirror
|
|
SEC_CMD="$SEC_BIN -c $core_mask -n 4 --proc-type secondary -- --client-id $sec_id -s $SPP_CTL_IP_ADDR:$SPP_SECONDARY_SOCK_PORT"
|
|
|
|
iniset -sudo $unitfile "Unit" "Description" "Devstack $service"
|
|
iniset -sudo $unitfile "Service" "User" "root"
|
|
iniset -sudo $unitfile "Service" "ExecStart" "$SEC_CMD"
|
|
}
|
|
|
|
function build_systemd_services() {
|
|
mkdir -p $SYSTEMD_DIR
|
|
build_spp_ctl_service
|
|
build_spp_primary_service
|
|
SEC_ID=1
|
|
MAPPINGS=${DPDK_PORT_MAPPINGS//,/ }
|
|
ARRAY=( $MAPPINGS )
|
|
for map in "${ARRAY[@]}"; do
|
|
mask=`echo $map | cut -f 4 -d "#"`
|
|
build_spp_vf_service $SEC_ID $mask
|
|
SEC_ID=$(( $SEC_ID + 1 ))
|
|
done
|
|
if [[ -n "$SPP_MIRROR" ]]; then
|
|
mask=`echo $SPP_MIRROR | cut -f 2 -d "#"`
|
|
build_spp_mirror_service $SEC_ID $mask
|
|
fi
|
|
|
|
# changes to existing units sometimes need a refresh
|
|
$SYSTEMCTL daemon-reload
|
|
$SYSTEMCTL enable spp_primary.service
|
|
for ((i=1; i<=${#ARRAY[@]}; i++)); do
|
|
$SYSTEMCTL enable spp_vf-$i.service
|
|
done
|
|
}
|
|
|
|
function start_spp_services() {
|
|
# make sure ASLR off.
|
|
# DPDK primary process and secondary processes must be same address layout.
|
|
# NOTE: this may not be necessary if you use DPDK v20.05 or later
|
|
# since a bug that let it be necessary was fixed in DPDK v20.05
|
|
# (see commit 7470f845c17a).
|
|
sudo sysctl -w kernel.randomize_va_space=0
|
|
|
|
# delete unnecessary files which were left by previous run.
|
|
sudo rm -rf /var/run/dpdk/rte
|
|
|
|
NUM_SEC=0
|
|
MAPPINGS=${DPDK_PORT_MAPPINGS//,/ }
|
|
ARRAY=( $MAPPINGS )
|
|
for map in "${ARRAY[@]}"; do
|
|
NUM_SEC=$(( $NUM_SEC + 1 ))
|
|
done
|
|
|
|
MIRROR_SUPPORT=0
|
|
if [[ -n "$SPP_MIRROR" ]]; then
|
|
MIRROR_SUPPORT=1
|
|
fi
|
|
|
|
sudo $NETWORKING_SPP_DIR/devstack/start-spp-services $NUM_SEC $MIRROR_SUPPORT $SPP_CTL_IP_ADDR:$SPP_API_PORT
|
|
}
|
|
|
|
function stop_systemd_services() {
|
|
stop_process q-spp-agt
|
|
$SYSTEMCTL stop spp_ctl.service
|
|
if [[ -n "$SPP_MIRROR" ]]; then
|
|
sudo systemctl stop spp_mirror.service
|
|
fi
|
|
MAPPINGS=${DPDK_PORT_MAPPINGS//,/ }
|
|
ARRAY=( $MAPPINGS )
|
|
for ((i=1; i<=${#ARRAY[@]}; i++)); do
|
|
$SYSTEMCTL stop spp_vf-$i.service
|
|
done
|
|
$SYSTEMCTL stop spp_primary.service
|
|
}
|
|
|
|
function prepare_tempest() {
|
|
# NOTE: DEFALUT_IMAGE_NAME must be specified in local.conf explicitly.
|
|
openstack flavor create "$DEFAULT_INSTANCE_TYPE" --ram 4096 --disk 20 --vcpus 2 --public --property hw:mem_page_size=large
|
|
|
|
if [ ! -e "$NETWORKING_SPP_DIR/devstack/image/image.qcow2" ]; then
|
|
$NETWORKING_SPP_DIR/devstack/image/build_image.sh $NETWORKING_SPP_DIR
|
|
fi
|
|
|
|
openstack --os-cloud=devstack-admin --os-region-name="$REGION_NAME" image create "$DEFAULT_IMAGE_NAME" --public --container-format bare --disk-format qcow2 < $NETWORKING_SPP_DIR/devstack/image/image.qcow2
|
|
}
|
|
|
|
if [[ "$1" == "stack" ]]; then
|
|
case "$2" in
|
|
pre-install)
|
|
if [ "$SPP_MODE" != "controller" ]; then
|
|
spp_pre_install
|
|
clone_spp_dpdk
|
|
fi
|
|
;;
|
|
install)
|
|
if [ "$SPP_MODE" != "controller" ]; then
|
|
build_spp_dpdk
|
|
fi
|
|
pushd $NETWORKING_SPP_DIR
|
|
sudo $PYTHON setup.py install
|
|
popd
|
|
if [ "$SPP_MODE" != "controller" ]; then
|
|
prepare_spp_dpdk
|
|
fi
|
|
;;
|
|
post-config)
|
|
if [ "$SPP_MODE" != "controller" ]; then
|
|
configure_spp_agent
|
|
fi
|
|
configure_etcd
|
|
;;
|
|
extra)
|
|
if [ "$SPP_MODE" != "controller" ]; then
|
|
build_systemd_services
|
|
# start SPP services
|
|
start_spp_services
|
|
# start spp-agent
|
|
run_process q-spp-agt "$SPP_AGENT_BINARY --config-file $NEUTRON_CONF --config-file /$Q_PLUGIN_CONF_FILE"
|
|
fi
|
|
if [ "$SPP_MODE" == "controller" ]; then
|
|
if is_service_enabled tempest; then
|
|
prepare_tempest
|
|
fi
|
|
fi
|
|
;;
|
|
esac
|
|
elif [[ "$1" == "unstack" ]]; then
|
|
if [ "$SPP_MODE" != "controller" ]; then
|
|
stop_systemd_services
|
|
cleanup_spp_dpdk
|
|
unconfigure_spp_agent
|
|
#TODO: more cleanup ?
|
|
fi
|
|
fi
|