Skip to content

Commit bbef2f1

Browse files
committed
fix(ns-ha): send gratuitous ARP for WANs
Keepalived automatically send gratuitous ARP for tracked interfaces. Since WAN interfaces are not tracked, gratuitous ARP packets must be sent just after the switch to master.
1 parent 859b970 commit bbef2f1

File tree

1 file changed

+33
-0
lines changed

1 file changed

+33
-0
lines changed

packages/ns-ha/files/ns-ha-enable

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,38 @@ def enable_interfaces(file):
3939
# Return code of ifup is not reliable, so we do not check it nor log it
4040
logger.info("Bringing up interface %s", interface)
4141

42+
def send_gratuitous_arp(file):
43+
# Get the mapping interface -> device
44+
proc = subprocess.run(["ubus", "-v", "call", "network.interface", "dump"], capture_output=True, text=True)
45+
try:
46+
network_dump = json.loads(proc.stdout)
47+
except json.JSONDecodeError:
48+
logger.error("Can't send gratuitous ARP: failed to decode JSON from network dump")
49+
return
50+
device_map = {}
51+
for iface in network_dump.get('interface', []):
52+
if 'device' in iface and 'interface' in iface:
53+
device_map[iface['interface']] = iface['device']
54+
# Load the file with the interfaces to send gratuitous ARP for
55+
with open(os.path.join(out_dir, file), 'r') as f:
56+
interfaces = json.load(f)
57+
for interface in interfaces:
58+
if 'ipaddr' in interfaces[interface]:
59+
device = device_map.get(interface)
60+
if not device:
61+
logger.error("Can't send gratuitous ARP: no device found for interface %s", interface)
62+
continue
63+
# It should not happen, but ipaddr can contain multiple IPs
64+
ipaddr = interfaces[interface]['ipaddr']
65+
if isinstance(ipaddr, str):
66+
ipaddr = [ipaddr]
67+
for ip in ipaddr:
68+
# Remove /mask if present
69+
ip = ip.split('/')[0]
70+
# Send gratuitous ARP to update switches ARP tables
71+
aproc = subprocess.run(["/usr/bin/arping", "-c", "1", "-U", "-I", device, ip], capture_output=True)
72+
logger.info("Sending gratuitous ARP on interface %s (%s) for IP %s: %s", interface, device, ip, "success" if aproc.returncode == 0 else "fail")
73+
4274
def enable_hotspot_mac():
4375
u = EUci()
4476
devices = utils.get_all_by_type(u, 'network', 'device')
@@ -60,4 +92,5 @@ if __name__ == "__main__":
6092
enable_interfaces('wg_interfaces')
6193
enable_interfaces('ipsec_interfaces')
6294
enable_hotspot_mac()
95+
send_gratuitous_arp('wan_interfaces')
6396
subprocess.run(["/sbin/reload_config"], capture_output=True)

0 commit comments

Comments
 (0)