4 # Copyright 2015 Telef�nica Investigaci�n y Desarrollo, S.A.U.
5 # This file is part of openvim
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may
9 # not use this file except in compliance with the License. You may obtain
10 # a copy of the License at
12 # http://www.apache.org/licenses/LICENSE-2.0
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 # License for the specific language governing permissions and limitations
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact with: nfvlabs@tid.es
24 #Get configuration of a host for using it as a compute node
27 echo -e "usage: $0 user ip_name [>> host.yaml]\n Get host parameters and generated a yaml file to be used for openvim host-add"
31 function load_vf_driver
(){
33 if [[ `lsmod | cut -d" " -f1 | grep $pf_driver | grep -v vf` ]] && [[ ! `lsmod | cut -d" " -f1 | grep ${pf_driver}vf` ]]
35 >&2 echo "$pf_driver is loaded but not ${pf_driver}vf. This is required in order to properly add SR-IOV."
36 read -p "Do you want to load ${pf_driver}vf [Y/n] " load_driver
39 * ) >&2 echo "Loading ${pf_driver}vf..."
40 modprobe
${pf_driver}vf
;
41 >&2 echo "Reloading ${pf_driver}..."
42 modprobe
-r $pf_driver;
48 function remove_vf_driver
(){
50 if [[ `lsmod | cut -d" " -f1 | grep $pf_driver | grep -v vf` ]] && [[ `lsmod | cut -d" " -f1 | grep ${pf_driver}vf` ]]
52 >&2 echo "${pf_driver}vf is loaded. In order to ensure proper SR-IOV behavior the driver must be removed."
53 read -p "Do you want to remove ${pf_driver}vf now? [Y/n] " remove_driver
54 case $remove_driver in
55 [nN
]* ) >&2 echo "OK. Remember to remove the driver prior start using the compute node executing:";
56 >&2 echo "modprobe -r ${pf_driver}vf";
57 >&2 echo "modprobe -r ${pf_driver}";
58 >&2 echo "modprobe ${pf_driver}";;
59 * ) >&2 echo "Removing ${pf_driver}vf..."
60 modprobe
-r ${pf_driver}vf
;
61 >&2 echo "Reloading ${pf_driver}..."
62 modprobe
-r $pf_driver;
68 function get_hash_value
() { echo `eval echo $\{\`echo $1[$2]\
`\}`; }
70 function xmlpath_args
()
72 local expr="${1//\// }"
79 while IFS
='' read -r -d '<' chunk
; do
81 IFS
='>' read -r tag_arg data
<<< "$chunk"
82 IFS
=' ' read -r tag arguments
<<< "$tag_arg"
83 #If last tag was single level remove it from path
84 if [[ $closing_tag -eq 1 ]]
86 unset path
[${#path[@]}-1]
89 #In case the tag is closed in the same line mark it
90 [[ $arguments = ?
*'/' ]] && closing_tag
=1
91 arguments
="${arguments//\//}"
96 '/'?
*) unset path
[${#path[@]}-1] ;;
100 #echo "\"${path[@]}\" \"$expr\" \"$data\" \"$arguments\" $exit_code $print_line"
102 if [[ "${path[@]}" == "$expr" ]]
104 #If there is data print it and append arguments if any
107 echo "$data $arguments"
108 #return code 0 means data was found
111 #if there is no data but there are arguments print arguments
112 elif [ "$arguments" != "" ]
115 #return code 2 means no data but arguments were found
118 #otherwise switch flag to start/stop echoing each line until the tag is closed
119 elif [[ $exit_code -eq 1 ]]
121 print_line
=$
(((print_line
+1)%2))
122 #return code 3 means that the whole xml segment is returned
126 [[ $print_line == "1" ]] && echo "<"$chunk
132 #check root privileges and non a root user behind
134 [[ "$#" -lt "2" ]] && echo "Missing parameters" && usage
138 HOST_NAME
=`cat /etc/hostname`
139 FEATURES
=`grep "^flags" /proc/cpuinfo`
141 if echo $FEATURES |
grep -q pdpe1gb
; then FEATURES_LIST
="${FEATURES_LIST},lps"; fi
142 if echo $FEATURES |
grep -q dca
; then FEATURES_LIST
="${FEATURES_LIST},dioc"; fi
143 if echo $FEATURES |
egrep -q "(vmx|svm)" ; then FEATURES_LIST
="${FEATURES_LIST},hwsv"; fi
144 if echo $FEATURES |
egrep -q "(ept|npt)" ; then FEATURES_LIST
="${FEATURES_LIST},tlbps"; fi
145 if echo $FEATURES |
grep -q ht
; then FEATURES_LIST
="${FEATURES_LIST},ht"; fi
146 if uname
-m |
grep -q x86_64
; then FEATURES_LIST
="${FEATURES_LIST},64b"; fi
147 if cat /var
/log
/dmesg |
grep -q -e Intel-IOMMU
; then FEATURES_LIST
="${FEATURES_LIST},iommu"; fi
148 FEATURES_LIST
=${FEATURES_LIST#,}
150 NUMAS
=`gawk 'BEGIN{numas=0;}
151 ($1=="physical" && $2=="id" ){ if ($4+1>numas){numas=$4+1} };
152 END{printf("%d",numas);}' /proc/cpuinfo`
154 CPUS
=`gawk '($1=="processor"){pro=$3;}
155 ($1=="physical" && $2=="id"){ phy=$4;}
156 ($1=="core" && $2=="id"){printf " %d-%d-%d", phy,$4,pro;}' /proc/cpuinfo`
158 if grep -q isolcpus
/proc
/cmdline
160 isolcpus
=`cat /proc/cmdline`
161 isolcpus
=${isolcpus##*isolcpus=}
162 isolcpus
=${isolcpus%% *}
163 isolcpus
=${isolcpus//,/ }
169 #obtain interfaces information
171 read -p "Do you want to provide the interfaces connectivity information (datapathid/dpid of the switch and switch port id)? [Y/n] " conn_info
173 [Nn
]* ) prov_conn
=false
;;
175 read -p "What is the switch dapapathid/dpdi? (01:02:03:04:05:06:07:08) " dpid
;
176 [[ -z $dpid ]] && dpid
="01:02:03:04:05:06:07:08";
184 for device
in `virsh nodedev-list --cap net | grep -v net_lo_00_00_00_00_00_00`
186 virsh nodedev-dumpxml
$device > device_xml
187 name
=`xmlpath_args "device/capability/interface" < device_xml`
189 address
=`xmlpath_args "device/capability/address" < device_xml`
190 address
="${address// /}"
191 parent
=`xmlpath_args "device/parent" < device_xml`
192 parent
="${parent// /}"
193 #the following line created variables 'speed' and 'state'
194 eval `xmlpath_args "device/capability/link" < device_xml`
195 virsh nodedev-dumpxml
$parent > parent_xml
196 driver
=`xmlpath_args "device/driver/name" < parent_xml`
197 [ $?
-eq 1 ] && driver
="N/A"
198 driver
="${driver// /}"
200 #If the device is not up try to bring it up and reload state
201 if [[ $state == 'down' ]] && ( [[ $driver == "ixgbe" ]] ||
[[ $driver == "i40e" ]] )
203 >&2 echo "$name is down. Trying to bring it up"
206 virsh nodedev-dumpxml
$device > device_xml
207 eval `xmlpath_args "device/capability/link" < device_xml`
210 if [[ $state == 'down' ]] && ( [[ $driver == "ixgbe" ]] ||
[[ $driver == "i40e" ]] )
212 >&2 echo "Interfaces must be connected and up in order to properly detect the speed. You can provide this information manually or skip the interface"
216 while $keep_asking; do
217 read -p "Do you want to skip interface $name ($address) [y/N] " -i "n" skip
219 [Yy
]* ) keep_asking
=false
;;
220 * ) skip_interface
=false
;
221 default_speed
="10000"
222 while $keep_asking; do
223 read -p "What is the speed of the interface expressed in Mbps? ($default_speed) " speed
;
224 [[ -z $speed ]] && speed
=$default_speed
225 [[ $speed =~
''|
*[!0-9] ]] && echo "The input must be an integer" && continue;
231 $skip_interface && continue
233 #the following line creates a 'node' variable
234 eval `xmlpath_args "device/capability/numa" < parent_xml`
235 #the following line creates the variable 'type'
236 #in case the interface is a PF the value is 'virt_functions'
237 #in case the interface is a VF the value is 'phys_function'
239 eval `xmlpath_args "device/capability/capability" < parent_xml`
241 #the following line creates the variables 'domain' 'bus' 'slot' and 'function'
242 eval `xmlpath_args "device/capability/iommuGroup/address" < parent_xml`
243 pci
="${domain#*x}:${bus#*x}:${slot#*x}.${function#*x}"
244 underscored_pci
="${pci//\:/_}"
245 underscored_pci
="pci_${underscored_pci//\./_}"
247 if ( [[ $driver == "ixgbe" ]] ||
[[ $driver == "i40e" ]] )
249 underscored_pci
="pf"$underscored_pci
250 PF_list
[${#PF_list[@]}]=$underscored_pci
251 eval declare -A $underscored_pci
252 eval $underscored_pci["name"]=$name
253 eval $underscored_pci["numa"]=$node
254 eval $underscored_pci["mac"]=$address
255 eval $underscored_pci["speed"]=$speed
256 eval $underscored_pci["pci"]=$pci
257 #request switch port to the user if this information is being provided and include it
261 read -p "What is the port name in the switch $dpid where port $name ($pci) is connected? (${name}-${PORT_RANDOM}/$iface_counter) " switch_port
262 [[ -z $switch_port ]] && switch_port
="${name}-${PORT_RANDOM}/$iface_counter"
263 iface_counter
=$
((iface_counter
+1))
264 eval $underscored_pci["dpid"]=$dpid
265 eval $underscored_pci["switch_port"]=$switch_port
268 #A�ado el pci de cada uno de los hijos
270 for child
in `xmlpath_args "device/capability/capability/address" < parent_xml`
272 SRIOV_counter
=$
((SRIOV_counter
+1))
273 #the following line creates the variables 'domain' 'bus' 'slot' and 'function'
275 eval $underscored_pci["SRIOV"$SRIOV_counter]="${domain#*x}_${bus#*x}_${slot#*x}_${function#*x}"
277 eval $underscored_pci["SRIOV"]=$SRIOV_counter
279 #Si se trata de un SRIOV (tiene una capability con type 'phys_function')
280 elif [[ $type == 'phys_function' ]]
282 underscored_pci
="vf"$underscored_pci
283 VF_list
[${#VF_list[@]}]=$underscored_pci
284 eval declare -A $underscored_pci
285 eval $underscored_pci["source_name"]=$name
286 eval $underscored_pci["mac"]=$address
287 eval $underscored_pci["pci"]=$pci
289 rm -f device_xml parent_xml
293 echo "#This file was created by $0"
294 echo "#for adding this compute node to openvim"
295 echo "#copy this file to openvim controller and run"
296 echo "#openvim host-add <this>"
299 echo " name: $HOST_NAME"
303 echo " name: $HOST_NAME"
307 echo " description: $HOST_NAME"
308 echo " features: $FEATURES_LIST"
312 while [[ $numa -lt $NUMAS ]]
314 echo " - numa_socket: $numa"
316 if [ -f /sys
/devices
/system
/node
/node
${numa}/hugepages
/hugepages-1048576kB
/nr_hugepages
]
318 echo " hugepages: " `cat /sys/devices/system/node/node${numa}/hugepages/hugepages-1048576kB/nr_hugepages`
320 #TODO hugepages of 2048kB size
323 memory
=`head -n1 /sys/devices/system/node/node${numa}/meminfo | gawk '($5=="kB"){print $4}'`
324 memory
=$
((memory
+1048576-1)) #memory must be ceiled
325 memory
=$
((memory
/1048576)) #from `kB to GB
326 echo " memory: $memory"
330 FIRST
="-" #first item in a list start with "-" in yaml files, then it will set to " "
333 PHYSICAL
=`echo $cpu | cut -f 1 -d"-"`
334 CORE
=`echo $cpu | cut -f 2 -d"-"`
335 THREAD
=`echo $cpu | cut -f 3 -d"-"`
336 [[ $PHYSICAL != $numa ]] && continue #skip non physical
337 echo " - core_id: $CORE"
338 echo " thread_id: $THREAD"
341 for isolcpu
in $isolcpus
343 isolcpu_start
=`echo $isolcpu | cut -f 1 -d"-"`
344 isolcpu_end
=`echo $isolcpu | cut -f 2 -d"-"`
345 if [ "$THREAD" -ge "$isolcpu_start" -a "$THREAD" -le "$isolcpu_end" ]
351 [[ $cpu_isolated == "no" ]] && echo " status: noteligible"
357 for ((i
=0; i
<${#PF_list[@]};i
++))
359 underscored_pci
=${PF_list[$i]}
360 pname
=$
(get_hash_value
$underscored_pci "name")
361 pnuma
=$
(get_hash_value
$underscored_pci "numa")
362 [[ $pnuma != $numa ]] && continue
363 pmac
=$
(get_hash_value
$underscored_pci "mac")
364 ppci
=$
(get_hash_value
$underscored_pci "pci")
365 pspeed
=$
(get_hash_value
$underscored_pci "speed")
366 pSRIOV
=$
(get_hash_value
$underscored_pci "SRIOV")
367 [[ $interfaces_nb -eq 0 ]] && echo " interfaces:"
368 interfaces_nb
=$
((interfaces_nb
+1))
370 echo " - source_name: $pname"
371 echo " Mbps: $pspeed"
372 echo " pci: \"$ppci\""
373 echo " mac: \"$pmac\""
376 pdpid
=$
(get_hash_value
$underscored_pci "dpid")
377 pswitch_port
=$
(get_hash_value
$underscored_pci "switch_port")
378 echo " switch_dpid: $pdpid"
379 echo " switch_port: $pswitch_port"
381 for ((j
=1;j
<=$pSRIOV;j
++))
383 childSRIOV
="vfpci_"$
(get_hash_value
$underscored_pci "SRIOV"$j)
384 pname
=$
(get_hash_value
$childSRIOV "source_name")
386 pmac
=$
(get_hash_value
$childSRIOV "mac")
387 ppci
=$
(get_hash_value
$childSRIOV "pci")
388 [[ $sriov_nb -eq 0 ]] && echo " sriovs:"
389 sriov_nb
=$
((sriov_nb
+1))
390 echo " - mac: \"$pmac\""
391 echo " pci: \"$ppci\""
392 echo " source_name: $index"
398 remove_vf_driver ixgbe
399 remove_vf_driver i40e
400 #Bring up all interfaces
401 for ((i
=0; i
<${#PF_list[@]};i
++))
403 underscored_pci
=${PF_list[$i]}
404 pname
=$
(get_hash_value
$underscored_pci "name")