From 76a7a3540b3e2f111c267df83fb0b528dd8c6fa5 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Fri, 22 Jun 2012 10:15:42 -0700 Subject: Migrate existing routes from flat_interface Right now, any routes that exist on flat_interface (other than the default route) get lost when we set up the bridge. This patch migrates them over to avoid losing that connectivity. It does so by using 'ip route' instead of 'route', which is much easier to script and is consistent with other use of iproute2 tools in linux_net.py. Bug 962822 Change-Id: I7d9e8e05169f2f87e8481595397c02fd3a3612f4 --- Authors | 1 + etc/nova/rootwrap.d/compute.filters | 11 +++----- etc/nova/rootwrap.d/network.filters | 11 +++----- nova/network/linux_net.py | 49 +++++++++++++++++++----------------- nova/tests/network/test_linux_net.py | 20 +++++++++------ 5 files changed, 45 insertions(+), 47 deletions(-) diff --git a/Authors b/Authors index fb6f98e02..e1a1ee839 100644 --- a/Authors +++ b/Authors @@ -44,6 +44,7 @@ Cory Wright Craig Vyvial Dan Prince Dan Wendlandt +Dan Smith Daniel P. Berrange Dave Lapsley Dave Walker diff --git a/etc/nova/rootwrap.d/compute.filters b/etc/nova/rootwrap.d/compute.filters index c2e760f0e..fffeff85a 100644 --- a/etc/nova/rootwrap.d/compute.filters +++ b/etc/nova/rootwrap.d/compute.filters @@ -78,6 +78,9 @@ cp: CommandFilter, /bin/cp, root # nova/network/linux_net.py: 'ip', 'addr', 'show', 'dev', interface, .. # nova/network/linux_net.py: 'ip', 'link', 'set', dev, address, .. # nova/network/linux_net.py: 'ip', 'link', 'set', dev, 'up' +# nova/network/linux_net.py: 'ip', 'route', 'add', .. +# nova/network/linux_net.py: 'ip', 'route', 'del', . +# nova/network/linux_net.py: 'ip', 'route', 'show', 'dev', dev ip: CommandFilter, /sbin/ip, root # nova/virt/libvirt/vif.py: 'tunctl', '-b', '-t', dev @@ -130,14 +133,6 @@ ip6tables-restore_usr: CommandFilter, /usr/sbin/ip6tables-restore, root arping: CommandFilter, /usr/bin/arping, root arping_sbin: CommandFilter, /sbin/arping, root -# nova/network/linux_net.py: 'route', '-n' -# nova/network/linux_net.py: 'route', 'del', 'default', 'gw' -# nova/network/linux_net.py: 'route', 'add', 'default', 'gw' -# nova/network/linux_net.py: 'route', '-n' -# nova/network/linux_net.py: 'route', 'del', 'default', 'gw', old_gw, .. -# nova/network/linux_net.py: 'route', 'add', 'default', 'gw', old_gateway -route: CommandFilter, /sbin/route, root - # nova/network/linux_net.py: 'dhcp_release', dev, address, mac_address dhcp_release: CommandFilter, /usr/bin/dhcp_release, root diff --git a/etc/nova/rootwrap.d/network.filters b/etc/nova/rootwrap.d/network.filters index c85ab9a33..c635f12e4 100644 --- a/etc/nova/rootwrap.d/network.filters +++ b/etc/nova/rootwrap.d/network.filters @@ -21,6 +21,9 @@ # nova/network/linux_net.py: 'ip', 'addr', 'show', 'dev', interface, .. # nova/network/linux_net.py: 'ip', 'link', 'set', dev, address, .. # nova/network/linux_net.py: 'ip', 'link', 'set', dev, 'up' +# nova/network/linux_net.py: 'ip', 'route', 'add', .. +# nova/network/linux_net.py: 'ip', 'route', 'del', . +# nova/network/linux_net.py: 'ip', 'route', 'show', 'dev', dev ip: CommandFilter, /sbin/ip, root # nova/virt/libvirt/vif.py: 'ovs-vsctl', ... @@ -48,14 +51,6 @@ ip6tables-restore_usr: CommandFilter, /usr/sbin/ip6tables-restore, root arping: CommandFilter, /usr/bin/arping, root arping_sbin: CommandFilter, /sbin/arping, root -# nova/network/linux_net.py: 'route', '-n' -# nova/network/linux_net.py: 'route', 'del', 'default', 'gw' -# nova/network/linux_net.py: 'route', 'add', 'default', 'gw' -# nova/network/linux_net.py: 'route', '-n' -# nova/network/linux_net.py: 'route', 'del', 'default', 'gw', old_gw, .. -# nova/network/linux_net.py: 'route', 'add', 'default', 'gw', old_gateway -route: CommandFilter, /sbin/route, root - # nova/network/linux_net.py: 'dhcp_release', dev, address, mac_address dhcp_release: CommandFilter, /usr/bin/dhcp_release, root diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 42fb9cc10..828174b3a 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -548,24 +548,27 @@ def initialize_gateway_device(dev, network_ref): if ip_params[0] != full_ip: new_ip_params.append(ip_params) if not old_ip_params or old_ip_params[0][0] != full_ip: - gateway = None - out, err = _execute('route', '-n', run_as_root=True) - for line in out.split('\n'): - fields = line.split() - if fields and fields[0] == '0.0.0.0' and fields[-1] == dev: - gateway = fields[1] - _execute('route', 'del', 'default', 'gw', gateway, - 'dev', dev, run_as_root=True, - check_exit_code=[0, 7]) + old_routes = [] + result = _execute('ip', 'route', 'show', 'dev', dev, + run_as_root=True) + if result: + out, err = result + for line in out.split('\n'): + fields = line.split() + if fields and 'via' in fields: + old_routes.append(fields) + _execute('ip', 'route', 'del', fields[0], + 'dev', dev, run_as_root=True) for ip_params in old_ip_params: _execute(*_ip_bridge_cmd('del', ip_params, dev), run_as_root=True, check_exit_code=[0, 2, 254]) for ip_params in new_ip_params: _execute(*_ip_bridge_cmd('add', ip_params, dev), run_as_root=True, check_exit_code=[0, 2, 254]) - if gateway: - _execute('route', 'add', 'default', 'gw', gateway, - run_as_root=True, check_exit_code=[0, 7]) + + for fields in old_routes: + _execute('ip', 'route', 'add', *fields, + run_as_root=True) if FLAGS.send_arp_for_ha: _execute('arping', '-U', network_ref['dhcp_server'], '-A', '-I', dev, @@ -1030,16 +1033,16 @@ class LinuxBridgeInterfaceDriver(LinuxNetInterfaceDriver): # NOTE(vish): This will break if there is already an ip on the # interface, so we move any ips to the bridge - old_gateway = None - out, err = _execute('route', '-n', run_as_root=True) + # NOTE(danms): We also need to copy routes to the bridge so as + # not to break existing connectivity on the interface + old_routes = [] + out, err = _execute('ip', 'route', 'show', 'dev', interface) for line in out.split('\n'): fields = line.split() - if (fields and fields[0] == '0.0.0.0' and - fields[-1] == interface): - old_gateway = fields[1] - _execute('route', 'del', 'default', 'gw', old_gateway, - 'dev', interface, run_as_root=True, - check_exit_code=[0, 7]) + if fields and 'via' in fields: + old_routes.append(fields) + _execute('ip', 'route', 'del', *fields, + run_as_root=True) out, err = _execute('ip', 'addr', 'show', 'dev', interface, 'scope', 'global', run_as_root=True) for line in out.split('\n'): @@ -1050,9 +1053,9 @@ class LinuxBridgeInterfaceDriver(LinuxNetInterfaceDriver): run_as_root=True, check_exit_code=[0, 2, 254]) _execute(*_ip_bridge_cmd('add', params, bridge), run_as_root=True, check_exit_code=[0, 2, 254]) - if old_gateway: - _execute('route', 'add', 'default', 'gw', old_gateway, - run_as_root=True, check_exit_code=[0, 7]) + for fields in old_routes: + _execute('ip', 'route', 'add', *fields, + run_as_root=True) if (err and err != "device %s is already a member of a bridge;" "can't enslave it to bridge %s.\n" % (interface, bridge)): diff --git a/nova/tests/network/test_linux_net.py b/nova/tests/network/test_linux_net.py index 4b60b624a..0660bb0f3 100644 --- a/nova/tests/network/test_linux_net.py +++ b/nova/tests/network/test_linux_net.py @@ -409,7 +409,7 @@ class LinuxNetworkTestCase(test.TestCase): executes.append(args) if args[0] == 'ip' and args[1] == 'addr' and args[2] == 'show': return existing, "" - if args[0] == 'route' and args[1] == '-n': + if args[0] == 'ip' and args[1] == 'route' and args[2] == 'show': return routes, "" self.stubs.Set(utils, 'execute', fake_execute) network = {'dhcp_server': '192.168.1.1', @@ -429,7 +429,7 @@ class LinuxNetworkTestCase(test.TestCase): expected = [ ('sysctl', '-w', 'net.ipv4.ip_forward=1'), ('ip', 'addr', 'show', 'dev', 'eth0', 'scope', 'global'), - ('route', '-n'), + ('ip', 'route', 'show', 'dev', 'eth0'), ('ip', 'addr', 'del', '192.168.0.1/24', 'brd', '192.168.0.255', 'scope', 'global', 'dev', 'eth0'), ('ip', 'addr', 'add', '192.168.1.1/24', @@ -442,8 +442,8 @@ class LinuxNetworkTestCase(test.TestCase): self._test_initialize_gateway(existing, expected) def test_initialize_gateway_resets_route(self): - routes = ("0.0.0.0 192.68.0.1 0.0.0.0 " - "UG 100 0 0 eth0") + routes = ("default via 192.168.0.1 dev eth0\n" + "192.168.100.0/24 via 192.168.0.254 dev eth0 proto static\n") existing = ("2: eth0: " " mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000\n" " link/ether de:ad:be:ef:be:ef brd ff:ff:ff:ff:ff:ff\n" @@ -453,15 +453,19 @@ class LinuxNetworkTestCase(test.TestCase): expected = [ ('sysctl', '-w', 'net.ipv4.ip_forward=1'), ('ip', 'addr', 'show', 'dev', 'eth0', 'scope', 'global'), - ('route', '-n'), - ('route', 'del', 'default', 'gw', '192.68.0.1', 'dev', 'eth0'), + ('ip', 'route', 'show', 'dev', 'eth0'), + ('ip', 'route', 'del', 'default', 'dev', 'eth0'), + ('ip', 'route', 'del', '192.168.100.0/24', 'dev', 'eth0'), ('ip', 'addr', 'del', '192.168.0.1/24', 'brd', '192.168.0.255', 'scope', 'global', 'dev', 'eth0'), ('ip', 'addr', 'add', '192.168.1.1/24', 'brd', '192.168.1.255', 'dev', 'eth0'), ('ip', 'addr', 'add', '192.168.0.1/24', 'brd', '192.168.0.255', 'scope', 'global', 'dev', 'eth0'), - ('route', 'add', 'default', 'gw', '192.68.0.1'), + ('ip', 'route', 'add', 'default', 'via', '192.168.0.1', + 'dev', 'eth0'), + ('ip', 'route', 'add', '192.168.100.0/24', 'via', '192.168.0.254', + 'dev', 'eth0', 'proto', 'static'), ('ip', '-f', 'inet6', 'addr', 'change', '2001:db8::/64', 'dev', 'eth0'), ] @@ -492,7 +496,7 @@ class LinuxNetworkTestCase(test.TestCase): expected = [ ('sysctl', '-w', 'net.ipv4.ip_forward=1'), ('ip', 'addr', 'show', 'dev', 'eth0', 'scope', 'global'), - ('route', '-n'), + ('ip', 'route', 'show', 'dev', 'eth0'), ('ip', 'addr', 'add', '192.168.1.1/24', 'brd', '192.168.1.255', 'dev', 'eth0'), ('ip', '-f', 'inet6', 'addr', 'change', -- cgit