Skip to content

Instantly share code, notes, and snippets.

@dosaboy
Last active March 18, 2021 08:26
Show Gist options
  • Save dosaboy/7bdd004d33d7eb39a93835576227ad4a to your computer and use it in GitHub Desktop.
Save dosaboy/7bdd004d33d7eb39a93835576227ad4a to your computer and use it in GitHub Desktop.
#!/bin/bash -u
# Origin: https://gist.github.com/dosaboy/7bdd004d33d7eb39a93835576227ad4a
#
# Authors:
# - edward.hope-morley@canonical.com
#
# Tested on Ubuntu Bionic Ussuri
#
# Description:
# Fix arp entries affected by https://bugs.launchpad.net/neutron/+bug/1916761.
#
# This currently only fixes entries for ports that exist and performs lookup
# based on tap device mac address since ip address is not available. It also
# filters ports that do not have an iptables NAT rule since we only care
# about ports used with FIPs since thats the only traffic impacted by this
# bug.
#
# By default this script is read-only and will print suggested commands to
# run. If you want to have commands executed automatically you can set
# export NON_INTERACTIVE=true before running the script.
#
# Logs to stdout or syslog if NON_INTERACTIVE=true
#
# e.g.to run as a cron every minute add the following to crontab:
#
# * * * * * NON_INTERACTIVE=true /path/to/fix-lp1916761-dvr-arp-cache.sh
#
declare -A ifaces=()
declare -a fix_commands=()
auto_execute=${NON_INTERACTIVE:-false}
logger=tee
$auto_execute && logger=logger
(
readarray -t taps<<<`ip -br a| sed -rn 's/^(tap[[:alnum:]\-]+).+/\1/p'`
if ((${#taps[@]})) && [[ -n ${taps[0]} ]]; then
echo "Checking (${#taps[@]}) tap devices: ${taps[@]}"
for tap in ${taps[@]}; do
# get mac address
ifaces[$tap]=`ip -br l| grep $tap| awk '{print $3}'`
done
fi
if ! ((${#ifaces[@]})); then
echo "INFO: nothing to fix - exiting"
exit 0
fi
for ns in `find /var/run/netns/ -name qrouter-\*`; do
ns=`basename $ns`
((${#taps[@]})) && [ -n "${taps[0]}" ] || continue
for iface in ${!ifaces[@]}; do
libvirt_mac=fa:${ifaces[$iface]:3}
readarray -t entries<<<`sudo ip netns exec $ns ip n| grep $libvirt_mac| grep PERMANENT`
((${#entries[@]})) && [[ -n ${entries[0]} ]] || continue
for perm in "${entries[@]}"; do
# if port has no NAT rule just ignore it
addr=`echo $perm| cut -d ' ' -f 1`
sudo ip netns exec $ns iptables -t nat -S| egrep "[SD]NAT"| grep -q $addr
(($?==0)) || continue
ip_n_cmd=`echo "$perm"| sed -r 's/PERMANENT/nud reachable/g'`
fix_commands+=( "sudo ip netns exec $ns ip n replace $ip_n_cmd" )
done
done
done
if ! ((${#fix_commands[@]})); then
echo "INFO: nothing to fix - exiting"
exit 0
else
echo "INFO: found ${#fix_commands[@]} arp entries that need fixing"
fi
if $auto_execute; then
echo "INFO: auto-executing commands to fix arp entries:"
for cmd in "${fix_commands[@]}"; do
echo "INFO: executing '$cmd'"
$cmd
done
else
echo "INFO: run the following commands to fix arp entries:"
for cmd in "${fix_commands[@]}"; do
echo $cmd
done
fi
echo -e "\nDone."
) | $logger
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment