]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Replace FLOATING_IP_CIDR_SUFFIX constant with utils
authorCarl Baldwin <carl.baldwin@hp.com>
Fri, 16 Jan 2015 19:39:46 +0000 (19:39 +0000)
committerBrian Haley <brian.haley@hp.com>
Wed, 21 Jan 2015 16:15:38 +0000 (11:15 -0500)
FLOATING_IP_CIDR_SUFFIX is a global constant used in manipulating ip
addresses and cidrs as string.  This patch replaces that with
well-tested utilities for doing the conversions more safely and
readably.

Change-Id: I96c79b1ada549ed4bd09a853a8019ff54b2888e2
Partially-Implements: bp/restructure-l3-agent

neutron/agent/l3/agent.py
neutron/common/constants.py
neutron/common/utils.py
neutron/tests/functional/agent/test_l3_agent.py
neutron/tests/unit/test_common_utils.py
neutron/tests/unit/test_l3_agent.py

index f973bc9f69ee0f4c549cfd10aadb4ea7ccc04070..33f77ac16f336153a5737c826d80d89769e0f700 100644 (file)
@@ -58,7 +58,6 @@ NS_PREFIX = 'qrouter-'
 INTERNAL_DEV_PREFIX = 'qr-'
 EXTERNAL_DEV_PREFIX = 'qg-'
 RPC_LOOP_INTERVAL = 1
-FLOATING_IP_CIDR_SUFFIX = '/32'
 
 
 class L3PluginApi(object):
@@ -654,7 +653,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
 
     def _add_floating_ip(self, ri, fip, interface_name, device):
         fip_ip = fip['floating_ip_address']
-        ip_cidr = str(fip_ip) + FLOATING_IP_CIDR_SUFFIX
+        ip_cidr = common_utils.ip_to_cidr(fip_ip)
 
         if ri.is_ha:
             self._add_vip(ri, ip_cidr, interface_name)
@@ -716,7 +715,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
         # Loop once to ensure that floating ips are configured.
         for fip in floating_ips:
             fip_ip = fip['floating_ip_address']
-            ip_cidr = str(fip_ip) + FLOATING_IP_CIDR_SUFFIX
+            ip_cidr = common_utils.ip_to_cidr(fip_ip)
             new_cidrs.add(ip_cidr)
             fip_statuses[fip['id']] = l3_constants.FLOATINGIP_STATUS_ACTIVE
             if ip_cidr not in existing_cidrs:
@@ -724,8 +723,8 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
                     ri, fip, interface_name, device)
 
         fips_to_remove = (
-            ip_cidr for ip_cidr in existing_cidrs - new_cidrs if
-            ip_cidr.endswith(FLOATING_IP_CIDR_SUFFIX))
+            ip_cidr for ip_cidr in existing_cidrs - new_cidrs
+            if common_utils.is_cidr_host(ip_cidr))
         for ip_cidr in fips_to_remove:
             self._remove_floating_ip(ri, device, ip_cidr)
 
@@ -781,7 +780,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
         # This avoids unnecessarily removing those addresses and
         # causing a momentarily network outage.
         floating_ips = self.get_floating_ips(ri)
-        preserve_ips = [ip['floating_ip_address'] + FLOATING_IP_CIDR_SUFFIX
+        preserve_ips = [common_utils.ip_to_cidr(ip['floating_ip_address'])
                         for ip in floating_ips]
 
         self._external_gateway_added(ri, ex_gw_port, interface_name,
@@ -803,7 +802,7 @@ class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,
         else:
             ns_name = ri.ns_name
             floating_ips = self.get_floating_ips(ri)
-            preserve_ips = [ip['floating_ip_address'] + FLOATING_IP_CIDR_SUFFIX
+            preserve_ips = [common_utils.ip_to_cidr(ip['floating_ip_address'])
                             for ip in floating_ips]
 
         self._external_gateway_added(ri, ex_gw_port, interface_name,
index c70773b85e60d6e89c29dcab2474c8ded0606322..54f671ba35b61059b0bff61ae7c1ea11ca0aaf90 100644 (file)
@@ -61,6 +61,8 @@ MINIMUM_AGENTS_FOR_HA = 2
 
 IPv4 = 'IPv4'
 IPv6 = 'IPv6'
+IPv4_BITS = 32
+IPv6_BITS = 128
 
 DHCP_RESPONSE_PORT = 68
 
index b5256a047fbdf27bb18571d5610f439c1eadece8..49103edd15a47c54c84defa898c0dbbb571b8bb0 100644 (file)
@@ -23,6 +23,7 @@ import functools
 import hashlib
 import logging as std_logging
 import multiprocessing
+import netaddr
 import os
 import random
 import signal
@@ -369,3 +370,33 @@ def get_keystone_url(conf):
              'port': conf.auth_port})
     # NOTE(ihrachys): all existing consumers assume version 2.0
     return '%s/v2.0/' % auth_uri
+
+
+def ip_to_cidr(ip, prefix=None):
+    """Convert an ip with no prefix to cidr notation
+
+    :param ip: An ipv4 or ipv6 address.  Convertable to netaddr.IPNetwork.
+    :param prefix: Optional prefix.  If None, the default 32 will be used for
+        ipv4 and 128 for ipv6.
+    """
+    net = netaddr.IPNetwork(ip)
+    if prefix is not None:
+        # Can't pass ip and prefix separately.  Must concatenate strings.
+        net = netaddr.IPNetwork(str(net.ip) + '/' + str(prefix))
+    return str(net)
+
+
+def is_cidr_host(cidr):
+    """Determines if the cidr passed in represents a single host network
+
+    :param cidr: Either an ipv4 or ipv6 cidr.
+    :returns: True if the cidr is /32 for ipv4 or /128 for ipv6.
+    :raises ValueError: raises if cidr does not contain a '/'.  This disallows
+        plain IP addresses specifically to avoid ambiguity.
+    """
+    if '/' not in str(cidr):
+        raise ValueError("cidr doesn't contain a '/'")
+    net = netaddr.IPNetwork(cidr)
+    if net.version == 4:
+        return net.prefixlen == q_const.IPv4_BITS
+    return net.prefixlen == q_const.IPv6_BITS
index 505dcd7f25c9acc643e05a069480c13f263d0b14..a24ad126cba82c6fc279e01647bdd4ddae42fc85 100644 (file)
@@ -24,7 +24,6 @@ import webob.dec
 import webob.exc
 
 from neutron.agent.common import config as agent_config
-from neutron.agent.l3 import agent as l3_agent
 from neutron.agent import l3_agent as l3_agent_main
 from neutron.agent.linux import dhcp
 from neutron.agent.linux import external_process
@@ -32,6 +31,7 @@ from neutron.agent.linux import ip_lib
 from neutron.agent.metadata import agent as metadata_agent
 from neutron.common import config as common_config
 from neutron.common import constants as l3_constants
+from neutron.common import utils as common_utils
 from neutron.openstack.common import log as logging
 from neutron.openstack.common import uuidutils
 from neutron.services import advanced_service as adv_svc
@@ -150,9 +150,8 @@ class L3AgentTestFramework(base.BaseOVSLinuxTestCase):
         internal_device_name = self.agent.get_internal_device_name(
             internal_port['id'])
         internal_device_cidr = internal_port['ip_cidr']
-        floating_ip_cidr = (
-            self.agent.get_floating_ips(router)[0]
-            ['floating_ip_address'] + l3_agent.FLOATING_IP_CIDR_SUFFIX)
+        floating_ip_cidr = common_utils.ip_to_cidr(
+            self.agent.get_floating_ips(router)[0]['floating_ip_address'])
         default_gateway_ip = external_port['subnet'].get('gateway_ip')
 
         return """vrrp_sync_group VG_1 {
index c4dfb5a1c0094c8a8b003797df25ceb75c35739c..dd16a2d972888566819062f5aa90c5da7361381b 100644 (file)
@@ -14,6 +14,7 @@
 
 import eventlet
 import mock
+import netaddr
 import testtools
 
 from neutron.common import constants
@@ -559,3 +560,60 @@ class TestDvrServices(base.BaseTestCase):
 
     def test_is_dvr_serviced_with_vm_port(self):
         self._test_is_dvr_serviced('compute:', True)
+
+
+class TestIpToCidr(base.BaseTestCase):
+    def test_ip_to_cidr_ipv4_default(self):
+        self.assertEqual('15.1.2.3/32', utils.ip_to_cidr('15.1.2.3'))
+
+    def test_ip_to_cidr_ipv4_prefix(self):
+        self.assertEqual('15.1.2.3/24', utils.ip_to_cidr('15.1.2.3', 24))
+
+    def test_ip_to_cidr_ipv4_netaddr(self):
+        ip_address = netaddr.IPAddress('15.1.2.3')
+        self.assertEqual('15.1.2.3/32', utils.ip_to_cidr(ip_address))
+
+    def test_ip_to_cidr_ipv4_bad_prefix(self):
+        self.assertRaises(netaddr.core.AddrFormatError,
+                          utils.ip_to_cidr, '15.1.2.3', 33)
+
+    def test_ip_to_cidr_ipv6_default(self):
+        self.assertEqual('::1/128', utils.ip_to_cidr('::1'))
+
+    def test_ip_to_cidr_ipv6_prefix(self):
+        self.assertEqual('::1/64', utils.ip_to_cidr('::1', 64))
+
+    def test_ip_to_cidr_ipv6_bad_prefix(self):
+        self.assertRaises(netaddr.core.AddrFormatError,
+                          utils.ip_to_cidr, '2000::1', 129)
+
+
+class TestCidrIsHost(base.BaseTestCase):
+    def test_is_cidr_host_ipv4(self):
+        self.assertTrue(utils.is_cidr_host('15.1.2.3/32'))
+
+    def test_is_cidr_host_ipv4_not_cidr(self):
+        self.assertRaises(ValueError,
+                          utils.is_cidr_host,
+                          '15.1.2.3')
+
+    def test_is_cidr_host_ipv6(self):
+        self.assertTrue(utils.is_cidr_host('2000::1/128'))
+
+    def test_is_cidr_host_ipv6_netaddr(self):
+        net = netaddr.IPNetwork("2000::1")
+        self.assertTrue(utils.is_cidr_host(net))
+
+    def test_is_cidr_host_ipv6_32(self):
+        self.assertFalse(utils.is_cidr_host('2000::1/32'))
+
+    def test_is_cidr_host_ipv6_not_cidr(self):
+        self.assertRaises(ValueError,
+                          utils.is_cidr_host,
+                          '2000::1')
+
+    def test_is_cidr_host_ipv6_not_cidr_netaddr(self):
+        ip_address = netaddr.IPAddress("2000::3")
+        self.assertRaises(ValueError,
+                          utils.is_cidr_host,
+                          ip_address)
index 0a94eeae731e01d1a9b89fd0ee7394fa9ab73936..ed0250a16bc9103508fb0fe2328602fa2670efd3 100644 (file)
@@ -36,6 +36,7 @@ from neutron.agent.metadata import driver as metadata_driver
 from neutron.common import config as base_config
 from neutron.common import constants as l3_constants
 from neutron.common import exceptions as n_exc
+from neutron.common import utils as common_utils
 from neutron.i18n import _LE
 from neutron.openstack.common import log
 from neutron.openstack.common import uuidutils
@@ -1921,8 +1922,7 @@ class TestBasicRouterOperations(base.BaseTestCase):
                'port_id': _uuid()}
         agent.agent_gateway_port = agent_gw_port
         ri.rtr_fip_subnet = lla.LinkLocalAddressPair('169.254.30.42/31')
-        ip_cidr = str(fip['floating_ip_address']) + (
-            l3_agent.FLOATING_IP_CIDR_SUFFIX)
+        ip_cidr = common_utils.ip_to_cidr(fip['floating_ip_address'])
         agent.floating_ip_added_dist(ri, fip, ip_cidr)
         self.mock_rule.add_rule_from.assert_called_with('192.168.0.1',
                                                         16, FIP_PRI)