diff --git a/vmware_nsx/db/db.py b/vmware_nsx/db/db.py index 55ee8d75ca..fc54bc858d 100644 --- a/vmware_nsx/db/db.py +++ b/vmware_nsx/db/db.py @@ -167,6 +167,11 @@ def get_nsx_dhcp_bindings(session, port_id): nsx_models.NeutronNsxDhcpBinding).filter_by(port_id=port_id)] +def get_nsx_dhcp_bindings_by_service(session, service_id): + return [binding for binding in session.query( + nsx_models.NeutronNsxDhcpBinding).filter_by(nsx_service_id=service_id)] + + def add_neutron_nsx_dhcp_binding(session, port_id, subnet_id, ip_address, service_id, binding_id): """Store DHCP binding of each Neutron port. diff --git a/vmware_nsx/plugins/nsx_v3/plugin.py b/vmware_nsx/plugins/nsx_v3/plugin.py index c8ef2b1ca5..ac0168f46e 100644 --- a/vmware_nsx/plugins/nsx_v3/plugin.py +++ b/vmware_nsx/plugins/nsx_v3/plugin.py @@ -1315,6 +1315,16 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, "%(server)s for network %(network)s"), {'server': dhcp_service['nsx_service_id'], 'network': orig_subnet['network_id']}) + if 'gateway_ip' in kwargs: + # Need to update the static binding of every VM in + # this logical DHCP server. + bindings = nsx_db.get_nsx_dhcp_bindings_by_service( + context.session, dhcp_service['nsx_service_id']) + for binding in bindings: + port = self._get_port(context, binding['port_id']) + self._update_dhcp_binding_on_server( + context, binding, port['mac_address'], + binding['ip_address'], kwargs['gateway_ip']) if (cfg.CONF.nsx_v3.metadata_on_demand and not cfg.CONF.nsx_v3.native_dhcp_metadata): @@ -1667,24 +1677,29 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, ip, port): try: hostname = 'host-%s' % ip.replace('.', '-') + gateway_ip = self.get_subnet( + context, subnet_id).get('gateway_ip') options = {'option121': {'static_routes': [ {'network': '%s' % cfg.CONF.nsx_v3.native_metadata_route, 'next_hop': ip}]}} binding = self._dhcp_server.create_binding( dhcp_service_id, port['mac_address'], ip, hostname, - cfg.CONF.nsx_v3.dhcp_lease_time, options) - LOG.debug("Created static binding (mac: %(mac)s, ip: %(ip)s) " - "for port %(port)s on logical DHCP server %(server)s", + cfg.CONF.nsx_v3.dhcp_lease_time, options, gateway_ip) + LOG.debug("Created static binding (mac: %(mac)s, ip: %(ip)s, " + "gateway: %(gateway)s) for port %(port)s on " + "logical DHCP server %(server)s", {'mac': port['mac_address'], 'ip': ip, - 'port': port['id'], 'server': dhcp_service_id}) + 'gateway': gateway_ip, 'port': port['id'], + 'server': dhcp_service_id}) return binding except nsx_lib_exc.ManagerError: with excutils.save_and_reraise_exception(): LOG.error(_LE("Unable to create static binding (mac: %(mac)s, " - "ip: %(ip)s) for port %(port)s on logical DHCP " - "server %(server)s"), + "ip: %(ip)s, gateway: %(gateway)s) for port " + "%(port)s on logical DHCP server %(server)s"), {'mac': port['mac_address'], 'ip': ip, - 'port': port['id'], 'server': dhcp_service_id}) + 'gateway': gateway_ip, 'port': port['id'], + 'server': dhcp_service_id}) def _delete_dhcp_binding(self, context, port): # Do not check device_owner here because Nova may have already @@ -1821,7 +1836,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, context, binding, new_port['mac_address'], binding['ip_address']) - def _update_dhcp_binding_on_server(self, context, binding, mac, ip): + def _update_dhcp_binding_on_server(self, context, binding, mac, ip, + gateway_ip=False): try: data = {'mac_address': mac, 'ip_address': ip} if ip != binding['ip_address']: @@ -1829,18 +1845,24 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, data['options'] = {'option121': {'static_routes': [ {'network': '%s' % cfg.CONF.nsx_v3.native_metadata_route, 'next_hop': ip}]}} + if gateway_ip is not False: + # Note that None is valid for gateway_ip, means deleting it. + data['gateway_ip'] = gateway_ip self._dhcp_server.update_binding( binding['nsx_service_id'], binding['nsx_binding_id'], **data) - LOG.debug("Updated static binding (mac: %(mac)s, ip: %(ip)s) " - "for port %(port)s on logical DHCP server %(server)s", - {'mac': mac, 'ip': ip, 'port': binding['port_id'], + LOG.debug("Updated static binding (mac: %(mac)s, ip: %(ip)s, " + "gateway: %(gateway)s) for port %(port)s on " + "logical DHCP server %(server)s", + {'mac': mac, 'ip': ip, 'gateway': gateway_ip, + 'port': binding['port_id'], 'server': binding['nsx_service_id']}) except nsx_lib_exc.ManagerError: with excutils.save_and_reraise_exception(): LOG.error(_LE("Unable to update static binding (mac: %(mac)s, " - "ip: %(ip)s) for port %(port)s on logical DHCP " - "server %(server)s"), - {'mac': mac, 'ip': ip, 'port': binding['port_id'], + "ip: %(ip)s, gateway: %(gateway)s) for port " + "%(port)s on logical DHCP server %(server)s"), + {'mac': mac, 'ip': ip, 'gateway': gateway_ip, + 'port': binding['port_id'], 'server': binding['nsx_service_id']}) def _update_lport_with_security_groups(self, context, lport_id, diff --git a/vmware_nsx/shell/admin/plugins/nsxv3/resources/dhcp_binding.py b/vmware_nsx/shell/admin/plugins/nsxv3/resources/dhcp_binding.py index 9d0e4aaac8..396ffb2ad6 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv3/resources/dhcp_binding.py +++ b/vmware_nsx/shell/admin/plugins/nsxv3/resources/dhcp_binding.py @@ -133,9 +133,11 @@ def nsx_update_dhcp_bindings(resource, event, trigger, **kwargs): options = {'option121': {'static_routes': [ {'network': '%s' % cfg.CONF.nsx_v3.native_metadata_route, 'next_hop': ip}]}} + subnet = neutron_client.get_subnet(subnet_id) binding = dhcp_server_resource.create_binding( dhcp_server_id, mac, ip, hostname, - cfg.CONF.nsx_v3.dhcp_lease_time, options) + cfg.CONF.nsx_v3.dhcp_lease_time, options, + subnet.get('gateway_ip')) # Add DHCP static binding in neutron DB. neutron_client.add_dhcp_static_binding( port_id, subnet_id, ip, dhcp_server_id, binding['id']) diff --git a/vmware_nsx/tests/unit/nsx_v3/test_dhcp_metadata.py b/vmware_nsx/tests/unit/nsx_v3/test_dhcp_metadata.py index 815561f19d..99a19b27ba 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_dhcp_metadata.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_dhcp_metadata.py @@ -378,7 +378,8 @@ class NsxNativeDhcpTestCase(test_plugin.NsxV3PluginTestCaseMixin): create_dhcp_binding.assert_called_once_with( dhcp_service['nsx_service_id'], port['port']['mac_address'], ip, hostname, - cfg.CONF.nsx_v3.dhcp_lease_time, options) + cfg.CONF.nsx_v3.dhcp_lease_time, options, + subnet['subnet']['gateway_ip']) def test_dhcp_binding_with_disable_enable_dhcp(self): # Test if DHCP binding is preserved after DHCP is disabled and