]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
cephadm: Make list_networks ipv6 enabled
authorMatthew Oliver <moliver@suse.com>
Thu, 2 Jul 2020 08:21:53 +0000 (18:21 +1000)
committerSebastian Wagner <sebastian.wagner@suse.com>
Wed, 15 Jul 2020 08:50:52 +0000 (10:50 +0200)
Currently the list_network command and methods in cephadm only run and
parse ipv4 output from `ip route`.

This patch extends the list_network command and internal methods to be
ipv6 enabled. It now also checks `ip -6 route` and `ip -6 addr` to
gather gather all networks from both protocol families.

Signed-off-by: Matthew Oliver <moliver@suse.com>
(cherry picked from commit c64d273084bcd3d43c6b63dc070de3f244f86ca8)

src/cephadm/cephadm
src/cephadm/tests/test_cephadm.py

index 3981607ef6833a7b375253b76ba10b358ee8c57f..21cb7f6d245f1d4d3302de1d18116d6db0877b57 100755 (executable)
@@ -2418,7 +2418,8 @@ def command_bootstrap():
         # make sure IP is configured locally, and then figure out the
         # CIDR network
         for net, ips in list_networks().items():
-            if base_ip in ips:
+            if ipaddress.ip_address(unicode(base_ip)) in \
+                    [ipaddress.ip_address(unicode(ip)) for ip in ips]:
                 mon_network = net
                 logger.info('Mon IP %s is in CIDR network %s' % (base_ip,
                                                                  mon_network))
@@ -3121,10 +3122,15 @@ def list_networks():
     #j = json.loads(out)
     #for x in j:
 
+    res = _list_ipv4_networks()
+    res.update(_list_ipv6_networks())
+    return res
+
+def _list_ipv4_networks():
     out, _, _ = call_throws([find_executable('ip'), 'route', 'ls'])
-    return _parse_ip_route(out)
+    return _parse_ipv4_route(out)
 
-def _parse_ip_route(out):
+def _parse_ipv4_route(out):
     r = {}  # type: Dict[str,List[str]]
     p = re.compile(r'^(\S+) (.*)scope link (.*)src (\S+)')
     for line in out.splitlines():
@@ -3138,6 +3144,36 @@ def _parse_ip_route(out):
         r[net].append(ip)
     return r
 
+def _list_ipv6_networks():
+    routes, _, _ = call_throws([find_executable('ip'), '-6', 'route', 'ls'])
+    ips, _, _ = call_throws([find_executable('ip'), '-6', 'addr', 'ls'])
+    return _parse_ipv6_route(routes, ips)
+
+def _parse_ipv6_route(routes, ips):
+    r = {}  # type: Dict[str,List[str]]
+    route_p = re.compile(r'^(\S+) dev (\S+) proto (\S+) metric (\S+) pref (\S+)$')
+    ip_p = re.compile(r'^\s+inet6 (\S+)/(.*)scope (.*)$')
+    for line in routes.splitlines():
+        m = route_p.findall(line)
+        if not m or m[0][0].lower() == 'default':
+            continue
+        net = m[0][0]
+        if net not in r:
+            r[net] = []
+
+    for line in ips.splitlines():
+        m = ip_p.findall(line)
+        if not m:
+            continue
+        ip = m[0][0]
+        # find the network it belongs to
+        net = [n for n in r.keys()
+               if ipaddress.ip_address(unicode(ip)) in ipaddress.ip_network(unicode(n))]
+        if net:
+            r[net[0]].append(ip)
+
+    return r
+
 def command_list_networks():
     # type: () -> None
     r = list_networks()
index b44f0b72219ffa199eae4d066ab68e3459d73370..bea83d71a657d8f306c386f3b8d94c67c209ce95 100644 (file)
@@ -90,8 +90,63 @@ default via 10.3.64.1 dev eno1 proto static metric 100
                 '192.168.122.0/24': ['192.168.122.1']}
         ),
     ])
-    def test_parse_ip_route(self, test_input, expected):
-        assert cd._parse_ip_route(test_input) == expected
+    def test_parse_ipv4_route(self, test_input, expected):
+        assert cd._parse_ipv4_route(test_input) == expected
+
+    @pytest.mark.parametrize("test_routes, test_ips, expected", [
+        (
+"""
+::1 dev lo proto kernel metric 256 pref medium
+fdbc:7574:21fe:9200::/64 dev wlp2s0 proto ra metric 600 pref medium
+fdd8:591e:4969:6363::/64 dev wlp2s0 proto ra metric 600 pref medium
+fe80::/64 dev tun0 proto kernel metric 256 pref medium
+fe80::/64 dev wlp2s0 proto kernel metric 600 pref medium
+default dev tun0 proto static metric 50 pref medium
+default via fe80::2480:28ec:5097:3fe2 dev wlp2s0 proto ra metric 20600 pref medium
+""",
+"""
+1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
+    inet6 ::1/128 scope host 
+       valid_lft forever preferred_lft forever
+2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
+    inet6 fdd8:591e:4969:6363:4c52:cafe:8dd4:dc4/64 scope global temporary dynamic 
+       valid_lft 86394sec preferred_lft 14394sec
+    inet6 fdbc:7574:21fe:9200:4c52:cafe:8dd4:dc4/64 scope global temporary dynamic 
+       valid_lft 6745sec preferred_lft 3145sec
+    inet6 fdd8:591e:4969:6363:103a:abcd:af1f:57f3/64 scope global temporary deprecated dynamic 
+       valid_lft 86394sec preferred_lft 0sec
+    inet6 fdbc:7574:21fe:9200:103a:abcd:af1f:57f3/64 scope global temporary deprecated dynamic 
+       valid_lft 6745sec preferred_lft 0sec
+    inet6 fdd8:591e:4969:6363:a128:1234:2bdd:1b6f/64 scope global temporary deprecated dynamic 
+       valid_lft 86394sec preferred_lft 0sec
+    inet6 fdbc:7574:21fe:9200:a128:1234:2bdd:1b6f/64 scope global temporary deprecated dynamic 
+       valid_lft 6745sec preferred_lft 0sec
+    inet6 fdd8:591e:4969:6363:d581:4321:380b:3905/64 scope global temporary deprecated dynamic 
+       valid_lft 86394sec preferred_lft 0sec
+    inet6 fdbc:7574:21fe:9200:d581:4321:380b:3905/64 scope global temporary deprecated dynamic 
+       valid_lft 6745sec preferred_lft 0sec
+    inet6 fe80::1111:2222:3333:4444/64 scope link noprefixroute 
+       valid_lft forever preferred_lft forever
+12: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 state UNKNOWN qlen 100
+    inet6 fe80::cafe:cafe:cafe:cafe/64 scope link stable-privacy 
+       valid_lft forever preferred_lft forever
+""",
+            {
+                "::1": ["::1"],
+                "fdbc:7574:21fe:9200::/64": ["fdbc:7574:21fe:9200:4c52:cafe:8dd4:dc4",
+                                             "fdbc:7574:21fe:9200:103a:abcd:af1f:57f3",
+                                             "fdbc:7574:21fe:9200:a128:1234:2bdd:1b6f",
+                                             "fdbc:7574:21fe:9200:d581:4321:380b:3905"],
+                "fdd8:591e:4969:6363::/64": ["fdd8:591e:4969:6363:4c52:cafe:8dd4:dc4",
+                                             "fdd8:591e:4969:6363:103a:abcd:af1f:57f3",
+                                             "fdd8:591e:4969:6363:a128:1234:2bdd:1b6f",
+                                             "fdd8:591e:4969:6363:d581:4321:380b:3905"],
+                "fe80::/64": ["fe80::1111:2222:3333:4444",
+                              "fe80::cafe:cafe:cafe:cafe"]
+            }
+        )])
+    def test_parse_ipv6_route(self, test_routes, test_ips, expected):
+        assert cd._parse_ipv6_route(test_routes, test_ips) == expected
 
     def test_is_ipv6(self):
         cd.logger = mock.Mock()