Fix VRRP gateway IP conflict on redundant VPC routers with external network providers (Netris/NSX) (#130)

Co-authored-by: Pearl Dsilva <pearl1954@gmail.com>
diff --git a/systemvm/debian/opt/cloud/bin/cs/CsAddress.py b/systemvm/debian/opt/cloud/bin/cs/CsAddress.py
index 37ca897..bdc2c91 100755
--- a/systemvm/debian/opt/cloud/bin/cs/CsAddress.py
+++ b/systemvm/debian/opt/cloud/bin/cs/CsAddress.py
@@ -23,12 +23,29 @@
 from . import CsHelper
 from .CsDatabag import CsDataBag
 from .CsApp import CsApache, CsDnsmasq, CsPasswdSvc
+from .CsGuestNetwork import CsGuestNetwork
 from .CsRoute import CsRoute
 from .CsRule import CsRule
 from .CsStaticRoutes import CsStaticRoutes
 
 VRRP_TYPES = ['guest']
 
+
+def _guest_needs_vrrp(device, config):
+    """
+    A guest interface only needs to be managed by keepalived (i.e. have the
+    network gateway floated onto it as a VRRP virtual address) when the
+    CloudStack virtual router is actually the gateway for that network.
+    When an external provider (e.g. Netris) owns the gateway/source NAT for
+    the tier, the router must not also claim the gateway IP.
+    If no guestnetwork data is found for the device, default to the
+    historical behaviour (needs vrrp) to avoid regressing existing setups.
+    """
+    gn = CsGuestNetwork(device, config)
+    if gn.is_guestnetwork():
+        return gn.is_vr_guest_gateway()
+    return True
+
 class CsAddress(CsDataBag):
 
     def compare(self):
@@ -99,7 +116,7 @@
         Returns if the ip needs to be managed by keepalived or not
         """
         if "nw_type" in o and o['nw_type'] in VRRP_TYPES:
-            return True
+            return _guest_needs_vrrp(o.get('device'), self.config)
         return False
 
     def get_control_if(self):
@@ -229,7 +246,7 @@
         Returns if the ip needs to be managed by keepalived or not
         """
         if "nw_type" in self.address and self.address['nw_type'] in VRRP_TYPES:
-            return True
+            return _guest_needs_vrrp(self.get_device(), self.config)
         return False
 
     def is_control(self):
@@ -909,7 +926,7 @@
         Returns if the ip needs to be managed by keepalived or not
         """
         if "nw_type" in self.address and self.address['nw_type'] in VRRP_TYPES:
-            return True
+            return _guest_needs_vrrp(self.dev, self.config)
         return False
 
     def is_public(self):