From 98618644ce3c36eabfcc0aea49e7962b0506a567 Mon Sep 17 00:00:00 2001
From: John Schwarz <jschwarz@redhat.com>
Date: Wed, 12 Aug 2015 13:39:28 +0300
Subject: [PATCH] Add configurable options for HA networks

The L3 HA mechanism creates a project network for HA (VRRP) traffic
among routers. The HA project network uses the first (default) network
type in 'tenant_network_types'. Depending on the environment, this
combination may not provide a desirable path for HA traffic. For
example, some operators may prefer to use a specific network for HA
traffic to prevent split-brain issues.

This patch adds configurable options that target the network_type and
the physical_network of the created HA network.

Doc-Impact
Closes-Bug: #1481443
Change-Id: I3527a780179b5982d6e0eb0b8c32d6dafeeab730
---
 etc/neutron.conf                           | 11 +++++++++++
 neutron/db/l3_hamode_db.py                 | 20 ++++++++++++++++++++
 neutron/tests/unit/db/test_l3_hamode_db.py | 11 +++++++++++
 3 files changed, 42 insertions(+)

diff --git a/etc/neutron.conf b/etc/neutron.conf
index ca3baa9cf32..d3ac78de296 100644
--- a/etc/neutron.conf
+++ b/etc/neutron.conf
@@ -256,6 +256,17 @@
 #
 # Enable snat by default on external gateway when available
 # enable_snat_by_default = True
+#
+# The network type to use when creating the HA network for an HA router.
+# By default or if empty, the first 'tenant_network_types'
+# is used. This is helpful when the VRRP traffic should use a specific
+# network which not the default one.
+# ha_network_type =
+# Example: ha_network_type = flat
+#
+# The physical network name with which the HA network can be created.
+# ha_network_physical_name =
+# Example: ha_network_physical_name = physnet1
 # =========== end of items for l3 extension =======
 
 # =========== items for metadata proxy configuration ==============
diff --git a/neutron/db/l3_hamode_db.py b/neutron/db/l3_hamode_db.py
index 8adc0307855..0d9b0bb3965 100644
--- a/neutron/db/l3_hamode_db.py
+++ b/neutron/db/l3_hamode_db.py
@@ -30,6 +30,7 @@ from neutron.db import model_base
 from neutron.db import models_v2
 from neutron.extensions import l3_ext_ha_mode as l3_ha
 from neutron.extensions import portbindings
+from neutron.extensions import providernet
 from neutron.i18n import _LI
 
 VR_ID_RANGE = set(range(1, 255))
@@ -53,6 +54,15 @@ L3_HA_OPTS = [
     cfg.StrOpt('l3_ha_net_cidr',
                default='169.254.192.0/18',
                help=_('Subnet used for the l3 HA admin network.')),
+    cfg.StrOpt('l3_ha_network_type', default='',
+               help=_("The network type to use when creating the HA network "
+                      "for an HA router. By default or if empty, the first "
+                      "'tenant_network_types' is used. This is helpful when "
+                      "the VRRP traffic should use a specific network which "
+                      "is not the default one.")),
+    cfg.StrOpt('l3_ha_network_physical_name', default='',
+               help=_("The physical network name with which the HA network "
+                      "can be created."))
 ]
 cfg.CONF.register_opts(L3_HA_OPTS)
 
@@ -230,6 +240,14 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin):
             context.session.add(ha_network)
         return ha_network
 
+    def _add_ha_network_settings(self, network):
+        if cfg.CONF.l3_ha_network_type:
+            network[providernet.NETWORK_TYPE] = cfg.CONF.l3_ha_network_type
+
+        if cfg.CONF.l3_ha_network_physical_name:
+            network[providernet.PHYSICAL_NETWORK] = (
+                cfg.CONF.l3_ha_network_physical_name)
+
     def _create_ha_network(self, context, tenant_id):
         admin_ctx = context.elevated()
 
@@ -239,6 +257,8 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin):
                  'shared': False,
                  'admin_state_up': True,
                  'status': constants.NET_STATUS_ACTIVE}}
+        self._add_ha_network_settings(args['network'])
+
         network = self._core_plugin.create_network(admin_ctx, args)
         try:
             ha_network = self._create_ha_network_tenant_binding(admin_ctx,
diff --git a/neutron/tests/unit/db/test_l3_hamode_db.py b/neutron/tests/unit/db/test_l3_hamode_db.py
index e988c400726..69a6826dfe8 100644
--- a/neutron/tests/unit/db/test_l3_hamode_db.py
+++ b/neutron/tests/unit/db/test_l3_hamode_db.py
@@ -29,6 +29,7 @@ from neutron.db import l3_hamode_db
 from neutron.extensions import l3
 from neutron.extensions import l3_ext_ha_mode
 from neutron.extensions import portbindings
+from neutron.extensions import providernet
 from neutron import manager
 from neutron.scheduler import l3_agent_scheduler
 from neutron.tests.common import helpers
@@ -178,6 +179,16 @@ class L3HATestCase(L3HATestFramework):
         router = self._create_router(ha=False)
         self.assertFalse(router['ha'])
 
+    def test_add_ha_network_settings(self):
+        cfg.CONF.set_override('l3_ha_network_type', 'abc')
+        cfg.CONF.set_override('l3_ha_network_physical_name', 'def')
+
+        network = {}
+        self.plugin._add_ha_network_settings(network)
+
+        self.assertEqual('abc', network[providernet.NETWORK_TYPE])
+        self.assertEqual('def', network[providernet.PHYSICAL_NETWORK])
+
     def test_router_create_with_ha_conf_enabled(self):
         cfg.CONF.set_override('l3_ha', True)