summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-02-02 00:50:14 +0000
committerGerrit Code Review <review@openstack.org>2012-02-02 00:50:14 +0000
commit5db0142d2f96e8e2d152aea59e7fc53d1e5ca012 (patch)
treebd751ab4ac2e100dce41110860cd9a3a627c1acb /nova
parent6a781345a8621258de39af30414b8ddead1c84b6 (diff)
parent9728ae541fc211e66260410b5dcb3bb3a92361ec (diff)
downloadnova-5db0142d2f96e8e2d152aea59e7fc53d1e5ca012.tar.gz
nova-5db0142d2f96e8e2d152aea59e7fc53d1e5ca012.tar.xz
nova-5db0142d2f96e8e2d152aea59e7fc53d1e5ca012.zip
Merge "Add support for pluggable l3 backends"
Diffstat (limited to 'nova')
-rw-r--r--nova/network/l3.py149
-rw-r--r--nova/network/manager.py61
-rw-r--r--nova/network/quantum/manager.py28
-rw-r--r--nova/tests/test_quantum.py4
-rw-r--r--nova/utils.py9
5 files changed, 193 insertions, 58 deletions
diff --git a/nova/network/l3.py b/nova/network/l3.py
new file mode 100644
index 000000000..034790f35
--- /dev/null
+++ b/nova/network/l3.py
@@ -0,0 +1,149 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 Nicira Networks, Inc
+# All Rights Reserved.
+#
+# 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
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import random
+
+from nova import flags
+from nova import log as logging
+from nova import utils
+from nova.network import linux_net
+
+LOG = logging.getLogger("nova.network.l3")
+
+FLAGS = flags.FLAGS
+
+
+class L3Driver(object):
+ """Abstract class that defines a generic L3 API"""
+
+ def __init__(self, l3_lib=None):
+ raise NotImplementedError()
+
+ def initialize(self, **kwargs):
+ """Set up basic L3 networking functionality"""
+ raise NotImplementedError()
+
+ def initialize_network(self, network):
+ """Enable rules for a specific network"""
+ raise NotImplementedError()
+
+ def initialize_gateway(self, network):
+ """Set up a gateway on this network"""
+ raise NotImplementedError()
+
+ def is_initialized(self):
+ """:returns: True/False (whether the driver is initialized)"""
+ raise NotImplementedError()
+
+ def add_floating_ip(self, floating_ip, fixed_ip, l3_interface_id):
+ """Add a floating IP bound to the fixed IP with an optional
+ l3_interface_id. Some drivers won't care about the
+ l3_interface_id so just pass None in that case"""
+ raise NotImplementedError()
+
+ def remove_floating_ip(self, floating_ip, fixed_ip, l3_interface_id):
+ raise NotImplementedError()
+
+ def add_vpn(self, public_ip, port, private_ip):
+ raise NotImplementedError()
+
+ def remove_vpn(self, public_ip, port, private_ip):
+ raise NotImplementedError()
+
+ def teardown(self):
+ raise NotImplementedError()
+
+
+class LinuxNetL3(L3Driver):
+ """L3 driver that uses linux_net as the backend"""
+ def __init__(self):
+ self.initialized = False
+
+ def initialize(self, **kwargs):
+ if self.initialized:
+ return
+ LOG.debug("Initializing linux_net L3 driver")
+ linux_net.init_host()
+ linux_net.ensure_metadata_ip()
+ linux_net.metadata_forward()
+ self.initialized = True
+
+ def is_initialized(self):
+ return self.initialized == True
+
+ def initialize_network(self, cidr):
+ linux_net.add_snat_rule(cidr)
+
+ def initialize_gateway(self, network_ref):
+ mac_address = utils.generate_mac_address()
+ dev = linux_net.plug(network_ref, mac_address,
+ gateway=(network_ref['gateway'] is not None))
+ linux_net.initialize_gateway_device(dev, network_ref)
+
+ def add_floating_ip(self, floating_ip, fixed_ip, l3_interface_id):
+ linux_net.bind_floating_ip(floating_ip, l3_interface_id)
+ linux_net.ensure_floating_forward(floating_ip, fixed_ip)
+
+ def remove_floating_ip(self, floating_ip, fixed_ip, l3_interface_id):
+ linux_net.unbind_floating_ip(floating_ip, l3_interface_id)
+ linux_net.remove_floating_forward(floating_ip, fixed_ip)
+
+ def add_vpn(self, public_ip, port, private_ip):
+ linux_net.ensure_vpn_forward(public_ip, port, private_ip)
+
+ def remove_vpn(self, public_ip, port, private_ip):
+ # Linux net currently doesn't implement any way of removing
+ # the VPN forwarding rules
+ pass
+
+ def teardown(self):
+ pass
+
+
+class NullL3(L3Driver):
+ """The L3 driver that doesn't do anything. This class can be used when
+ nova-network shuld not manipulate L3 forwarding at all (e.g., in a Flat
+ or FlatDHCP scenario"""
+ def __init__(self):
+ pass
+
+ def initialize(self, **kwargs):
+ pass
+
+ def is_initialized(self):
+ return True
+
+ def initialize_network(self, cidr):
+ pass
+
+ def initialize_gateway(self, network_ref):
+ pass
+
+ def add_floating_ip(self, floating_ip, fixed_ip, l3_interface_id):
+ pass
+
+ def remove_floating_ip(self, floating_ip, fixed_ip, l3_interface_id):
+ pass
+
+ def add_vpn(self, public_ip, port, private_ip):
+ pass
+
+ def remove_vpn(self, public_ip, port, private_ip):
+ pass
+
+ def teardown(self):
+ pass
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 3a0350bc2..350c01a69 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -155,8 +155,12 @@ network_opts = [
cfg.StrOpt('dhcp_domain',
default='novalocal',
help='domain to use for building the hostnames'),
+ cfg.StrOpt('l3_lib',
+ default='nova.network.l3.LinuxNetL3',
+ help="Indicates underlying L3 management library")
]
+
FLAGS = flags.FLAGS
FLAGS.add_options(network_opts)
@@ -264,16 +268,13 @@ class FloatingIP(object):
fixed_address = floating_ip['fixed_ip']['address']
interface = floating_ip['interface']
try:
- self.driver.bind_floating_ip(floating_ip['address'],
- interface)
+ self.l3driver.add_floating_ip(floating_ip['address'],
+ fixed_address, floating_ip['interface'])
except exception.ProcessExecutionError:
msg = _('Interface %(interface)s not found' % locals())
LOG.debug(msg)
raise exception.NoFloatingIpInterface(interface=interface)
- self.driver.ensure_floating_forward(floating_ip['address'],
- fixed_address)
-
@wrap_check_policy
def allocate_for_instance(self, context, **kwargs):
"""Handles allocating the floating IP resources for an instance.
@@ -458,7 +459,8 @@ class FloatingIP(object):
self.host)
try:
# gogo driver time
- self.driver.bind_floating_ip(floating_address, interface)
+ self.l3driver.add_floating_ip(floating_address, fixed_address,
+ interface)
except exception.ProcessExecutionError as e:
fixed_address = self.db.floating_ip_disassociate(context,
floating_address)
@@ -466,9 +468,6 @@ class FloatingIP(object):
msg = _('Interface %(interface)s not found' % locals())
LOG.error(msg)
raise exception.NoFloatingIpInterface(interface=interface)
- raise
-
- self.driver.ensure_floating_forward(floating_address, fixed_address)
@wrap_check_policy
def disassociate_floating_ip(self, context, address,
@@ -520,8 +519,7 @@ class FloatingIP(object):
fixed_address = self.db.floating_ip_disassociate(context, address)
# go go driver time
- self.driver.unbind_floating_ip(address, interface)
- self.driver.remove_floating_forward(address, fixed_address)
+ self.l3driver.remove_floating_ip(address, fixed_address, interface)
@wrap_check_policy
def get_floating_ip(self, context, id):
@@ -694,6 +692,8 @@ class NetworkManager(manager.SchedulerDependentManager):
# already imported ipam, import nova ipam here
if not hasattr(self, 'ipam'):
self._import_ipam_lib('nova.network.quantum.nova_ipam_lib')
+ l3_lib = kwargs.get("l3_lib", FLAGS.l3_lib)
+ self.l3driver = utils.import_object(l3_lib)
super(NetworkManager, self).__init__(service_name='network',
*args, **kwargs)
@@ -1064,7 +1064,7 @@ class NetworkManager(manager.SchedulerDependentManager):
self.add_virtual_interface(context, instance_id, network['id'])
def add_virtual_interface(self, context, instance_id, network_id):
- vif = {'address': self.generate_mac_address(),
+ vif = {'address': utils.generate_mac_address(),
'instance_id': instance_id,
'network_id': network_id,
'uuid': str(utils.gen_uuid())}
@@ -1073,20 +1073,12 @@ class NetworkManager(manager.SchedulerDependentManager):
try:
return self.db.virtual_interface_create(context, vif)
except exception.VirtualInterfaceCreateException:
- vif['address'] = self.generate_mac_address()
+ vif['address'] = utils.generate_mac_address()
else:
self.db.virtual_interface_delete_by_instance(context,
instance_id)
raise exception.VirtualInterfaceMacAddressException()
- def generate_mac_address(self):
- """Generate an Ethernet MAC address."""
- mac = [0x02, 0x16, 0x3e,
- random.randint(0x00, 0x7f),
- random.randint(0x00, 0xff),
- random.randint(0x00, 0xff)]
- return ':'.join(map(lambda x: "%02x" % x, mac))
-
@wrap_check_policy
def add_fixed_ip_to_instance(self, context, instance_id, host, network_id):
"""Adds a fixed ip to an instance from specified network."""
@@ -1558,23 +1550,18 @@ class FlatDHCPManager(RPCAllocateFixedIP, FloatingIP, NetworkManager):
"""Do any initialization that needs to be run if this is a
standalone service.
"""
- self.driver.init_host()
- self.driver.ensure_metadata_ip()
-
+ self.l3driver.initialize()
super(FlatDHCPManager, self).init_host()
self.init_host_floating_ips()
- self.driver.metadata_forward()
-
def _setup_network(self, context, network_ref):
"""Sets up network on this host."""
network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref)
- mac_address = self.generate_mac_address()
- dev = self.driver.plug(network_ref, mac_address)
- self.driver.initialize_gateway_device(dev, network_ref)
+ self.l3driver.initialize_gateway(network_ref)
if not FLAGS.fake_network:
+ dev = self.driver.get_dev(network_ref)
self.driver.update_dhcp(context, dev, network_ref)
if(FLAGS.use_ipv6):
self.driver.update_ra(context, dev, network_ref)
@@ -1627,14 +1614,10 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager):
standalone service.
"""
- self.driver.init_host()
- self.driver.ensure_metadata_ip()
-
+ self.l3driver.initialize()
NetworkManager.init_host(self)
self.init_host_floating_ips()
- self.driver.metadata_forward()
-
def allocate_fixed_ip(self, context, instance_id, network, **kwargs):
"""Gets a fixed ip from the pool."""
if kwargs.get('vpn', None):
@@ -1711,17 +1694,15 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager):
address = network_ref['vpn_public_address']
network_ref['dhcp_server'] = self._get_dhcp_ip(context, network_ref)
- mac_address = self.generate_mac_address()
- dev = self.driver.plug(network_ref, mac_address)
- self.driver.initialize_gateway_device(dev, network_ref)
+ self.l3driver.initialize_gateway(network_ref)
# NOTE(vish): only ensure this forward if the address hasn't been set
# manually.
if address == FLAGS.vpn_ip and hasattr(self.driver,
"ensure_vpn_forward"):
- self.driver.ensure_vpn_forward(FLAGS.vpn_ip,
- network_ref['vpn_public_port'],
- network_ref['vpn_private_address'])
+ self.l3driver.add_vpn(FLAGS.vpn_ip,
+ network_ref['vpn_public_port'],
+ network_ref['vpn_private_address'])
if not FLAGS.fake_network:
self.driver.update_dhcp(context, dev, network_ref)
if(FLAGS.use_ipv6):
diff --git a/nova/network/quantum/manager.py b/nova/network/quantum/manager.py
index f209e7abc..518676be0 100644
--- a/nova/network/quantum/manager.py
+++ b/nova/network/quantum/manager.py
@@ -27,11 +27,10 @@ from nova import exception
from nova import flags
from nova import log as logging
from nova.network import manager
-from nova.network.quantum import quantum_connection
from nova.network.quantum import melange_ipam_lib
+from nova.network.quantum import quantum_connection
from nova import utils
-
LOG = logging.getLogger("nova.network.quantum.manager")
quantum_opts = [
@@ -93,10 +92,8 @@ class QuantumManager(manager.FloatingIP, manager.FlatManager):
# Don't call into self.driver (linux_net) unless dhcp is enabled
if not FLAGS.quantum_use_dhcp:
return
-
- # Initialize forwarding rules for anything specified in
- # FLAGS.fixed_range()
- self.driver.init_host()
+ # Initialize general L3 networking
+ self.l3driver.initialize()
# Initialize floating ip support (only works for nova ipam currently)
if FLAGS.quantum_ipam_lib == 'nova.network.quantum.nova_ipam_lib':
LOG.debug("Initializing FloatingIP support")
@@ -104,13 +101,15 @@ class QuantumManager(manager.FloatingIP, manager.FlatManager):
# Set up all the forwarding rules for any network that has a
# gateway set.
networks = self.get_all_networks()
+ cidrs = []
for net in networks:
if net['gateway']:
LOG.debug("Initializing NAT: %s (cidr: %s, gw: %s)" % (
net['label'], net['cidr'], net['gateway']))
- self.driver.add_snat_rule(net['cidr'])
- self.driver.ensure_metadata_ip()
- self.driver.metadata_forward()
+ cidrs.append(net['cidr'])
+ # .. and for each network
+ for c in cidrs:
+ self.l3driver.initialize_network(c)
def _get_nova_id(self, instance=None):
# When creating the network we need to pass in an identifier for
@@ -213,9 +212,8 @@ class QuantumManager(manager.FloatingIP, manager.FlatManager):
priority, cidr, gateway, gateway_v6,
cidr_v6, dns1, dns2)
- # Initialize forwarding if gateway is set
- if gateway and FLAGS.quantum_use_dhcp:
- self.driver.add_snat_rule(cidr)
+ # Initialize forwarding
+ self.l3driver.initialize_network(cidr)
return [{'uuid': quantum_net_id}]
@@ -408,10 +406,8 @@ class QuantumManager(manager.FloatingIP, manager.FlatManager):
port = self.q_conn.get_port_by_attachment(q_tenant_id,
quantum_net_id, interface_id)
if not port: # No dhcp server has been started
- mac_address = self.generate_mac_address()
- dev = self.driver.plug(network_ref, mac_address,
- gateway=(network_ref['gateway'] is not None))
- self.driver.initialize_gateway_device(dev, network_ref)
+ self.l3driver.initialize_gateway(network_ref)
+ dev = self.driver.get_dev(network_ref)
LOG.debug("Intializing DHCP for network: %s" %
network_ref)
self.q_conn.create_and_attach_port(q_tenant_id,
diff --git a/nova/tests/test_quantum.py b/nova/tests/test_quantum.py
index 32f30fbf6..2e60bbc45 100644
--- a/nova/tests/test_quantum.py
+++ b/nova/tests/test_quantum.py
@@ -397,8 +397,8 @@ class QuantumNovaMACGenerationTestCase(QuantumNovaTestCase):
def test_local_mac_address_creation(self):
self.flags(use_melange_mac_generation=False)
fake_mac = "ab:cd:ef:ab:cd:ef"
- self.stubs.Set(manager.FlatManager, "generate_mac_address",
- lambda x: fake_mac)
+ self.stubs.Set(utils, "generate_mac_address",
+ lambda: fake_mac)
project_id = "fake_project1"
ctx = context.RequestContext('user1', project_id)
self._create_network(networks[0])
diff --git a/nova/utils.py b/nova/utils.py
index 675ec8623..0d3067fd3 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -1399,3 +1399,12 @@ def service_is_up(service):
# Timestamps in DB are UTC.
elapsed = total_seconds(utcnow() - last_heartbeat)
return abs(elapsed) <= FLAGS.service_down_time
+
+
+def generate_mac_address():
+ """Generate an Ethernet MAC address."""
+ mac = [0x02, 0x16, 0x3e,
+ random.randint(0x00, 0x7f),
+ random.randint(0x00, 0xff),
+ random.randint(0x00, 0xff)]
+ return ':'.join(map(lambda x: "%02x" % x, mac))