From 8c0ab43f050e65a34d404cff196c0d057fff9864 Mon Sep 17 00:00:00 2001 From: David Gwynne Date: Wed, 6 Nov 2019 10:36:04 +1000 Subject: [PATCH] Use more route information to improve default_ipvX facts on BSDs (#64172) * Use "default" route info to help pick the default address. Before this change, the address information used for the "default_ipv4" and "default_ipv6" information is whatever is first on the interface identified by the looking up the "default" route. On OpenBSD at least, the first IPv6 address tends to be a link-local address, which is not useful if you want to try and put a globally routable v6 address in a template somewhere. OpenBSD and NetBSD list the local address used for the default route, so we can then use that to filter the addresses on the interface and use the right one when it is available. This should also help in situations where the interface has a lot of aliases, or if you're doing IP multipath. Thanks to John-Mark Gurney and Jared McNeill for providing me output from the route command on FreeBSD and NetBSD respectively. * Use "route get default" to get default route information. Using some other arbitrary address makes these facts produce unexpected results in some situations. --- .../module_utils/facts/network/generic_bsd.py | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/ansible/module_utils/facts/network/generic_bsd.py b/lib/ansible/module_utils/facts/network/generic_bsd.py index f8d6867e045..8f4d145f8c1 100644 --- a/lib/ansible/module_utils/facts/network/generic_bsd.py +++ b/lib/ansible/module_utils/facts/network/generic_bsd.py @@ -73,12 +73,12 @@ class GenericBsdIfconfigNetwork(Network): def get_default_interfaces(self, route_path): # Use the commands: - # route -n get 8.8.8.8 -> Google public DNS - # route -n get -inet6 2404:6800:400a:800::1012 -> ipv6.google.com + # route -n get default + # route -n get -inet6 default # to find out the default outgoing interface, address, and gateway - command = dict(v4=[route_path, '-n', 'get', '8.8.8.8'], - v6=[route_path, '-n', 'get', '-inet6', '2404:6800:400a:800::1012']) + command = dict(v4=[route_path, '-n', 'get', 'default'], + v6=[route_path, '-n', 'get', '-inet6', 'default']) interface = dict(v4={}, v6={}) @@ -92,13 +92,19 @@ class GenericBsdIfconfigNetwork(Network): # RTNETLINK answers: Invalid argument continue for line in out.splitlines(): - words = line.split() + words = line.strip().split(': ') # Collect output from route command if len(words) > 1: - if words[0] == 'interface:': + if words[0] == 'interface': interface[v]['interface'] = words[1] - if words[0] == 'gateway:': + if words[0] == 'gateway': interface[v]['gateway'] = words[1] + # help pick the right interface address on OpenBSD + if words[0] == 'if address': + interface[v]['address'] = words[1] + # help pick the right interface address on NetBSD + if words[0] == 'local addr': + interface[v]['address'] = words[1] return interface['v4'], interface['v6'] @@ -291,6 +297,14 @@ class GenericBsdIfconfigNetwork(Network): for item in ifinfo: if item != 'ipv4' and item != 'ipv6': defaults[item] = ifinfo[item] - if len(ifinfo[ip_type]) > 0: - for item in ifinfo[ip_type][0]: - defaults[item] = ifinfo[ip_type][0][item] + + ipinfo = [] + if 'address' in defaults: + ipinfo = [x for x in ifinfo[ip_type] if x['address'] == defaults['address']] + + if len(ipinfo) == 0: + ipinfo = ifinfo[ip_type] + + if len(ipinfo) > 0: + for item in ipinfo[0]: + defaults[item] = ipinfo[0][item]