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