blob: 5643c88c32b8da5a834ce3ed8df8a3f8d7b22c67 [file] [log] [blame]
Sergey Shnaidmanf0ce2252014-08-28 13:05:08 +04001# Copyright 2014 OpenStack Foundation
2# All Rights Reserved.
3#
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
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
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
14# under the License.
15
16import netaddr
17import random
18
19from tempest.api.network import base
20from tempest.common.utils import data_utils
21from tempest import config
22from tempest import exceptions
23
24CONF = config.CONF
25
26
27class NetworksTestDHCPv6(base.BaseNetworkTest):
28 _interface = 'json'
29 _ip_version = 6
30
31 """ Test DHCPv6 specific features using SLAAC, stateless and
32 stateful settings for subnets. Also it shall check dual-stack
33 functionality (IPv4 + IPv6 together).
34 The tests include:
35 generating of SLAAC EUI-64 address in subnets with various settings
36 receiving SLAAC addresses in combinations of various subnets
37 receiving stateful IPv6 addresses
38 addressing in subnets with router
39 """
40
41 @classmethod
42 def resource_setup(cls):
43 msg = None
44 if not CONF.network_feature_enabled.ipv6:
45 msg = "IPv6 is not enabled"
46 elif not CONF.network_feature_enabled.ipv6_subnet_attributes:
47 msg = "DHCPv6 attributes are not enabled."
48 if msg:
49 raise cls.skipException(msg)
50 super(NetworksTestDHCPv6, cls).resource_setup()
51 cls.network = cls.create_network()
52
53 def _remove_from_list_by_index(self, things_list, elem):
54 for index, i in enumerate(things_list):
55 if i['id'] == elem['id']:
56 break
57 del things_list[index]
58
59 def _clean_network(self):
David Kranz34e88122014-12-11 15:24:05 -050060 body = self.client.list_ports()
Sergey Shnaidmanf0ce2252014-08-28 13:05:08 +040061 ports = body['ports']
62 for port in ports:
Michael Smithc0514d52014-12-18 10:37:49 -080063 if (port['device_owner'].startswith('network:router_interface')
Sergey Shnaidmanf0ce2252014-08-28 13:05:08 +040064 and port['device_id'] in [r['id'] for r in self.routers]):
65 self.client.remove_router_interface_with_port_id(
66 port['device_id'], port['id']
67 )
68 else:
69 if port['id'] in [p['id'] for p in self.ports]:
70 self.client.delete_port(port['id'])
71 self._remove_from_list_by_index(self.ports, port)
David Kranz34e88122014-12-11 15:24:05 -050072 body = self.client.list_subnets()
Sergey Shnaidmanf0ce2252014-08-28 13:05:08 +040073 subnets = body['subnets']
74 for subnet in subnets:
75 if subnet['id'] in [s['id'] for s in self.subnets]:
76 self.client.delete_subnet(subnet['id'])
77 self._remove_from_list_by_index(self.subnets, subnet)
David Kranz34e88122014-12-11 15:24:05 -050078 body = self.client.list_routers()
Sergey Shnaidmanf0ce2252014-08-28 13:05:08 +040079 routers = body['routers']
80 for router in routers:
81 if router['id'] in [r['id'] for r in self.routers]:
82 self.client.delete_router(router['id'])
83 self._remove_from_list_by_index(self.routers, router)
84
85 def _get_ips_from_subnet(self, **kwargs):
86 subnet = self.create_subnet(self.network, **kwargs)
87 port_mac = data_utils.rand_mac_address()
88 port = self.create_port(self.network, mac_address=port_mac)
89 real_ip = next(iter(port['fixed_ips']), None)['ip_address']
90 eui_ip = data_utils.get_ipv6_addr_by_EUI64(subnet['cidr'],
91 port_mac).format()
92 return real_ip, eui_ip
93
94 def test_dhcpv6_stateless_eui64(self):
95 """When subnets configured with RAs SLAAC (AOM=100) and DHCP stateless
96 (AOM=110) both for radvd and dnsmasq, port shall receive IP address
97 calculated from its MAC.
98 """
99 for ra_mode, add_mode in (
100 ('slaac', 'slaac'),
101 ('dhcpv6-stateless', 'dhcpv6-stateless'),
102 ):
103 kwargs = {'ipv6_ra_mode': ra_mode,
104 'ipv6_address_mode': add_mode}
105 real_ip, eui_ip = self._get_ips_from_subnet(**kwargs)
106 self._clean_network()
107 self.assertEqual(eui_ip, real_ip,
108 ('Real port IP is %s, but shall be %s when '
109 'ipv6_ra_mode=%s and ipv6_address_mode=%s') % (
110 real_ip, eui_ip, ra_mode, add_mode))
111
112 def test_dhcpv6_stateless_no_ra(self):
113 """When subnets configured with dnsmasq SLAAC and DHCP stateless
114 and there is no radvd, port shall receive IP address calculated
115 from its MAC and mask of subnet.
116 """
117 for ra_mode, add_mode in (
118 (None, 'slaac'),
119 (None, 'dhcpv6-stateless'),
120 ):
121 kwargs = {'ipv6_ra_mode': ra_mode,
122 'ipv6_address_mode': add_mode}
123 kwargs = {k: v for k, v in kwargs.iteritems() if v}
124 real_ip, eui_ip = self._get_ips_from_subnet(**kwargs)
125 self._clean_network()
126 self.assertEqual(eui_ip, real_ip,
127 ('Real port IP %s shall be equal to EUI-64 %s'
128 'when ipv6_ra_mode=%s,ipv6_address_mode=%s') % (
129 real_ip, eui_ip,
130 ra_mode if ra_mode else "Off",
131 add_mode if add_mode else "Off"))
132
133 def test_dhcpv6_invalid_options(self):
134 """Different configurations for radvd and dnsmasq are not allowed"""
135 for ra_mode, add_mode in (
136 ('dhcpv6-stateless', 'dhcpv6-stateful'),
137 ('dhcpv6-stateless', 'slaac'),
138 ('slaac', 'dhcpv6-stateful'),
139 ('dhcpv6-stateful', 'dhcpv6-stateless'),
140 ('dhcpv6-stateful', 'slaac'),
141 ('slaac', 'dhcpv6-stateless'),
142 ):
143 kwargs = {'ipv6_ra_mode': ra_mode,
144 'ipv6_address_mode': add_mode}
145 self.assertRaises(exceptions.BadRequest,
146 self.create_subnet,
147 self.network,
148 **kwargs)
149
150 def test_dhcpv6_stateless_no_ra_no_dhcp(self):
151 """If no radvd option and no dnsmasq option is configured
152 port shall receive IP from fixed IPs list of subnet.
153 """
154 real_ip, eui_ip = self._get_ips_from_subnet()
155 self._clean_network()
156 self.assertNotEqual(eui_ip, real_ip,
157 ('Real port IP %s equal to EUI-64 %s when '
158 'ipv6_ra_mode=Off and ipv6_address_mode=Off,'
159 'but shall be taken from fixed IPs') % (
160 real_ip, eui_ip))
161
162 def test_dhcpv6_two_subnets(self):
163 """When one IPv6 subnet configured with dnsmasq SLAAC or DHCP stateless
164 and other IPv6 is with DHCP stateful, port shall receive EUI-64 IP
165 addresses from first subnet and DHCP address from second one.
166 Order of subnet creating should be unimportant.
167 """
168 for order in ("slaac_first", "dhcp_first"):
169 for ra_mode, add_mode in (
170 ('slaac', 'slaac'),
171 ('dhcpv6-stateless', 'dhcpv6-stateless'),
172 ):
173 kwargs = {'ipv6_ra_mode': ra_mode,
174 'ipv6_address_mode': add_mode}
175 kwargs_dhcp = {'ipv6_address_mode': 'dhcpv6-stateful'}
176 if order == "slaac_first":
177 subnet_slaac = self.create_subnet(self.network, **kwargs)
178 subnet_dhcp = self.create_subnet(
179 self.network, **kwargs_dhcp)
180 else:
181 subnet_dhcp = self.create_subnet(
182 self.network, **kwargs_dhcp)
183 subnet_slaac = self.create_subnet(self.network, **kwargs)
184 port_mac = data_utils.rand_mac_address()
185 dhcp_ip = subnet_dhcp["allocation_pools"][0]["start"]
186 eui_ip = data_utils.get_ipv6_addr_by_EUI64(
187 subnet_slaac['cidr'],
188 port_mac
189 ).format()
190 # TODO(sergsh): remove this when 1219795 is fixed
191 dhcp_ip = [dhcp_ip, (netaddr.IPAddress(dhcp_ip) + 1).format()]
192 port = self.create_port(self.network, mac_address=port_mac)
193 real_ips = dict([(k['subnet_id'], k['ip_address'])
194 for k in port['fixed_ips']])
195 real_dhcp_ip, real_eui_ip = [real_ips[sub['id']]
196 for sub in subnet_dhcp,
197 subnet_slaac]
198 self.client.delete_port(port['id'])
199 self.ports.pop()
David Kranz34e88122014-12-11 15:24:05 -0500200 body = self.client.list_ports()
Sergey Shnaidmanf0ce2252014-08-28 13:05:08 +0400201 ports_id_list = [i['id'] for i in body['ports']]
202 self.assertNotIn(port['id'], ports_id_list)
203 self._clean_network()
204 self.assertEqual(real_eui_ip,
205 eui_ip,
206 'Real IP is {0}, but shall be {1}'.format(
207 real_eui_ip,
208 eui_ip))
209 self.assertIn(
210 real_dhcp_ip, dhcp_ip,
211 'Real IP is {0}, but shall be one from {1}'.format(
212 real_dhcp_ip,
213 str(dhcp_ip)))
214
215 def test_dhcpv6_64_subnets(self):
216 """When one IPv6 subnet configured with dnsmasq SLAAC or DHCP stateless
217 and other IPv4 is with DHCP of IPv4, port shall receive EUI-64 IP
218 addresses from first subnet and IPv4 DHCP address from second one.
219 Order of subnet creating should be unimportant.
220 """
221 for order in ("slaac_first", "dhcp_first"):
222 for ra_mode, add_mode in (
223 ('slaac', 'slaac'),
224 ('dhcpv6-stateless', 'dhcpv6-stateless'),
225 ):
226 kwargs = {'ipv6_ra_mode': ra_mode,
227 'ipv6_address_mode': add_mode}
228 if order == "slaac_first":
229 subnet_slaac = self.create_subnet(self.network, **kwargs)
230 subnet_dhcp = self.create_subnet(
231 self.network, ip_version=4)
232 else:
233 subnet_dhcp = self.create_subnet(
234 self.network, ip_version=4)
235 subnet_slaac = self.create_subnet(self.network, **kwargs)
236 port_mac = data_utils.rand_mac_address()
237 dhcp_ip = subnet_dhcp["allocation_pools"][0]["start"]
238 eui_ip = data_utils.get_ipv6_addr_by_EUI64(
239 subnet_slaac['cidr'],
240 port_mac
241 ).format()
242 # TODO(sergsh): remove this when 1219795 is fixed
243 dhcp_ip = [dhcp_ip, (netaddr.IPAddress(dhcp_ip) + 1).format()]
244 port = self.create_port(self.network, mac_address=port_mac)
245 real_ips = dict([(k['subnet_id'], k['ip_address'])
246 for k in port['fixed_ips']])
247 real_dhcp_ip, real_eui_ip = [real_ips[sub['id']]
248 for sub in subnet_dhcp,
249 subnet_slaac]
250 self._clean_network()
251 self.assertTrue({real_eui_ip,
252 real_dhcp_ip}.issubset([eui_ip] + dhcp_ip))
253 self.assertEqual(real_eui_ip,
254 eui_ip,
255 'Real IP is {0}, but shall be {1}'.format(
256 real_eui_ip,
257 eui_ip))
258 self.assertIn(
259 real_dhcp_ip, dhcp_ip,
260 'Real IP is {0}, but shall be one from {1}'.format(
261 real_dhcp_ip,
262 str(dhcp_ip)))
263
264 def test_dhcp_stateful(self):
265 """With all options below, DHCPv6 shall allocate first
266 address from subnet pool to port.
267 """
268 for ra_mode, add_mode in (
269 ('dhcpv6-stateful', 'dhcpv6-stateful'),
270 ('dhcpv6-stateful', None),
271 (None, 'dhcpv6-stateful'),
272 ):
273 kwargs = {'ipv6_ra_mode': ra_mode,
274 'ipv6_address_mode': add_mode}
275 kwargs = {k: v for k, v in kwargs.iteritems() if v}
276 subnet = self.create_subnet(self.network, **kwargs)
277 port = self.create_port(self.network)
278 port_ip = next(iter(port['fixed_ips']), None)['ip_address']
279 dhcp_ip = subnet["allocation_pools"][0]["start"]
280 # TODO(sergsh): remove this when 1219795 is fixed
281 dhcp_ip = [dhcp_ip, (netaddr.IPAddress(dhcp_ip) + 1).format()]
282 self._clean_network()
283 self.assertIn(
284 port_ip, dhcp_ip,
285 'Real IP is {0}, but shall be one from {1}'.format(
286 port_ip,
287 str(dhcp_ip)))
288
289 def test_dhcp_stateful_fixedips(self):
290 """With all options below, port shall be able to get
291 requested IP from fixed IP range not depending on
292 DHCP stateful (not SLAAC!) settings configured.
293 """
294 for ra_mode, add_mode in (
295 ('dhcpv6-stateful', 'dhcpv6-stateful'),
296 ('dhcpv6-stateful', None),
297 (None, 'dhcpv6-stateful'),
298 ):
299 kwargs = {'ipv6_ra_mode': ra_mode,
300 'ipv6_address_mode': add_mode}
301 kwargs = {k: v for k, v in kwargs.iteritems() if v}
302 subnet = self.create_subnet(self.network, **kwargs)
303 ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"],
304 subnet["allocation_pools"][0]["end"])
305 ip = netaddr.IPAddress(random.randrange(ip_range.first,
306 ip_range.last)).format()
307 port = self.create_port(self.network,
308 fixed_ips=[{'subnet_id': subnet['id'],
309 'ip_address': ip}])
310 port_ip = next(iter(port['fixed_ips']), None)['ip_address']
311 self._clean_network()
312 self.assertEqual(port_ip, ip,
313 ("Port IP %s is not as fixed IP from "
314 "port create request: %s") % (
315 port_ip, ip))
316
317 def test_dhcp_stateful_fixedips_outrange(self):
318 """When port gets IP address from fixed IP range it
319 shall be checked if it's from subnets range.
320 """
321 kwargs = {'ipv6_ra_mode': 'dhcpv6-stateful',
322 'ipv6_address_mode': 'dhcpv6-stateful'}
323 subnet = self.create_subnet(self.network, **kwargs)
324 ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"],
325 subnet["allocation_pools"][0]["end"])
326 ip = netaddr.IPAddress(random.randrange(
327 ip_range.last + 1, ip_range.last + 10)).format()
328 self.assertRaisesRegexp(exceptions.BadRequest,
329 "not a valid IP for the defined subnet",
330 self.create_port,
331 self.network,
332 fixed_ips=[{'subnet_id': subnet['id'],
333 'ip_address': ip}])
334
335 def test_dhcp_stateful_fixedips_duplicate(self):
336 """When port gets IP address from fixed IP range it
337 shall be checked if it's not duplicate.
338 """
339 kwargs = {'ipv6_ra_mode': 'dhcpv6-stateful',
340 'ipv6_address_mode': 'dhcpv6-stateful'}
341 subnet = self.create_subnet(self.network, **kwargs)
342 ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"],
343 subnet["allocation_pools"][0]["end"])
344 ip = netaddr.IPAddress(random.randrange(
345 ip_range.first, ip_range.last)).format()
346 self.create_port(self.network,
347 fixed_ips=[
348 {'subnet_id': subnet['id'],
349 'ip_address': ip}])
350 self.assertRaisesRegexp(exceptions.Conflict,
351 "object with that identifier already exists",
352 self.create_port,
353 self.network,
354 fixed_ips=[{'subnet_id': subnet['id'],
355 'ip_address': ip}])
356
357 def _create_subnet_router(self, kwargs):
358 subnet = self.create_subnet(self.network, **kwargs)
359 router = self.create_router(
360 router_name=data_utils.rand_name("routerv6-"),
361 admin_state_up=True)
362 port = self.create_router_interface(router['id'],
363 subnet['id'])
David Kranz34e88122014-12-11 15:24:05 -0500364 body = self.client.show_port(port['port_id'])
Sergey Shnaidmanf0ce2252014-08-28 13:05:08 +0400365 return subnet, body['port']
366
367 def test_dhcp_stateful_router(self):
368 """With all options below the router interface shall
369 receive DHCPv6 IP address from allocation pool.
370 """
371 for ra_mode, add_mode in (
372 ('dhcpv6-stateful', 'dhcpv6-stateful'),
373 ('dhcpv6-stateful', None),
Sergey Shnaidmanf0ce2252014-08-28 13:05:08 +0400374 ):
375 kwargs = {'ipv6_ra_mode': ra_mode,
376 'ipv6_address_mode': add_mode}
377 kwargs = {k: v for k, v in kwargs.iteritems() if v}
378 subnet, port = self._create_subnet_router(kwargs)
379 port_ip = next(iter(port['fixed_ips']), None)['ip_address']
380 self._clean_network()
381 self.assertEqual(port_ip, subnet['gateway_ip'],
382 ("Port IP %s is not as first IP from "
383 "subnets allocation pool: %s") % (
384 port_ip, subnet['gateway_ip']))
385
386 def tearDown(self):
387 self._clean_network()
388 super(NetworksTestDHCPv6, self).tearDown()