Index: neutron-9.4.2.dev21/neutron/agent/l3/dvr_local_router.py
===================================================================
--- neutron-9.4.2.dev21.orig/neutron/agent/l3/dvr_local_router.py
+++ neutron-9.4.2.dev21/neutron/agent/l3/dvr_local_router.py
@@ -65,9 +65,10 @@ class DvrLocalRouter(dvr_router_base.Dvr
         dnat_from_floatingip_to_fixedip = (
             'PREROUTING', '-d %s/32 -i %s -j DNAT --to-destination %s' % (
                 floating_ip, rtr_2_fip_name, fixed_ip))
-        snat_from_fixedip_to_floatingip = (
-            'float-snat', '-s %s/32 -j SNAT --to-source %s' % (
-                fixed_ip, floating_ip))
+        to_source = '-s %s/32 -j SNAT --to-source %s' % (fixed_ip, floating_ip)
+        if self.iptables_manager.random_fully:
+            to_source += ' --random-fully'
+        snat_from_fixedip_to_floatingip = ('float-snat', to_source)
         return [dnat_from_floatingip_to_fixedip,
                 snat_from_fixedip_to_floatingip]
 
Index: neutron-9.4.2.dev21/neutron/agent/l3/router_info.py
===================================================================
--- neutron-9.4.2.dev21.orig/neutron/agent/l3/router_info.py
+++ neutron-9.4.2.dev21/neutron/agent/l3/router_info.py
@@ -157,12 +157,14 @@ class RouterInfo(object):
         return self.router.get(lib_constants.FLOATINGIP_KEY, [])
 
     def floating_forward_rules(self, floating_ip, fixed_ip):
+        to_source = '-s %s/32 -j SNAT --to-source %s' % (fixed_ip, floating_ip)
+        if self.iptables_manager.random_fully:
+            to_source += ' --random-fully'
         return [('PREROUTING', '-d %s/32 -j DNAT --to-destination %s' %
                  (floating_ip, fixed_ip)),
                 ('OUTPUT', '-d %s/32 -j DNAT --to-destination %s' %
                  (floating_ip, fixed_ip)),
-                ('float-snat', '-s %s/32 -j SNAT --to-source %s' %
-                 (fixed_ip, floating_ip))]
+                 ('float-snat', to_source)]
 
     def floating_mangle_rules(self, floating_ip, fixed_ip, internal_mark):
         mark_traffic_to_floating_ip = (
@@ -794,19 +796,21 @@ class RouterInfo(object):
             self._prevent_snat_for_internal_traffic_rule(interface_name))
         # Makes replies come back through the router to reverse DNAT
         ext_in_mark = self.agent_conf.external_ingress_mark
-        snat_internal_traffic_to_floating_ip = (
-            'snat', '-m mark ! --mark %s/%s '
-                    '-m conntrack --ctstate DNAT '
-                    '-j SNAT --to-source %s'
-                    % (ext_in_mark, n_const.ROUTER_MARK_MASK, ex_gw_ip))
+        to_source = ('-m mark ! --mark %s/%s '
+                     '-m conntrack --ctstate DNAT '
+                     '-j SNAT --to-source %s'
+                     % (ext_in_mark, n_const.ROUTER_MARK_MASK, ex_gw_ip))
+        if self.iptables_manager.random_fully:
+            to_source += ' --random-fully'
+        snat_internal_traffic_to_floating_ip = ('snat', to_source)
         return [dont_snat_traffic_to_internal_ports_if_not_to_floating_ip,
                 snat_internal_traffic_to_floating_ip]
 
     def external_gateway_nat_snat_rules(self, ex_gw_ip, interface_name):
-        snat_normal_external_traffic = (
-            'snat', '-o %s -j SNAT --to-source %s' %
-                    (interface_name, ex_gw_ip))
-        return [snat_normal_external_traffic]
+        to_source = '-o %s -j SNAT --to-source %s' % (interface_name, ex_gw_ip)
+        if self.iptables_manager.random_fully:
+            to_source += ' --random-fully'
+        return [('snat', to_source)]
 
     def external_gateway_mangle_rules(self, interface_name):
         mark = self.agent_conf.external_ingress_mark
Index: neutron-9.4.2.dev21/neutron/agent/linux/iptables_manager.py
===================================================================
--- neutron-9.4.2.dev21.orig/neutron/agent/linux/iptables_manager.py
+++ neutron-9.4.2.dev21/neutron/agent/linux/iptables_manager.py
@@ -36,6 +36,7 @@ from neutron.agent.common import config
 from neutron.agent.linux import ip_lib
 from neutron.agent.linux import iptables_comments as ic
 from neutron.agent.linux import utils as linux_utils
+from neutron.common import constants
 from neutron.common import exceptions as n_exc
 from neutron.common import utils
 
@@ -299,6 +300,9 @@ class IptablesManager(object):
 
     """
 
+    # Flag to denote iptables supports --random-fully argument
+    _random_fully = None
+
     def __init__(self, _execute=None, state_less=False, use_ipv6=False,
                  namespace=None, binary_name=binary_name):
         if _execute:
@@ -462,6 +466,23 @@ class IptablesManager(object):
             args = ['ip', 'netns', 'exec', self.namespace] + args
         return self.execute(args, run_as_root=True).split('\n')
 
+    def _get_version(self):
+        # Output example is "iptables v1.6.2"
+        args = ['iptables', '--version']
+        version = str(self.execute(args, run_as_root=True).split()[1][1:])
+        LOG.debug("IPTables version installed: %s", version)
+        return version
+
+    @property
+    def random_fully(self):
+        if self._random_fully is not None:
+            return self._random_fully
+
+        version = self._get_version()
+        self.__class__._random_fully = utils.is_version_greater_equal(
+            version, constants.IPTABLES_RANDOM_FULLY_VERSION)
+        return self._random_fully
+
     @property
     def xlock_wait_time(self):
         # give agent some time to report back to server
Index: neutron-9.4.2.dev21/neutron/common/constants.py
===================================================================
--- neutron-9.4.2.dev21.orig/neutron/common/constants.py
+++ neutron-9.4.2.dev21/neutron/common/constants.py
@@ -151,6 +151,10 @@ L3_HA_NET_CIDR = '169.254.192.0/18'
 METADATA_CIDR = '169.254.169.254/32'
 
 
+# IPtables version to support --random-fully option.
+# Do not move this constant to neutron-lib, since it is temporary
+IPTABLES_RANDOM_FULLY_VERSION = '1.6.2'
+
 # Neutron-lib migration shim. This will emit a deprecation warning on any
 # reference to constants that have been moved out of this module and into
 # the neutron_lib.constants module.
Index: neutron-9.4.2.dev21/neutron/common/utils.py
===================================================================
--- neutron-9.4.2.dev21.orig/neutron/common/utils.py
+++ neutron-9.4.2.dev21/neutron/common/utils.py
@@ -46,6 +46,7 @@ from oslo_db import exception as db_exc
 from oslo_log import log as logging
 from oslo_utils import excutils
 from oslo_utils import importutils
+import pkg_resources
 import six
 from stevedore import driver
 
@@ -398,6 +399,12 @@ def is_port_trusted(port):
     return port['device_owner'].startswith(n_const.DEVICE_OWNER_NETWORK_PREFIX)
 
 
+def is_version_greater_equal(version1, version2):
+    """Returns True if version1 is greater or equal than version2 else False"""
+    return (pkg_resources.parse_version(version1) >=
+            pkg_resources.parse_version(version2))
+
+
 class DelayedStringRenderer(object):
     """Takes a callable and its args and calls when __str__ is called
 
Index: neutron-9.4.2.dev21/neutron/tests/unit/agent/l3/test_agent.py
===================================================================
--- neutron-9.4.2.dev21.orig/neutron/tests/unit/agent/l3/test_agent.py
+++ neutron-9.4.2.dev21/neutron/tests/unit/agent/l3/test_agent.py
@@ -18,6 +18,7 @@ from itertools import chain as iter_chai
 from itertools import combinations as iter_combinations
 
 import eventlet
+import fixtures
 import mock
 import netaddr
 from neutron_lib import constants as lib_constants
@@ -184,10 +185,27 @@ class BasicRouterOperationsFramework(bas
         ri.process(agent)
 
 
+class IptablesFixture(fixtures.Fixture):
+    def _setUp(self):
+        # We MUST save and restore random_fully because it is a class
+        # attribute and could change state in some tests, which can cause
+        # the other router test cases to randomly fail due to race conditions.
+        self.random_fully = iptables_manager.IptablesManager.random_fully
+        iptables_manager.IptablesManager.random_fully = True
+        self.addCleanup(self._reset)
+
+    def _reset(self):
+        iptables_manager.IptablesManager.random_fully = self.random_fully
+
+
 class TestBasicRouterOperations(BasicRouterOperationsFramework):
+    def setUp(self):
+        super(TestBasicRouterOperations, self).setUp()
+        self.useFixture(IptablesFixture())
     def test_request_id_changes(self):
         a = l3_agent.L3NATAgent(HOSTNAME, self.conf)
         self.assertNotEqual(a.context.request_id, a.context.request_id)
+        self.useFixture(IptablesFixture)
 
     def test_init_ha_conf(self):
         with mock.patch('os.path.dirname', return_value='/etc/ha/'):
@@ -864,7 +882,7 @@ class TestBasicRouterOperations(BasicRou
         self._test_external_gateway_action('remove', router, dual_stack=True)
 
     def _verify_snat_mangle_rules(self, nat_rules, mangle_rules, router,
-                                  negate=False):
+                                  random_fully, negate=False):
         interfaces = router[lib_constants.INTERFACE_KEY]
         source_cidrs = []
         for iface in interfaces:
@@ -875,13 +893,18 @@ class TestBasicRouterOperations(BasicRou
                 source_cidrs.append(source_cidr)
         source_nat_ip = router['gw_port']['fixed_ips'][0]['ip_address']
         interface_name = ('qg-%s' % router['gw_port']['id'])[:14]
+        mask_rule = ('-m mark ! --mark 0x2/%s -m conntrack --ctstate DNAT '
+                     '-j SNAT --to-source %s' %
+                     (n_const.ROUTER_MARK_MASK, source_nat_ip))
+        snat_rule = ('-o %s -j SNAT --to-source %s' %
+                     (interface_name, source_nat_ip))
+        if random_fully:
+            mask_rule += ' --random-fully'
+            snat_rule += ' --random-fully'
         expected_rules = [
             '! -i %s ! -o %s -m conntrack ! --ctstate DNAT -j ACCEPT' %
             (interface_name, interface_name),
-            '-o %s -j SNAT --to-source %s' % (interface_name, source_nat_ip),
-            '-m mark ! --mark 0x2/%s -m conntrack --ctstate DNAT '
-            '-j SNAT --to-source %s' %
-            (n_const.ROUTER_MARK_MASK, source_nat_ip)]
+            mask_rule, snat_rule]
         for r in nat_rules:
             if negate:
                 self.assertNotIn(r.rule, expected_rules)
@@ -1271,7 +1294,8 @@ class TestBasicRouterOperations(BasicRou
         ri.get_external_device_name = mock.Mock(return_value='exgw')
         self._test_process_floating_ip_addresses_add(ri, agent)
 
-    def test_process_router_snat_disabled(self):
+    def _test_process_router_snat_disabled(self, random_fully):
+        iptables_manager.IptablesManager.random_fully = random_fully
         agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
         router = l3_test_common.prepare_router_data(enable_snat=True)
         ri = l3router.RouterInfo(router['id'], router, **self.ri_kwargs)
@@ -1295,10 +1319,17 @@ class TestBasicRouterOperations(BasicRou
             if r not in ri.iptables_manager.ipv4['mangle'].rules]
         self.assertEqual(1, len(mangle_rules_delta))
         self._verify_snat_mangle_rules(nat_rules_delta, mangle_rules_delta,
-                                       router)
+                                       router, random_fully)
         self.assertEqual(1, self.send_adv_notif.call_count)
 
-    def test_process_router_snat_enabled(self):
+    def test_process_router_snat_disabled_random_fully(self):
+        self._test_process_router_snat_disabled(True)
+
+    def test_process_router_snat_disabled_random_fully_false(self):
+        self._test_process_router_snat_disabled(False)
+
+    def _test_process_router_snat_enabled(self, random_fully):
+        iptables_manager.IptablesManager.random_fully = random_fully
         agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
         router = l3_test_common.prepare_router_data(enable_snat=False)
         ri = l3router.RouterInfo(router['id'], router, **self.ri_kwargs)
@@ -1322,9 +1353,15 @@ class TestBasicRouterOperations(BasicRou
             if r not in orig_mangle_rules]
         self.assertEqual(1, len(mangle_rules_delta))
         self._verify_snat_mangle_rules(nat_rules_delta, mangle_rules_delta,
-                                       router)
+                                       router, random_fully)
         self.assertEqual(1, self.send_adv_notif.call_count)
 
+    def test_process_router_snat_enabled_random_fully(self):
+        self._test_process_router_snat_enabled(True)
+
+    def test_process_router_snat_enabled_random_fully_false(self):
+        self._test_process_router_snat_enabled(False)
+
     def _test_update_routing_table(self, is_snat_host=True):
         router = l3_test_common.prepare_router_data()
         uuid = router['id']
@@ -1925,11 +1962,12 @@ class TestBasicRouterOperations(BasicRou
 
         jump_float_rule = "-A %s-snat -j %s-float-snat" % (wrap_name,
                                                            wrap_name)
-        snat_rule1 = ("-A %s-snat -o iface -j SNAT --to-source %s") % (
+        snat_rule1 = ("-A %s-snat -o iface -j SNAT --to-source %s "
+                      "--random-fully") % (
             wrap_name, ex_gw_port['fixed_ips'][0]['ip_address'])
         snat_rule2 = ("-A %s-snat -m mark ! --mark 0x2/%s "
                       "-m conntrack --ctstate DNAT "
-                      "-j SNAT --to-source %s") % (
+                      "-j SNAT --to-source %s --random-fully") % (
             wrap_name, n_const.ROUTER_MARK_MASK,
             ex_gw_port['fixed_ips'][0]['ip_address'])
 
Index: neutron-9.4.2.dev21/neutron/tests/unit/agent/l3/test_dvr_local_router.py
===================================================================
--- neutron-9.4.2.dev21.orig/neutron/tests/unit/agent/l3/test_dvr_local_router.py
+++ neutron-9.4.2.dev21/neutron/tests/unit/agent/l3/test_dvr_local_router.py
@@ -186,6 +186,68 @@ class TestDvrRouterOperations(base.BaseT
 
         self.assertEqual([{'host': HOSTNAME}], fips)
 
+    def test_floating_forward_rules(self):
+        router = mock.MagicMock()
+        router.get.return_value = [{'host': HOSTNAME},
+                                   {'host': mock.sentinel.otherhost}]
+        ri = self._create_router(router)
+        floating_ip = '15.1.2.3'
+        rtr_2_fip_name = 'fake_router'
+        fixed_ip = '192.168.0.1'
+        fip = {'id': _uuid(),
+               'fixed_ip_address': '192.168.0.1',
+               'floating_ip_address': '15.1.2.3'}
+        instance = mock.Mock()
+        instance.get_rtr_ext_device_name = mock.Mock(
+                                               return_value=rtr_2_fip_name)
+        ri.fip_ns = instance
+        dnat_from_floatingip_to_fixedip = (
+            'PREROUTING', '-d %s/32 -i %s -j DNAT --to-destination %s' % (
+                floating_ip, rtr_2_fip_name, fixed_ip))
+        to_source = '-s %s/32 -j SNAT --to-source %s' % (fixed_ip, floating_ip)
+
+        if ri.iptables_manager.random_fully:
+            to_source += ' --random-fully'
+        snat_from_fixedip_to_floatingip = ('float-snat', to_source)
+        actual = ri.floating_forward_rules(fip.get('floating_ip_address'),
+                                           fip.get('fixed_ip_address'))
+        expected = [dnat_from_floatingip_to_fixedip,
+                    snat_from_fixedip_to_floatingip]
+        self.assertEqual(expected, actual)
+
+    def test_floating_mangle_rules_no_fip_ns(self):
+        router = mock.MagicMock()
+        router.get.return_value = [{'host': HOSTNAME},
+                                   {'host': mock.sentinel.otherhost}]
+        ri = self._create_router(router)
+        floating_ip = mock.Mock()
+        fixed_ip = mock.Mock()
+        internal_mark = mock.Mock()
+        self.assertFalse(ri.floating_mangle_rules(floating_ip, fixed_ip,
+                                                  internal_mark))
+
+    def test_floating_mangle_rules(self):
+        router = mock.MagicMock()
+        router.get.return_value = [{'host': HOSTNAME},
+                                   {'host': mock.sentinel.otherhost}]
+        ri = self._create_router(router)
+        floating_ip = '15.1.2.3'
+        fixed_ip = '192.168.0.1'
+        internal_mark = 'fake_mark'
+        rtr_2_fip_name = 'fake_router'
+        instance = mock.Mock()
+        instance.get_rtr_ext_device_name = mock.Mock(
+                                               return_value=rtr_2_fip_name)
+        ri.fip_ns = instance
+        mark_traffic_to_floating_ip = (
+            'floatingip', '-d %s/32 -i %s -j MARK --set-xmark %s' % (
+                floating_ip, rtr_2_fip_name, internal_mark))
+        mark_traffic_from_fixed_ip = (
+            'FORWARD', '-s %s/32 -j $float-snat' % fixed_ip)
+        actual = ri.floating_mangle_rules(floating_ip, fixed_ip, internal_mark)
+        expected = [mark_traffic_to_floating_ip, mark_traffic_from_fixed_ip]
+        self.assertEqual(expected, actual)
+
     @mock.patch.object(ip_lib, 'send_ip_addr_adv_notif')
     @mock.patch.object(ip_lib, 'IPDevice')
     @mock.patch.object(ip_lib, 'IPRule')
Index: neutron-9.4.2.dev21/neutron/tests/unit/common/test_utils.py
===================================================================
--- neutron-9.4.2.dev21.orig/neutron/tests/unit/common/test_utils.py
+++ neutron-9.4.2.dev21/neutron/tests/unit/common/test_utils.py
@@ -652,6 +652,17 @@ class TestIpVersionFromInt(base.BaseTest
                           8)
 
 
+class TestIsVersionGreaterEqual(base.BaseTestCase):
+    def test_is_version_greater_equal_greater(self):
+        self.assertTrue(utils.is_version_greater_equal('1.6.2', '1.6.0'))
+
+    def test_is_version_greater_equal_equal(self):
+        self.assertTrue(utils.is_version_greater_equal('1.6.2', '1.6.2'))
+
+    def test_is_version_greater_equal_less(self):
+        self.assertFalse(utils.is_version_greater_equal('1.6.0', '1.6.2'))
+
+
 class TestDelayedStringRenderer(base.BaseTestCase):
     def test_call_deferred_until_str(self):
         my_func = mock.MagicMock(return_value='Brie cheese!')
