1
# Copyright 2014 OpenStack Foundation
4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5
# not use this file except in compliance with the License. You may obtain
6
# a copy of the License at
8
# http://www.apache.org/licenses/LICENSE-2.0
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
# License for the specific language governing permissions and limitations
19
from tempest_lib.common.utils import data_utils
20
from tempest_lib import exceptions as lib_exc
22
from neutron.tests.tempest.api.network import base
23
from neutron.tests.tempest import config
24
from neutron.tests.tempest import test
29
class NetworksTestDHCPv6(base.BaseNetworkTest):
32
""" Test DHCPv6 specific features using SLAAC, stateless and
33
stateful settings for subnets. Also it shall check dual-stack
34
functionality (IPv4 + IPv6 together).
36
generating of SLAAC EUI-64 address in subnets with various settings
37
receiving SLAAC addresses in combinations of various subnets
38
receiving stateful IPv6 addresses
39
addressing in subnets with router
45
if not CONF.network_feature_enabled.ipv6:
46
msg = "IPv6 is not enabled"
47
elif not CONF.network_feature_enabled.ipv6_subnet_attributes:
48
msg = "DHCPv6 attributes are not enabled."
50
raise cls.skipException(msg)
53
def resource_setup(cls):
54
super(NetworksTestDHCPv6, cls).resource_setup()
55
cls.network = cls.create_network()
57
def _remove_from_list_by_index(self, things_list, elem):
58
for index, i in enumerate(things_list):
59
if i['id'] == elem['id']:
61
del things_list[index]
63
def _clean_network(self):
64
body = self.client.list_ports()
67
if (port['device_owner'].startswith('network:router_interface')
68
and port['device_id'] in [r['id'] for r in self.routers]):
69
self.client.remove_router_interface_with_port_id(
70
port['device_id'], port['id']
73
if port['id'] in [p['id'] for p in self.ports]:
74
self.client.delete_port(port['id'])
75
self._remove_from_list_by_index(self.ports, port)
76
body = self.client.list_subnets()
77
subnets = body['subnets']
78
for subnet in subnets:
79
if subnet['id'] in [s['id'] for s in self.subnets]:
80
self.client.delete_subnet(subnet['id'])
81
self._remove_from_list_by_index(self.subnets, subnet)
82
body = self.client.list_routers()
83
routers = body['routers']
84
for router in routers:
85
if router['id'] in [r['id'] for r in self.routers]:
86
self.client.delete_router(router['id'])
87
self._remove_from_list_by_index(self.routers, router)
89
def _get_ips_from_subnet(self, **kwargs):
90
subnet = self.create_subnet(self.network, **kwargs)
91
port_mac = data_utils.rand_mac_address()
92
port = self.create_port(self.network, mac_address=port_mac)
93
real_ip = next(iter(port['fixed_ips']), None)['ip_address']
94
eui_ip = data_utils.get_ipv6_addr_by_EUI64(subnet['cidr'],
96
return real_ip, eui_ip
98
@test.idempotent_id('e5517e62-6f16-430d-a672-f80875493d4c')
99
def test_dhcpv6_stateless_eui64(self):
100
"""When subnets configured with RAs SLAAC (AOM=100) and DHCP stateless
101
(AOM=110) both for radvd and dnsmasq, port shall receive IP address
102
calculated from its MAC.
104
for ra_mode, add_mode in (
106
('dhcpv6-stateless', 'dhcpv6-stateless'),
108
kwargs = {'ipv6_ra_mode': ra_mode,
109
'ipv6_address_mode': add_mode}
110
real_ip, eui_ip = self._get_ips_from_subnet(**kwargs)
111
self._clean_network()
112
self.assertEqual(eui_ip, real_ip,
113
('Real port IP is %s, but shall be %s when '
114
'ipv6_ra_mode=%s and ipv6_address_mode=%s') % (
115
real_ip, eui_ip, ra_mode, add_mode))
117
@test.idempotent_id('ae2f4a5d-03ff-4c42-a3b0-ce2fcb7ea832')
118
def test_dhcpv6_stateless_no_ra(self):
119
"""When subnets configured with dnsmasq SLAAC and DHCP stateless
120
and there is no radvd, port shall receive IP address calculated
121
from its MAC and mask of subnet.
123
for ra_mode, add_mode in (
125
(None, 'dhcpv6-stateless'),
127
kwargs = {'ipv6_ra_mode': ra_mode,
128
'ipv6_address_mode': add_mode}
129
kwargs = {k: v for k, v in kwargs.iteritems() if v}
130
real_ip, eui_ip = self._get_ips_from_subnet(**kwargs)
131
self._clean_network()
132
self.assertEqual(eui_ip, real_ip,
133
('Real port IP %s shall be equal to EUI-64 %s'
134
'when ipv6_ra_mode=%s,ipv6_address_mode=%s') % (
136
ra_mode if ra_mode else "Off",
137
add_mode if add_mode else "Off"))
139
@test.idempotent_id('81f18ef6-95b5-4584-9966-10d480b7496a')
140
def test_dhcpv6_invalid_options(self):
141
"""Different configurations for radvd and dnsmasq are not allowed"""
142
for ra_mode, add_mode in (
143
('dhcpv6-stateless', 'dhcpv6-stateful'),
144
('dhcpv6-stateless', 'slaac'),
145
('slaac', 'dhcpv6-stateful'),
146
('dhcpv6-stateful', 'dhcpv6-stateless'),
147
('dhcpv6-stateful', 'slaac'),
148
('slaac', 'dhcpv6-stateless'),
150
kwargs = {'ipv6_ra_mode': ra_mode,
151
'ipv6_address_mode': add_mode}
152
self.assertRaises(lib_exc.BadRequest,
157
@test.idempotent_id('21635b6f-165a-4d42-bf49-7d195e47342f')
158
def test_dhcpv6_stateless_no_ra_no_dhcp(self):
159
"""If no radvd option and no dnsmasq option is configured
160
port shall receive IP from fixed IPs list of subnet.
162
real_ip, eui_ip = self._get_ips_from_subnet()
163
self._clean_network()
164
self.assertNotEqual(eui_ip, real_ip,
165
('Real port IP %s equal to EUI-64 %s when '
166
'ipv6_ra_mode=Off and ipv6_address_mode=Off,'
167
'but shall be taken from fixed IPs') % (
170
@test.idempotent_id('4544adf7-bb5f-4bdc-b769-b3e77026cef2')
171
def test_dhcpv6_two_subnets(self):
172
"""When one IPv6 subnet configured with dnsmasq SLAAC or DHCP stateless
173
and other IPv6 is with DHCP stateful, port shall receive EUI-64 IP
174
addresses from first subnet and DHCP address from second one.
175
Order of subnet creating should be unimportant.
177
for order in ("slaac_first", "dhcp_first"):
178
for ra_mode, add_mode in (
180
('dhcpv6-stateless', 'dhcpv6-stateless'),
182
kwargs = {'ipv6_ra_mode': ra_mode,
183
'ipv6_address_mode': add_mode}
184
kwargs_dhcp = {'ipv6_address_mode': 'dhcpv6-stateful'}
185
if order == "slaac_first":
186
subnet_slaac = self.create_subnet(self.network, **kwargs)
187
subnet_dhcp = self.create_subnet(
188
self.network, **kwargs_dhcp)
190
subnet_dhcp = self.create_subnet(
191
self.network, **kwargs_dhcp)
192
subnet_slaac = self.create_subnet(self.network, **kwargs)
193
port_mac = data_utils.rand_mac_address()
194
dhcp_ip = subnet_dhcp["allocation_pools"][0]["start"]
195
eui_ip = data_utils.get_ipv6_addr_by_EUI64(
196
subnet_slaac['cidr'],
199
# TODO(sergsh): remove this when 1219795 is fixed
200
dhcp_ip = [dhcp_ip, (netaddr.IPAddress(dhcp_ip) + 1).format()]
201
port = self.create_port(self.network, mac_address=port_mac)
202
real_ips = dict([(k['subnet_id'], k['ip_address'])
203
for k in port['fixed_ips']])
204
real_dhcp_ip, real_eui_ip = [real_ips[sub['id']]
205
for sub in subnet_dhcp,
207
self.client.delete_port(port['id'])
209
body = self.client.list_ports()
210
ports_id_list = [i['id'] for i in body['ports']]
211
self.assertNotIn(port['id'], ports_id_list)
212
self._clean_network()
213
self.assertEqual(real_eui_ip,
215
'Real IP is {0}, but shall be {1}'.format(
219
real_dhcp_ip, dhcp_ip,
220
'Real IP is {0}, but shall be one from {1}'.format(
224
@test.idempotent_id('4256c61d-c538-41ea-9147-3c450c36669e')
225
def test_dhcpv6_64_subnets(self):
226
"""When one IPv6 subnet configured with dnsmasq SLAAC or DHCP stateless
227
and other IPv4 is with DHCP of IPv4, port shall receive EUI-64 IP
228
addresses from first subnet and IPv4 DHCP address from second one.
229
Order of subnet creating should be unimportant.
231
for order in ("slaac_first", "dhcp_first"):
232
for ra_mode, add_mode in (
234
('dhcpv6-stateless', 'dhcpv6-stateless'),
236
kwargs = {'ipv6_ra_mode': ra_mode,
237
'ipv6_address_mode': add_mode}
238
if order == "slaac_first":
239
subnet_slaac = self.create_subnet(self.network, **kwargs)
240
subnet_dhcp = self.create_subnet(
241
self.network, ip_version=4)
243
subnet_dhcp = self.create_subnet(
244
self.network, ip_version=4)
245
subnet_slaac = self.create_subnet(self.network, **kwargs)
246
port_mac = data_utils.rand_mac_address()
247
dhcp_ip = subnet_dhcp["allocation_pools"][0]["start"]
248
eui_ip = data_utils.get_ipv6_addr_by_EUI64(
249
subnet_slaac['cidr'],
252
# TODO(sergsh): remove this when 1219795 is fixed
253
dhcp_ip = [dhcp_ip, (netaddr.IPAddress(dhcp_ip) + 1).format()]
254
port = self.create_port(self.network, mac_address=port_mac)
255
real_ips = dict([(k['subnet_id'], k['ip_address'])
256
for k in port['fixed_ips']])
257
real_dhcp_ip, real_eui_ip = [real_ips[sub['id']]
258
for sub in subnet_dhcp,
260
self._clean_network()
261
self.assertTrue({real_eui_ip,
262
real_dhcp_ip}.issubset([eui_ip] + dhcp_ip))
263
self.assertEqual(real_eui_ip,
265
'Real IP is {0}, but shall be {1}'.format(
269
real_dhcp_ip, dhcp_ip,
270
'Real IP is {0}, but shall be one from {1}'.format(
274
@test.idempotent_id('4ab211a0-276f-4552-9070-51e27f58fecf')
275
def test_dhcp_stateful(self):
276
"""With all options below, DHCPv6 shall allocate first
277
address from subnet pool to port.
279
for ra_mode, add_mode in (
280
('dhcpv6-stateful', 'dhcpv6-stateful'),
281
('dhcpv6-stateful', None),
282
(None, 'dhcpv6-stateful'),
284
kwargs = {'ipv6_ra_mode': ra_mode,
285
'ipv6_address_mode': add_mode}
286
kwargs = {k: v for k, v in kwargs.iteritems() if v}
287
subnet = self.create_subnet(self.network, **kwargs)
288
port = self.create_port(self.network)
289
port_ip = next(iter(port['fixed_ips']), None)['ip_address']
290
dhcp_ip = subnet["allocation_pools"][0]["start"]
291
# TODO(sergsh): remove this when 1219795 is fixed
292
dhcp_ip = [dhcp_ip, (netaddr.IPAddress(dhcp_ip) + 1).format()]
293
self._clean_network()
296
'Real IP is {0}, but shall be one from {1}'.format(
300
@test.idempotent_id('51a5e97f-f02e-4e4e-9a17-a69811d300e3')
301
def test_dhcp_stateful_fixedips(self):
302
"""With all options below, port shall be able to get
303
requested IP from fixed IP range not depending on
304
DHCP stateful (not SLAAC!) settings configured.
306
for ra_mode, add_mode in (
307
('dhcpv6-stateful', 'dhcpv6-stateful'),
308
('dhcpv6-stateful', None),
309
(None, 'dhcpv6-stateful'),
311
kwargs = {'ipv6_ra_mode': ra_mode,
312
'ipv6_address_mode': add_mode}
313
kwargs = {k: v for k, v in kwargs.iteritems() if v}
314
subnet = self.create_subnet(self.network, **kwargs)
315
ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"],
316
subnet["allocation_pools"][0]["end"])
317
ip = netaddr.IPAddress(random.randrange(ip_range.first,
318
ip_range.last)).format()
319
port = self.create_port(self.network,
320
fixed_ips=[{'subnet_id': subnet['id'],
322
port_ip = next(iter(port['fixed_ips']), None)['ip_address']
323
self._clean_network()
324
self.assertEqual(port_ip, ip,
325
("Port IP %s is not as fixed IP from "
326
"port create request: %s") % (
329
@test.idempotent_id('98244d88-d990-4570-91d4-6b25d70d08af')
330
def test_dhcp_stateful_fixedips_outrange(self):
331
"""When port gets IP address from fixed IP range it
332
shall be checked if it's from subnets range.
334
kwargs = {'ipv6_ra_mode': 'dhcpv6-stateful',
335
'ipv6_address_mode': 'dhcpv6-stateful'}
336
subnet = self.create_subnet(self.network, **kwargs)
337
ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"],
338
subnet["allocation_pools"][0]["end"])
339
ip = netaddr.IPAddress(random.randrange(
340
ip_range.last + 1, ip_range.last + 10)).format()
341
self.assertRaises(lib_exc.BadRequest,
344
fixed_ips=[{'subnet_id': subnet['id'],
347
@test.idempotent_id('57b8302b-cba9-4fbb-8835-9168df029051')
348
def test_dhcp_stateful_fixedips_duplicate(self):
349
"""When port gets IP address from fixed IP range it
350
shall be checked if it's not duplicate.
352
kwargs = {'ipv6_ra_mode': 'dhcpv6-stateful',
353
'ipv6_address_mode': 'dhcpv6-stateful'}
354
subnet = self.create_subnet(self.network, **kwargs)
355
ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"],
356
subnet["allocation_pools"][0]["end"])
357
ip = netaddr.IPAddress(random.randrange(
358
ip_range.first, ip_range.last)).format()
359
self.create_port(self.network,
361
{'subnet_id': subnet['id'],
363
self.assertRaisesRegexp(lib_exc.Conflict,
364
"object with that identifier already exists",
367
fixed_ips=[{'subnet_id': subnet['id'],
370
def _create_subnet_router(self, kwargs):
371
subnet = self.create_subnet(self.network, **kwargs)
372
router = self.create_router(
373
router_name=data_utils.rand_name("routerv6-"),
375
port = self.create_router_interface(router['id'],
377
body = self.client.show_port(port['port_id'])
378
return subnet, body['port']
380
@test.idempotent_id('e98f65db-68f4-4330-9fea-abd8c5192d4d')
381
def test_dhcp_stateful_router(self):
382
"""With all options below the router interface shall
383
receive DHCPv6 IP address from allocation pool.
385
for ra_mode, add_mode in (
386
('dhcpv6-stateful', 'dhcpv6-stateful'),
387
('dhcpv6-stateful', None),
389
kwargs = {'ipv6_ra_mode': ra_mode,
390
'ipv6_address_mode': add_mode}
391
kwargs = {k: v for k, v in kwargs.iteritems() if v}
392
subnet, port = self._create_subnet_router(kwargs)
393
port_ip = next(iter(port['fixed_ips']), None)['ip_address']
394
self._clean_network()
395
self.assertEqual(port_ip, subnet['gateway_ip'],
396
("Port IP %s is not as first IP from "
397
"subnets allocation pool: %s") % (
398
port_ip, subnet['gateway_ip']))
401
self._clean_network()
402
super(NetworksTestDHCPv6, self).tearDown()