#! /bin/bash ############################ Common Utilities ################################ GREEN='\033[0;32m' RED='\033[0;31m' NC='\033[0m' FL_PCAP=1 FL_DPDK=2 FL_NETMAP=3 # vercomp returns 0 (=), 1 (>), or 2 (<) vercomp () { if [[ $1 == $2 ]] then return 0 fi local IFS=. local i ver1=($1) ver2=($2) # fill empty fields in ver1 with zeros for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)) do ver1[i]=0 done for ((i=0; i<${#ver1[@]}; i++)) do if [[ -z ${ver2[i]} ]] then # fill empty fields in ver2 with zeros ver2[i]=0 fi if ((10#${ver1[i]} > 10#${ver2[i]})) then return 1 fi if ((10#${ver1[i]} < 10#${ver2[i]})) then return 2 fi done return 0 } # valid_ip_addr returns 1 for valid ip address valid_ip_addr() { local ip=$1 local stat=1 if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then OIFS=$IFS IFS='.' ip=($ip) IFS=$OIFS [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \ && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]] stat=$? fi return $stat } # Create a mos.conf file create_config() { cd $CUR_DIR mkdir -p $2 CONF_FILE=$2/mos.conf CONF_MASTER_FILE=$2/mos-master.conf CONF_SLAVE_FILE=$2/mos-slave.conf echo echo "----------------------------------------" echo "Creating mos.conf file in $2" echo "----------------------------------------" if [ -f $CONF_FILE ]; then echo echo "The config file $2/mos.conf already exists." echo "Skip writing a new config file.." return fi # Get the number of CPUs and translate it into CPU mask let "z=2**$(nproc)-1" CPU_MASK=$(printf '0x%04X\n' $z) # Get # of CPU sockets let "sockets=$(cat /proc/cpuinfo | grep "physical id" | awk '{print $4}' | sort -ur | head -n 1) + 1" # Get the number of memory channels command -v dmidecode >/dev/null && let "NUM_MEMCH=($(sudo dmidecode -t 17 | grep -c 'Size:')-$(sudo dmidecode -t 17 | grep -c 'Size: No Module'))/$sockets" || { echo "dmidecode command not found. setting num_mem_ch = 4"; let "NUM_MEMCH=4"; } # Get the number of interfaces counter=0 if [[ $1 == $FL_DPDK ]]; then cd /sys/module/igb_uio/drivers/pci:igb_uio/ DEV_NAME="dpdk" elif [[ ( $1 != $FL_PCAP ) && ( $1 != $FL_NETMAP ) ]]; then echo "invalid function call 1" exit 1 fi for i in * do if [[ $i == *":"* ]] then let "counter=$counter + 1" fi done cd $CUR_DIR # Write up a new configuration file if [[ $1 == $FL_PCAP ]]; then cat .standalone-template.conf > $CONF_FILE DEVLIST=`ifconfig -s | grep -Eo '^[^ ]+' | tail -n+2` for dev in $DEVLIST; do printf "Found $dev. Press y to select [y/N]: " read option if [[ "$option" == y* ]]; then DEVICE="\n\t\t$dev" DEVICEMASK="__coremask__devicemask" FMT=$(printf 's/__devicemask/%s %s/g' $DEVICE $DEVICEMASK) sed -i -e "$FMT" $CONF_FILE DEVICE="$dev""__devicelist" FMT=$(printf 's/__devicelist/ %s/g' $DEVICE) sed -i -e "$FMT" $CONF_FILE fi done sed -i -e 's/__devicemask//g' $CONF_FILE sed -i -e 's/__devicelist//g' $CONF_FILE sed -i -e 's/__coremask/0x0001/g' $CONF_FILE sed -i -e 's/__num_memch//g' $CONF_FILE sed -i -e 's/__forward/1/g' $CONF_FILE sed -i -e 's/__multiprocess//g' $CONF_FILE elif [[ $1 == $FL_NETMAP ]]; then if [ "$3" = "epserver" ] || [ "$3" = "epwget" ] ; then cat .end-template.conf > $CONF_FILE else cat .standalone-template.conf > $CONF_FILE fi DEVLIST=`ifconfig -s | grep -Eo '^[^ ]+' | tail -n+2` for dev in $DEVLIST; do printf "Found $dev. Press y to select [y/N]: " read option if [[ "$option" == y* ]]; then DEVICE="\n\t\t$dev" DEVICEMASK="__coremask__devicemask" FMT=$(printf 's/__devicemask/%s %s/g' $DEVICE $DEVICEMASK) sed -i -e "$FMT" $CONF_FILE DEVICE="$dev""__devicelist" FMT=$(printf 's/__devicelist/ %s/g' $DEVICE) sed -i -e "$FMT" $CONF_FILE fi done sed -i -e 's/__devicemask//g' $CONF_FILE sed -i -e 's/__devicelist//g' $CONF_FILE sed -i -e 's/__coremask/'$CPU_MASK'/g' $CONF_FILE sed -i -e 's/__num_memch//g' $CONF_FILE sed -i -e 's/__forward/1/g' $CONF_FILE sed -i -e 's/__app/'$3'/g' $CONF_FILE sed -i -e 's/__multiprocess//g' $CONF_FILE if [ "$3" = "nat" ] ; then sed -i -e 's/\# tcp_tw_interval = 30/tcp_tw_interval = 30/g' $CONF_FILE fi else if [ "$3" = "epserver" ] || [ "$3" = "epwget" ] ; then cat .end-template.conf > $CONF_FILE cat .end-template.conf > $CONF_MASTER_FILE cat .end-template.conf > $CONF_SLAVE_FILE else cat .standalone-template.conf > $CONF_FILE fi start=0 while [ $start -lt $counter ] do DEVICE="\n\t\t$DEV_NAME$(($start))" DEVICEMASK="__coremask__devicemask" FMT=$(printf 's/__devicemask/%s %s/g' $DEVICE $DEVICEMASK) sed -i -e "$FMT" $CONF_FILE DEVICE="$DEV_NAME$(($start))__devicelist" FMT=$(printf 's/__devicelist/ %s/g' $DEVICE) sed -i -e "$FMT" $CONF_FILE let "start=$start + 1" done sed -i -e 's/__devicemask//g' $CONF_FILE sed -i -e 's/__devicelist//g' $CONF_FILE sed -i -e 's/__coremask/'$CPU_MASK'/g' $CONF_FILE sed -i -e 's/__forward/1/g' $CONF_FILE sed -i -e 's/__app/'$3'/g' $CONF_FILE if [ "$3" = "nat" ] ; then sed -i -e 's/\# tcp_tw_interval = 30/tcp_tw_interval = 30/g' $CONF_FILE fi if [[ $1 == $FL_DPDK ]]; then FMT=$(printf 's/__num_memch/%snb_mem_channels = %d%s/g' '# number of memory channels per socket [mandatory for DPDK]\n\t' $NUM_MEMCH '\n') sed -i -e "$FMT" $CONF_FILE if [ "$3" = "epserver" ] || [ "$3" = "epwget" ] ; then cp $CONF_FILE $CONF_MASTER_FILE cp $CONF_FILE $CONF_SLAVE_FILE sed -i -e 's/__multiprocess/multiprocess = 0 master/g' $CONF_MASTER_FILE sed -i -e 's/__multiprocess/multiprocess = slave/g' $CONF_SLAVE_FILE fi else echo "invalid function call 2" exit 1 fi sed -i -e 's/__multiprocess//g' $CONF_FILE fi echo cat $CONF_FILE } create_makefile() { cd $CUR_DIR/samples for d in * ; do if [ -f $CUR_DIR/samples/$d/Makefile.in ]; then cp $CUR_DIR/samples/$d/Makefile.in $CUR_DIR/samples/$d/Makefile if [[ $1 == $FL_DPDK ]]; then FMT=$(printf 's/__IO_LIB_ARGS/LIBS += -m64 -g -pthread -lrt -march=native -Wl,-export-dynamic -L\$(RTE_SDK)\/\$(RTE_TARGET)\/lib -Wl,-lnuma -Wl,-lmtcp -Wl,-lpthread -Wl,-lrt -Wl,-ldl -Wl,$(shell cat \$(RTE_SDK)\/\$(RTE_TARGET)\/lib\/ldflags.txt)/g') elif [[ $1 == $FL_PCAP ]]; then FMT=$(printf 's/__IO_LIB_ARGS/GCC_OPT += -D__thread="" -DBE_RESILIENT_TO_PACKET_DROP\\nINC += -DENABLE_PCAP\\nLIBS += -lpcap/g') elif [[ $1 == $FL_NETMAP ]]; then FMT=$(printf 's/__IO_LIB_ARGS/GCC_OPT += -DENABLE_NETMAP/g') fi sed -i -e "$FMT" $CUR_DIR/samples/$d/Makefile fi done } # Setup MOS library setup_mos_library() { echo "Start building up the MOS library" cd $CUR_DIR if [[ $1 == $FL_DPDK ]]; then cd $CUR_DIR/scripts/ ./configure --enable-dpdk elif [[ $1 == $FL_PCAP ]]; then cd $CUR_DIR/scripts/ ./configure --enable-pcap elif [[ $1 == $FL_NETMAP ]]; then cd $CUR_DIR/scripts/ ./configure --enable-netmap fi cd $CUR_DIR/core/src make clean;make cd $CUR_DIR create_makefile $1 echo echo "----------------------------------------------------------" echo "Done with MOS library setup" echo "----------------------------------------------------------" echo } ############################################################################# ############################### DPDK Utilities ############################## # Creates hugepage filesystem. create_mnt_huge() { echo "Creating /mnt/huge and mounting as hugetlbfs" sudo mkdir -p /mnt/huge grep -s '/mnt/huge' /proc/mounts > /dev/null if [ $? -ne 0 ] ; then sudo mount -t hugetlbfs nodev /mnt/huge fi } # Removes hugepage filesystem. remove_mnt_huge() { echo "Unmounting /mnt/huge and removing directory" grep -s '/mnt/huge' /proc/mounts > /dev/null if [ $? -eq 0 ] ; then sudo umount /mnt/huge fi if [ -d /mnt/huge ] ; then sudo rm -R /mnt/huge fi } # Unloads igb_uio.ko. remove_igb_uio_module() { echo "Unloading any existing DPDK UIO module" /sbin/lsmod | grep -s igb_uio > /dev/null if [ $? -eq 0 ] ; then sudo /sbin/rmmod igb_uio fi /sbin/lsmod | grep -s dpdk_iface > /dev/null if [ $? -eq 0 ] ; then sudo /sbin/rmmod dpdk_iface.ko fi } # Loads new igb_uio.ko (and uio module if needed). load_igb_uio_module() { if [ ! -f $RTE_SDK/$RTE_TARGET/kmod/igb_uio.ko ];then echo "## ERROR: Target does not have the DPDK UIO Kernel Module." echo " To fix, please try to rebuild target." return fi if lsmod | grep igb_uio &> /dev/null ; then : else /sbin/lsmod | grep -s uio > /dev/null if [ $? -ne 0 ] ; then modinfo uio > /dev/null if [ $? -eq 0 ]; then echo "Loading uio module" sudo /sbin/modprobe uio fi fi # UIO may be compiled into kernel, so it may not be an error if it can't # be loaded. echo "Loading DPDK UIO module" sudo /sbin/insmod $RTE_SDK/$RTE_TARGET/kmod/igb_uio.ko if [ $? -ne 0 ] ; then echo "## ERROR: Could not load kmod/igb_uio.ko." quit fi fi } # Removes all reserved hugepages. clear_numa_pages() { echo > .echo_tmp for d in /sys/devices/system/node/node? ; do echo "echo 0 > $d/hugepages/hugepages-2048kB/nr_hugepages" >> .echo_tmp done echo "Removing currently reserved hugepages" sudo sh .echo_tmp rm -f .echo_tmp remove_mnt_huge } # Removes all reserved hugepages. clear_non_numa_pages() { echo > .echo_tmp echo "echo 0 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages" > .echo_tmp echo "Removing currently reserved hugepages" sudo sh .echo_tmp rm -f .echo_tmp remove_mnt_huge } # # Creates hugepages. # set_non_numa_pages_default() { clear_non_numa_pages echo > .echo_tmp echo "Number of pages : 1024" Pages=1024 echo "echo $Pages > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages" >> .echo_tmp echo "Reserving hugepages" sudo sh .echo_tmp rm -f .echo_tmp create_mnt_huge } # # Creates hugepages. # set_non_numa_pages() { clear_non_numa_pages echo "" echo " Input the number of 2MB pages" echo " Example: to have 128MB of hugepages available, enter '64' to" echo " reserve 64 * 2MB pages" echo -n "Number of pages: " read Pages echo "echo $Pages > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages" > .echo_tmp echo "Reserving hugepages" sudo sh .echo_tmp rm -f .echo_tmp create_mnt_huge } # Creates hugepages on specific NUMA nodes. set_numa_pages_default() { clear_numa_pages echo > .echo_tmp for d in /sys/devices/system/node/node? ; do node=$(basename $d) echo "Number of pages for $node: 1024" Pages=1024 echo "echo $Pages > $d/hugepages/hugepages-2048kB/nr_hugepages" >> .echo_tmp done echo "Reserving hugepages" sudo sh .echo_tmp rm -f .echo_tmp create_mnt_huge } # Creates hugepages on specific NUMA nodes. set_numa_pages() { clear_numa_pages echo "" echo " Input the number of 2MB pages for each node" echo " Example: to have 128MB of hugepages available per node," echo " enter '64' to reserve 64 * 2MB pages on each node" echo > .echo_tmp for d in /sys/devices/system/node/node? ; do node=$(basename $d) echo -n "Number of pages for $node: " read Pages echo "echo $Pages > $d/hugepages/hugepages-2048kB/nr_hugepages" >> .echo_tmp done echo "Reserving hugepages" sudo sh .echo_tmp rm -f .echo_tmp create_mnt_huge } # Uses dpdk-devbind.py to move devices to work with igb_uio bind_nics_to_igb_uio() { if /sbin/lsmod | grep -q igb_uio ; then ${RTE_SDK}/usertools/dpdk-devbind.py --status echo "" echo "Enter PCI address of device(s) to bind to IGB UIO driver (e.g., \"04:00.0 04:00.1\")." echo -n "> " read PCI_PATH sudo ${RTE_SDK}/usertools/dpdk-devbind.py -b igb_uio $PCI_PATH && echo "OK" else echo "# Please load the 'igb_uio' kernel module before querying or " echo "# adjusting NIC device bindings" fi # Create interfaces printf "Creating ${GREEN}dpdk$NC interface entries\n" cd dpdk-iface-kmod make if lsmod | grep dpdk_iface &> /dev/null ; then : else sudo insmod ./dpdk_iface.ko fi sudo -E make run cd .. } # # Uses dpdk-devbind.py to move devices to work with kernel drivers again # unbind_nics() { DEVLIST=`ifconfig -s | grep -Eo '^[^ ]+' | tail -n+2` for dev in $DEVLIST do echo $dev if [[ "$dev" == dpdk* ]]; then sudo ifconfig $dev down fi done ${RTE_SDK}/usertools/dpdk-devbind.py --status echo "" echo -n "Enter PCI address of device to unbind: " read PCI_PATH echo "" echo -n "Enter name of kernel driver to bind the device to: " read DRV sudo ${RTE_SDK}/usertools/dpdk-devbind.py -b $DRV $PCI_PATH && echo "OK" } # Brings up the interface of DPDK devices up setup_iface_dpdk() { # First check whether igb_uio module is already loaded MODULE="igb_uio" if sudo lsmod | grep "$MODULE" &> /dev/null ; then echo "$MODULE is loaded!" else echo "$MODULE is not loaded!" exit 1 fi # set ip address for dpdk-enabled interfaces in the system list=`basename -a /sys/class/net/dpdk*` for if_name in ${list//\\n/ }; do while [ 1 ]; do echo echo "[$if_name] enter IP address[/mask] (e.g., 10.0.0.1[/24])" echo -n "> " read line ip_addr=`echo $line | awk -F '/' '{print $1}'` mask=`echo $line | awk -F '/' '{print $2}'` valid_ip_addr $ip_addr if [ $? -eq 0 ]; then break fi echo "invalid IP address!" # continue done if [ "$mask" == "" ];then echo "sudo /sbin/ifconfig $if_name $ip_addr up" sudo /sbin/ifconfig $if_name $ip_addr up else echo "sudo /sbin/ifconfig $if_name $ip_addr/$mask up" sudo /sbin/ifconfig $if_name $ip_addr/$mask up fi done } ############################################################################# ############################### DPDK ######################################## step0_func_dpdk() { if [ -d "/sys/devices/system/node" ]; then set_numa_pages_default else set_non_numa_pages_default fi step2_func_dpdk step3_func_dpdk step4_func_dpdk } step1_func_dpdk() { if [ -d "/sys/devices/system/node" ]; then set_numa_pages else set_non_numa_pages fi } step2_func_dpdk() { load_igb_uio_module bind_nics_to_igb_uio } step3_func_dpdk() { setup_iface_dpdk $last_octet } step4_func_dpdk() { cd $CUR_DIR/samples for d in * ; do create_config $FL_DPDK "samples/$d/config" $d done echo echo "------------------------------------------------" echo "Done with configuration file setup." echo "Use the arp command to add static ARP entries" echo "------------------------------------------------" } step5_func_dpdk() { unbind_nics } step6_func_dpdk() { echo exit 1 } ############################################################################# ############################### PCAP ######################################## step0_func_pcap() { cd $CUR_DIR/samples for d in * ; do if [ -d $CUR_DIR/samples/$d/config ]; then create_config $FL_PCAP "samples/$d/config" $d fi done echo echo "------------------------------------------------" echo "Done with configuration file setup." echo "Use the arp command to add static ARP entries" echo "------------------------------------------------" exit 1 } ############################################################################# ############################## NETMAP ####################################### step0_func_netmap() { cd $CUR_DIR/samples for d in * ; do if [ -d $CUR_DIR/samples/$d/config ]; then create_config $FL_NETMAP "samples/$d/config" $d fi done echo echo "------------------------------------------------" echo "Done with configuration file setup." echo "Use the arp command to add static ARP entries" echo "------------------------------------------------" exit 1 } ############################################################################# ############################# Main Script ################################### # Get to script directory cd $(dirname ${BASH_SOURCE[0]})/ export CUR_DIR=$PWD kerver=$(uname -r) if [ "$1" == "--compile-dpdk" ]; then # check if RTE_SDK and RTE_TARGET env variables exist if [[ -z "${RTE_SDK}" ]]; then printf "${RED}Please define RTE_SDK env variable first\n $NC" exit 1 fi if [[ -z "${RTE_TARGET}" ]]; then printf "${RED}Please define RTE_TARGET env variable first\n $NC" exit 1 fi # First download dpdk if [ -z "$(ls -A $PWD/drivers/dpdk)" ]; then cd drivers printf "${GREEN}Cloning dpdk...\n $NC" git submodule init git submodule update cd .. fi vercomp $kerver "2.6.33" # if kernel version < 2.6.33 if [ "$?" == "2" ]; then echo "[note] current kerner version ("$kerver") does not support DPDK" exit 1 fi if grep "ldflags.txt" $RTE_SDK/mk/rte.app.mk > /dev/null then : else sed -i -e 's/O_TO_EXE_STR =/\$(shell if [ \! -d \${RTE_SDK}\/\${RTE_TARGET}\/lib ]\; then mkdir \${RTE_SDK}\/\${RTE_TARGET}\/lib\; fi)\nLINKER_FLAGS = \$(call linkerprefix,\$(LDLIBS))\n\$(shell echo \${LINKER_FLAGS} \> \${RTE_SDK}\/\${RTE_TARGET}\/lib\/ldflags\.txt)\nO_TO_EXE_STR =/g' $RTE_SDK/mk/rte.app.mk fi # Build and install DPDK library export DESTDIR="." echo echo "Selected DPDK library to be used for MOS" echo "----------------------------------------------------------" echo " RTE_SDK exported as $RTE_SDK" echo " RTE_TARGET exported as $RTE_TARGET" echo "----------------------------------------------------------" echo echo -n "Press enter to continue ..."; read cd $RTE_SDK make install T=$RTE_TARGET echo echo -n "Done with DPDK setup. Press enter to start MOS setup ..."; read # Build and compile MOS library setup_mos_library $FL_DPDK elif [ "$1" == "--compile-pcap" ]; then setup_mos_library $FL_PCAP elif [ "$1" == "--compile-netmap" ]; then setup_mos_library $FL_NETMAP elif [ "$1" == "--run-dpdk" ]; then # check if RTE_SDK and RTE_TARGET env variables exist if [[ -z "${RTE_SDK}" ]]; then printf "${RED}Please define RTE_SDK env variable first\n $NC" exit 1 fi if [[ -z "${RTE_TARGET}" ]]; then printf "${RED}Please define RTE_TARGET env variable first\n $NC" exit 1 fi while [ 1 ]; do clear echo echo "----------------------------------------------------------" echo " Full setup (from start)" echo "----------------------------------------------------------" echo "[0] Full setup for running mOS with DPDK" echo echo "----------------------------------------------------------" echo " Step-by-step setup for running mOS with DPDK" echo "----------------------------------------------------------" echo "[1] Setup hugepage mappings" echo "[2] Load and bind Ethernet devices to IGB_UIO module" echo "[3] Bring the interfaces up (DPDK devices)" echo "[4] Create new MOS configuration files for sample apps" echo "[5] Unbind dpdk-registered NICs" echo echo "[6] Exit script" echo echo -n "Option: " read entry if [ "$entry" ]; then step"$entry"_func_dpdk echo echo -n "Press enter to continue ..."; read fi done elif [ "$1" == "--run-pcap" ]; then while [ 1 ]; do clear echo echo "----------------------------------------------------------" echo " Full setup (from start)" echo "----------------------------------------------------------" step0_func_pcap echo echo -n "Press enter to continue ..."; read done elif [ "$1" == "--run-netmap" ]; then while [ 1 ]; do clear echo echo "----------------------------------------------------------" echo " Full setup (from start)" echo "----------------------------------------------------------" step0_func_netmap echo echo -n "Press enter to continue ..."; read done elif [ "$1" == "--cleanup" ]; then find | grep mos.conf | xargs rm -f find | grep log__* | xargs rm -f find | grep mos-master.conf | xargs rm -f find | grep mos-slave.conf | xargs rm -f for d in $CUR_DIR/samples/* ; do cd $d make clean > /dev/null 2> /dev/null cd .. done cd .. cd core/src make clean > /dev/null 2> /dev/null cd bpf rm -rf *.o cd .. rm -rf .*.d rm -f Makefile cd ../.. find ./samples/ -name 'Makefile' | xargs rm -f rm -f scripts/config.log scripts/config.status cd dpdk-iface-kmod/ make clean cd .. else echo "[error] please specify one of the following options" echo "--compile-dpdk : compile and build mOS library with dpdk" echo "--compile-pcap : compile and build mOS library with pcap" echo "--compile-netmap : compile and build mOS library with netmap" echo "--run-dpdk : setup environments and configurations for running applications with dpdk" echo "--run-pcap : setup environments and configurations for running applications with pcap" echo "--run-netmap : setup environments and configurations for running applications with netmap" echo "--cleanup : delete all binaries, config and Makefiles" fi