Skip to content

Instantly share code, notes, and snippets.

@dosaboy
Last active October 29, 2020 17:02
Show Gist options
  • Save dosaboy/f0f0b88a0fcb3553d3eeb21c9bb3963e to your computer and use it in GitHub Desktop.
Save dosaboy/f0f0b88a0fcb3553d3eeb21c9bb3963e to your computer and use it in GitHub Desktop.
#!/bin/bash -u
# Origin: https://gist.github.com/dosaboy/f0f0b88a0fcb3553d3eeb21c9bb3963e
#
# Authors:
# - edward.hope-morley@canonical.com
#
# Tested on Ubuntu Bionic
#
# Description:
# Discover incorrect arp entries for rfp/fpr interfaces
#
declare -A map=()
declare -A rfps_mac_actual=()
declare -A rfps_mac_cache=()
declare -A rfps_gw_actual=()
declare -A rfps_gw_cache=()
declare -A rfps_entry=()
declare -A fprs_mac_actual=()
declare -A fprs_mac_cache=()
declare -A fprs_gw_actual=()
declare -A fprs_gw_cache=()
declare -A fprs_entry=()
for ns in `find /var/run/netns/ -name qrouter-\*`; do
ns=`basename $ns`
readarray -t interfaces<<<`sudo ip netns exec $ns ip -4 -br a| sed -rn 's/^(rfp-[[:alnum:]\-]+)@.+/\1/p'`
((${#interfaces[@]})) && [ -n "${interfaces[0]}" ] || continue
for iface in ${interfaces[@]}; do
rfps_mac_actual[${ns}_$iface]=`ip netns exec $ns ip a s| grep "${iface}@" -A 1| sed -rn 's/.+link\/ether\s+([[:alnum:]\:]+)\s+.+/\1/p'`
rfps_gw_actual[${ns}_$iface]=`ip netns exec $ns ip -4 a s| grep "${iface}@" -A 1| sed -rn 's/.+inet\s+([[:digit:]\.]+)\/[[:digit:]]+\s+.+/\1/p'`
rfps_mac_cache[${ns}_$iface]=`ip netns exec $ns ip n| sed -rn "s/.+dev\s+${iface}\s+lladdr\s+([[:alnum:]\:]+)\s*.*/\1/p"`
rfps_gw_cache[${ns}_$iface]=`ip netns exec $ns ip n| sed -rn "s/(^[[:digit:]\.]+).+dev\s+${iface}\s+.+/\1/p"`
rfps_entry[${ns}_$iface]=`ip netns exec $ns ip n| grep $iface`
done
done
for ns in `find /var/run/netns/ -name fip-\*`; do
ns=`basename $ns`
readarray -t interfaces<<<`sudo ip netns exec $ns ip -4 -br a| sed -rn 's/^(fpr-[[:alnum:]\-]+)@.+/\1/p'`
((${#interfaces[@]})) && [ -n "${interfaces[0]}" ] || continue
for iface in ${interfaces[@]}; do
fprs_mac_actual[${ns}_$iface]=`ip netns exec $ns ip a s| grep "${iface}@" -A 1| sed -rn 's/.+link\/ether\s+([[:alnum:]\:]+)\s+.+/\1/p'`
fprs_gw_actual[${ns}_$iface]=`ip netns exec $ns ip -4 a s| grep "${iface}@" -A 1| sed -rn 's/.+inet\s+([[:digit:]\.]+)\/[[:digit:]]+\s+.+/\1/p'`
fprs_mac_cache[${ns}_$iface]=`ip netns exec $ns ip n| sed -rn "s/.+dev\s+${iface}\s+lladdr\s+([[:alnum:]\:]+)\s*.*/\1/p"`
fprs_gw_cache[${ns}_$iface]=`ip netns exec $ns ip n| sed -rn "s/(^[[:digit:]\.]+).+dev\s+${iface}\s+.+/\1/p"`
fprs_entry[${ns}_$iface]=`ip netns exec $ns ip n| grep $iface`
map[$iface]=$ns
done
done
declare -a cleanup_commands=()
declare -A hits=()
count=0
for rfp in ${!rfps_mac_actual[@]}; do
((count+=2))
ns=${rfp%%_*}
iface=${rfp##*_}
rfp_mac_actual=${rfps_mac_actual[$rfp]}
rfp_mac_cache=${rfps_mac_cache[$rfp]}
rfp_gw_actual=${rfps_gw_actual[$rfp]}
rfp_gw_cache=${rfps_gw_cache[$rfp]}
fpr_name="fpr${iface#*rfp}"
fip_ns=${map[$fpr_name]}
fpr_key="${fip_ns}_$fpr_name"
fpr_mac_actual=${fprs_mac_actual[$fpr_key]}
fpr_mac_cache=${fprs_mac_cache[$fpr_key]}
fpr_gw_actual=${fprs_gw_actual[$fpr_key]}
fpr_gw_cache=${fprs_gw_cache[$fpr_key]}
if ! [[ $rfp_mac_cache == $fpr_mac_actual ]]; then
hits[$ns]=0
old="`echo ${rfps_entry[$rfp]}| sed -rn 's/(.+\s+)[[:alpha:]]+$/\1/p'`"
if [ -n "$old" ]; then
cleanup_commands+=( "sudo ip netns exec $ns ip n del $old" )
new=`echo $old| sed -e "s/$rfp_mac_cache/$fpr_mac_actual/g" -e "s/$rfp_gw_cache/$fpr_gw_actual/g"`
else
new="$fpr_gw_actual dev $iface lladdr $fpr_mac_actual"
fi
cleanup_commands+=( "sudo ip netns exec $ns ip n add $new nud permanent" )
cleanup_commands+=( "((\$?==0)) || sudo ip netns exec $ns ip n replace $new nud permanent" )
fi
if ! [[ $fpr_mac_cache == $rfp_mac_actual ]]; then
hits[$fip_ns]=0
old="`echo ${fprs_entry[$fpr_key]}| sed -rn 's/(.+\s+)[[:alpha:]]+$/\1/p'`"
if [ -n "$old" ]; then
cleanup_commands+=( "sudo ip netns exec $fip_ns ip n del $old" )
new=`echo $old| sed -e "s/$fpr_mac_cache/$rfp_mac_actual/g" -e "s/$fpr_gw_cache/$rfp_gw_actual/g"`
else
new="$rfp_gw_actual dev $fpr_name lladdr $rfp_mac_actual"
fi
cleanup_commands+=( "sudo ip netns exec $fip_ns ip n add $new nud permanent" )
cleanup_commands+=( "((\$?==0)) || sudo ip netns exec $fip_ns ip n replace $new nud permanent" )
fi
done
if ((${#cleanup_commands[@]})); then
echo -e "Checked $count namespaces and found ${#hits[@]} namespaces with bad arp entries:\n"
for cmd in "${cleanup_commands[@]}"; do
echo $cmd
done
else
echo "Checked $count namespaces and no issues found."
fi
echo -e "\nDone."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment