Merge "By default, add floating IP NAT rules to each vnic on router"
This commit is contained in:
commit
854fb2098f
@ -631,6 +631,12 @@ nsxv_opts = [
|
|||||||
help=_("(Optional) Sets the network address for distributed "
|
help=_("(Optional) Sets the network address for distributed "
|
||||||
"router TLR-PLR connectivity, with "
|
"router TLR-PLR connectivity, with "
|
||||||
"<network IP>/<prefix> syntax")),
|
"<network IP>/<prefix> syntax")),
|
||||||
|
cfg.BoolOpt('bind_floatingip_to_all_interfaces', default=True,
|
||||||
|
help=_("If set to False, router will associate floating ip "
|
||||||
|
"with external interface of only, thus denying "
|
||||||
|
"connectivity between hosts on same network via "
|
||||||
|
"their floating ips. If True, floating ip will "
|
||||||
|
"be associated with all router interfaces.")),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Register the configuration options
|
# Register the configuration options
|
||||||
|
@ -213,9 +213,12 @@ class RouterSharedDriver(router_driver.RouterBaseDriver):
|
|||||||
snat, dnat = self.plugin._get_nat_rules(context, router)
|
snat, dnat = self.plugin._get_nat_rules(context, router)
|
||||||
snats.extend(snat)
|
snats.extend(snat)
|
||||||
dnats.extend(dnat)
|
dnats.extend(dnat)
|
||||||
if len(dnat) > 0:
|
if (not cfg.CONF.nsxv.bind_floatingip_to_all_interfaces and
|
||||||
|
len(dnat) > 0):
|
||||||
# Copy each DNAT rule to all vnics of the other routers,
|
# Copy each DNAT rule to all vnics of the other routers,
|
||||||
# to allow NAT-ed traffic between routers
|
# to allow NAT-ed traffic between routers
|
||||||
|
# no need for that if bind_floatingip_to_all_interfaces
|
||||||
|
# is on (default)
|
||||||
other_vnics = []
|
other_vnics = []
|
||||||
for other_router_id in router_ids:
|
for other_router_id in router_ids:
|
||||||
if other_router_id != router_id:
|
if other_router_id != router_id:
|
||||||
|
@ -539,14 +539,15 @@ class EdgeApplianceDriver(object):
|
|||||||
|
|
||||||
def _assemble_nat_rule(self, action, original_address,
|
def _assemble_nat_rule(self, action, original_address,
|
||||||
translated_address,
|
translated_address,
|
||||||
vnic_index=constants.EXTERNAL_VNIC_INDEX,
|
vnic_index=None,
|
||||||
enabled=True,
|
enabled=True,
|
||||||
protocol='any',
|
protocol='any',
|
||||||
original_port='any',
|
original_port='any',
|
||||||
translated_port='any'):
|
translated_port='any'):
|
||||||
nat_rule = {}
|
nat_rule = {}
|
||||||
nat_rule['action'] = action
|
nat_rule['action'] = action
|
||||||
nat_rule['vnic'] = vnic_index
|
if vnic_index is not None:
|
||||||
|
nat_rule['vnic'] = vnic_index
|
||||||
nat_rule['originalAddress'] = original_address
|
nat_rule['originalAddress'] = original_address
|
||||||
nat_rule['translatedAddress'] = translated_address
|
nat_rule['translatedAddress'] = translated_address
|
||||||
nat_rule['enabled'] = enabled
|
nat_rule['enabled'] = enabled
|
||||||
@ -564,31 +565,57 @@ class EdgeApplianceDriver(object):
|
|||||||
e.response)
|
e.response)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
def update_nat_rules(self, edge_id, snats, dnats):
|
def update_nat_rules(self, edge_id, snats, dnats, indices=None):
|
||||||
LOG.debug("VCNS: update nat rule\n"
|
LOG.debug("VCNS: update nat rule\n"
|
||||||
"SNAT:%(snat)s\n"
|
"SNAT:%(snat)s\n"
|
||||||
"DNAT:%(dnat)s\n", {
|
"DNAT:%(dnat)s\n"
|
||||||
'snat': snats, 'dnat': dnats})
|
"INDICES: %(index)s\n", {
|
||||||
|
'snat': snats, 'dnat': dnats, 'index': indices})
|
||||||
nat_rules = []
|
nat_rules = []
|
||||||
|
|
||||||
for dnat in dnats:
|
for dnat in dnats:
|
||||||
vnic_index = constants.EXTERNAL_VNIC_INDEX
|
vnic_index = None
|
||||||
if 'vnic_index' in dnat:
|
if 'vnic_index' in dnat:
|
||||||
vnic_index = dnat['vnic_index']
|
vnic_index = dnat['vnic_index']
|
||||||
nat_rules.append(self._assemble_nat_rule(
|
if vnic_index or not indices:
|
||||||
'dnat', dnat['dst'], dnat['translated'], vnic_index=vnic_index
|
# we are adding a predefined index or
|
||||||
))
|
# adding to all interfaces
|
||||||
nat_rules.append(self._assemble_nat_rule(
|
nat_rules.append(self._assemble_nat_rule(
|
||||||
'snat', dnat['translated'], dnat['dst'], vnic_index=vnic_index
|
'dnat', dnat['dst'], dnat['translated'],
|
||||||
))
|
vnic_index=vnic_index
|
||||||
|
))
|
||||||
|
nat_rules.append(self._assemble_nat_rule(
|
||||||
|
'snat', dnat['translated'], dnat['dst'],
|
||||||
|
vnic_index=vnic_index
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
for index in indices:
|
||||||
|
nat_rules.append(self._assemble_nat_rule(
|
||||||
|
'dnat', dnat['dst'], dnat['translated'],
|
||||||
|
vnic_index=index
|
||||||
|
))
|
||||||
|
nat_rules.append(self._assemble_nat_rule(
|
||||||
|
'snat', dnat['translated'], dnat['dst'],
|
||||||
|
vnic_index=index
|
||||||
|
))
|
||||||
|
|
||||||
for snat in snats:
|
for snat in snats:
|
||||||
vnic_index = constants.EXTERNAL_VNIC_INDEX
|
vnic_index = None
|
||||||
if 'vnic_index' in snat:
|
if 'vnic_index' in snat:
|
||||||
vnic_index = snat['vnic_index']
|
vnic_index = snat['vnic_index']
|
||||||
nat_rules.append(self._assemble_nat_rule(
|
if vnic_index or not indices:
|
||||||
'snat', snat['src'], snat['translated'], vnic_index=vnic_index
|
# we are adding a predefined index
|
||||||
))
|
# or adding to all interfaces
|
||||||
|
nat_rules.append(self._assemble_nat_rule(
|
||||||
|
'snat', snat['src'], snat['translated'],
|
||||||
|
vnic_index=vnic_index
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
for index in indices:
|
||||||
|
nat_rules.append(self._assemble_nat_rule(
|
||||||
|
'snat', snat['src'], snat['translated'],
|
||||||
|
vnic_index=index
|
||||||
|
))
|
||||||
|
|
||||||
nat = {
|
nat = {
|
||||||
'featureType': 'nat',
|
'featureType': 'nat',
|
||||||
|
@ -2299,7 +2299,29 @@ def _delete_interface(nsxv_manager, context, router_id, network_id,
|
|||||||
def update_nat_rules(nsxv_manager, context, router_id, snat, dnat):
|
def update_nat_rules(nsxv_manager, context, router_id, snat, dnat):
|
||||||
binding = nsxv_db.get_nsxv_router_binding(context.session, router_id)
|
binding = nsxv_db.get_nsxv_router_binding(context.session, router_id)
|
||||||
if binding:
|
if binding:
|
||||||
nsxv_manager.update_nat_rules(binding['edge_id'], snat, dnat)
|
bind_to_all = cfg.CONF.nsxv.bind_floatingip_to_all_interfaces
|
||||||
|
|
||||||
|
indices = None
|
||||||
|
if bind_to_all:
|
||||||
|
# from 6.2.4 onwards, unspecified vnic will result
|
||||||
|
# in binding the rule to all interfaces
|
||||||
|
ver = nsxv_manager.vcns.get_version()
|
||||||
|
if version.LooseVersion(ver) < version.LooseVersion('6.2.4'):
|
||||||
|
LOG.debug("NSX version %s requires explicit nat rule "
|
||||||
|
"for each interface", ver)
|
||||||
|
edge_id = binding['edge_id']
|
||||||
|
vnic_bindings = nsxv_db.get_edge_vnic_bindings_by_edge(
|
||||||
|
context.session, edge_id)
|
||||||
|
indices = [vnic_binding.vnic_index
|
||||||
|
for vnic_binding in vnic_bindings]
|
||||||
|
|
||||||
|
indices.append(vcns_const.EXTERNAL_VNIC_INDEX)
|
||||||
|
else:
|
||||||
|
LOG.debug("Configuring nat rules on external "
|
||||||
|
"interface only for %s", router_id)
|
||||||
|
indices = [vcns_const.EXTERNAL_VNIC_INDEX]
|
||||||
|
|
||||||
|
nsxv_manager.update_nat_rules(binding['edge_id'], snat, dnat, indices)
|
||||||
else:
|
else:
|
||||||
LOG.warning(_LW("Bindings do not exists for %s"), router_id)
|
LOG.warning(_LW("Bindings do not exists for %s"), router_id)
|
||||||
|
|
||||||
|
@ -411,6 +411,7 @@ class VcnsDriverTestCase(base.BaseTestCase):
|
|||||||
'translated': '192.168.2.1'
|
'translated': '192.168.2.1'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
result = self.vcns_driver.update_nat_rules(self.edge_id, snats, dnats)
|
result = self.vcns_driver.update_nat_rules(self.edge_id, snats, dnats)
|
||||||
self.assertTrue(result)
|
self.assertTrue(result)
|
||||||
|
|
||||||
@ -425,6 +426,97 @@ class VcnsDriverTestCase(base.BaseTestCase):
|
|||||||
self.natEquals(rules[5], snats[1])
|
self.natEquals(rules[5], snats[1])
|
||||||
self.natEquals(rules[6], snats[2])
|
self.natEquals(rules[6], snats[2])
|
||||||
|
|
||||||
|
def test_update_nat_rules_for_all_vnics(self):
|
||||||
|
self._deploy_edge()
|
||||||
|
snats = [{
|
||||||
|
'src': '192.168.1.0/24',
|
||||||
|
'translated': '10.0.0.1'
|
||||||
|
}, {
|
||||||
|
'src': '192.168.2.0/24',
|
||||||
|
'translated': '10.0.0.2'
|
||||||
|
}, {
|
||||||
|
'src': '192.168.3.0/24',
|
||||||
|
'translated': '10.0.0.3'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
dnats = [{
|
||||||
|
'dst': '100.0.0.4',
|
||||||
|
'translated': '192.168.1.1'
|
||||||
|
}, {
|
||||||
|
'dst': '100.0.0.5',
|
||||||
|
'translated': '192.168.2.1'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
indices = [0, 1, 2, 3]
|
||||||
|
result = self.vcns_driver.update_nat_rules(self.edge_id,
|
||||||
|
snats, dnats, indices)
|
||||||
|
self.assertTrue(result)
|
||||||
|
|
||||||
|
natcfg = self.vcns_driver.get_nat_config(self.edge_id)
|
||||||
|
rules = natcfg['rules']['natRulesDtos']
|
||||||
|
|
||||||
|
self.assertEqual(len(rules), 2 * len(indices) * len(dnats)
|
||||||
|
+ len(indices) * len(snats))
|
||||||
|
|
||||||
|
sorted_rules = sorted(rules, key=lambda k: k['vnic'])
|
||||||
|
for i in range(0, len(sorted_rules), 7):
|
||||||
|
self.natEquals(sorted_rules[i], dnats[0])
|
||||||
|
self.natEquals(sorted_rules[i + 1], self.snat_for_dnat(dnats[0]))
|
||||||
|
self.natEquals(sorted_rules[i + 2], dnats[1])
|
||||||
|
self.natEquals(sorted_rules[i + 3], self.snat_for_dnat(dnats[1]))
|
||||||
|
self.natEquals(sorted_rules[i + 4], snats[0])
|
||||||
|
self.natEquals(sorted_rules[i + 5], snats[1])
|
||||||
|
self.natEquals(sorted_rules[i + 6], snats[2])
|
||||||
|
|
||||||
|
def test_update_nat_rules_for_specific_vnics(self):
|
||||||
|
self._deploy_edge()
|
||||||
|
snats = [{
|
||||||
|
'src': '192.168.1.0/24',
|
||||||
|
'translated': '10.0.0.1',
|
||||||
|
'vnic_index': 5
|
||||||
|
}, {
|
||||||
|
'src': '192.168.2.0/24',
|
||||||
|
'translated': '10.0.0.2'
|
||||||
|
}, {
|
||||||
|
'src': '192.168.3.0/24',
|
||||||
|
'translated': '10.0.0.3'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
dnats = [{
|
||||||
|
'dst': '100.0.0.4',
|
||||||
|
'translated': '192.168.1.1',
|
||||||
|
'vnic_index': 2
|
||||||
|
}, {
|
||||||
|
'dst': '100.0.0.5',
|
||||||
|
'translated': '192.168.2.1'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
result = self.vcns_driver.update_nat_rules(self.edge_id, snats, dnats)
|
||||||
|
self.assertTrue(result)
|
||||||
|
|
||||||
|
natcfg = self.vcns_driver.get_nat_config(self.edge_id)
|
||||||
|
|
||||||
|
rules = natcfg['rules']['natRulesDtos']
|
||||||
|
|
||||||
|
self.assertEqual(len(rules), 2 * len(dnats) + len(snats))
|
||||||
|
|
||||||
|
self.natEquals(rules[0], dnats[0])
|
||||||
|
self.assertEqual(rules[0]['vnic'], 2)
|
||||||
|
self.natEquals(rules[1], self.snat_for_dnat(dnats[0]))
|
||||||
|
self.assertEqual(rules[1]['vnic'], 2)
|
||||||
|
self.natEquals(rules[2], dnats[1])
|
||||||
|
self.assertNotIn('vnic', rules[2])
|
||||||
|
self.natEquals(rules[3], self.snat_for_dnat(dnats[1]))
|
||||||
|
self.assertNotIn('vnic', rules[3])
|
||||||
|
self.natEquals(rules[4], snats[0])
|
||||||
|
self.assertEqual(rules[4]['vnic'], 5)
|
||||||
|
self.natEquals(rules[5], snats[1])
|
||||||
|
self.assertNotIn('vnic', rules[5])
|
||||||
|
self.natEquals(rules[6], snats[2])
|
||||||
|
self.assertNotIn('vnic', rules[6])
|
||||||
|
|
||||||
def snat_for_dnat(self, dnat):
|
def snat_for_dnat(self, dnat):
|
||||||
return {
|
return {
|
||||||
'src': dnat['translated'],
|
'src': dnat['translated'],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user