From 4fdb0a6a2b355750ae8071e53a74b9257b18eeee Mon Sep 17 00:00:00 2001 From: Matthew Flusche Date: Wed, 19 Oct 2016 18:10:08 +0000 Subject: Add route_options parameter route_options will append additional options to route definitions. Change-Id: I2b70efdd9c6df7ea252576e245fbc0e9c46ea4bd --- etc/os-net-config/samples/interface.json | 5 +++++ etc/os-net-config/samples/interface.yaml | 6 +++++- os_net_config/impl_eni.py | 11 +++++++---- os_net_config/impl_ifcfg.py | 25 ++++++++++++++---------- os_net_config/objects.py | 7 +++++-- os_net_config/tests/test_impl_eni.py | 18 ++++++++++++----- os_net_config/tests/test_impl_ifcfg.py | 33 +++++++++++++++++++++++--------- os_net_config/tests/test_objects.py | 18 ++++++++++++----- 8 files changed, 87 insertions(+), 36 deletions(-) diff --git a/etc/os-net-config/samples/interface.json b/etc/os-net-config/samples/interface.json index 8a942b5..9ae0b76 100644 --- a/etc/os-net-config/samples/interface.json +++ b/etc/os-net-config/samples/interface.json @@ -13,6 +13,11 @@ "ip_netmask": "0.0.0.0/0", "next_hop": "192.0.2.254", "default": "true" + }, + { + "ip_netmask": "10.1.2.0/24", + "next_hop": "192.0.2.5", + "route_options": "metric 10" } ] }, diff --git a/etc/os-net-config/samples/interface.yaml b/etc/os-net-config/samples/interface.yaml index 4f76e07..6b366e2 100644 --- a/etc/os-net-config/samples/interface.yaml +++ b/etc/os-net-config/samples/interface.yaml @@ -11,8 +11,12 @@ network_config: ip_netmask: 0.0.0.0/0 next_hop: 192.0.2.254 default: true + - + ip_netmask: 10.1.2.0/24 + next_hop: 192.0.2.5 + route_options: "metric 10" - type: interface name: em2 use_dhcp: true - defroute: no \ No newline at end of file + defroute: no diff --git a/os_net_config/impl_eni.py b/os_net_config/impl_eni.py index ae60099..1d59b57 100644 --- a/os_net_config/impl_eni.py +++ b/os_net_config/impl_eni.py @@ -181,14 +181,17 @@ class ENINetConfig(os_net_config.NetConfig): logger.info('adding custom route for interface: %s' % interface_name) data = "" for route in routes: + options = "" + if route.route_options: + options = " %s" % (route.route_options) if route.default and not route.ip_netmask: rt = netaddr.IPNetwork("0.0.0.0/0") else: rt = netaddr.IPNetwork(route.ip_netmask) - data += "up route add -net %s netmask %s gw %s\n" % ( - str(rt.ip), str(rt.netmask), route.next_hop) - data += "down route del -net %s netmask %s gw %s\n" % ( - str(rt.ip), str(rt.netmask), route.next_hop) + data += "up route add -net %s netmask %s gw %s%s\n" % ( + str(rt.ip), str(rt.netmask), route.next_hop, options) + data += "down route del -net %s netmask %s gw %s%s\n" % ( + str(rt.ip), str(rt.netmask), route.next_hop, options) self.routes[interface_name] = data logger.debug('route data: %s' % self.routes[interface_name]) diff --git a/os_net_config/impl_ifcfg.py b/os_net_config/impl_ifcfg.py index 56f2b33..4a4caaa 100644 --- a/os_net_config/impl_ifcfg.py +++ b/os_net_config/impl_ifcfg.py @@ -313,24 +313,29 @@ class IfcfgNetConfig(os_net_config.NetConfig): data6 = "" first_line6 = "" for route in routes: + options = "" + if route.route_options: + options = " %s" % (route.route_options) if ":" not in route.next_hop: # Route is an IPv4 route if route.default: - first_line = "default via %s dev %s\n" % (route.next_hop, - interface_name) + first_line = "default via %s dev %s%s\n" % ( + route.next_hop, interface_name, + options) else: - data += "%s via %s dev %s\n" % (route.ip_netmask, - route.next_hop, - interface_name) + data += "%s via %s dev %s%s\n" % ( + route.ip_netmask, route.next_hop, + interface_name, options) else: # Route is an IPv6 route if route.default: - first_line6 = "default via %s dev %s\n" % (route.next_hop, - interface_name) + first_line6 = "default via %s dev %s%s\n" % ( + route.next_hop, interface_name, + options) else: - data6 += "%s via %s dev %s\n" % (route.ip_netmask, - route.next_hop, - interface_name) + data6 += "%s via %s dev %s%s\n" % ( + route.ip_netmask, route.next_hop, + interface_name, options) self.route_data[interface_name] = first_line + data self.route6_data[interface_name] = first_line6 + data6 logger.debug('route data: %s' % self.route_data[interface_name]) diff --git a/os_net_config/objects.py b/os_net_config/objects.py index 3c67ada..0e5ce08 100644 --- a/os_net_config/objects.py +++ b/os_net_config/objects.py @@ -134,17 +134,20 @@ def _mapped_nics(nic_mapping=None): class Route(object): """Base class for network routes.""" - def __init__(self, next_hop, ip_netmask="", default=False): + def __init__(self, next_hop, ip_netmask="", default=False, + route_options=""): self.next_hop = next_hop self.ip_netmask = ip_netmask self.default = default + self.route_options = route_options @staticmethod def from_json(json): next_hop = _get_required_field(json, 'next_hop', 'Route') ip_netmask = json.get('ip_netmask', "") + route_options = json.get('route_options', "") default = strutils.bool_from_string(str(json.get('default', False))) - return Route(next_hop, ip_netmask, default) + return Route(next_hop, ip_netmask, default, route_options) class Address(object): diff --git a/os_net_config/tests/test_impl_eni.py b/os_net_config/tests/test_impl_eni.py index 7f909ff..5d3bb8c 100644 --- a/os_net_config/tests/test_impl_eni.py +++ b/os_net_config/tests/test_impl_eni.py @@ -90,6 +90,8 @@ iface vlan5 inet manual _RTS = """up route add -net 172.19.0.0 netmask 255.255.255.0 gw 192.168.1.1 down route del -net 172.19.0.0 netmask 255.255.255.0 gw 192.168.1.1 +up route add -net 172.20.0.0 netmask 255.255.255.0 gw 192.168.1.5 metric 100 +down route del -net 172.20.0.0 netmask 255.255.255.0 gw 192.168.1.5 metric 100 """ @@ -169,8 +171,10 @@ class TestENINetConfig(base.TestCase): def test_network_with_routes(self): route1 = objects.Route('192.168.1.1', '172.19.0.0/24') + route2 = objects.Route('192.168.1.5', '172.20.0.0/24', + route_options="metric 100") v4_addr = objects.Address('192.168.1.2/24') - interface = self._default_interface([v4_addr], [route1]) + interface = self._default_interface([v4_addr], [route1, route2]) self.provider.add_interface(interface) self.assertEqual(_V4_IFACE_STATIC_IP, self.get_interface_config()) self.assertEqual(_RTS, self.get_route_config()) @@ -261,10 +265,12 @@ class TestENINetConfigApply(base.TestCase): super(TestENINetConfigApply, self).tearDown() def test_network_apply(self): - route = objects.Route('192.168.1.1', '172.19.0.0/24') + route1 = objects.Route('192.168.1.1', '172.19.0.0/24') + route2 = objects.Route('192.168.1.5', '172.20.0.0/24', + route_options="metric 100") v4_addr = objects.Address('192.168.1.2/24') interface = objects.Interface('eth0', addresses=[v4_addr], - routes=[route]) + routes=[route1, route2]) self.provider.add_interface(interface) self.provider.apply() @@ -273,10 +279,12 @@ class TestENINetConfigApply(base.TestCase): self.assertIn('eth0', self.ifup_interface_names) def test_apply_noactivate(self): - route = objects.Route('192.168.1.1', '172.19.0.0/24') + route1 = objects.Route('192.168.1.1', '172.19.0.0/24') + route2 = objects.Route('192.168.1.5', '172.20.0.0/24', + route_options="metric 100") v4_addr = objects.Address('192.168.1.2/24') interface = objects.Interface('eth0', addresses=[v4_addr], - routes=[route]) + routes=[route1, route2]) self.provider.add_interface(interface) self.provider.apply(activate=False) diff --git a/os_net_config/tests/test_impl_ifcfg.py b/os_net_config/tests/test_impl_ifcfg.py index 8586daa..0c14418 100644 --- a/os_net_config/tests/test_impl_ifcfg.py +++ b/os_net_config/tests/test_impl_ifcfg.py @@ -115,12 +115,14 @@ _OVS_BRIDGE_IFCFG = _BASE_IFCFG + "DEVICETYPE=ovs\n" _LINUX_BRIDGE_IFCFG = _BASE_IFCFG + "BRIDGE=br-ctlplane\nBOOTPROTO=none\n" -_ROUTES = """default via 192.168.1.1 dev em1 +_ROUTES = """default via 192.168.1.1 dev em1 metric 10 172.19.0.0/24 via 192.168.1.1 dev em1 +172.20.0.0/24 via 192.168.1.5 dev em1 metric 100 """ _ROUTES_V6 = """default via 2001:db8::1 dev em1 2001:db8:dead:beef:cafe::/56 via fd00:fd00:2000::1 dev em1 +2001:db8:dead:beff::/64 via fd00:fd00:2000::1 dev em1 metric 100 """ @@ -454,25 +456,35 @@ class TestIfcfgNetConfig(base.TestCase): self.assertEqual(_V6_IFCFG_MULTIPLE, self.get_interface_config()) def test_network_with_routes(self): - route1 = objects.Route('192.168.1.1', default=True) + route1 = objects.Route('192.168.1.1', default=True, + route_options="metric 10") route2 = objects.Route('192.168.1.1', '172.19.0.0/24') + route3 = objects.Route('192.168.1.5', '172.20.0.0/24', + route_options="metric 100") v4_addr = objects.Address('192.168.1.2/24') interface = objects.Interface('em1', addresses=[v4_addr], - routes=[route1, route2]) + routes=[route1, route2, route3]) self.provider.add_interface(interface) self.assertEqual(_V4_IFCFG, self.get_interface_config()) self.assertEqual(_ROUTES, self.get_route_config()) def test_network_with_ipv6_routes(self): - route1 = objects.Route('192.168.1.1', default=True) + route1 = objects.Route('192.168.1.1', default=True, + route_options="metric 10") route2 = objects.Route('192.168.1.1', '172.19.0.0/24') - route3 = objects.Route('2001:db8::1', default=True) - route4 = objects.Route('fd00:fd00:2000::1', + route3 = objects.Route('192.168.1.5', '172.20.0.0/24', + route_options="metric 100") + route4 = objects.Route('2001:db8::1', default=True) + route5 = objects.Route('fd00:fd00:2000::1', '2001:db8:dead:beef:cafe::/56') + route6 = objects.Route('fd00:fd00:2000::1', + '2001:db8:dead:beff::/64', + route_options="metric 100") v4_addr = objects.Address('192.168.1.2/24') v6_addr = objects.Address('2001:abc:a::/64') interface = objects.Interface('em1', addresses=[v4_addr, v6_addr], - routes=[route1, route2, route3, route4]) + routes=[route1, route2, route3, + route4, route5, route6]) self.provider.add_interface(interface) self.assertEqual(_V4_V6_IFCFG, self.get_interface_config()) self.assertEqual(_ROUTES_V6, self.get_route6_config()) @@ -884,11 +896,14 @@ class TestIfcfgNetConfigApply(base.TestCase): super(TestIfcfgNetConfigApply, self).tearDown() def test_network_apply(self): - route1 = objects.Route('192.168.1.1', default=True) + route1 = objects.Route('192.168.1.1', default=True, + route_options="metric 10") route2 = objects.Route('192.168.1.1', '172.19.0.0/24') + route3 = objects.Route('192.168.1.5', '172.20.0.0/24', + route_options="metric 100") v4_addr = objects.Address('192.168.1.2/24') interface = objects.Interface('em1', addresses=[v4_addr], - routes=[route1, route2]) + routes=[route1, route2, route3]) self.provider.add_interface(interface) self.provider.apply() diff --git a/os_net_config/tests/test_objects.py b/os_net_config/tests/test_objects.py index 7500392..4c71265 100644 --- a/os_net_config/tests/test_objects.py +++ b/os_net_config/tests/test_objects.py @@ -25,26 +25,30 @@ from os_net_config import utils class TestRoute(base.TestCase): def test_from_json(self): - data = '{"next_hop": "172.19.0.1", "ip_netmask": "172.19.0.0/24"}' + data = '{"next_hop": "172.19.0.1", "ip_netmask": "172.19.0.0/24", ' \ + '"route_options": "metric 10"}' route = objects.Route.from_json(json.loads(data)) self.assertEqual("172.19.0.1", route.next_hop) self.assertEqual("172.19.0.0/24", route.ip_netmask) self.assertFalse(route.default) + self.assertEqual("metric 10", route.route_options) def test_from_json_default_route(self): data = '{"next_hop": "172.19.0.1", "ip_netmask": "172.19.0.0/24", ' \ - '"default": true}' + '"default": true, "route_options": "metric 10"}' route = objects.Route.from_json(json.loads(data)) self.assertEqual("172.19.0.1", route.next_hop) self.assertEqual("172.19.0.0/24", route.ip_netmask) self.assertTrue(route.default) + self.assertEqual("metric 10", route.route_options) data = '{"next_hop": "172.19.0.1", "ip_netmask": "172.19.0.0/24", ' \ - '"default": "true"}' + '"default": "true", "route_options": "metric 10"}' route = objects.Route.from_json(json.loads(data)) self.assertEqual("172.19.0.1", route.next_hop) self.assertEqual("172.19.0.0/24", route.ip_netmask) self.assertTrue(route.default) + self.assertEqual("metric 10", route.route_options) class TestAddress(base.TestCase): @@ -151,7 +155,8 @@ class TestInterface(base.TestCase): }], "routes": [{ "next_hop": "192.0.2.1", - "ip_netmask": "192.0.2.1/24" + "ip_netmask": "192.0.2.1/24", + "route_options": "metric 10" }] } """ @@ -166,6 +171,7 @@ class TestInterface(base.TestCase): route1 = interface.routes[0] self.assertEqual("192.0.2.1", route1.next_hop) self.assertEqual("192.0.2.1/24", route1.ip_netmask) + self.assertEqual("metric 10", route1.route_options) class TestVlan(base.TestCase): @@ -727,7 +733,8 @@ class TestIbInterface(base.TestCase): }], "routes": [{ "next_hop": "192.0.2.1", - "ip_netmask": "192.0.2.1/24" + "ip_netmask": "192.0.2.1/24", + "route_options": "metric 10" }] } """ @@ -742,6 +749,7 @@ class TestIbInterface(base.TestCase): route1 = ib_interface.routes[0] self.assertEqual("192.0.2.1", route1.next_hop) self.assertEqual("192.0.2.1/24", route1.ip_netmask) + self.assertEqual("metric 10", route1.route_options) class TestNicMapping(base.TestCase): -- cgit 1.2.3-korg