56
57
from nova.compute import api as compute_api
57
58
from nova import context
58
59
from nova import exception
59
from nova import flags
60
60
from nova import ipv6
61
61
from nova import manager
62
62
from nova.network import api as network_api
63
63
from nova.network import model as network_model
64
from nova.network import rpcapi as network_rpcapi
64
65
from nova.openstack.common import cfg
65
66
from nova.openstack.common import excutils
66
67
from nova.openstack.common import importutils
67
from nova.openstack.common import jsonutils
68
from nova.openstack.common import lockutils
68
69
from nova.openstack.common import log as logging
69
70
from nova.openstack.common.notifier import api as notifier
70
from nova.openstack.common import rpc
71
71
from nova.openstack.common import timeutils
72
from nova.openstack.common import uuidutils
73
74
from nova import quota
74
75
from nova import utils
159
160
help="Indicates underlying L3 management library")
164
FLAGS.register_opts(network_opts)
164
CONF.register_opts(network_opts)
165
CONF.import_opt('fake_network', 'nova.config')
166
CONF.import_opt('floating_ip_dns_manager', 'nova.config')
167
CONF.import_opt('instance_dns_domain', 'nova.config')
168
CONF.import_opt('instance_dns_manager', 'nova.config')
169
CONF.import_opt('network_driver', 'nova.config')
170
CONF.import_opt('use_ipv6', 'nova.config')
171
CONF.import_opt('my_ip', 'nova.config')
167
174
class RPCAllocateFixedIP(object):
191
198
host = network['host']
192
199
# NOTE(vish): if there is no network host, set one
194
host = rpc.call(context, FLAGS.network_topic,
195
{'method': 'set_network_host',
196
'args': {'network_ref':
197
jsonutils.to_primitive(network)}})
201
host = self.network_rpcapi.set_network_host(context, network)
198
202
if host != self.host:
199
203
# need to call allocate_fixed_ip to correct network host
200
topic = rpc.queue_get_for(context, FLAGS.network_topic, host)
202
args['instance_id'] = instance_id
203
args['network_id'] = network['id']
204
args['address'] = address
207
green_pool.spawn_n(rpc.call, context, topic,
208
{'method': '_rpc_allocate_fixed_ip',
204
green_pool.spawn_n(self.network_rpcapi._rpc_allocate_fixed_ip,
205
context, instance_id, network['id'], address, vpn,
211
208
# i am the correct host, run here
212
209
self.allocate_fixed_ip(context, instance_id, network,
223
220
network = self._get_network_by_id(context, network_id)
224
221
return self.allocate_fixed_ip(context, instance_id, network, **kwargs)
226
def deallocate_fixed_ip(self, context, address, host=None):
223
def deallocate_fixed_ip(self, context, address, host=None, teardown=True):
227
224
"""Call the superclass deallocate_fixed_ip if i'm the correct host
228
225
otherwise call to the correct host"""
229
226
fixed_ip = self.db.fixed_ip_get_by_address(context, address)
233
230
# NOTE(tr3buchet): but if we are, host came from instance['host']
234
231
if not network['multi_host']:
235
232
host = network['host']
236
if host != self.host:
237
# need to call deallocate_fixed_ip on correct network host
238
topic = rpc.queue_get_for(context, FLAGS.network_topic, host)
239
args = {'address': address,
241
rpc.call(context, topic,
242
{'method': 'deallocate_fixed_ip',
245
# i am the correct host, run here
246
super(RPCAllocateFixedIP, self).deallocate_fixed_ip(context,
233
if host == self.host:
234
# NOTE(vish): deallocate the fixed ip locally
235
return super(RPCAllocateFixedIP, self).deallocate_fixed_ip(context,
238
if network['multi_host']:
239
service = self.db.service_get_by_host_and_topic(context,
242
if not service or not utils.service_is_up(service):
243
# NOTE(vish): deallocate the fixed ip locally but don't
244
# teardown network devices
245
return super(RPCAllocateFixedIP, self).deallocate_fixed_ip(
246
context, address, teardown=False)
248
self.network_rpcapi.deallocate_fixed_ip(context, address, host)
250
251
def wrap_check_policy(func):
528
529
host = network['host']
530
interface = FLAGS.public_interface or floating_ip['interface']
531
interface = CONF.public_interface or floating_ip['interface']
531
532
if host == self.host:
532
533
# i'm the correct host
533
534
self._associate_floating_ip(context, floating_address,
534
535
fixed_address, interface)
536
537
# send to correct host
538
rpc.queue_get_for(context, FLAGS.network_topic, host),
539
{'method': '_associate_floating_ip',
540
'args': {'floating_address': floating_address,
541
'fixed_address': fixed_address,
542
'interface': interface}})
538
self.network_rpcapi._associate_floating_ip(context,
539
floating_address, fixed_address, interface, host)
544
541
return orig_instance_uuid
595
592
# send to correct host, unless i'm the correct host
596
593
network = self._get_network_by_id(context, fixed_ip['network_id'])
594
interface = CONF.public_interface or floating_ip['interface']
597
595
if network['multi_host']:
598
596
instance = self.db.instance_get_by_uuid(context,
599
597
fixed_ip['instance_uuid'])
600
host = instance['host']
598
service = self.db.service_get_by_host_and_topic(
599
context.elevated(), instance['host'], 'network')
600
if service and utils.service_is_up(service):
601
host = instance['host']
603
# NOTE(vish): if the service is down just deallocate the data
604
# locally. Set the host to local so the call will
605
# not go over rpc and set interface to None so the
606
# teardown in the driver does not happen.
602
610
host = network['host']
604
interface = FLAGS.public_interface or floating_ip['interface']
605
612
if host == self.host:
606
613
# i'm the correct host
607
614
self._disassociate_floating_ip(context, address, interface)
609
616
# send to correct host
611
rpc.queue_get_for(context, FLAGS.network_topic, host),
612
{'method': '_disassociate_floating_ip',
613
'args': {'address': address,
614
'interface': interface}})
617
self.network_rpcapi._disassociate_floating_ip(context, address,
616
620
def _disassociate_floating_ip(self, context, address, interface):
617
621
"""Performs db and driver calls to disassociate floating ip"""
618
622
# disassociate floating ip
619
623
fixed_address = self.db.floating_ip_disassociate(context, address)
622
self.l3driver.remove_floating_ip(address, fixed_address, interface)
627
self.l3driver.remove_floating_ip(address, fixed_address, interface)
623
628
payload = dict(project_id=context.project_id, floating_ip=address)
624
629
notifier.notify(context,
625
630
notifier.publisher_id("network"),
658
663
return [floating_ip['address'] for floating_ip in floating_ips]
665
def _is_stale_floating_ip_address(self, context, floating_ip):
667
self._floating_ip_owned_by_project(context, floating_ip)
668
except exception.NotAuthorized:
670
return False if floating_ip.get('fixed_ip_id') else True
673
def migrate_instance_start(self, context, instance_uuid,
675
rxtx_factor=None, project_id=None,
676
source=None, dest=None):
677
# We only care if floating_addresses are provided and we're
679
if not floating_addresses or (source and source == dest):
682
LOG.info(_("Starting migration network for instance"
683
" %(instance_uuid)s"), locals())
684
for address in floating_addresses:
685
floating_ip = self.db.floating_ip_get_by_address(context,
688
if self._is_stale_floating_ip_address(context, floating_ip):
689
LOG.warn(_("Floating ip address |%(address)s| no longer "
690
"belongs to instance %(instance_uuid)s. Will not"
691
"migrate it "), locals())
694
interface = CONF.public_interface or floating_ip['interface']
695
fixed_ip = self.db.fixed_ip_get(context,
696
floating_ip['fixed_ip_id'])
697
self.l3driver.remove_floating_ip(floating_ip['address'],
701
# NOTE(wenjianhn): Make this address will not be bound to public
702
# interface when restarts nova-network on dest compute node
703
self.db.floating_ip_update(context,
704
floating_ip['address'],
708
def migrate_instance_finish(self, context, instance_uuid,
709
floating_addresses, host=None,
710
rxtx_factor=None, project_id=None,
711
source=None, dest=None):
712
# We only care if floating_addresses are provided and we're
714
if host and not dest:
716
if not floating_addresses or (source and source == dest):
719
LOG.info(_("Finishing migration network for instance"
720
" %(instance_uuid)s"), locals())
722
for address in floating_addresses:
723
floating_ip = self.db.floating_ip_get_by_address(context,
726
if self._is_stale_floating_ip_address(context, floating_ip):
727
LOG.warn(_("Floating ip address |%(address)s| no longer "
728
"belongs to instance %(instance_uuid)s. Will not"
729
"setup it."), locals())
732
self.db.floating_ip_update(context,
733
floating_ip['address'],
736
interface = CONF.public_interface or floating_ip['interface']
737
fixed_ip = self.db.fixed_ip_get(context,
738
floating_ip['fixed_ip_id'])
739
self.l3driver.add_floating_ip(floating_ip['address'],
660
743
def _prepare_domain_entry(self, context, domain):
661
744
domainref = self.db.dnsdomain_get(context, domain)
662
745
scope = domainref.scope
786
871
def __init__(self, network_driver=None, *args, **kwargs):
787
872
if not network_driver:
788
network_driver = FLAGS.network_driver
873
network_driver = CONF.network_driver
789
874
self.driver = importutils.import_module(network_driver)
790
temp = importutils.import_object(FLAGS.instance_dns_manager)
791
self.instance_dns_manager = temp
792
self.instance_dns_domain = FLAGS.instance_dns_domain
793
temp = importutils.import_object(FLAGS.floating_ip_dns_manager)
794
self.floating_dns_manager = temp
875
self.instance_dns_manager = importutils.import_object(
876
CONF.instance_dns_manager)
877
self.instance_dns_domain = CONF.instance_dns_domain
878
self.floating_dns_manager = importutils.import_object(
879
CONF.floating_ip_dns_manager)
795
880
self.network_api = network_api.API()
881
self.network_rpcapi = network_rpcapi.NetworkAPI()
796
882
self.security_group_api = compute_api.SecurityGroupAPI()
797
883
self.compute_api = compute_api.API(
798
884
security_group_api=self.security_group_api)
801
887
# already imported ipam, import nova ipam here
802
888
if not hasattr(self, 'ipam'):
803
889
self._import_ipam_lib('nova.network.nova_ipam_lib')
804
l3_lib = kwargs.get("l3_lib", FLAGS.l3_lib)
890
l3_lib = kwargs.get("l3_lib", CONF.l3_lib)
805
891
self.l3driver = importutils.import_object(l3_lib)
807
893
super(NetworkManager, self).__init__(service_name='network',
810
896
def _import_ipam_lib(self, ipam_lib):
811
897
self.ipam = importutils.import_module(ipam_lib).get_ipam_lib(self)
813
@utils.synchronized('get_dhcp')
899
@lockutils.synchronized('get_dhcp', 'nova-')
814
900
def _get_dhcp_ip(self, context, network_ref, host=None):
815
901
"""Get the proper dhcp address to listen on."""
816
902
# NOTE(vish): this is for compatibility
1189
1275
vif = {'address': utils.generate_mac_address(),
1190
1276
'instance_uuid': instance_uuid,
1191
1277
'network_id': network_id,
1192
'uuid': str(utils.gen_uuid())}
1278
'uuid': str(uuid.uuid4())}
1193
1279
# try FLAG times to create a vif record with a unique mac_address
1194
for i in xrange(FLAGS.create_unique_mac_address_attempts):
1280
for i in xrange(CONF.create_unique_mac_address_attempts):
1196
1282
return self.db.virtual_interface_create(context, vif)
1197
1283
except exception.VirtualInterfaceCreateException:
1204
1290
@wrap_check_policy
1205
1291
def add_fixed_ip_to_instance(self, context, instance_id, host, network_id):
1206
1292
"""Adds a fixed ip to an instance from specified network."""
1207
if utils.is_uuid_like(network_id):
1293
if uuidutils.is_uuid_like(network_id):
1208
1294
network = self.get_network(context, network_id)
1210
1296
network = self._get_network_by_id(context, network_id)
1211
1297
self._allocate_fixed_ips(context, instance_id, host, [network])
1299
def get_backdoor_port(self, context):
1300
"""Return backdoor port for eventlet_backdoor"""
1301
return self.backdoor_port
1213
1303
@wrap_check_policy
1214
1304
def remove_fixed_ip_from_instance(self, context, instance_id, host,
1284
1374
self._setup_network_on_host(context, network)
1287
def deallocate_fixed_ip(self, context, address, host=None):
1377
def deallocate_fixed_ip(self, context, address, host=None, teardown=True):
1288
1378
"""Returns a fixed ip to the pool."""
1289
1379
fixed_ip_ref = self.db.fixed_ip_get_by_address(context, address)
1290
1380
vif_id = fixed_ip_ref['virtual_interface_id']
1301
1391
self.instance_dns_manager.delete_entry(n,
1302
1392
self.instance_dns_domain)
1304
network = self._get_network_by_id(context, fixed_ip_ref['network_id'])
1305
self._teardown_network_on_host(context, network)
1307
if FLAGS.force_dhcp_release:
1308
dev = self.driver.get_dev(network)
1309
# NOTE(vish): The below errors should never happen, but there may
1310
# be a race condition that is causing them per
1311
# https://code.launchpad.net/bugs/968457, so we log
1312
# an error to help track down the possible race.
1313
msg = _("Unable to release %s because vif doesn't exist.")
1315
LOG.error(msg % address)
1318
vif = self.db.virtual_interface_get(context, vif_id)
1321
LOG.error(msg % address)
1324
# NOTE(vish): This forces a packet so that the release_fixed_ip
1325
# callback will get called by nova-dhcpbridge.
1326
self.driver.release_dhcp(dev, address, vif['address'])
1328
1394
self.db.fixed_ip_update(context, address,
1329
1395
{'allocated': False,
1330
1396
'virtual_interface_id': None})
1399
network = self._get_network_by_id(context,
1400
fixed_ip_ref['network_id'])
1401
self._teardown_network_on_host(context, network)
1403
if CONF.force_dhcp_release:
1404
dev = self.driver.get_dev(network)
1405
# NOTE(vish): The below errors should never happen, but there
1406
# may be a race condition that is causing them per
1407
# https://code.launchpad.net/bugs/968457, so we log
1408
# an error to help track down the possible race.
1409
msg = _("Unable to release %s because vif doesn't exist.")
1411
LOG.error(msg % address)
1414
vif = self.db.virtual_interface_get(context, vif_id)
1417
LOG.error(msg % address)
1420
# NOTE(vish): This forces a packet so that the release_fixed_ip
1421
# callback will get called by nova-dhcpbridge.
1422
self.driver.release_dhcp(dev, address, vif['address'])
1332
1424
def lease_fixed_ip(self, context, address):
1333
1425
"""Called by dhcp-bridge when ip is leased."""
1334
1426
LOG.debug(_('Leased IP |%(address)s|'), locals(), context=context)
1403
1495
if not (kwargs["cidr"] or kwargs["cidr_v6"]):
1404
1496
raise exception.NetworkNotCreated(req="cidr or cidr_v6")
1406
kwargs["bridge"] = kwargs["bridge"] or FLAGS.flat_network_bridge
1498
kwargs["bridge"] = kwargs["bridge"] or CONF.flat_network_bridge
1407
1499
kwargs["bridge_interface"] = (kwargs["bridge_interface"] or
1408
FLAGS.flat_interface)
1500
CONF.flat_interface)
1410
1502
for fld in self.required_create_args:
1411
1503
if not kwargs[fld]:
1412
1504
raise exception.NetworkNotCreated(req=fld)
1414
kwargs["num_networks"] = kwargs["num_networks"] or FLAGS.num_networks
1506
kwargs["num_networks"] = kwargs["num_networks"] or CONF.num_networks
1415
1507
if not kwargs["network_size"]:
1416
1508
if kwargs["cidr"]:
1417
1509
fixnet = netaddr.IPNetwork(kwargs["cidr"])
1418
1510
each_subnet_size = fixnet.size / kwargs["num_networks"]
1419
if each_subnet_size > FLAGS.network_size:
1420
subnet = 32 - int(math.log(FLAGS.network_size_size, 2))
1511
if each_subnet_size > CONF.network_size:
1512
subnet = 32 - int(math.log(CONF.network_size_size, 2))
1421
1513
oversize_msg = _(
1422
1514
'Subnet(s) too large, defaulting to /%s.'
1423
1515
' To override, specify network_size flag.') % subnet
1424
1516
LOG.warn(oversize_msg)
1425
kwargs["network_size"] = FLAGS.network_size
1517
kwargs["network_size"] = CONF.network_size
1427
1519
kwargs["network_size"] = fixnet.size
1429
kwargs["network_size"] = FLAGS.network_size
1521
kwargs["network_size"] = CONF.network_size
1431
kwargs["multi_host"] = (FLAGS.multi_host
1523
kwargs["multi_host"] = (CONF.multi_host
1432
1524
if kwargs["multi_host"] is None
1434
1526
utils.bool_from_str(kwargs["multi_host"]))
1435
kwargs["vlan_start"] = kwargs.get("vlan_start") or FLAGS.vlan_start
1436
kwargs["vpn_start"] = kwargs.get("vpn_start") or FLAGS.vpn_start
1437
kwargs["dns1"] = kwargs["dns1"] or FLAGS.flat_network_dns
1527
kwargs["vlan_start"] = kwargs.get("vlan_start") or CONF.vlan_start
1528
kwargs["vpn_start"] = kwargs.get("vpn_start") or CONF.vpn_start
1529
kwargs["dns1"] = kwargs["dns1"] or CONF.flat_network_dns
1439
1531
if kwargs["fixed_cidr"]:
1440
1532
kwargs["fixed_cidr"] = netaddr.IPNetwork(kwargs["fixed_cidr"])
1657
1750
call_func(context, network)
1659
1752
# i'm not the right host, run call on correct host
1660
topic = rpc.queue_get_for(context, FLAGS.network_topic, host)
1661
args = {'network_id': network['id'], 'teardown': teardown}
1662
# NOTE(tr3buchet): the call is just to wait for completion
1663
green_pool.spawn_n(rpc.call, context, topic,
1664
{'method': 'rpc_setup_network_on_host',
1754
self.network_rpcapi.rpc_setup_network_on_host, context,
1755
network['id'], teardown, host)
1667
1757
# wait for all of the setups (if any) to finish
1668
1758
green_pool.waitall()
1831
1921
self.allocate_fixed_ip(context, instance_id,
1832
1922
network, address=address)
1834
def deallocate_fixed_ip(self, context, address, host=None):
1924
def deallocate_fixed_ip(self, context, address, host=None, teardown=True):
1835
1925
"""Returns a fixed ip to the pool."""
1836
super(FlatManager, self).deallocate_fixed_ip(context, address)
1926
super(FlatManager, self).deallocate_fixed_ip(context, address, host,
1837
1928
self.db.fixed_ip_disassociate(context, address)
1839
1930
def _setup_network_on_host(self, context, network):
1842
1933
# allocation, this functionality makes more sense in create_network
1843
1934
# but we'd have to move the flat_injected flag to compute
1845
net['injected'] = FLAGS.flat_injected
1936
net['injected'] = CONF.flat_injected
1846
1937
self.db.network_update(context, network['id'], net)
1848
1939
def _teardown_network_on_host(self, context, network):
1878
1969
"""Returns the floating IPs associated with a fixed_address"""
1972
def migrate_instance_start(self, context, instance_uuid,
1974
rxtx_factor=None, project_id=None,
1975
source=None, dest=None):
1978
def migrate_instance_finish(self, context, instance_uuid,
1979
floating_addresses, host=None,
1980
rxtx_factor=None, project_id=None,
1981
source=None, dest=None):
1882
1985
class FlatDHCPManager(RPCAllocateFixedIP, FloatingIP, NetworkManager):
1883
1986
"""Flat networking with dhcp.
1907
2010
self.l3driver.initialize_gateway(network)
1909
if not FLAGS.fake_network:
2012
if not CONF.fake_network:
1910
2013
dev = self.driver.get_dev(network)
1911
2014
self.driver.update_dhcp(context, dev, network)
1913
2016
self.driver.update_ra(context, dev, network)
1914
2017
gateway = utils.get_my_linklocal(dev)
1915
2018
self.db.network_update(context, network['id'],
1916
2019
{'gateway_v6': gateway})
1918
2021
def _teardown_network_on_host(self, context, network):
1919
if not FLAGS.fake_network:
2022
if not CONF.fake_network:
1920
2023
network['dhcp_server'] = self._get_dhcp_ip(context, network)
1921
2024
dev = self.driver.get_dev(network)
1922
2025
self.driver.update_dhcp(context, dev, network)
1996
2099
values = {'allocated': True,
1997
2100
'virtual_interface_id': vif['id']}
1998
2101
self.db.fixed_ip_update(context, address, values)
2103
if self._validate_instance_zone_for_dns_domain(context, instance):
2104
name = instance['display_name']
2105
uuid = instance['uuid']
2106
self.instance_dns_manager.create_entry(name, address,
2108
self.instance_dns_domain)
2109
self.instance_dns_manager.create_entry(uuid, address,
2111
self.instance_dns_domain)
1999
2113
self._setup_network_on_host(context, network)
2070
2184
# NOTE(vish): only ensure this forward if the address hasn't been set
2072
if address == FLAGS.vpn_ip and hasattr(self.driver,
2186
if address == CONF.vpn_ip and hasattr(self.driver,
2073
2187
"ensure_vpn_forward"):
2074
self.l3driver.add_vpn(FLAGS.vpn_ip,
2188
self.l3driver.add_vpn(CONF.vpn_ip,
2075
2189
network['vpn_public_port'],
2076
2190
network['vpn_private_address'])
2077
if not FLAGS.fake_network:
2191
if not CONF.fake_network:
2078
2192
dev = self.driver.get_dev(network)
2079
2193
self.driver.update_dhcp(context, dev, network)
2081
2195
self.driver.update_ra(context, dev, network)
2082
2196
gateway = utils.get_my_linklocal(dev)
2083
2197
self.db.network_update(context, network['id'],
2084
2198
{'gateway_v6': gateway})
2086
2200
def _teardown_network_on_host(self, context, network):
2087
if not FLAGS.fake_network:
2201
if not CONF.fake_network:
2088
2202
network['dhcp_server'] = self._get_dhcp_ip(context, network)
2089
2203
dev = self.driver.get_dev(network)
2090
2204
self.driver.update_dhcp(context, dev, network)