nb: provide 'route_table' in lr-route-{add,del,list}
Adds possibility to specify 'route_table' in methods for static
routes.
See this commit for more information:
1655a6c146
Closes-bug: 2037652
Change-Id: Ic965ae098adb6db2e5a057eee74250e3b6331b01
This commit is contained in:
parent
033b6e3bd2
commit
dae455b6ee
|
@ -39,5 +39,6 @@ PROTO_TCP = 'tcp'
|
|||
PROTO_UDP = 'udp'
|
||||
|
||||
ROUTE_DISCARD = "discard"
|
||||
MAIN_ROUTE_TABLE = ""
|
||||
|
||||
LOCALNET = 'localnet'
|
||||
|
|
|
@ -735,7 +735,8 @@ class API(api.API, metaclass=abc.ABCMeta):
|
|||
|
||||
@abc.abstractmethod
|
||||
def lr_route_add(self, router, prefix, nexthop, port=None,
|
||||
policy='dst-ip', may_exist=False, ecmp=False):
|
||||
policy='dst-ip', may_exist=False, ecmp=False,
|
||||
route_table=const.MAIN_ROUTE_TABLE):
|
||||
"""Add a route to 'router'
|
||||
|
||||
:param router: The name or uuid of the router
|
||||
|
@ -758,11 +759,14 @@ class API(api.API, metaclass=abc.ABCMeta):
|
|||
same IP prefix is allowed as long as the nexthop is
|
||||
different
|
||||
:type ecmp: boolean
|
||||
:param route_table: The name of route table
|
||||
:type route_table: str
|
||||
returns: :class:`Command` with RowView result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def lr_route_del(self, router, prefix=None, if_exists=False, nexthop=None):
|
||||
def lr_route_del(self, router, prefix=None, if_exists=False, nexthop=None,
|
||||
route_table=const.MAIN_ROUTE_TABLE):
|
||||
"""Remove routes from 'router'
|
||||
|
||||
:param router: The name or uuid of the router
|
||||
|
@ -775,16 +779,21 @@ class API(api.API, metaclass=abc.ABCMeta):
|
|||
the IP address of one of `router`'s logical router
|
||||
ports or the IP address of a logical port
|
||||
:type nexthop: string
|
||||
:param route_table: The name of route table
|
||||
:type route_table: str
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def lr_route_list(self, router):
|
||||
def lr_route_list(self, router, route_table=None):
|
||||
"""Get the UUIDs of static logical routes from 'router'
|
||||
|
||||
:param router: The name or uuid of the router
|
||||
:type router: string or uuid.UUID
|
||||
:returns: :class:`Command` with RowView list result
|
||||
:param router: The name or uuid of the router
|
||||
:type router: string or uuid.UUID
|
||||
:param route_table: The name of route table. Pass "" to get routes of
|
||||
global route table only
|
||||
:type route_table: str
|
||||
:returns: :class:`Command` with RowView list result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
|
|
|
@ -1139,7 +1139,8 @@ class BFDGetCommand(cmd.BaseGetRowCommand):
|
|||
|
||||
class LrRouteAddCommand(cmd.BaseCommand):
|
||||
def __init__(self, api, router, prefix, nexthop, port=None,
|
||||
policy='dst-ip', may_exist=False, ecmp=False):
|
||||
policy='dst-ip', may_exist=False, ecmp=False,
|
||||
route_table=const.MAIN_ROUTE_TABLE):
|
||||
prefix = str(netaddr.IPNetwork(prefix))
|
||||
if nexthop != const.ROUTE_DISCARD:
|
||||
nexthop = str(netaddr.IPAddress(nexthop))
|
||||
|
@ -1150,12 +1151,16 @@ class LrRouteAddCommand(cmd.BaseCommand):
|
|||
self.port = port
|
||||
self.policy = policy
|
||||
self.ecmp = ecmp
|
||||
self.route_table = route_table
|
||||
self.may_exist = may_exist
|
||||
|
||||
def run_idl(self, txn):
|
||||
lr = self.api.lookup('Logical_Router', self.router)
|
||||
for route in lr.static_routes:
|
||||
if self.prefix == route.ip_prefix:
|
||||
if (
|
||||
self.prefix == route.ip_prefix and
|
||||
self.route_table == route.route_table
|
||||
):
|
||||
if self.ecmp and self.nexthop != route.nexthop:
|
||||
continue
|
||||
if not self.may_exist:
|
||||
|
@ -1172,6 +1177,7 @@ class LrRouteAddCommand(cmd.BaseCommand):
|
|||
route.ip_prefix = self.prefix
|
||||
route.nexthop = self.nexthop
|
||||
route.policy = self.policy
|
||||
route.route_table = self.route_table
|
||||
if self.port:
|
||||
route.output_port = self.port
|
||||
lr.addvalue('static_routes', route)
|
||||
|
@ -1187,13 +1193,14 @@ class LrRouteAddCommand(cmd.BaseCommand):
|
|||
|
||||
class LrRouteDelCommand(cmd.BaseCommand):
|
||||
def __init__(self, api, router, prefix=None, if_exists=False,
|
||||
nexthop=None):
|
||||
nexthop=None, route_table=const.MAIN_ROUTE_TABLE):
|
||||
if prefix is not None:
|
||||
prefix = str(netaddr.IPNetwork(prefix))
|
||||
super().__init__(api)
|
||||
self.router = router
|
||||
self.prefix = prefix
|
||||
self.nexthop = nexthop
|
||||
self.route_table = route_table
|
||||
self.if_exists = if_exists
|
||||
|
||||
def run_idl(self, txn):
|
||||
|
@ -1202,7 +1209,10 @@ class LrRouteDelCommand(cmd.BaseCommand):
|
|||
lr.static_routes = []
|
||||
return
|
||||
for route in lr.static_routes:
|
||||
if self.prefix == route.ip_prefix:
|
||||
if (
|
||||
self.prefix == route.ip_prefix and
|
||||
self.route_table == route.route_table
|
||||
):
|
||||
if self.nexthop and route.nexthop != self.nexthop:
|
||||
continue
|
||||
|
||||
|
@ -1216,13 +1226,19 @@ class LrRouteDelCommand(cmd.BaseCommand):
|
|||
|
||||
|
||||
class LrRouteListCommand(cmd.ReadOnlyCommand):
|
||||
def __init__(self, api, router):
|
||||
def __init__(self, api, router, route_table=None):
|
||||
super().__init__(api)
|
||||
self.router = router
|
||||
self.route_table = route_table
|
||||
|
||||
def run_idl(self, txn):
|
||||
lr = self.api.lookup('Logical_Router', self.router)
|
||||
self.result = [rowview.RowView(r) for r in lr.static_routes]
|
||||
if self.route_table is not None:
|
||||
self.result = [rowview.RowView(r)
|
||||
for r in lr.static_routes
|
||||
if r.route_table == self.route_table]
|
||||
else:
|
||||
self.result = [rowview.RowView(r) for r in lr.static_routes]
|
||||
|
||||
|
||||
class LrNatAddCommand(cmd.BaseCommand):
|
||||
|
|
|
@ -236,15 +236,18 @@ class OvnNbApiIdlImpl(ovs_idl.Backend, api.API):
|
|||
return cmd.LrpDelNetworksCommand(self, port, networks, if_exists)
|
||||
|
||||
def lr_route_add(self, router, prefix, nexthop, port=None,
|
||||
policy='dst-ip', may_exist=False, ecmp=False):
|
||||
policy='dst-ip', may_exist=False, ecmp=False,
|
||||
route_table=const.MAIN_ROUTE_TABLE):
|
||||
return cmd.LrRouteAddCommand(self, router, prefix, nexthop, port,
|
||||
policy, may_exist, ecmp)
|
||||
policy, may_exist, ecmp, route_table)
|
||||
|
||||
def lr_route_del(self, router, prefix=None, if_exists=False, nexthop=None):
|
||||
return cmd.LrRouteDelCommand(self, router, prefix, if_exists, nexthop)
|
||||
def lr_route_del(self, router, prefix=None, if_exists=False, nexthop=None,
|
||||
route_table=const.MAIN_ROUTE_TABLE):
|
||||
return cmd.LrRouteDelCommand(self, router, prefix, if_exists, nexthop,
|
||||
route_table)
|
||||
|
||||
def lr_route_list(self, router):
|
||||
return cmd.LrRouteListCommand(self, router)
|
||||
def lr_route_list(self, router, route_table=None):
|
||||
return cmd.LrRouteListCommand(self, router, route_table)
|
||||
|
||||
def lr_nat_add(self, router, nat_type, external_ip, logical_ip,
|
||||
logical_port=None, external_mac=None, may_exist=False):
|
||||
|
|
|
@ -956,14 +956,18 @@ class TestLogicalRouterOps(OvnNorthboundTest):
|
|||
self.assertTrue(lrs.issubset(lr_set), "%s vs %s" % (lrs, lr_set))
|
||||
|
||||
def _lr_add_route(self, router=None, prefix=None, nexthop=None, port=None,
|
||||
ecmp=False, **kwargs):
|
||||
ecmp=False, route_table=const.MAIN_ROUTE_TABLE,
|
||||
**kwargs):
|
||||
lr = self._lr_add(router or utils.get_rand_device_name(),
|
||||
may_exist=True)
|
||||
prefix = prefix or '192.0.2.0/25'
|
||||
nexthop = nexthop or '192.0.2.254'
|
||||
port = port or "port_name"
|
||||
sr = self.api.lr_route_add(lr.uuid, prefix, nexthop, port, ecmp=ecmp,
|
||||
**kwargs).execute(check_error=True)
|
||||
sr = self.api.lr_route_add(
|
||||
lr.uuid, prefix, nexthop, port,
|
||||
ecmp=ecmp, route_table=route_table,
|
||||
**kwargs
|
||||
).execute(check_error=True)
|
||||
self.assertIn(sr, lr.static_routes)
|
||||
self.assertEqual(prefix, sr.ip_prefix)
|
||||
self.assertEqual(nexthop, sr.nexthop)
|
||||
|
@ -1003,6 +1007,20 @@ class TestLogicalRouterOps(OvnNorthboundTest):
|
|||
self.assertRaises(netaddr.AddrFormatError, self._lr_add_route,
|
||||
prefix='not-discard')
|
||||
|
||||
def test_lr_route_add_route_table(self):
|
||||
lr = self._lr_add()
|
||||
route_table = "route-table"
|
||||
|
||||
# add route to 'main' route table
|
||||
route = self._lr_add_route(lr.name)
|
||||
self.assertEqual(route.route_table, const.MAIN_ROUTE_TABLE)
|
||||
|
||||
route = self._lr_add_route(lr.name, route_table=route_table)
|
||||
self.assertEqual(route.route_table, route_table)
|
||||
|
||||
self.assertEqual(
|
||||
len(self.api.tables['Logical_Router_Static_Route'].rows), 2)
|
||||
|
||||
def test_lr_route_del(self):
|
||||
prefix = "192.0.2.0/25"
|
||||
route = self._lr_add_route(prefix=prefix)
|
||||
|
@ -1057,6 +1075,29 @@ class TestLogicalRouterOps(OvnNorthboundTest):
|
|||
self.assertEqual(
|
||||
len(self.api.tables['Logical_Router_Static_Route'].rows), 1)
|
||||
|
||||
def test_lr_route_del_route_table(self):
|
||||
lr = self._lr_add()
|
||||
route_table = "route-table"
|
||||
|
||||
route_in_main = self._lr_add_route(lr.uuid, prefix="10.0.0.0/24")
|
||||
route = self._lr_add_route(
|
||||
lr.uuid, prefix="10.0.1.0/24", route_table=route_table)
|
||||
|
||||
self.assertEqual(len(lr.static_routes), 2)
|
||||
|
||||
# try to delete from the 'main' table implicitly
|
||||
cmd = self.api.lr_route_del(lr.uuid, route.ip_prefix)
|
||||
self.assertRaises(RuntimeError, cmd.execute, check_error=True)
|
||||
|
||||
self.api.lr_route_del(
|
||||
lr.uuid, prefix=route.ip_prefix, route_table=route_table
|
||||
).execute(check_error=True)
|
||||
self.assertEqual(len(lr.static_routes), 1)
|
||||
|
||||
self.api.lr_route_del(
|
||||
lr.uuid, route_in_main.ip_prefix).execute(check_error=True)
|
||||
self.assertEqual(len(lr.static_routes), 0)
|
||||
|
||||
def test_lr_route_list(self):
|
||||
lr = self._lr_add()
|
||||
routes = {self._lr_add_route(lr.uuid, prefix="192.0.%s.0/25" % p)
|
||||
|
@ -1065,6 +1106,29 @@ class TestLogicalRouterOps(OvnNorthboundTest):
|
|||
check_error=True))
|
||||
self.assertTrue(routes.issubset(route_set))
|
||||
|
||||
def test_lr_route_list_route_table(self):
|
||||
lr = self._lr_add()
|
||||
route_table = "route-table"
|
||||
|
||||
prefix1 = "10.0.0.0/24"
|
||||
prefix2 = "10.0.1.0/24"
|
||||
|
||||
self._lr_add_route(lr.uuid, prefix=prefix1)
|
||||
self._lr_add_route(lr.uuid, prefix=prefix2, route_table=route_table)
|
||||
|
||||
routes = self.api.lr_route_list(lr.uuid).execute(check_error=True)
|
||||
self.assertEqual(len(routes), 2) # all routes in logical router
|
||||
|
||||
for route_table, prefix in zip(
|
||||
[const.MAIN_ROUTE_TABLE, route_table],
|
||||
[prefix1, prefix2]
|
||||
):
|
||||
routes = self.api.lr_route_list(
|
||||
lr.uuid, route_table=route_table).execute(check_error=True)
|
||||
self.assertEqual(len(routes), 1)
|
||||
self.assertEqual(routes[0].ip_prefix, prefix)
|
||||
self.assertEqual(routes[0].route_table, route_table)
|
||||
|
||||
def _lr_nat_add(self, *args, **kwargs):
|
||||
lr = kwargs.pop('router', self._lr_add(utils.get_rand_device_name()))
|
||||
nat = self.api.lr_nat_add(
|
||||
|
|
Loading…
Reference in New Issue