diff --git a/neutron/agent/linux/dhcp.py b/neutron/agent/linux/dhcp.py index a46bc12f01c..dfac0f360fe 100644 --- a/neutron/agent/linux/dhcp.py +++ b/neutron/agent/linux/dhcp.py @@ -403,6 +403,14 @@ class Dnsmasq(DhcpLocalProcess): cmd.append('--dhcp-lease-max=%d' % min(possible_leases, self.conf.dnsmasq_lease_max)) + if self.conf.dhcp_renewal_time > 0: + cmd.append('--dhcp-option-force=option:T1,%ds' % + self.conf.dhcp_renewal_time) + + if self.conf.dhcp_rebinding_time > 0: + cmd.append('--dhcp-option-force=option:T2,%ds' % + self.conf.dhcp_rebinding_time) + cmd.append('--conf-file=%s' % self.conf.dnsmasq_config_file) for server in self.conf.dnsmasq_dns_servers: cmd.append('--server=%s' % server) diff --git a/neutron/conf/agent/dhcp.py b/neutron/conf/agent/dhcp.py index 8433fb7c7bf..7cca7295985 100644 --- a/neutron/conf/agent/dhcp.py +++ b/neutron/conf/agent/dhcp.py @@ -94,6 +94,12 @@ DNSMASQ_OPTS = [ help=_('Limit number of leases to prevent a denial-of-service.')), cfg.BoolOpt('dhcp_broadcast_reply', default=False, help=_("Use broadcast in DHCP replies.")), + cfg.IntOpt('dhcp_renewal_time', default=0, + help=_("DHCP renewal time T1 (in seconds). If set to 0, it " + "will default to half of the lease time.")), + cfg.IntOpt('dhcp_rebinding_time', default=0, + help=_("DHCP rebinding time T2 (in seconds). If set to 0, it " + "will default to 7/8 of the lease time.")), ] diff --git a/neutron/tests/unit/agent/linux/test_dhcp.py b/neutron/tests/unit/agent/linux/test_dhcp.py index d155cc94c31..eb8edb8bf2c 100644 --- a/neutron/tests/unit/agent/linux/test_dhcp.py +++ b/neutron/tests/unit/agent/linux/test_dhcp.py @@ -1173,7 +1173,7 @@ class TestDnsmasq(TestBase): def _test_spawn(self, extra_options, network=FakeDualNetwork(), max_leases=16777216, lease_duration=86400, has_static=True, no_resolv='--no-resolv', - has_stateless=True): + has_stateless=True, dhcp_t1=0, dhcp_t2=0): def mock_get_conf_file_name(kind): return '/dhcp/%s/%s' % (network.id, kind) @@ -1230,6 +1230,11 @@ class TestDnsmasq(TestBase): expected.append('--dhcp-lease-max=%d' % min( possible_leases, max_leases)) + + if dhcp_t1: + expected.append('--dhcp-option-force=option:T1,%ds' % dhcp_t1) + if dhcp_t2: + expected.append('--dhcp-option-force=option:T2,%ds' % dhcp_t2) expected.extend(extra_options) self.execute.return_value = ('', '') @@ -1361,6 +1366,12 @@ class TestDnsmasq(TestBase): self._test_spawn(['--conf-file=', '--domain=openstacklocal'], network) + def test_spawn_cfg_with_dhcp_timers(self): + self.conf.set_override('dhcp_renewal_time', 30) + self.conf.set_override('dhcp_rebinding_time', 100) + self._test_spawn(['--conf-file=', '--domain=openstacklocal'], + dhcp_t1=30, dhcp_t2=100) + def _test_output_init_lease_file(self, timestamp): expected = [ '00:00:80:aa:bb:cc 192.168.0.2 * *', diff --git a/releasenotes/notes/add_dhcp_dnsmasq_t1t2_options-3cef427d8109c165.yaml b/releasenotes/notes/add_dhcp_dnsmasq_t1t2_options-3cef427d8109c165.yaml new file mode 100644 index 00000000000..c8f6e5a14d2 --- /dev/null +++ b/releasenotes/notes/add_dhcp_dnsmasq_t1t2_options-3cef427d8109c165.yaml @@ -0,0 +1,11 @@ +--- +features: + - | + Allow configuration of DHCP renewal (T1) and rebinding (T2) timers in + ``neutron-dhcp-agent``. By allowing these timers to be set (options 58 + and 59 as per RFC2132) in ``dnsmasq`` it allows users to change + other parameters, like MTU, on instances without having to wait for + the lease time to expire. The advantage of changing T1 over the + lease time is that if the DHCP server becomes unreachable within + the lease time, instances will not drop their IP addresses and it + will not cause a dataplane disruption.