Merge "Fix DHCP extension if subnet has no gateway_ip"
This commit is contained in:
commit
aa64bd2651
@ -26,6 +26,10 @@ from neutron.agent.l2.extensions.dhcp import ipv6
|
||||
from neutron.api.rpc.callbacks import resources
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
LINK_LOCAL_GATEWAY = {
|
||||
constants.IP_VERSION_4: constants.METADATA_V4_IP,
|
||||
constants.IP_VERSION_6: constants.METADATA_V6_IP
|
||||
}
|
||||
|
||||
|
||||
class DHCPExtensionPortInfoAPI:
|
||||
@ -64,7 +68,9 @@ class DHCPExtensionPortInfoAPI:
|
||||
'cidr': subnet.cidr,
|
||||
'host_routes': subnet.host_routes,
|
||||
'dns_nameservers': subnet.dns_nameservers,
|
||||
'gateway_ip': subnet.gateway_ip}
|
||||
'gateway_ip': subnet.gateway_ip or LINK_LOCAL_GATEWAY[
|
||||
subnet.ip_version
|
||||
]}
|
||||
fixed_ips.append(info)
|
||||
net = self.cache_api.get_resource_by_id(
|
||||
resources.NETWORK, port_obj.network_id)
|
||||
|
@ -49,13 +49,13 @@ class DHCPIPv4Responder(dhcp_base.DHCPResponderBase):
|
||||
def get_bin_routes(self, gateway=None, routes=None):
|
||||
bin_routes = b''
|
||||
|
||||
# Default routes
|
||||
default_route = self.get_bin_route(constants.IPv4_ANY, gateway)
|
||||
bin_routes += default_route
|
||||
if gateway and gateway != constants.METADATA_V4_IP:
|
||||
# Default routes
|
||||
default_route = self.get_bin_route(constants.IPv4_ANY, gateway)
|
||||
bin_routes += default_route
|
||||
|
||||
# For some VMs they may need the metadata IP's route, we move
|
||||
# the destination to gateway IP.
|
||||
if gateway:
|
||||
# For some VMs they may need the metadata IP's route, we move
|
||||
# the destination to gateway IP.
|
||||
meta_route = self.get_bin_route(
|
||||
constants.METADATA_V4_CIDR, gateway)
|
||||
bin_routes += meta_route
|
||||
@ -71,7 +71,7 @@ class DHCPIPv4Responder(dhcp_base.DHCPResponderBase):
|
||||
net = netaddr.IPNetwork(fixed_ips[0]['cidr'])
|
||||
dns_nameservers = fixed_ips[0]['dns_nameservers']
|
||||
host_routes = fixed_ips[0]['host_routes']
|
||||
gateway_ip = fixed_ips[0]['gateway_ip']
|
||||
gateway_ip = str(fixed_ips[0]['gateway_ip'])
|
||||
bin_server = addrconv.ipv4.text_to_bin(gateway_ip)
|
||||
|
||||
option_list = []
|
||||
@ -122,9 +122,10 @@ class DHCPIPv4Responder(dhcp_base.DHCPResponderBase):
|
||||
value=struct.pack(
|
||||
'!%ds' % len(cfg.CONF.dns_domain),
|
||||
str.encode(cfg.CONF.dns_domain))))
|
||||
option_list.append(
|
||||
dhcp.option(tag=dhcp.DHCP_GATEWAY_ADDR_OPT,
|
||||
value=bin_server))
|
||||
if gateway_ip != constants.METADATA_V4_IP:
|
||||
option_list.append(
|
||||
dhcp.option(tag=dhcp.DHCP_GATEWAY_ADDR_OPT,
|
||||
value=bin_server))
|
||||
# Static routes
|
||||
option_list.append(
|
||||
dhcp.option(tag=dhcp.DHCP_CLASSLESS_ROUTE_OPT,
|
||||
|
@ -147,7 +147,7 @@ class DHCPIPv6Responder(dhcp_base.DHCPResponderBase):
|
||||
|
||||
def get_dhcp_options(self, mac, ip_info, req_options, req_type):
|
||||
ip_addr = ip_info['ip_address']
|
||||
gateway_ip = ip_info['gateway_ip']
|
||||
gateway_ip = str(ip_info['gateway_ip'])
|
||||
dns_nameservers = ip_info['dns_nameservers']
|
||||
|
||||
option_list = []
|
||||
@ -210,9 +210,9 @@ class DHCPIPv6Responder(dhcp_base.DHCPResponderBase):
|
||||
dhcp6.option(
|
||||
code=DHCPV6_OPTION_DNS_RECURSIVE_NS,
|
||||
data=domain_serach, length=len(domain_serach)))
|
||||
else:
|
||||
elif gateway_ip != constants.METADATA_V6_IP:
|
||||
# use gateway as the default DNS server address
|
||||
domain_serach = addrconv.ipv6.text_to_bin(str(gateway_ip))
|
||||
domain_serach = addrconv.ipv6.text_to_bin(gateway_ip)
|
||||
option_list.append(
|
||||
dhcp6.option(
|
||||
code=DHCPV6_OPTION_DNS_RECURSIVE_NS,
|
||||
|
@ -61,41 +61,81 @@ class FakeMsg:
|
||||
self.data = packet.data
|
||||
|
||||
|
||||
IPV4_INFO = {
|
||||
'version': 4,
|
||||
'host_routes': [
|
||||
subnet_obj.Route(
|
||||
destination=netaddr.IPNetwork('1.1.1.0/24'),
|
||||
nexthop='192.168.1.100',
|
||||
subnet_id='daed3c3d-d95a-48a8-a8b1-17d408cd760f'
|
||||
),
|
||||
subnet_obj.Route(
|
||||
destination=netaddr.IPNetwork('2.2.2.2/32'),
|
||||
nexthop='192.168.1.101',
|
||||
subnet_id='daed3c3d-d95a-48a8-a8b1-17d408cd760f'
|
||||
)
|
||||
],
|
||||
'subnet_id': 'daed3c3d-d95a-48a8-a8b1-17d408cd760f',
|
||||
'dns_nameservers': [
|
||||
subnet_obj.DNSNameServer(
|
||||
address='8.8.8.8',
|
||||
order=0,
|
||||
subnet_id='daed3c3d-d95a-48a8-a8b1-17d408cd760f'
|
||||
),
|
||||
subnet_obj.DNSNameServer(
|
||||
address='8.8.4.4',
|
||||
order=1,
|
||||
subnet_id='daed3c3d-d95a-48a8-a8b1-17d408cd760f'
|
||||
)
|
||||
],
|
||||
'cidr': net_utils.AuthenticIPNetwork('192.168.111.0/24'),
|
||||
'ip_address': '192.168.111.45',
|
||||
'gateway_ip': netaddr.IPAddress('192.168.111.1')
|
||||
}
|
||||
|
||||
|
||||
IPV6_INFO = {
|
||||
'version': 6,
|
||||
'host_routes': [],
|
||||
'subnet_id': 'bd013460-b05f-4927-a4c6-5127584b2487',
|
||||
'dns_nameservers': [],
|
||||
'cidr': net_utils.AuthenticIPNetwork('fda7:a5cc:3460:1::/64'),
|
||||
'ip_address': 'fda7:a5cc:3460:1::bf',
|
||||
'gateway_ip': netaddr.IPAddress('fda7:a5cc:3460:1::1')
|
||||
}
|
||||
|
||||
|
||||
PORT_INFO = {
|
||||
'device_owner': 'compute:nova',
|
||||
'admin_state_up': True,
|
||||
'network_id': 'd666ccb3-69e9-46cb-b157-bb3741d87d5a',
|
||||
'fixed_ips': [
|
||||
{'version': 4,
|
||||
'host_routes': [
|
||||
subnet_obj.Route(
|
||||
destination=netaddr.IPNetwork('1.1.1.0/24'),
|
||||
nexthop='192.168.1.100',
|
||||
subnet_id='daed3c3d-d95a-48a8-a8b1-17d408cd760f'),
|
||||
subnet_obj.Route(
|
||||
destination=netaddr.IPNetwork('2.2.2.2/32'),
|
||||
nexthop='192.168.1.101',
|
||||
subnet_id='daed3c3d-d95a-48a8-a8b1-17d408cd760f')],
|
||||
'subnet_id': 'daed3c3d-d95a-48a8-a8b1-17d408cd760f',
|
||||
'dns_nameservers': [
|
||||
subnet_obj.DNSNameServer(
|
||||
address='8.8.8.8',
|
||||
order=0,
|
||||
subnet_id='daed3c3d-d95a-48a8-a8b1-17d408cd760f'),
|
||||
subnet_obj.DNSNameServer(
|
||||
address='8.8.4.4',
|
||||
order=1,
|
||||
subnet_id='daed3c3d-d95a-48a8-a8b1-17d408cd760f')],
|
||||
'cidr': net_utils.AuthenticIPNetwork('192.168.111.0/24'),
|
||||
'ip_address': '192.168.111.45',
|
||||
'gateway_ip': netaddr.IPAddress('192.168.111.1')},
|
||||
{'version': 6,
|
||||
'host_routes': [],
|
||||
'subnet_id': 'bd013460-b05f-4927-a4c6-5127584b2487',
|
||||
'dns_nameservers': [],
|
||||
'cidr': net_utils.AuthenticIPNetwork('fda7:a5cc:3460:1::/64'),
|
||||
'ip_address': 'fda7:a5cc:3460:1::bf',
|
||||
'gateway_ip': netaddr.IPAddress('fda7:a5cc:3460:1::1')}
|
||||
IPV4_INFO,
|
||||
IPV6_INFO
|
||||
],
|
||||
'mac_address': '00:01:02:03:04:05',
|
||||
'port_id': '9a0e1889-f05f-43c7-a319-e1a723ed1587',
|
||||
'mtu': 1450
|
||||
}
|
||||
|
||||
|
||||
IPV4_INFO_NO_GATEWAY = {
|
||||
**IPV4_INFO,
|
||||
'gateway_ip': netaddr.IPAddress(constants.METADATA_V4_IP)
|
||||
}
|
||||
IPV6_INFO_NO_GATEWAY = {
|
||||
**IPV6_INFO,
|
||||
'gateway_ip': netaddr.IPAddress(constants.METADATA_V6_IP)
|
||||
}
|
||||
|
||||
|
||||
NO_GATEWAY_PORT_INFO = {
|
||||
'device_owner': 'compute:nova',
|
||||
'admin_state_up': True,
|
||||
'network_id': 'd666ccb3-69e9-46cb-b157-bb3741d87d5a',
|
||||
'fixed_ips': [
|
||||
IPV4_INFO_NO_GATEWAY,
|
||||
IPV6_INFO_NO_GATEWAY
|
||||
],
|
||||
'mac_address': '00:01:02:03:04:05',
|
||||
'port_id': '9a0e1889-f05f-43c7-a319-e1a723ed1587',
|
||||
@ -128,6 +168,7 @@ class DHCPResponderBaseTestCase(base.BaseTestCase):
|
||||
self.base_responer.handle_dhcp = mock.Mock()
|
||||
|
||||
self.port_info = PORT_INFO
|
||||
self.no_gateway_port_info = NO_GATEWAY_PORT_INFO
|
||||
|
||||
def _create_test_dhcp_request_packet(self):
|
||||
option_list = []
|
||||
|
@ -67,53 +67,70 @@ class DHCPIPv4ResponderTestCase(dhcp_test_base.DHCPResponderBaseTestCase):
|
||||
dhcp_pkt = ret_pkt.get_protocols(dhcp.dhcp)
|
||||
self.assertIsNotNone(dhcp_pkt)
|
||||
|
||||
def test_get_dhcp_options(self):
|
||||
expect_bin_routes = (b'\x00\xc0\xa8o\x01 \xa9\xfe\xa9\xfe\xc0\xa8o\x01'
|
||||
b'\x18\x01\x01\x01\xc0\xa8\x01d '
|
||||
b'\x02\x02\x02\x02\xc0\xa8\x01e')
|
||||
def _test_get_dhcp_options(self, port_info, has_gateway_ip=False):
|
||||
expect_bin_routes = (
|
||||
b'\x18\x01\x01\x01\xc0\xa8\x01d '
|
||||
b'\x02\x02\x02\x02\xc0\xa8\x01e'
|
||||
)
|
||||
offer_option_list = [
|
||||
dhcp.option(length=0, tag=53, value=b'\x02'),
|
||||
dhcp.option(length=0, tag=54, value=b'\xa9\xfe\xa9\xfe'),
|
||||
dhcp.option(length=0, tag=51, value=b'\x00\x01Q\x80'),
|
||||
dhcp.option(length=0, tag=1, value=b'\xff\xff\xff\x00'),
|
||||
dhcp.option(length=0, tag=28, value=b'\xc0\xa8o\xff'),
|
||||
dhcp.option(length=0, tag=6,
|
||||
value=b'\x08\x08\x08\x08\x08\x08\x04\x04'),
|
||||
dhcp.option(length=0, tag=15, value=b'openstacklocal'),
|
||||
dhcp.option(length=0, tag=121, value=expect_bin_routes),
|
||||
dhcp.option(length=0, tag=26, value=b'\x05\xaa')
|
||||
]
|
||||
ack_option_list = list(offer_option_list)
|
||||
ack_option_list[0] = dhcp.option(length=0, tag=53, value=b'\x05')
|
||||
if has_gateway_ip:
|
||||
expect_bin_routes = (
|
||||
b'\x00\xc0\xa8o\x01 \xa9\xfe\xa9\xfe\xc0\xa8o\x01'
|
||||
b'\x18\x01\x01\x01\xc0\xa8\x01d '
|
||||
b'\x02\x02\x02\x02\xc0\xa8\x01e'
|
||||
)
|
||||
offer_option_list[1] = dhcp.option(
|
||||
length=0, tag=54, value=b'\xc0\xa8o\x01'
|
||||
)
|
||||
ack_option_list[1] = dhcp.option(
|
||||
length=0, tag=54, value=b'\xc0\xa8o\x01'
|
||||
)
|
||||
offer_option_list[7] = dhcp.option(
|
||||
length=0, tag=121, value=expect_bin_routes
|
||||
)
|
||||
ack_option_list[7] = dhcp.option(
|
||||
length=0, tag=121, value=expect_bin_routes
|
||||
)
|
||||
offer_option_list.append(
|
||||
dhcp.option(length=0, tag=3, value=b'\xc0\xa8o\x01')
|
||||
)
|
||||
ack_option_list.append(
|
||||
dhcp.option(length=0, tag=3, value=b'\xc0\xa8o\x01')
|
||||
)
|
||||
|
||||
expect_offer_options = dhcp.options(
|
||||
magic_cookie='99.130.83.99',
|
||||
option_list=[
|
||||
dhcp.option(length=0, tag=53, value=b'\x02'),
|
||||
dhcp.option(length=0, tag=54, value=b'\xc0\xa8o\x01'),
|
||||
dhcp.option(length=0, tag=51, value=b'\x00\x01Q\x80'),
|
||||
dhcp.option(length=0, tag=1, value=b'\xff\xff\xff\x00'),
|
||||
dhcp.option(length=0, tag=28, value=b'\xc0\xa8o\xff'),
|
||||
dhcp.option(length=0, tag=6,
|
||||
value=b'\x08\x08\x08\x08\x08\x08\x04\x04'),
|
||||
dhcp.option(length=0, tag=15, value=b'openstacklocal'),
|
||||
dhcp.option(length=0, tag=3, value=b'\xc0\xa8o\x01'),
|
||||
dhcp.option(
|
||||
length=0, tag=121,
|
||||
value=expect_bin_routes),
|
||||
dhcp.option(length=0, tag=26, value=b'\x05\xaa')],
|
||||
option_list=offer_option_list,
|
||||
options_len=0)
|
||||
offer_options = self.dhcp4_responer.get_dhcp_options(self.port_info)
|
||||
offer_options = self.dhcp4_responer.get_dhcp_options(port_info)
|
||||
self._compare_option_values(expect_offer_options.option_list,
|
||||
offer_options.option_list)
|
||||
|
||||
expect_ack_options = dhcp.options(
|
||||
magic_cookie='99.130.83.99',
|
||||
option_list=[
|
||||
dhcp.option(length=0, tag=53, value=b'\x05'),
|
||||
dhcp.option(length=0, tag=54, value=b'\xc0\xa8o\x01'),
|
||||
dhcp.option(length=0, tag=51, value=b'\x00\x01Q\x80'),
|
||||
dhcp.option(length=0, tag=1, value=b'\xff\xff\xff\x00'),
|
||||
dhcp.option(length=0, tag=28, value=b'\xc0\xa8o\xff'),
|
||||
dhcp.option(length=0, tag=6,
|
||||
value=b'\x08\x08\x08\x08\x08\x08\x04\x04'),
|
||||
dhcp.option(length=0, tag=15, value=b'openstacklocal'),
|
||||
dhcp.option(length=0, tag=3, value=b'\xc0\xa8o\x01'),
|
||||
dhcp.option(
|
||||
length=0, tag=121,
|
||||
value=expect_bin_routes),
|
||||
dhcp.option(length=0, tag=26, value=b'\x05\xaa')],
|
||||
option_list=ack_option_list,
|
||||
options_len=0)
|
||||
ack_options = self.dhcp4_responer.get_dhcp_options(
|
||||
self.port_info, is_ack=True)
|
||||
port_info, is_ack=True)
|
||||
self._compare_option_values(expect_ack_options.option_list,
|
||||
ack_options.option_list)
|
||||
|
||||
def test_get_dhcp_options(self):
|
||||
self._test_get_dhcp_options(self.port_info, has_gateway_ip=True)
|
||||
|
||||
def test_get_bin_routes(self):
|
||||
expect_bin_routes = (b'\x00\xc0\xa8o\x01 \xa9\xfe\xa9\xfe\xc0\xa8o\x01'
|
||||
b'\x18\x01\x01\x01\xc0\xa8\x01d '
|
||||
@ -122,3 +139,15 @@ class DHCPIPv4ResponderTestCase(dhcp_test_base.DHCPResponderBaseTestCase):
|
||||
self.port_info['fixed_ips'][0]['gateway_ip'],
|
||||
self.port_info['fixed_ips'][0]['host_routes'])
|
||||
self.assertEqual(expect_bin_routes, bin_routes)
|
||||
|
||||
def test_get_dhcp_options_no_gateway(self):
|
||||
self._test_get_dhcp_options(
|
||||
self.no_gateway_port_info, has_gateway_ip=False
|
||||
)
|
||||
|
||||
def test_get_bin_routes_no_gateway(self):
|
||||
expect_bin_routes = (b'\x18\x01\x01\x01\xc0\xa8\x01d '
|
||||
b'\x02\x02\x02\x02\xc0\xa8\x01e')
|
||||
bin_routes = self.dhcp4_responer.get_bin_routes(
|
||||
routes=self.port_info['fixed_ips'][0]['host_routes'])
|
||||
self.assertEqual(expect_bin_routes, bin_routes)
|
||||
|
@ -114,14 +114,27 @@ class DHCPIPv6ResponderTestCase(dhcp_test_base.DHCPResponderBaseTestCase):
|
||||
self.assertEqual(expect_status_code, status_code)
|
||||
|
||||
def test_get_dhcp_options(self):
|
||||
self._test_get_dhcp_options()
|
||||
self._test_get_dhcp_options(self.port_info, has_gateway_ip=True)
|
||||
|
||||
def test_get_dhcp_options_zero_time(self):
|
||||
self._test_get_dhcp_options(zero_time=True)
|
||||
self._test_get_dhcp_options(
|
||||
self.port_info, has_gateway_ip=True, zero_time=True
|
||||
)
|
||||
|
||||
def _test_get_dhcp_options(self, zero_time=False):
|
||||
ip_info = self.dhcp6_responer.get_port_ip(self.port_info, ip_version=6)
|
||||
mac = self.port_info['mac_address']
|
||||
def test_get_dhcp_options_no_gateway(self):
|
||||
self._test_get_dhcp_options(
|
||||
self.no_gateway_port_info, has_gateway_ip=False
|
||||
)
|
||||
|
||||
def test_get_dhcp_options_zero_time_no_gateway(self):
|
||||
self._test_get_dhcp_options(
|
||||
self.no_gateway_port_info, has_gateway_ip=False, zero_time=True
|
||||
)
|
||||
|
||||
def _test_get_dhcp_options(self, port_info,has_gateway_ip=False,
|
||||
zero_time=False):
|
||||
ip_info = self.dhcp6_responer.get_port_ip(port_info, ip_version=6)
|
||||
mac = port_info['mac_address']
|
||||
|
||||
option_list = [
|
||||
dhcp6.option(
|
||||
@ -135,11 +148,6 @@ class DHCPIPv6ResponderTestCase(dhcp_test_base.DHCPResponderBaseTestCase):
|
||||
dhcp6.option(code=13,
|
||||
data=b'\x00\x00success',
|
||||
length=9),
|
||||
dhcp6.option(
|
||||
code=23,
|
||||
data=(b'\xfd\xa7\xa5\xcc4`\x00\x01\x00'
|
||||
b'\x00\x00\x00\x00\x00\x00\x01'),
|
||||
length=16),
|
||||
dhcp6.option(
|
||||
code=24,
|
||||
data=b'\x0eopenstacklocal\x00',
|
||||
@ -148,6 +156,26 @@ class DHCPIPv6ResponderTestCase(dhcp_test_base.DHCPResponderBaseTestCase):
|
||||
code=39,
|
||||
data=b'\x03(host-fda7-a5cc-3460-1--bf.openstacklocal',
|
||||
length=42)]
|
||||
|
||||
if has_gateway_ip:
|
||||
option_list.append(
|
||||
dhcp6.option(
|
||||
code=23,
|
||||
data=(b'\xfd\xa7\xa5\xcc4`\x00\x01\x00'
|
||||
b'\x00\x00\x00\x00\x00\x00\x01'),
|
||||
length=16
|
||||
)
|
||||
)
|
||||
else:
|
||||
option_list.append(
|
||||
dhcp6.option(
|
||||
code=23,
|
||||
data=(b'\xfe\x80\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x00\xa9\xfe\xa9\xfe'),
|
||||
length=16
|
||||
)
|
||||
)
|
||||
|
||||
if zero_time:
|
||||
option_list.append(
|
||||
dhcp6.option(
|
||||
|
Loading…
x
Reference in New Issue
Block a user