summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/db/api.py13
-rw-r--r--nova/db/sqlalchemy/api.py25
-rw-r--r--nova/db/sqlalchemy/models.py6
-rw-r--r--nova/network/l3.py25
-rw-r--r--nova/network/linux_net.py25
-rw-r--r--nova/network/manager.py42
-rw-r--r--nova/tests/network/test_linux_net.py24
-rw-r--r--nova/tests/network/test_manager.py28
-rw-r--r--nova/tests/test_db_api.py4
9 files changed, 115 insertions, 77 deletions
diff --git a/nova/db/api.py b/nova/db/api.py
index 6af81e5f9..3c1425691 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -305,7 +305,7 @@ def floating_ip_destroy(context, address):
def floating_ip_disassociate(context, address):
"""Disassociate a floating ip from a fixed ip by address.
- :returns: the address of the previous fixed ip or None
+ :returns: the fixed ip record joined to network record or None
if the ip was not associated to an ip.
"""
@@ -316,7 +316,7 @@ def floating_ip_fixed_ip_associate(context, floating_address,
fixed_address, host):
"""Associate a floating ip to a fixed_ip by address.
- :returns: the address of the new fixed ip (fixed_address) or None
+ :returns: the fixed ip record joined to network record or None
if the ip was already associated to the fixed ip.
"""
@@ -477,9 +477,12 @@ def fixed_ip_disassociate_all_by_timeout(context, host, time):
return IMPL.fixed_ip_disassociate_all_by_timeout(context, host, time)
-def fixed_ip_get(context, id):
- """Get fixed ip by id or raise if it does not exist."""
- return IMPL.fixed_ip_get(context, id)
+def fixed_ip_get(context, id, get_network=False):
+ """Get fixed ip by id or raise if it does not exist.
+
+ If get_network is true, also return the assocated network.
+ """
+ return IMPL.fixed_ip_get(context, id, get_network)
def fixed_ip_get_all(context):
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index a6f585eef..61f27f31c 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -793,15 +793,16 @@ def floating_ip_fixed_ip_associate(context, floating_address,
floating_ip_ref = _floating_ip_get_by_address(context,
floating_address,
session=session)
- fixed_ip_ref = fixed_ip_get_by_address(context,
- fixed_address,
- session=session)
+ fixed_ip_ref = model_query(context, models.FixedIp, session=session).\
+ filter_by(address=fixed_address).\
+ options(joinedload('network')).\
+ first()
if floating_ip_ref.fixed_ip_id == fixed_ip_ref["id"]:
return None
floating_ip_ref.fixed_ip_id = fixed_ip_ref["id"]
floating_ip_ref.host = host
floating_ip_ref.save(session=session)
- return fixed_address
+ return fixed_ip_ref
@require_context
@@ -834,15 +835,12 @@ def floating_ip_disassociate(context, address):
fixed_ip_ref = model_query(context, models.FixedIp, session=session).\
filter_by(id=floating_ip_ref['fixed_ip_id']).\
+ options(joinedload('network')).\
first()
- if fixed_ip_ref:
- fixed_ip_address = fixed_ip_ref['address']
- else:
- fixed_ip_address = None
floating_ip_ref.fixed_ip_id = None
floating_ip_ref.host = None
floating_ip_ref.save(session=session)
- return fixed_ip_address
+ return fixed_ip_ref
@require_context
@@ -1140,10 +1138,11 @@ def fixed_ip_disassociate_all_by_timeout(context, host, time):
@require_context
-def fixed_ip_get(context, id):
- result = model_query(context, models.FixedIp).\
- filter_by(id=id).\
- first()
+def fixed_ip_get(context, id, get_network=False):
+ query = model_query(context, models.FixedIp).filter_by(id=id)
+ if get_network:
+ query = query.options(joinedload('network'))
+ result = query.first()
if not result:
raise exception.FixedIpNotFound(id=id)
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 05452f2ad..53d6f53bd 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -719,6 +719,12 @@ class FixedIp(BASE, NovaBase):
leased = Column(Boolean, default=False)
reserved = Column(Boolean, default=False)
host = Column(String(255))
+ network = relationship(Network,
+ backref=backref('fixed_ips'),
+ foreign_keys=network_id,
+ primaryjoin='and_('
+ 'FixedIp.network_id == Network.id,'
+ 'FixedIp.deleted == False)')
class FloatingIp(BASE, NovaBase):
diff --git a/nova/network/l3.py b/nova/network/l3.py
index baf77c112..14abf41eb 100644
--- a/nova/network/l3.py
+++ b/nova/network/l3.py
@@ -48,13 +48,16 @@ class L3Driver(object):
""":returns: True/False (whether the driver is initialized)."""
raise NotImplementedError()
- def add_floating_ip(self, floating_ip, fixed_ip, l3_interface_id):
+ def add_floating_ip(self, floating_ip, fixed_ip, l3_interface_id,
+ network=None):
"""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"""
+ l3_interface_id so just pass None in that case. Network
+ is also an optional parameter."""
raise NotImplementedError()
- def remove_floating_ip(self, floating_ip, fixed_ip, l3_interface_id):
+ def remove_floating_ip(self, floating_ip, fixed_ip, l3_interface_id,
+ network=None):
raise NotImplementedError()
def add_vpn(self, public_ip, port, private_ip):
@@ -96,15 +99,17 @@ class LinuxNetL3(L3Driver):
def remove_gateway(self, network_ref):
linux_net.unplug(network_ref)
- def add_floating_ip(self, floating_ip, fixed_ip, l3_interface_id):
+ def add_floating_ip(self, floating_ip, fixed_ip, l3_interface_id,
+ network=None):
linux_net.bind_floating_ip(floating_ip, l3_interface_id)
linux_net.ensure_floating_forward(floating_ip, fixed_ip,
- l3_interface_id)
+ l3_interface_id, network)
- def remove_floating_ip(self, floating_ip, fixed_ip, l3_interface_id):
+ def remove_floating_ip(self, floating_ip, fixed_ip, l3_interface_id,
+ network=None):
linux_net.unbind_floating_ip(floating_ip, l3_interface_id)
linux_net.remove_floating_forward(floating_ip, fixed_ip,
- l3_interface_id)
+ l3_interface_id, network)
def add_vpn(self, public_ip, port, private_ip):
linux_net.ensure_vpn_forward(public_ip, port, private_ip)
@@ -140,10 +145,12 @@ class NullL3(L3Driver):
def remove_gateway(self, network_ref):
pass
- def add_floating_ip(self, floating_ip, fixed_ip, l3_interface_id):
+ def add_floating_ip(self, floating_ip, fixed_ip, l3_interface_id,
+ network=None):
pass
- def remove_floating_ip(self, floating_ip, fixed_ip, l3_interface_id):
+ def remove_floating_ip(self, floating_ip, fixed_ip, l3_interface_id,
+ network=None):
pass
def add_vpn(self, public_ip, port, private_ip):
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index 434ce0b73..49afc65c4 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -654,18 +654,29 @@ def ensure_vpn_forward(public_ip, port, private_ip):
iptables_manager.apply()
-def ensure_floating_forward(floating_ip, fixed_ip, device):
+def ensure_floating_forward(floating_ip, fixed_ip, device, network):
"""Ensure floating ip forwarding rule."""
for chain, rule in floating_forward_rules(floating_ip, fixed_ip, device):
iptables_manager.ipv4['nat'].add_rule(chain, rule)
iptables_manager.apply()
+ if device != network['bridge']:
+ ensure_ebtables_rules(*floating_ebtables_rules(fixed_ip, network))
-def remove_floating_forward(floating_ip, fixed_ip, device):
+def remove_floating_forward(floating_ip, fixed_ip, device, network):
"""Remove forwarding for floating ip."""
for chain, rule in floating_forward_rules(floating_ip, fixed_ip, device):
iptables_manager.ipv4['nat'].remove_rule(chain, rule)
iptables_manager.apply()
+ if device != network['bridge']:
+ remove_ebtables_rules(*floating_ebtables_rules(fixed_ip, network))
+
+
+def floating_ebtables_rules(fixed_ip, network):
+ """Makes sure only in-network traffic is bridged."""
+ return (['PREROUTING --logical-in %s -p ipv4 --ip-src %s '
+ '! --ip-dst %s -j redirect --redirect-target ACCEPT' %
+ (network['bridge'], fixed_ip, network['cidr'])], 'nat')
def floating_forward_rules(floating_ip, fixed_ip, device):
@@ -1430,18 +1441,18 @@ class LinuxBridgeInterfaceDriver(LinuxNetInterfaceDriver):
@lockutils.synchronized('ebtables', 'nova-', external=True)
-def ensure_ebtables_rules(rules):
+def ensure_ebtables_rules(rules, table='filter'):
for rule in rules:
- cmd = ['ebtables', '-D'] + rule.split()
+ cmd = ['ebtables', '-t', table, '-D'] + rule.split()
_execute(*cmd, check_exit_code=False, run_as_root=True)
- cmd[1] = '-I'
+ cmd[3] = '-I'
_execute(*cmd, run_as_root=True)
@lockutils.synchronized('ebtables', 'nova-', external=True)
-def remove_ebtables_rules(rules):
+def remove_ebtables_rules(rules, table='filter'):
for rule in rules:
- cmd = ['ebtables', '-D'] + rule.split()
+ cmd = ['ebtables', '-t', table, '-D'] + rule.split()
_execute(*cmd, check_exit_code=False, run_as_root=True)
diff --git a/nova/network/manager.py b/nova/network/manager.py
index 8ee8f0290..d1dabdfd9 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -293,17 +293,19 @@ class FloatingIP(object):
fixed_ip_id = floating_ip.get('fixed_ip_id')
if fixed_ip_id:
try:
- fixed_ip_ref = self.db.fixed_ip_get(admin_context,
- fixed_ip_id)
+ fixed_ip = self.db.fixed_ip_get(admin_context,
+ fixed_ip_id,
+ get_network=True)
except exception.FixedIpNotFound:
msg = _('Fixed ip %(fixed_ip_id)s not found') % locals()
LOG.debug(msg)
continue
- fixed_address = fixed_ip_ref['address']
interface = CONF.public_interface or floating_ip['interface']
try:
self.l3driver.add_floating_ip(floating_ip['address'],
- fixed_address, interface)
+ fixed_ip['address'],
+ interface,
+ fixed_ip['network'])
except exception.ProcessExecutionError:
LOG.debug(_('Interface %(interface)s not found'), locals())
raise exception.NoFloatingIpInterface(interface=interface)
@@ -558,17 +560,17 @@ class FloatingIP(object):
@lockutils.synchronized(unicode(floating_address), 'nova-')
def do_associate():
# associate floating ip
- res = self.db.floating_ip_fixed_ip_associate(context,
- floating_address,
- fixed_address,
- self.host)
- if not res:
+ fixed = self.db.floating_ip_fixed_ip_associate(context,
+ floating_address,
+ fixed_address,
+ self.host)
+ if not fixed:
# NOTE(vish): ip was already associated
return
try:
# gogo driver time
self.l3driver.add_floating_ip(floating_address, fixed_address,
- interface)
+ interface, fixed['network'])
except exception.ProcessExecutionError as e:
self.db.floating_ip_disassociate(context, floating_address)
if "Cannot find device" in str(e):
@@ -651,15 +653,15 @@ class FloatingIP(object):
# don't worry about this case because the minuscule
# window where the ip is on both hosts shouldn't cause
# any problems.
- fixed_address = self.db.floating_ip_disassociate(context, address)
+ fixed = self.db.floating_ip_disassociate(context, address)
- if not fixed_address:
+ if not fixed:
# NOTE(vish): ip was already disassociated
return
if interface:
# go go driver time
- self.l3driver.remove_floating_ip(address, fixed_address,
- interface)
+ self.l3driver.remove_floating_ip(address, fixed['address'],
+ interface, fixed['network'])
payload = dict(project_id=context.project_id,
instance_id=instance_uuid,
floating_ip=address)
@@ -732,10 +734,12 @@ class FloatingIP(object):
interface = CONF.public_interface or floating_ip['interface']
fixed_ip = self.db.fixed_ip_get(context,
- floating_ip['fixed_ip_id'])
+ floating_ip['fixed_ip_id'],
+ get_network=True)
self.l3driver.remove_floating_ip(floating_ip['address'],
fixed_ip['address'],
- interface)
+ interface,
+ fixed_ip['network'])
# NOTE(wenjianhn): Make this address will not be bound to public
# interface when restarts nova-network on dest compute node
@@ -773,10 +777,12 @@ class FloatingIP(object):
interface = CONF.public_interface or floating_ip['interface']
fixed_ip = self.db.fixed_ip_get(context,
- floating_ip['fixed_ip_id'])
+ floating_ip['fixed_ip_id'],
+ get_network=True)
self.l3driver.add_floating_ip(floating_ip['address'],
fixed_ip['address'],
- interface)
+ interface,
+ fixed_ip['network'])
def _prepare_domain_entry(self, context, domain):
domainref = self.db.dnsdomain_get(context, domain)
diff --git a/nova/tests/network/test_linux_net.py b/nova/tests/network/test_linux_net.py
index 8a7865b83..3c219f5f4 100644
--- a/nova/tests/network/test_linux_net.py
+++ b/nova/tests/network/test_linux_net.py
@@ -461,14 +461,14 @@ class LinuxNetworkTestCase(test.TestCase):
'bridge_interface': iface}
driver.plug(network, 'fakemac')
expected = [
- ('ebtables', '-D', 'INPUT', '-p', 'ARP', '-i', iface,
- '--arp-ip-dst', dhcp, '-j', 'DROP'),
- ('ebtables', '-I', 'INPUT', '-p', 'ARP', '-i', iface,
- '--arp-ip-dst', dhcp, '-j', 'DROP'),
- ('ebtables', '-D', 'OUTPUT', '-p', 'ARP', '-o', iface,
- '--arp-ip-src', dhcp, '-j', 'DROP'),
- ('ebtables', '-I', 'OUTPUT', '-p', 'ARP', '-o', iface,
- '--arp-ip-src', dhcp, '-j', 'DROP'),
+ ('ebtables', '-t', 'filter', '-D', 'INPUT', '-p', 'ARP', '-i',
+ iface, '--arp-ip-dst', dhcp, '-j', 'DROP'),
+ ('ebtables', '-t', 'filter', '-I', 'INPUT', '-p', 'ARP', '-i',
+ iface, '--arp-ip-dst', dhcp, '-j', 'DROP'),
+ ('ebtables', '-t', 'filter', '-D', 'OUTPUT', '-p', 'ARP', '-o',
+ iface, '--arp-ip-src', dhcp, '-j', 'DROP'),
+ ('ebtables', '-t', 'filter', '-I', 'OUTPUT', '-p', 'ARP', '-o',
+ iface, '--arp-ip-src', dhcp, '-j', 'DROP'),
('iptables-save', '-c'),
('iptables-restore', '-c'),
('ip6tables-save', '-c'),
@@ -500,10 +500,10 @@ class LinuxNetworkTestCase(test.TestCase):
driver.unplug(network)
expected = [
- ('ebtables', '-D', 'INPUT', '-p', 'ARP', '-i', iface,
- '--arp-ip-dst', dhcp, '-j', 'DROP'),
- ('ebtables', '-D', 'OUTPUT', '-p', 'ARP', '-o', iface,
- '--arp-ip-src', dhcp, '-j', 'DROP'),
+ ('ebtables', '-t', 'filter', '-D', 'INPUT', '-p', 'ARP', '-i',
+ iface, '--arp-ip-dst', dhcp, '-j', 'DROP'),
+ ('ebtables', '-t', 'filter', '-D', 'OUTPUT', '-p', 'ARP', '-o',
+ iface, '--arp-ip-src', dhcp, '-j', 'DROP'),
('iptables-save', '-c'),
('iptables-restore', '-c'),
('ip6tables-save', '-c'),
diff --git a/nova/tests/network/test_manager.py b/nova/tests/network/test_manager.py
index c665aa1b3..2cc19bbb8 100644
--- a/nova/tests/network/test_manager.py
+++ b/nova/tests/network/test_manager.py
@@ -668,7 +668,7 @@ class VlanNetworkTestCase(test.TestCase):
is_admin=False)
def fake1(*args, **kwargs):
- return '10.0.0.1'
+ return {'address': '10.0.0.1', 'network': 'fakenet'}
# floating ip that's already associated
def fake2(*args, **kwargs):
@@ -788,9 +788,9 @@ class VlanNetworkTestCase(test.TestCase):
self.stubs.Set(self.network.db, 'floating_ip_get_all_by_host',
get_all_by_host)
- def fixed_ip_get(_context, fixed_ip_id):
+ def fixed_ip_get(_context, fixed_ip_id, get_network):
if fixed_ip_id == 1:
- return {'address': 'fakefixed'}
+ return {'address': 'fakefixed', 'network': 'fakenet'}
raise exception.FixedIpNotFound(id=fixed_ip_id)
self.stubs.Set(self.network.db, 'fixed_ip_get', fixed_ip_get)
@@ -798,7 +798,8 @@ class VlanNetworkTestCase(test.TestCase):
self.flags(public_interface=False)
self.network.l3driver.add_floating_ip('fakefloat',
'fakefixed',
- 'fakeiface')
+ 'fakeiface',
+ 'fakenet')
self.mox.ReplayAll()
self.network.init_host_floating_ips()
self.mox.UnsetStubs()
@@ -808,7 +809,8 @@ class VlanNetworkTestCase(test.TestCase):
self.flags(public_interface='fooiface')
self.network.l3driver.add_floating_ip('fakefloat',
'fakefixed',
- 'fooiface')
+ 'fooiface',
+ 'fakenet')
self.mox.ReplayAll()
self.network.init_host_floating_ips()
self.mox.UnsetStubs()
@@ -1803,11 +1805,13 @@ class FloatingIPTestCase(test.TestCase):
def fake_is_stale_floating_ip_address(context, floating_ip):
return floating_ip['address'] == '172.24.4.23'
- def fake_fixed_ip_get(context, fixed_ip_id):
+ def fake_fixed_ip_get(context, fixed_ip_id, get_network):
return {'instance_uuid': 'fake_uuid',
- 'address': '10.0.0.2'}
+ 'address': '10.0.0.2',
+ 'network': 'fakenet'}
- def fake_remove_floating_ip(floating_addr, fixed_addr, interface):
+ def fake_remove_floating_ip(floating_addr, fixed_addr, interface,
+ network):
called['count'] += 1
def fake_floating_ip_update(context, address, args):
@@ -1844,11 +1848,13 @@ class FloatingIPTestCase(test.TestCase):
def fake_is_stale_floating_ip_address(context, floating_ip):
return floating_ip['address'] == '172.24.4.23'
- def fake_fixed_ip_get(context, fixed_ip_id):
+ def fake_fixed_ip_get(context, fixed_ip_id, get_network):
return {'instance_uuid': 'fake_uuid',
- 'address': '10.0.0.2'}
+ 'address': '10.0.0.2',
+ 'network': 'fakenet'}
- def fake_add_floating_ip(floating_addr, fixed_addr, interface):
+ def fake_add_floating_ip(floating_addr, fixed_addr, interface,
+ network):
called['count'] += 1
def fake_floating_ip_update(context, address, args):
diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py
index 40552d1c0..4485be4f9 100644
--- a/nova/tests/test_db_api.py
+++ b/nova/tests/test_db_api.py
@@ -253,11 +253,11 @@ class DbApiTestCase(test.TestCase):
values = {'address': 'fixed'}
fixed = db.fixed_ip_create(ctxt, values)
res = db.floating_ip_fixed_ip_associate(ctxt, floating, fixed, 'foo')
- self.assertEqual(res, fixed)
+ self.assertEqual(res['address'], fixed)
res = db.floating_ip_fixed_ip_associate(ctxt, floating, fixed, 'foo')
self.assertEqual(res, None)
res = db.floating_ip_disassociate(ctxt, floating)
- self.assertEqual(res, fixed)
+ self.assertEqual(res['address'], fixed)
res = db.floating_ip_disassociate(ctxt, floating)
self.assertEqual(res, None)