diff --git a/neutron/agent/linux/dhcp.py b/neutron/agent/linux/dhcp.py index b14429605fa..75e80068671 100644 --- a/neutron/agent/linux/dhcp.py +++ b/neutron/agent/linux/dhcp.py @@ -61,6 +61,9 @@ DNSMASQ_SERVICE_NAME = 'dnsmasq' DHCP_RELEASE_TRIES = 3 DHCP_RELEASE_TRIES_SLEEP = 0.3 +# this variable will be removed when neutron-lib is updated with this value +DHCP_OPT_CLIENT_ID_NUM = 61 + class DictModel(dict): """Convert dict into an object that provides attribute access to values.""" @@ -734,7 +737,8 @@ class Dnsmasq(DhcpLocalProcess): def _get_client_id(self, port): if self._get_port_extra_dhcp_opts(port): for opt in port.extra_dhcp_opts: - if opt.opt_name == edo_ext.DHCP_OPT_CLIENT_ID: + if opt.opt_name in (edo_ext.DHCP_OPT_CLIENT_ID, + DHCP_OPT_CLIENT_ID_NUM): return opt.opt_value def _read_hosts_file_leases(self, filename): @@ -1021,7 +1025,8 @@ class Dnsmasq(DhcpLocalProcess): [netaddr.IPAddress(ip.ip_address).version for ip in port.fixed_ips]) for opt in port.extra_dhcp_opts: - if opt.opt_name == edo_ext.DHCP_OPT_CLIENT_ID: + if opt.opt_name in (edo_ext.DHCP_OPT_CLIENT_ID, + DHCP_OPT_CLIENT_ID_NUM): continue opt_ip_version = opt.ip_version if opt_ip_version in port_ip_versions: diff --git a/neutron/tests/unit/agent/linux/test_dhcp.py b/neutron/tests/unit/agent/linux/test_dhcp.py index 957fce453d5..adb2a86d4e9 100644 --- a/neutron/tests/unit/agent/linux/test_dhcp.py +++ b/neutron/tests/unit/agent/linux/test_dhcp.py @@ -356,6 +356,13 @@ class FakePortMultipleAgents2(object): self.extra_dhcp_opts = [] +class FakePortWithClientIdNum(object): + def __init__(self): + self.extra_dhcp_opts = [ + DhcpOpt(opt_name=dhcp.DHCP_OPT_CLIENT_ID_NUM, + opt_value='test_client_id_num')] + + class FakeV4HostRoute(object): def __init__(self): self.destination = '20.0.0.1/24' @@ -623,6 +630,14 @@ class FakeV4NetworkClientId(object): self.namespace = 'qdhcp-ns' +class FakeV4NetworkClientIdNum(object): + def __init__(self): + self.id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' + self.subnets = [FakeV4Subnet()] + self.ports = [FakePortWithClientIdNum()] + self.namespace = 'qdhcp-ns' + + class FakeV6Network(object): def __init__(self): self.id = 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb' @@ -2616,6 +2631,11 @@ class TestDnsmasq(TestBase): 'force_metadata': True} self._test__generate_opts_per_subnet_helper(config, True) + def test_client_id_num(self): + dm = self._get_dnsmasq(FakeV4NetworkClientIdNum()) + self.assertEqual('test_client_id_num', + dm._get_client_id(FakePortWithClientIdNum())) + class TestDeviceManager(TestConfBase): def setUp(self): diff --git a/releasenotes/notes/ib-dhcp-allocation-fix-a4ebe8b55bb2c065.yaml b/releasenotes/notes/ib-dhcp-allocation-fix-a4ebe8b55bb2c065.yaml new file mode 100644 index 00000000000..7ddfa60466b --- /dev/null +++ b/releasenotes/notes/ib-dhcp-allocation-fix-a4ebe8b55bb2c065.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + For Infiniband support, Ironic needs to send the 'client-id' DHCP option + as a number in order for IP address assignment to work. + This is now supported in Neutron, and can be specified as option number + 61 as defined in RFC 4776. For more information see bug + `1770932 `_ \ No newline at end of file