1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
6
# Licensed under the Apache License, Version 2.0 (the "License"); you may
7
# not use this file except in compliance with the License. You may obtain
8
# a copy of the License at
10
# http://www.apache.org/licenses/LICENSE-2.0
12
# Unless required by applicable law or agreed to in writing, software
13
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
# License for the specific language governing permissions and limitations
22
from nova import context
24
from nova import flags
25
from nova import log as logging
27
from nova import utils
28
from nova.network import linux_net
33
LOG = logging.getLogger(__name__)
38
instances = [{'id': 0,
39
'host': 'fake_instance00',
40
'created_at': 'fakedate',
41
'updated_at': 'fakedate',
42
'hostname': 'fake_instance00'},
44
'host': 'fake_instance01',
45
'created_at': 'fakedate',
46
'updated_at': 'fakedate',
47
'hostname': 'fake_instance01'}]
50
addresses = [{"address": "10.0.0.1"},
51
{"address": "10.0.0.2"},
52
{"address": "10.0.0.3"},
53
{"address": "10.0.0.4"},
54
{"address": "10.0.0.5"},
55
{"address": "10.0.0.6"}]
59
'uuid': "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
63
'cidr': '192.168.0.0/24',
64
'cidr_v6': '2001:db8::/64',
65
'gateway_v6': '2001:db8::1',
67
'netmask': '255.255.255.0',
69
'bridge_interface': 'fake_fa0',
70
'gateway': '192.168.0.1',
71
'broadcast': '192.168.0.255',
72
'dns1': '192.168.0.1',
73
'dns2': '192.168.0.2',
74
'dhcp_server': '0.0.0.0',
75
'dhcp_start': '192.168.100.1',
78
'project_id': 'fake_project',
79
'vpn_public_address': '192.168.0.2'},
81
'uuid': "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
85
'cidr': '192.168.1.0/24',
86
'cidr_v6': '2001:db9::/64',
87
'gateway_v6': '2001:db9::1',
89
'netmask': '255.255.255.0',
91
'bridge_interface': 'fake_fa1',
92
'gateway': '192.168.1.1',
93
'broadcast': '192.168.1.255',
94
'dns1': '192.168.0.1',
95
'dns2': '192.168.0.2',
96
'dhcp_server': '0.0.0.0',
97
'dhcp_start': '192.168.100.1',
100
'project_id': 'fake_project',
101
'vpn_public_address': '192.168.1.2'}]
104
fixed_ips = [{'id': 0,
106
'address': '192.168.0.100',
109
'virtual_interface_id': 0,
114
'address': '192.168.1.100',
117
'virtual_interface_id': 1,
122
'address': '192.168.0.101',
125
'virtual_interface_id': 2,
130
'address': '192.168.1.101',
133
'virtual_interface_id': 3,
138
'address': '192.168.0.102',
141
'virtual_interface_id': 4,
146
'address': '192.168.1.102',
149
'virtual_interface_id': 5,
155
'address': 'DE:AD:BE:EF:00:00',
156
'uuid': '00000000-0000-0000-0000-0000000000000000',
160
'address': 'DE:AD:BE:EF:00:01',
161
'uuid': '00000000-0000-0000-0000-0000000000000001',
165
'address': 'DE:AD:BE:EF:00:02',
166
'uuid': '00000000-0000-0000-0000-0000000000000002',
170
'address': 'DE:AD:BE:EF:00:03',
171
'uuid': '00000000-0000-0000-0000-0000000000000003',
175
'address': 'DE:AD:BE:EF:00:04',
176
'uuid': '00000000-0000-0000-0000-0000000000000004',
180
'address': 'DE:AD:BE:EF:00:05',
181
'uuid': '00000000-0000-0000-0000-0000000000000005',
186
def get_associated(context, network_id, host=None):
188
for datum in fixed_ips:
189
if (datum['network_id'] == network_id and datum['allocated']
190
and datum['instance_id'] is not None
191
and datum['virtual_interface_id'] is not None):
192
instance = instances[datum['instance_id']]
193
if host and host != instance['host']:
196
cleaned['address'] = datum['address']
197
cleaned['instance_id'] = datum['instance_id']
198
cleaned['network_id'] = datum['network_id']
199
cleaned['vif_id'] = datum['virtual_interface_id']
200
vif = vifs[datum['virtual_interface_id']]
201
cleaned['vif_address'] = vif['address']
202
cleaned['instance_hostname'] = instance['hostname']
203
cleaned['instance_updated'] = instance['updated_at']
204
cleaned['instance_created'] = instance['created_at']
205
result.append(cleaned)
209
class LinuxNetworkTestCase(test.TestCase):
212
super(LinuxNetworkTestCase, self).setUp()
213
network_driver = FLAGS.network_driver
214
self.driver = utils.import_object(network_driver)
216
self.context = context.RequestContext('testuser', 'testproject',
219
def get_vifs(_context, instance_id):
220
return [vif for vif in vifs if vif['instance_id'] == instance_id]
222
def get_instance(_context, instance_id):
223
return instances[instance_id]
225
self.stubs.Set(db, 'virtual_interface_get_by_instance', get_vifs)
226
self.stubs.Set(db, 'instance_get', get_instance)
227
self.stubs.Set(db, 'network_get_associated_fixed_ips', get_associated)
229
def test_update_dhcp_for_nw00(self):
230
self.flags(use_single_default_gateway=True)
232
self.mox.StubOutWithMock(self.driver, 'write_to_file')
233
self.mox.StubOutWithMock(self.driver, 'ensure_path')
234
self.mox.StubOutWithMock(os, 'chmod')
236
self.driver.write_to_file(mox.IgnoreArg(), mox.IgnoreArg())
237
self.driver.write_to_file(mox.IgnoreArg(), mox.IgnoreArg())
238
self.driver.ensure_path(mox.IgnoreArg())
239
self.driver.ensure_path(mox.IgnoreArg())
240
self.driver.ensure_path(mox.IgnoreArg())
241
self.driver.ensure_path(mox.IgnoreArg())
242
self.driver.ensure_path(mox.IgnoreArg())
243
self.driver.ensure_path(mox.IgnoreArg())
244
self.driver.ensure_path(mox.IgnoreArg())
245
os.chmod(mox.IgnoreArg(), mox.IgnoreArg())
246
os.chmod(mox.IgnoreArg(), mox.IgnoreArg())
250
self.driver.update_dhcp(self.context, "eth0", networks[0])
252
def test_update_dhcp_for_nw01(self):
253
self.flags(use_single_default_gateway=True)
255
self.mox.StubOutWithMock(self.driver, 'write_to_file')
256
self.mox.StubOutWithMock(self.driver, 'ensure_path')
257
self.mox.StubOutWithMock(os, 'chmod')
259
self.driver.write_to_file(mox.IgnoreArg(), mox.IgnoreArg())
260
self.driver.write_to_file(mox.IgnoreArg(), mox.IgnoreArg())
261
self.driver.ensure_path(mox.IgnoreArg())
262
self.driver.ensure_path(mox.IgnoreArg())
263
self.driver.ensure_path(mox.IgnoreArg())
264
self.driver.ensure_path(mox.IgnoreArg())
265
self.driver.ensure_path(mox.IgnoreArg())
266
self.driver.ensure_path(mox.IgnoreArg())
267
self.driver.ensure_path(mox.IgnoreArg())
268
os.chmod(mox.IgnoreArg(), mox.IgnoreArg())
269
os.chmod(mox.IgnoreArg(), mox.IgnoreArg())
273
self.driver.update_dhcp(self.context, "eth0", networks[0])
275
def test_get_dhcp_hosts_for_nw00(self):
276
self.flags(use_single_default_gateway=True)
279
"DE:AD:BE:EF:00:00,fake_instance00.novalocal,"
280
"192.168.0.100,net:NW-0\n"
281
"DE:AD:BE:EF:00:03,fake_instance01.novalocal,"
282
"192.168.1.101,net:NW-3\n"
283
"DE:AD:BE:EF:00:04,fake_instance00.novalocal,"
284
"192.168.0.102,net:NW-4"
286
actual_hosts = self.driver.get_dhcp_hosts(self.context, networks[0])
288
self.assertEquals(actual_hosts, expected)
290
def test_get_dhcp_hosts_for_nw01(self):
291
self.flags(use_single_default_gateway=True)
292
self.flags(host='fake_instance01')
295
"DE:AD:BE:EF:00:02,fake_instance01.novalocal,"
296
"192.168.0.101,net:NW-2\n"
297
"DE:AD:BE:EF:00:05,fake_instance01.novalocal,"
298
"192.168.1.102,net:NW-5"
300
actual_hosts = self.driver.get_dhcp_hosts(self.context, networks[1])
302
self.assertEquals(actual_hosts, expected)
304
def test_get_dhcp_opts_for_nw00(self):
305
expected_opts = 'NW-0,3\nNW-3,3\nNW-4,3'
306
actual_opts = self.driver.get_dhcp_opts(self.context, networks[0])
308
self.assertEquals(actual_opts, expected_opts)
310
def test_get_dhcp_opts_for_nw01(self):
311
self.flags(host='fake_instance01')
312
expected_opts = "NW-5,3"
313
actual_opts = self.driver.get_dhcp_opts(self.context, networks[1])
315
self.assertEquals(actual_opts, expected_opts)
317
def test_dhcp_opts_not_default_gateway_network(self):
319
data = get_associated(self.context, 0)[0]
320
actual = self.driver._host_dhcp_opts(data)
321
self.assertEquals(actual, expected)
323
def test_host_dhcp_without_default_gateway_network(self):
324
expected = ','.join(['DE:AD:BE:EF:00:00',
325
'fake_instance00.novalocal',
327
data = get_associated(self.context, 0)[0]
328
actual = self.driver._host_dhcp(data)
329
self.assertEquals(actual, expected)
331
def test_linux_bridge_driver_plug(self):
332
"""Makes sure plug doesn't drop FORWARD by default.
334
Ensures bug 890195 doesn't reappear."""
336
def fake_execute(*args, **kwargs):
338
self.stubs.Set(utils, 'execute', fake_execute)
340
def verify_add_rule(chain, rule):
341
self.assertEqual(chain, 'FORWARD')
342
self.assertIn('ACCEPT', rule)
343
self.stubs.Set(linux_net.iptables_manager.ipv4['filter'],
344
'add_rule', verify_add_rule)
345
driver = linux_net.LinuxBridgeInterfaceDriver()
346
driver.plug({"bridge": "br100", "bridge_interface": "eth0"},
349
def test_vlan_override(self):
350
"""Makes sure vlan_interface flag overrides network bridge_interface.
352
Allows heterogeneous networks a la bug 833426"""
354
driver = linux_net.LinuxBridgeInterfaceDriver()
359
def test_ensure(_self, vlan, bridge, interface, network, mac_address):
360
info['passed_interface'] = interface
362
self.stubs.Set(linux_net.LinuxBridgeInterfaceDriver,
363
'ensure_vlan_bridge', test_ensure)
367
"bridge_interface": "base_interface",
370
driver.plug(network, "fakemac")
371
self.assertEqual(info['passed_interface'], "base_interface")
372
self.flags(vlan_interface="override_interface")
373
driver.plug(network, "fakemac")
374
self.assertEqual(info['passed_interface'], "override_interface")
375
driver.plug(network, "fakemac")
377
def test_flat_override(self):
378
"""Makes sure flat_interface flag overrides network bridge_interface.
380
Allows heterogeneous networks a la bug 833426"""
382
driver = linux_net.LinuxBridgeInterfaceDriver()
387
def test_ensure(_self, bridge, interface, network, gateway):
388
info['passed_interface'] = interface
390
self.stubs.Set(linux_net.LinuxBridgeInterfaceDriver,
391
'ensure_bridge', test_ensure)
395
"bridge_interface": "base_interface",
397
driver.plug(network, "fakemac")
398
self.assertEqual(info['passed_interface'], "base_interface")
399
self.flags(flat_interface="override_interface")
400
driver.plug(network, "fakemac")
401
self.assertEqual(info['passed_interface'], "override_interface")
403
def _test_initialize_gateway(self, existing, expected, routes=''):
404
self.flags(fake_network=False)
407
def fake_execute(*args, **kwargs):
408
executes.append(args)
409
if args[0] == 'ip' and args[1] == 'addr' and args[2] == 'show':
411
if args[0] == 'route' and args[1] == '-n':
413
self.stubs.Set(utils, 'execute', fake_execute)
414
network = {'dhcp_server': '192.168.1.1',
415
'cidr': '192.168.1.0/24',
416
'broadcast': '192.168.1.255',
417
'cidr_v6': '2001:db8::/64'}
418
self.driver.initialize_gateway_device('eth0', network)
419
self.assertEqual(executes, expected)
421
def test_initialize_gateway_moves_wrong_ip(self):
422
existing = ("2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> "
423
" mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000\n"
424
" link/ether de:ad:be:ef:be:ef brd ff:ff:ff:ff:ff:ff\n"
425
" inet 192.168.0.1/24 brd 192.168.0.255 scope global eth0\n"
426
" inet6 dead::beef:dead:beef:dead/64 scope link\n"
427
" valid_lft forever preferred_lft forever\n")
429
('ip', 'addr', 'show', 'dev', 'eth0', 'scope', 'global'),
431
('ip', 'addr', 'del', '192.168.0.1/24',
432
'brd', '192.168.0.255', 'scope', 'global', 'dev', 'eth0'),
433
('ip', 'addr', 'add', '192.168.1.1/24',
434
'brd', '192.168.1.255', 'dev', 'eth0'),
435
('ip', 'addr', 'add', '192.168.0.1/24',
436
'brd', '192.168.0.255', 'scope', 'global', 'dev', 'eth0'),
437
('ip', '-f', 'inet6', 'addr', 'change',
438
'2001:db8::/64', 'dev', 'eth0'),
440
self._test_initialize_gateway(existing, expected)
442
def test_initialize_gateway_resets_route(self):
443
routes = ("0.0.0.0 192.68.0.1 0.0.0.0 "
445
existing = ("2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> "
446
" mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000\n"
447
" link/ether de:ad:be:ef:be:ef brd ff:ff:ff:ff:ff:ff\n"
448
" inet 192.168.0.1/24 brd 192.168.0.255 scope global eth0\n"
449
" inet6 dead::beef:dead:beef:dead/64 scope link\n"
450
" valid_lft forever preferred_lft forever\n")
452
('ip', 'addr', 'show', 'dev', 'eth0', 'scope', 'global'),
454
('route', 'del', 'default', 'gw', '192.68.0.1', 'dev', 'eth0'),
455
('ip', 'addr', 'del', '192.168.0.1/24',
456
'brd', '192.168.0.255', 'scope', 'global', 'dev', 'eth0'),
457
('ip', 'addr', 'add', '192.168.1.1/24',
458
'brd', '192.168.1.255', 'dev', 'eth0'),
459
('ip', 'addr', 'add', '192.168.0.1/24',
460
'brd', '192.168.0.255', 'scope', 'global', 'dev', 'eth0'),
461
('route', 'add', 'default', 'gw', '192.68.0.1'),
462
('ip', '-f', 'inet6', 'addr', 'change',
463
'2001:db8::/64', 'dev', 'eth0'),
465
self._test_initialize_gateway(existing, expected, routes)
467
def test_initialize_gateway_no_move_right_ip(self):
468
existing = ("2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> "
469
" mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000\n"
470
" link/ether de:ad:be:ef:be:ef brd ff:ff:ff:ff:ff:ff\n"
471
" inet 192.168.1.1/24 brd 192.168.1.255 scope global eth0\n"
472
" inet 192.168.0.1/24 brd 192.168.0.255 scope global eth0\n"
473
" inet6 dead::beef:dead:beef:dead/64 scope link\n"
474
" valid_lft forever preferred_lft forever\n")
476
('ip', 'addr', 'show', 'dev', 'eth0', 'scope', 'global'),
477
('ip', '-f', 'inet6', 'addr', 'change',
478
'2001:db8::/64', 'dev', 'eth0'),
480
self._test_initialize_gateway(existing, expected)
482
def test_initialize_gateway_add_if_blank(self):
483
existing = ("2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> "
484
" mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000\n"
485
" link/ether de:ad:be:ef:be:ef brd ff:ff:ff:ff:ff:ff\n"
486
" inet6 dead::beef:dead:beef:dead/64 scope link\n"
487
" valid_lft forever preferred_lft forever\n")
489
('ip', 'addr', 'show', 'dev', 'eth0', 'scope', 'global'),
491
('ip', 'addr', 'add', '192.168.1.1/24',
492
'brd', '192.168.1.255', 'dev', 'eth0'),
493
('ip', '-f', 'inet6', 'addr', 'change',
494
'2001:db8::/64', 'dev', 'eth0'),
496
self._test_initialize_gateway(existing, expected)