2 # Common Functions used by OPNFV Apex
3 # author: Tim Rozet (trozet@redhat.com)
5 ##converts subnet mask to prefix
8 # Number of args to shift, 255..255, first non-255 byte, zeroes
9 set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
10 [ $1 -gt 1 ] && shift $1 || shift
11 echo ${1-0}.${2-0}.${3-0}.${4-0}
14 ##find ip of interface
15 ##params: interface name
17 ip addr show $1 | grep -Eo '^\s+inet\s+[\.0-9]+' | awk '{print $2}'
20 ##finds subnet of ip and netmask
22 function find_subnet {
23 IFS=. read -r i1 i2 i3 i4 <<< "$1"
24 IFS=. read -r m1 m2 m3 m4 <<< "$2"
25 printf "%d.%d.%d.%d\n" "$((i1 & m1))" "$((i2 & m2))" "$((i3 & m3))" "$((i4 & m4))"
28 ##verify subnet has at least n IPs
29 ##params: subnet mask, n IPs
30 function verify_subnet_size {
31 IFS=. read -r i1 i2 i3 i4 <<< "$1"
34 ##this function assumes you would never need more than 254
35 ##we check here to make sure
36 if [ "$num_ips_required" -ge 254 ]; then
37 echo -e "\n\n${red}ERROR: allocating more than 254 IPs is unsupported...Exiting${reset}\n\n"
41 ##we just return if 3rd octet is not 255
42 ##because we know the subnet is big enough
43 if [ "$i3" -ne 255 ]; then
45 elif [ $((254-$i4)) -ge "$num_ips_required" ]; then
48 echo -e "\n\n${red}ERROR: Subnet is too small${reset}\n\n"
53 ##finds last usable ip (broadcast minus 1) of a subnet from an IP and netmask
54 ## Warning: This function only works for IPv4 at the moment.
56 function find_last_ip_subnet {
57 IFS=. read -r i1 i2 i3 i4 <<< "$1"
58 IFS=. read -r m1 m2 m3 m4 <<< "$2"
59 IFS=. read -r s1 s2 s3 s4 <<< "$((i1 & m1)).$((i2 & m2)).$((i3 & m3)).$((i4 & m4))"
60 printf "%d.%d.%d.%d\n" "$((255 - $m1 + $s1))" "$((255 - $m2 + $s2))" "$((255 - $m3 + $s3))" "$((255 - $m4 + $s4 - 1))"
63 ##increments subnet by a value
66 function increment_subnet {
67 IFS=. read -r i1 i2 i3 i4 <<< "$1"
68 printf "%d.%d.%d.%d\n" "$i1" "$i2" "$i3" "$((i4 | $2))"
71 ##finds netmask of interface
73 ##returns long format 255.255.x.x
74 function find_netmask {
75 ifconfig $1 | grep -Eo 'netmask\s+[\.0-9]+' | awk '{print $2}'
78 ##finds short netmask of interface
80 ##returns short format, ex: /21
81 function find_short_netmask {
82 echo "/$(ip addr show $1 | grep -Eo '^\s+inet\s+[\/\.0-9]+' | awk '{print $2}' | cut -d / -f2)"
87 ##assumes a /24 subnet
89 baseaddr="$(echo $1 | cut -d. -f1-3)"
90 lsv="$(echo $1 | cut -d. -f4)"
91 if [ "$lsv" -ge 254 ]; then
98 ##subtracts a value from an IP address
99 ##params: last ip, ip_count
100 ##assumes ip_count is less than the last octect of the address
102 IFS=. read -r i1 i2 i3 i4 <<< "$1"
104 if [ $i4 -lt $ip_count ]; then
105 echo -e "\n\n${red}ERROR: Can't subtract $ip_count from IP address $1 Exiting${reset}\n\n"
108 printf "%d.%d.%d.%d\n" "$i1" "$i2" "$i3" "$((i4 - $ip_count ))"
111 ##check if IP is in use
113 ##ping ip to get arp entry, then check arp
114 function is_ip_used {
115 ping -c 5 $1 > /dev/null 2>&1
116 arp -n | grep "$1 " | grep -iv incomplete > /dev/null 2>&1
119 ##find next usable IP
121 function next_usable_ip {
123 while [ "$new_ip" ]; do
124 if ! is_ip_used $new_ip; then
128 new_ip=$(next_ip $new_ip)
133 ##increment ip by value
134 ##params: ip, amount to increment by
135 ##increment_ip $next_private_ip 10
136 function increment_ip {
137 baseaddr="$(echo $1 | cut -d. -f1-3)"
138 lsv="$(echo $1 | cut -d. -f4)"
141 if [ "$lsv" -ge 254 ]; then
147 ##finds gateway on system
148 ##params: interface to validate gateway on (optional)
150 function find_gateway {
151 local gw gw_interface
155 gw=$(ip route | grep default | awk '{print $3}')
156 gw_interface=$(ip route get $gw | awk '{print $3}')
158 if [ "$gw_interface" == "$1" ]; then
164 ##finds subnet in CIDR notation for interface
165 ##params: interface to find CIDR
167 local cidr network ip netmask short_mask
172 netmask=$(find_netmask $1)
173 if [[ -z "$ip" || -z "$netmask" ]]; then
176 network=$(find_subnet ${ip} ${netamsk})
177 short_mask=$(find_short_netmask $1)
178 if [[ -z "$network" || -z "$short_mask" ]]; then
181 cidr="${subnet}'\'${short_mask}"
185 ##finds block of usable IP addresses for an interface
186 ##simply returns at the moment the correct format
187 ##after first 20 IPs, and leave 20 IPs at end of subnet (for floating ips, etc)
188 ##params: interface to find IP
189 function find_usable_ip_range {
190 local interface_ip subnet_mask first_block_ip last_block_ip
194 interface_ip=$(find_ip $1)
195 subnet_mask=$(find_netmask $1)
196 if [[ -z "$interface_ip" || -z "$subnet_mask" ]]; then
199 interface_ip=$(increment_ip ${interface_ip} 20)
200 first_block_ip=$(next_usable_ip ${interface_ip})
201 if [ -z "$first_block_ip" ]; then
204 last_block_ip=$(find_last_ip_subnet ${interface_ip} ${subnet_mask})
205 if [ -z "$last_block_ip" ]; then
208 last_block_ip=$(subtract_ip ${last_block_ip} 21)
209 echo "${first_block_ip},${last_block_ip}"
214 ##generates usable IP range in correct format based on CIDR
215 ##assumes the first 20 IPs are used (by instack or otherwise)
217 function generate_usable_ip_range {
218 local first_ip first_block_ip last_block_ip
219 #first_ip=$(ipcalc -nb $1 | grep HostMin: | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
220 first_ip=$(ipcalc -nmpb $1 | grep NETWORK= | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
221 first_ip=$(increment_ip ${first_ip} 1)
222 first_block_ip=$(increment_ip ${first_ip} 20)
223 #last_block_ip=$(ipcalc -nb $1 | grep HostMax: | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
224 last_block_ip=$(ipcalc -nmpb $1 | grep BROADCAST= | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
225 last_block_ip=$(subtract_ip ${last_block_ip} 1)
226 if [[ -z "$first_block_ip" || -z "$last_block_ip" ]]; then
229 last_block_ip=$(subtract_ip ${last_block_ip} 21)
230 echo "${first_block_ip},${last_block_ip}"
234 ##find the instack IP address
235 ##finds first usable IP on subnet
237 function find_provisioner_ip {
242 interface_ip=$(find_ip $1)
243 if [ -z "$interface_ip" ]; then
246 echo $(increment_ip ${interface_ip} 1)
249 ##generates instack IP address based on CIDR
251 function generate_provisioner_ip {
253 #provisioner_ip=$(ipcalc -nb $1 | grep HostMin: | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
254 provisioner_ip=$(ipcalc -nmpb $1 | grep NETWORK= | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
255 if [ -z "$provisioner_ip" ]; then
258 provisioner_ip=$(increment_ip ${provisioner_ip} 1)
259 echo "$provisioner_ip"
262 ##finds the dhcp range available via interface
263 ##uses first 8 IPs, after 2nd IP
265 function find_dhcp_range {
266 local dhcp_range_start dhcp_range_end interface_ip
270 interface_ip=$(find_ip $1)
271 if [ -z "$interface_ip" ]; then
274 dhcp_range_start=$(increment_ip ${interface_ip} 2)
275 dhcp_range_end=$(increment_ip ${dhcp_range_start} 8)
276 echo "${dhcp_range_start},${dhcp_range_end}"
279 ##generates the dhcp range available via CIDR
280 ##uses first 8 IPs, after 1st IP
282 function generate_dhcp_range {
283 local dhcp_range_start dhcp_range_end first_ip
284 #first_ip=$(ipcalc -nb $1 | grep HostMin: | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
285 first_ip=$(ipcalc -nmpb $1 | grep NETWORK= | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
286 if [ -z "$first_ip" ]; then
289 first_ip=$(increment_ip ${first_ip} 1)
290 dhcp_range_start=$(increment_ip ${first_ip} 1)
291 dhcp_range_end=$(increment_ip ${dhcp_range_start} 8)
292 echo "${dhcp_range_start},${dhcp_range_end}"
295 ##finds the introspection range available via interface
296 ##uses 8 IPs, after the first 10 IPs
298 function find_introspection_range {
299 local inspect_range_start inspect_range_end interface_ip
303 interface_ip=$(find_ip $1)
304 if [ -z "$interface_ip" ]; then
307 inspect_range_start=$(increment_ip ${interface_ip} 10)
308 inspect_range_end=$(increment_ip ${inspect_range_start} 8)
309 echo "${inspect_range_start},${inspect_range_end}"
312 ##generate the introspection range available via CIDR
313 ##uses 8 IPs, after the first 10 IPs
315 function generate_introspection_range {
316 local inspect_range_start inspect_range_end first_ip
317 #first_ip=$(ipcalc -nb $1 | grep HostMin: | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
318 first_ip=$(ipcalc -nmpb $1 | grep NETWORK= | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
319 if [ -z "$first_ip" ]; then
322 first_ip=$(increment_ip ${first_ip} 1)
323 inspect_range_start=$(increment_ip ${first_ip} 10)
324 inspect_range_end=$(increment_ip ${inspect_range_start} 8)
325 echo "${inspect_range_start},${inspect_range_end}"
328 ##finds the floating ip range available via interface
329 ##uses last 20 IPs of a subnet, minus last IP
331 function find_floating_ip_range {
332 local float_range_start float_range_end interface_ip subnet_mask
336 interface_ip=$(find_ip $1)
337 subnet_mask=$(find_netmask $1)
338 if [[ -z "$interface_ip" || -z "$subnet_mask" ]]; then
341 float_range_end=$(find_last_ip_subnet ${interface_ip} ${subnet_mask})
342 float_range_end=$(subtract_ip ${float_range_end} 1)
343 float_range_start=$(subtract_ip ${float_range_end} 19)
344 echo "${float_range_start},${float_range_end}"
347 ##generate the floating range available via CIDR
348 ##uses last 20 IPs of subnet, minus last IP
350 function generate_floating_ip_range {
351 local float_range_start float_range_end last_ip
352 #last_ip=$(ipcalc -nb $1 | grep HostMax: | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
353 last_ip=$(ipcalc -nmpb $1 | grep BROADCAST= | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")
354 if [ -z "$last_ip" ]; then
357 last_ip=$(subtract_ip ${last_ip} 2)
358 float_range_start=$(subtract_ip ${last_ip} 19)
359 float_range_end=${last_ip}
360 echo "${float_range_start},${float_range_end}"
363 ##attach interface to OVS and set the network config correctly
364 ##params: bride to attach to, interface to attach, network type (optional)
365 ##public indicates attaching to a public interface
366 function attach_interface_to_ovs {
367 local bridge interface
368 local if_ip if_mask if_gw if_file ovs_file if_prefix
370 if [[ -z "$1" || -z "$2" ]]; then
377 if ovs-vsctl list-ports ${bridge} | grep ${interface}; then
381 if_file=/etc/sysconfig/network-scripts/ifcfg-${interface}
382 ovs_file=/etc/sysconfig/network-scripts/ifcfg-${bridge}
384 if [ -e "$if_file" ]; then
385 if_ip=$(sed -n 's/^IPADDR=\(.*\)$/\1/p' ${if_file})
386 if_mask=$(sed -n 's/^NETMASK=\(.*\)$/\1/p' ${if_file})
387 if_gw=$(sed -n 's/^GATEWAY=\(.*\)$/\1/p' ${if_file})
389 echo "ERROR: ifcfg file missing for ${interface}"
393 if [ -z "$if_mask" ]; then
394 # we can look for PREFIX here, then convert it to NETMASK
395 if_prefix=$(sed -n 's/^PREFIX=\(.*\)$/\1/p' ${if_file})
396 if_mask=$(prefix2mask ${if_prefix})
399 if [[ -z "$if_ip" || -z "$if_mask" ]]; then
400 echo "ERROR: IPADDR or NETMASK/PREFIX missing for ${interface}"
402 elif [[ -z "$if_gw" && "$3" == "public_network" ]]; then
403 echo "ERROR: GATEWAY missing for ${interface}, which is public"
407 # move old config file to .orig
408 mv -f ${if_file} ${if_file}.orig
409 echo "DEVICE=${interface}
417 PROMISC=yes" > ${if_file}
419 if [ -z ${if_gw} ]; then
421 echo "DEVICE=${bridge}
429 PEERDNS=no" > ${ovs_file}
432 echo "DEVICE=${bridge}
441 PEERDNS=no" > ${ovs_file}
444 sudo systemctl restart network
447 ##detach interface from OVS and set the network config correctly
448 ##params: bridge to detach from
449 ##assumes only 1 real interface attached to OVS
450 function detach_interface_from_ovs {
452 local port_output ports_no_orig
454 local if_ip if_mask if_gw if_prefix
456 net_path=/etc/sysconfig/network-scripts/
457 if [[ -z "$1" ]]; then
463 # if no interfaces attached then return
464 if ! ovs-vsctl list-ports ${bridge} | grep -Ev "vnet[0-9]*"; then
468 # look for .orig ifcfg files to use
469 port_output=$(ovs-vsctl list-ports ${bridge} | grep -Ev "vnet[0-9]*")
470 while read -r line; do
471 if [ -z "$line" ]; then
473 elif [ -e ${net_path}/ifcfg-${line}.orig ]; then
474 mv -f ${net_path}/ifcfg-${line}.orig ${net_path}/ifcfg-${line}
475 elif [ -e ${net_path}/ifcfg-${bridge} ]; then
476 if_ip=$(sed -n 's/^IPADDR=\(.*\)$/\1/p' ${if_file})
477 if_mask=$(sed -n 's/^NETMASK=\(.*\)$/\1/p' ${if_file})
478 if_gw=$(sed -n 's/^GATEWAY=\(.*\)$/\1/p' ${if_file})
480 if [ -z "$if_mask" ]; then
481 if_prefix=$(sed -n 's/^PREFIX=\(.*\)$/\1/p' ${if_file})
482 if_mask=$(prefix2mask ${if_prefix})
485 if [[ -z "$if_ip" || -z "$if_mask" ]]; then
486 echo "ERROR: IPADDR or PREFIX/NETMASK missing for ${bridge} and no .orig file for interface ${line}"
490 if [ -z ${if_gw} ]; then
499 PEERDNS=no" > ${net_path}/ifcfg-${line}
509 PEERDNS=no" > ${net_path}/ifcfg-${line}
513 echo "ERROR: Real interface ${line} attached to bridge, but no interface or ${bridge} ifcfg file exists"
517 done <<< "$port_output"
519 # modify the bridge ifcfg file
520 # to remove IP params
521 sudo sed -i 's/IPADDR=.*//' ${net_path}/ifcfg-${bridge}
522 sudo sed -i 's/NETMASK=.*//' ${net_path}/ifcfg-${bridge}
523 sudo sed -i 's/GATEWAY=.*//' ${net_path}/ifcfg-${bridge}
525 sudo systemctl restart network
528 # Update iptables rule for external network reach internet
529 # for virtual deployments
530 # params: external_cidr
531 function configure_undercloud_nat {
533 if [[ -z "$1" ]]; then
539 ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" <<EOI
540 iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
541 iptables -t nat -A POSTROUTING -s ${external_cidr} -o eth0 -j MASQUERADE
542 iptables -A FORWARD -i eth2 -j ACCEPT
543 iptables -A FORWARD -s ${external_cidr} -m state --state ESTABLISHED,RELATED -j ACCEPT
544 service iptables save
548 # Interactive prompt handler
549 # params: step stage, ex. deploy, undercloud install, etc
550 function prompt_user {
552 echo -n "Would you like to proceed with ${1}? (y/n) "
554 if [ "$response" == 'y' ]; then
556 elif [ "$response" == 'n' ]; then