From 2807ea5464e610b4ac77d95f9216b86b5f36bde0 Mon Sep 17 00:00:00 2001 From: Ben Nemec Date: Mon, 13 May 2013 23:06:11 +0000 Subject: Don't inject settings for dynamic network When using Quantum for networking and setting flat_injected to inject network settings into the guest VM, Nova injects a static network configuration for networks using DHCP. This change checks for the existence of a dhcp server and, if found, does not inject static settings for that network. Due to limitations of the legacy network info, the fix only applies when new-style network info is passed to the injection template function. The only code still passing in legacy network info is in libvirt, and there is work ongoing to remove that dependency. Fixes bug 1163985 Fixes bug 1112659 Change-Id: I8d3f16bde22e1c6dc0d2432aa263e2b15ae5c93a --- nova/virt/netutils.py | 114 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 103 insertions(+), 11 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/netutils.py b/nova/virt/netutils.py index d38197948..301fa3b09 100644 --- a/nova/virt/netutils.py +++ b/nova/virt/netutils.py @@ -4,6 +4,7 @@ # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # Copyright (c) 2010 Citrix Systems, Inc. +# Copyright 2013 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -25,6 +26,8 @@ import netaddr from oslo.config import cfg +from nova.network import model + CONF = cfg.CONF CONF.import_opt('use_ipv6', 'nova.netconf') CONF.import_opt('injected_network_template', 'nova.virt.disk.api') @@ -55,6 +58,91 @@ def get_ip_version(cidr): return int(net.version) +def get_non_legacy_network_template(network_info, use_ipv6=CONF.use_ipv6, + template=CONF.injected_network_template): + """A new version of get_injected_network_template that does not rely on + legacy network info. + + Returns a rendered network template for the given network_info. When + libvirt's dependency on using legacy network info for network config + injection goes away, this function can replace + get_injected_network_template entirely. + + :param network_info: + :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info` + :param use_ipv6: If False, do not return IPv6 template information + even if an IPv6 subnet is present in network_info. + :param template: Path to the interfaces template file. + """ + if not (network_info and template): + return + + nets = [] + ifc_num = -1 + ipv6_is_available = False + + for vif in network_info: + if not vif['network'] or not vif['network']['subnets']: + continue + + network = vif['network'] + # NOTE(bnemec): The template only supports a single subnet per + # interface and I'm not sure how/if that can be fixed, so this + # code only takes the first subnet of the appropriate type. + subnet_v4 = [i for i in network['subnets'] if i['version'] == 4][0] + subnet_v6 = [i for i in network['subnets'] if i['version'] == 6] + if subnet_v6: + subnet_v6 = subnet_v6[0] + + ifc_num += 1 + + if (not network.get_meta('injected') or not subnet_v4['ips'] or + subnet_v4.get_meta('dhcp_server') is not None): + continue + + ip = subnet_v4['ips'][0] + address = ip['address'] + netmask = model.get_netmask(ip, subnet_v4) + gateway = '' + if subnet_v4['gateway']: + gateway = subnet_v4['gateway']['address'] + broadcast = str(subnet_v4.as_netaddr().broadcast) + dns = ' '.join([i['address'] for i in subnet_v4['dns']]) + # NOTE(bnemec): I don't think this code would handle a pure IPv6 + # environment properly, but I don't have such an environment in + # which to test/fix that. + address_v6 = None + gateway_v6 = None + netmask_v6 = None + have_ipv6 = (use_ipv6 and subnet_v6) + if have_ipv6: + if subnet_v6['ips']: + ipv6_is_available = True + ip_v6 = subnet_v6['ips'][0] + address_v6 = ip_v6['address'] + netmask_v6 = model.get_netmask(ip_v6, subnet_v6) + gateway_v6 = '' + if subnet_v6['gateway']: + gateway_v6 = subnet_v6['gateway']['address'] + + net_info = {'name': 'eth%d' % ifc_num, + 'address': address, + 'netmask': netmask, + 'gateway': gateway, + 'broadcast': broadcast, + 'dns': dns, + 'address_v6': address_v6, + 'gateway_v6': gateway_v6, + 'netmask_v6': netmask_v6, + } + nets.append(net_info) + + if not nets: + return + + return build_template(template, nets, ipv6_is_available) + + def get_injected_network_template(network_info, use_ipv6=CONF.use_ipv6, template=CONF.injected_network_template): """ @@ -62,17 +150,20 @@ def get_injected_network_template(network_info, use_ipv6=CONF.use_ipv6, :param network_info: :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info` - - Note: this code actually depends on the legacy network_info, but will - convert the type itself if necessary. + :param use_ipv6: If False, do not return IPv6 template information + even if an IPv6 subnet is present in network_info. + :param template: Path to the interfaces template file. """ - if network_info is None: - return None + if not (network_info and template): + return - # the code below depends on the legacy 'network_info' - if hasattr(network_info, 'legacy'): - network_info = network_info.legacy() + # If we're passed new network_info, make use of it instead of forcing + # it to the legacy format required below. + if isinstance(network_info, model.NetworkInfo): + return get_non_legacy_network_template(network_info, + use_ipv6, + template) nets = [] ifc_num = -1 @@ -107,11 +198,12 @@ def get_injected_network_template(network_info, use_ipv6=CONF.use_ipv6, nets.append(net_info) if have_injected_networks is False: - return None + return + + return build_template(template, nets, ipv6_is_available) - if not template: - return None +def build_template(template, nets, ipv6_is_available): _late_load_cheetah() ifc_template = open(template).read() -- cgit