@@ -89,32 +89,47 @@ while /bin/true; do
8989 eval ` eval $ip6cmd `
9090
9191 if [[ $SUBTYPE == " dualtor" ]]; then
92- # manually set any remaining FAILED/INCOMPLETE entries to permanently INCOMPLETE
93- # this prevents any remaining INCOMPLETE entries from automatically transitioning to FAILED
94- # once these entries are incomplete, any subsequent neighbor advertisement messages
95- # are able to resolve the entry
96-
97- # generates the following command for each failed or incomplete IPv6 neighbor
98- # ip neigh replace <neighbor IPv6> dev <VLAN name> nud incomplete
99- neigh_replace_template=" sed -e 's/^/ip neigh replace /' -e 's/,/ dev /' -e 's/$/ nud incomplete;/'"
100- ip_neigh_replace_cmd=" ip -6 neigh show | grep -v fe80 | grep $vlan | grep -E 'FAILED|INCOMPLETE' | cut -d ' ' -f 1,3 --output-delimiter=',' | $neigh_replace_template "
101- eval ` eval $ip_neigh_replace_cmd `
102-
103- # on dual ToR devices, try to resolve failed neighbor entries since
104- # these entries will have tunnel routes installed, preventing normal
105- # neighbor resolution (SWSS PR #2137)
106-
107- # since ndisc6 is a userland process, the above ndisc6 commands are
108- # insufficient to update the kernel neighbor table for failed entries
109-
110- # we don't need to do this for ipv4 neighbors since arping is able to
111- # update the kernel neighbor table
112-
113- # generates the following command for each failed or incomplete IPv6 neighbor
92+ # capture all current failed/incomplete IPv6 neighbors in the kernel to avoid situations where new neighbors are learned
93+ # in the middle of the below sequence of commands
94+ unresolved_kernel_neighbors=$( ip -6 neigh show | grep -v fe80 | grep $vlan | grep -E ' FAILED|INCOMPLETE' )
95+ failed_kernel_neighbors=$( echo " $unresolved_kernel_neighbors " | grep FAILED | cut -d ' ' -f 1)
96+
97+ # it's possible for kernel neighbors to fall out of sync with the hardware
98+ # this can result in failed neighbors entries that don't have corresponding zero MAC neighbor entries
99+ # and therefore don't have tunnel routes installed in the hardware
100+ # flush these neighbors from the kernel to force relearning and resync them to the hardware:
101+ # 1. for every FAILED or INCOMPLETE neighbor in the kernel, check if there is a corresponding zero MAC neighbor in APPL_DB
102+ # 2. if no zero MAC neighbor entry exists, flush the kernel neighbor entry
103+ # - generates the command 'ip neigh flush <neighbor IPv6>' for all such neighbors
104+ unsync_neighbors=$( echo " $unresolved_kernel_neighbors " | cut -d ' ' -f 1 | xargs -I{} bash -c " if [[ -z \"\$ (sonic-db-cli APPL_DB hget NEIGH_TABLE:$vlan :{} neigh)\" ]]; then echo '{}'; fi" )
105+ if [[ ! -z " $unsync_neighbors " ]]; then
106+ ip_neigh_flush_cmd=" echo \" $unsync_neighbors \" | sed -e 's/^/ip neigh flush /' -e 's/$/;/'"
107+ eval ` eval " $ip_neigh_flush_cmd " `
108+ sleep 2
109+ fi
110+
111+ # generates the following command for each FAILED or INCOMPLETE IPv6 neighbor
114112 # timeout 0.2 ping <neighbor IPv6> -n -q -i 0 -c 1 -W 1 -I <VLAN name> >/dev/null
115- ping6_template=" sed -e 's/^/timeout 0.2 ping /' -e 's/,/ -n -q -i 0 -c 1 -W 1 -I /' -e 's/$/ >\/dev\/null;/'"
116- failed_ip6_neigh_cmd=" ip -6 neigh show | grep -v fe80 | grep $vlan | grep -E 'FAILED|INCOMPLETE' | cut -d ' ' -f 1,3 --output-delimiter=',' | $ping6_template "
117- eval ` eval $failed_ip6_neigh_cmd `
113+ if [[ ! -z " $unresolved_kernel_neighbors " ]]; then
114+ ping6_template=" sed -e 's/^/timeout 0.2 ping /' -e 's/,/ -n -q -i 0 -c 1 -W 1 -I /' -e 's/$/ >\/dev\/null;/'"
115+ failed_ip6_neigh_cmd=" echo \" $unresolved_kernel_neighbors \" | cut -d ' ' -f 1,3 --output-delimiter=',' | $ping6_template "
116+ eval ` eval " $failed_ip6_neigh_cmd " `
117+ # allow some time for any transient INCOMPLETE neighbors to transition to FAILED
118+ sleep 5
119+ fi
120+
121+ # manually set any remaining FAILED entries to permanently INCOMPLETE
122+ # once these entries are INCOMPLETE, any subsequent neighbor advertisement messages are able to resolve the entry
123+ # ignore INCOMPLETE neighbors since if they are transiently incomplete (i.e. new kernel neighbors that we are attempting to resolve for the first time),
124+ # setting them to permanently incomplete here means the kernel will never generate a netlink message for that neighbor
125+ # generates the following command for each FAILED IPv6 neighbor
126+ # ip neigh replace <neighbor IPv6> dev <VLAN name> nud incomplete
127+ failed_kernel_neighbors=$( ip -6 neigh show | grep -v fe80 | grep $vlan | grep -E ' FAILED' )
128+ if [[ ! -z " $failed_kernel_neighbors " ]]; then
129+ neigh_replace_template=" sed -e 's/^/ip neigh replace /' -e 's/,/ dev /' -e 's/$/ nud incomplete;/'"
130+ ip_neigh_replace_cmd=" echo \" $failed_kernel_neighbors \" | cut -d ' ' -f 1,3 --output-delimiter=',' | $neigh_replace_template "
131+ eval ` eval " $ip_neigh_replace_cmd " `
132+ fi
118133 fi
119134 done
120135
0 commit comments