Add dhcp metadata host-route support
At NSXv version 6.2.3 and higher, dhcp options 121,66/67,150 and 26 is supported. This patch enhanced dhcp metadata support via using option121 to insert metadata host route into VMs. So that VM doesn't need to insert a metadata host route manually for dhcp metadata support case. Change-Id: I1e051903f5b136308634346c6d546118bfc9bbe9
This commit is contained in:
parent
c946784134
commit
b882b0cacf
@ -199,6 +199,15 @@
|
||||
# logged.
|
||||
# log_security_groups_allowed_traffic = False
|
||||
|
||||
# (Optional) In some cases the Neutron router is not present to provide the
|
||||
# metadata IP but the DHCP server can be used to provide this info. Setting
|
||||
# this value will force the DHCP edge server to append specific host routes
|
||||
# to the DHCP request. If this option is set, then the metadata service will
|
||||
# be activated for all the dhcp enabled networks.
|
||||
# Note: this option can only be supported at NSX manager version 6.2.3 or
|
||||
# higher
|
||||
# dhcp_force_metadata = True
|
||||
|
||||
[nsx]
|
||||
# Maximum number of ports for each bridged logical switch
|
||||
# The recommended value for this parameter varies with NSX version
|
||||
|
@ -417,6 +417,14 @@ nsxv_opts = [
|
||||
default=False,
|
||||
help=_("Indicates whether distributed-firewall "
|
||||
"security-groups allowed traffic is logged")),
|
||||
cfg.BoolOpt('dhcp_force_metadata', default=True,
|
||||
help=_("In some cases the Neutron router is not present to "
|
||||
"provide the metadata IP but the DHCP server can be "
|
||||
"used to provide this info. Setting this value will "
|
||||
"force the DHCP server to append specific host routes "
|
||||
"to the DHCP request. If this option is set, then the "
|
||||
"metadata service will be activated for all the "
|
||||
"dhcp enabled networks.")),
|
||||
]
|
||||
|
||||
# Register the configuration options
|
||||
|
@ -1196,6 +1196,24 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
|
||||
return False
|
||||
|
||||
def _get_dhcp_ip_addr_from_subnet(self, context, subnet_id):
|
||||
dhcp_port_filters = {'fixed_ips': {'subnet_id': [subnet_id]},
|
||||
'device_owner': [constants.DEVICE_OWNER_DHCP]}
|
||||
dhcp_ports = self.get_ports(context, filters=dhcp_port_filters)
|
||||
if dhcp_ports and dhcp_ports[0].get('fixed_ips'):
|
||||
return dhcp_ports[0]['fixed_ips'][0]['ip_address']
|
||||
|
||||
def is_dhcp_metadata(self, context, subnet_id):
|
||||
try:
|
||||
subnet = self.get_subnet(context, subnet_id)
|
||||
except n_exc.SubnetNotFound:
|
||||
LOG.debug("subnet %s not found to determine its dhcp meta",
|
||||
subnet_id)
|
||||
return False
|
||||
return bool(subnet['enable_dhcp'] and
|
||||
self.metadata_proxy_handler and
|
||||
cfg.CONF.nsxv.dhcp_force_metadata)
|
||||
|
||||
def create_subnet(self, context, subnet):
|
||||
"""Create subnet on nsx_v provider network.
|
||||
|
||||
@ -1284,7 +1302,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
update_dns_search_domain = self._process_subnet_ext_attr_update(
|
||||
context.session, subnet, s)
|
||||
if (gateway_ip != subnet['gateway_ip'] or update_dns_search_domain or
|
||||
set(orig['dns_nameservers']) != set(subnet['dns_nameservers'])):
|
||||
set(orig['dns_nameservers']) != set(subnet['dns_nameservers']) or
|
||||
enable_dhcp and not subnet['enable_dhcp']):
|
||||
# Need to ensure that all of the subnet attributes will be reloaded
|
||||
# when creating the edge bindings. Without adding this the original
|
||||
# subnet details are provided.
|
||||
|
@ -17,6 +17,7 @@ from distutils import version
|
||||
import eventlet
|
||||
import netaddr
|
||||
import random
|
||||
import six
|
||||
from sqlalchemy import exc as db_base_exc
|
||||
import time
|
||||
|
||||
@ -115,6 +116,19 @@ class EdgeManager(object):
|
||||
self.per_interface_rp_filter = self._get_per_edge_rp_filter_state()
|
||||
self.worker_pool = eventlet.GreenPool(WORKER_POOL_SIZE)
|
||||
self._check_backup_edge_pools()
|
||||
self._validate_new_features()
|
||||
|
||||
def _validate_new_features(self):
|
||||
self.is_dhcp_opt_enabled = False
|
||||
|
||||
ver = self.nsxv_manager.vcns.get_version()
|
||||
if version.LooseVersion(ver) >= version.LooseVersion('6.2.3'):
|
||||
self.is_dhcp_opt_enabled = True
|
||||
elif cfg.CONF.nsxv.dhcp_force_metadata:
|
||||
LOG.warning(_LW("Skipping dhcp_force_metadata param since dhcp "
|
||||
"option feature can only be supported at version "
|
||||
"6.2.3 or higher"))
|
||||
self.is_dhcp_opt_enabled = False
|
||||
|
||||
def _get_per_edge_rp_filter_state(self):
|
||||
ver = self.nsxv_manager.vcns.get_version()
|
||||
@ -726,10 +740,50 @@ class EdgeManager(object):
|
||||
subnet_id)
|
||||
if sub_binding:
|
||||
static_config['domainName'] = sub_binding.dns_search_domain
|
||||
self.handle_meta_static_route(
|
||||
context, subnet_id, [static_config])
|
||||
|
||||
static_bindings.append(static_config)
|
||||
return static_bindings
|
||||
|
||||
def add_host_route_on_static_bindings(self, static_bindings,
|
||||
dest_cidr, nexthop):
|
||||
"""Add one host route on a bulk of static bindings config.
|
||||
|
||||
We can add host route on VM via dhcp option121. this func can only
|
||||
works at NSXv version 6.2.3 or higher.
|
||||
"""
|
||||
for binding in static_bindings:
|
||||
if 'dhcpOptions' not in six.iterkeys(binding):
|
||||
binding['dhcpOptions'] = {}
|
||||
if 'option121' not in six.iterkeys(binding['dhcpOptions']):
|
||||
binding['dhcpOptions']['option121'] = {'staticRoutes': []}
|
||||
binding_opt121 = binding['dhcpOptions']['option121']
|
||||
if 'staticRoutes' not in six.iterkeys(binding_opt121):
|
||||
binding_opt121['staticRoutes'] = []
|
||||
binding_opt121['staticRoutes'].append({
|
||||
'destinationSubnet': dest_cidr,
|
||||
'router': nexthop})
|
||||
return static_bindings
|
||||
|
||||
def handle_meta_static_route(self, context, subnet_id, static_bindings):
|
||||
is_dhcp_option121 = (
|
||||
self.is_dhcp_opt_enabled and
|
||||
self.nsxv_plugin.is_dhcp_metadata(
|
||||
context, subnet_id))
|
||||
if is_dhcp_option121:
|
||||
dhcp_ip = self.nsxv_plugin._get_dhcp_ip_addr_from_subnet(
|
||||
context, subnet_id)
|
||||
if dhcp_ip:
|
||||
self.add_host_route_on_static_bindings(
|
||||
static_bindings,
|
||||
'169.254.169.254/32',
|
||||
dhcp_ip)
|
||||
else:
|
||||
LOG.error(_LE("Failed to find the dhcp port on subnet "
|
||||
"%s to do metadata host route insertion"),
|
||||
subnet_id)
|
||||
|
||||
def update_dhcp_service_config(self, context, edge_id):
|
||||
"""Reconfigure the DHCP to the edge."""
|
||||
# Get all networks attached to the edge
|
||||
@ -737,16 +791,23 @@ class EdgeManager(object):
|
||||
context.session, edge_id)
|
||||
dhcp_networks = [edge_vnic_binding.network_id
|
||||
for edge_vnic_binding in edge_vnic_bindings]
|
||||
ports = self.nsxv_plugin.get_ports(
|
||||
context.elevated(), filters={'network_id': dhcp_networks})
|
||||
inst_ports = [port
|
||||
for port in ports
|
||||
if port['device_owner'].startswith("compute")]
|
||||
|
||||
subnets = self.nsxv_plugin.get_subnets(
|
||||
context.elevated(), filters={'network_id': dhcp_networks,
|
||||
'enable_dhcp': [True]})
|
||||
|
||||
static_bindings = []
|
||||
for port in inst_ports:
|
||||
static_bindings.extend(
|
||||
self.create_static_binding(
|
||||
context.elevated(), port))
|
||||
for subnet in subnets:
|
||||
ports = self.nsxv_plugin.get_ports(
|
||||
context.elevated(),
|
||||
filters={'network_id': [subnet['network_id']],
|
||||
'fixed_ips': {'subnet_id': [subnet['id']]}})
|
||||
inst_ports = [port for port in ports
|
||||
if port['device_owner'].startswith('compute')]
|
||||
for port in inst_ports:
|
||||
static_bindings.extend(
|
||||
self.create_static_binding(
|
||||
context.elevated(), port))
|
||||
dhcp_request = {
|
||||
'featureType': "dhcp_4.0",
|
||||
'enabled': True,
|
||||
|
@ -1912,6 +1912,29 @@ class L3NatTestCaseBase(test_l3_plugin.L3NatTestCaseMixin):
|
||||
None,
|
||||
expected_code=error_code)
|
||||
|
||||
def test_subnet_dhcp_metadata_with_update(self):
|
||||
cfg.CONF.set_override('dhcp_force_metadata', True, group='nsxv')
|
||||
self.plugin_instance.metadata_proxy_handler = mock.Mock()
|
||||
with self.subnet(cidr="10.0.0.0/24", enable_dhcp=True) as s1:
|
||||
subnet_id = s1['subnet']['id']
|
||||
is_dhcp_meta = self.plugin_instance.is_dhcp_metadata(
|
||||
context.get_admin_context(), subnet_id)
|
||||
self.assertTrue(is_dhcp_meta)
|
||||
port_data = {'port': {'tenant_id': s1['subnet']['tenant_id'],
|
||||
'network_id': s1['subnet']['network_id'],
|
||||
'device_owner': 'compute:None'}}
|
||||
req = self.new_create_request(
|
||||
'ports', port_data).get_response(self.api)
|
||||
port_req = self.deserialize(self.fmt, req)
|
||||
subnet_data = {'subnet': {'enable_dhcp': False}}
|
||||
self.new_update_request(
|
||||
'subnets', subnet_data,
|
||||
s1['subnet']['id']).get_response(self.api)
|
||||
is_dhcp_meta = self.plugin_instance.is_dhcp_metadata(
|
||||
context.get_admin_context(), subnet_id)
|
||||
self.assertFalse(is_dhcp_meta)
|
||||
self.new_delete_request('ports', port_req['port']['id'])
|
||||
|
||||
def test_router_delete_ipv6_slaac_subnet_inuse_returns_409(self):
|
||||
self.skipTest('No DHCP v6 Support yet')
|
||||
|
||||
|
@ -1130,3 +1130,10 @@ class FakeVcns(object):
|
||||
}
|
||||
response = {}
|
||||
return (header, response)
|
||||
|
||||
def get_routes(self, edge_id):
|
||||
header = {
|
||||
'status': 204
|
||||
}
|
||||
response = {'staticRoutes': {'staticRoutes': []}}
|
||||
return (header, response)
|
||||
|
Loading…
x
Reference in New Issue
Block a user