Testing Network Connection

The context is Ignition Edge 8.1 on Ubuntu linux.

We have two copper Ethernet connections that take separate paths to connect to a central network. The path connected to one is preferred because it is faster. We want to monitor the status of each path by determining if a central server can be reached.

This function almost works reliably.

def PingCheck2(source, dest):
# Ping destination IPv4 address through
# network interface with source IPv4 address
# Both source and dest string
# Returns true if ICMP ping succeeds
	from java.net import InetAddress
	from java.net import NetworkInterface
	try:
		ip1 = InetAddress.getByName(source)
		netif = NetworkInterface.getByInetAddress(ip1)
		ip2 = InetAddress.getByName(dest)
		if netif != None:
			return ip2.isReachable(netif, 0, 10000)
		else:
			return False
	except:
		return False

This doesn't quite work because it is sensitive to routes even though you would think routes are to be ignored if the interface is being specified.

If no explicit route to the server is in the routes table, this works for the preferred interface, which has a lower metric for the general 0.0.0.0 route.

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.99.94   0.0.0.0         UG    20010  0        0 enp6s0
0.0.0.0         192.168.133.1   0.0.0.0         UG    20050  0        0 enp7s0
169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 enp6s0
192.168.99.80   0.0.0.0         255.255.255.240 U     10     0        0 enp6s0
192.168.133.0   0.0.0.0         255.255.255.0   U     50     0        0 enp7s0

However, it fails for the second interface even though a command line ping -I with the network interface specified works fine. The java isReachable() method returns nothing until I add a static route through the slower interface. Once that is added the test for the primary path becomes unreliable, working some of the time.

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.99.94   0.0.0.0         UG    20010  0        0 enp6s0
0.0.0.0         192.168.133.1   0.0.0.0         UG    20050  0        0 enp7s0
169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 enp6s0
192.168.0.0     192.168.133.1   255.255.255.0   UG    50     0        0 enp7s0
192.168.99.80   0.0.0.0         255.255.255.240 U     10     0        0 enp6s0
192.168.133.0   0.0.0.0         255.255.255.0   U     50     0        0 enp7s0

If a route is present for each connection, it only works for the entry with the lower metric.

Is anyone aware of a workaround for this? Ping -I at the shell command works as expected but isReachable() fails in this condition.

Thanks,
Max

I would not expect this to work without table-based routing and dynamic adjustment of the table-selection rules.

You are trying to implement a poor-man's "software defined network" but aren't really isolating the routing decisions involved.

Java will simply delegate routing to the OS. Specifying a source IP removes one degree of freedom, but the kernel is free to decide otherwise. (A table-selection rule can fix this.)

Table-based routing is a bear. (Been there, done that, stopped when I could.) All the necessary functionality is present in Linux, but the concepts and techniques are not trivial.

Edit: All useful information from a quick search is terribly old, except the instructions to study the ip route and ip rule man pages. (Use the table ... modifier to ip route to manipulate multiple tables.)

If you are really determined to establish redundant network paths, consider deploying rapid spanning tree protocol via commercial switches. Combine the paths in Linux using OpenVSwitch.

Thanks for the reply, Phil!

I could see this was quickly becoming non-trivial the further I looked.

We may need to shift the architecture... kind of got backed into this corner by a change in VPN.