Merge pull request #9640 from opensourcerouting/ospf6d-filters

ospf6d: rework filtering commands to be in line with ospfd
This commit is contained in:
Russ White 2021-09-21 11:28:58 -04:00 committed by GitHub
commit 48f23c8879
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 224 additions and 136 deletions

View File

@ -198,6 +198,47 @@ OSPF6 area
advertisement of summaries into the area. In that case, a single Type-3 LSA advertisement of summaries into the area. In that case, a single Type-3 LSA
containing a default route is originated into the NSSA. containing a default route is originated into the NSSA.
.. clicmd:: area A.B.C.D export-list NAME
.. clicmd:: area (0-4294967295) export-list NAME
Filter Type-3 summary-LSAs announced to other areas originated from intra-
area paths from specified area.
.. code-block:: frr
router ospf6
area 0.0.0.10 export-list foo
!
ipv6 access-list foo permit 2001:db8:1000::/64
ipv6 access-list foo deny any
With example above any intra-area paths from area 0.0.0.10 and from range
2001:db8::/32 (for example 2001:db8:1::/64 and 2001:db8:2::/64) are announced
into other areas as Type-3 summary-LSA's, but any others (for example
2001:200::/48) aren't.
This command is only relevant if the router is an ABR for the specified
area.
.. clicmd:: area A.B.C.D import-list NAME
.. clicmd:: area (0-4294967295) import-list NAME
Same as export-list, but it applies to paths announced into specified area
as Type-3 summary-LSAs.
.. clicmd:: area A.B.C.D filter-list prefix NAME in
.. clicmd:: area A.B.C.D filter-list prefix NAME out
.. clicmd:: area (0-4294967295) filter-list prefix NAME in
.. clicmd:: area (0-4294967295) filter-list prefix NAME out
Filtering Type-3 summary-LSAs to/from area using prefix lists. This command
makes sense in ABR only.
.. _ospf6-interface: .. _ospf6-interface:
OSPF6 interface OSPF6 interface

View File

@ -231,6 +231,69 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
return 0; return 0;
} }
if (route->type == OSPF6_DEST_TYPE_NETWORK) {
bool filter = false;
route_area =
ospf6_area_lookup(route->path.area_id, area->ospf6);
assert(route_area);
/* Check export-list */
if (EXPORT_LIST(route_area)
&& access_list_apply(EXPORT_LIST(route_area),
&route->prefix)
== FILTER_DENY) {
if (IS_OSPF6_DEBUG_ABR)
zlog_debug(
"%s: prefix %pFX was denied by export-list",
__func__, &route->prefix);
filter = true;
}
/* Check output prefix-list */
if (PREFIX_LIST_OUT(route_area)
&& prefix_list_apply(PREFIX_LIST_OUT(route_area),
&route->prefix)
!= PREFIX_PERMIT) {
if (IS_OSPF6_DEBUG_ABR)
zlog_debug(
"%s: prefix %pFX was denied by prefix-list out",
__func__, &route->prefix);
filter = true;
}
/* Check import-list */
if (IMPORT_LIST(area)
&& access_list_apply(IMPORT_LIST(area), &route->prefix)
== FILTER_DENY) {
if (IS_OSPF6_DEBUG_ABR)
zlog_debug(
"%s: prefix %pFX was denied by import-list",
__func__, &route->prefix);
filter = true;
}
/* Check input prefix-list */
if (PREFIX_LIST_IN(area)
&& prefix_list_apply(PREFIX_LIST_IN(area), &route->prefix)
!= PREFIX_PERMIT) {
if (IS_OSPF6_DEBUG_ABR)
zlog_debug(
"%s: prefix %pFX was denied by prefix-list in",
__func__, &route->prefix);
filter = true;
}
if (filter) {
if (summary) {
ospf6_route_remove(summary, summary_table);
if (old)
ospf6_lsa_purge(old);
}
return 0;
}
}
/* do not generate if the nexthops belongs to the target area */ /* do not generate if the nexthops belongs to the target area */
if (ospf6_abr_nexthops_belong_to_area(route, area)) { if (ospf6_abr_nexthops_belong_to_area(route, area)) {
if (IS_OSPF6_DEBUG_ABR) if (IS_OSPF6_DEBUG_ABR)
@ -430,39 +493,6 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
} }
} }
/* Check export list */
if (EXPORT_NAME(area)) {
if (EXPORT_LIST(area) == NULL)
EXPORT_LIST(area) =
access_list_lookup(AFI_IP6, EXPORT_NAME(area));
if (EXPORT_LIST(area))
if (access_list_apply(EXPORT_LIST(area), &route->prefix)
== FILTER_DENY) {
if (is_debug)
zlog_debug(
"prefix %pFX was denied by export list",
&route->prefix);
ospf6_abr_delete_route(route, summary,
summary_table, old);
return 0;
}
}
/* Check filter-list */
if (PREFIX_LIST_OUT(area))
if (prefix_list_apply(PREFIX_LIST_OUT(area), &route->prefix)
!= PREFIX_PERMIT) {
if (is_debug)
zlog_debug(
"prefix %pFX was denied by filter-list out",
&route->prefix);
ospf6_abr_delete_route(route, summary, summary_table,
old);
return 0;
}
/* the route is going to be originated. store it in area's summary_table /* the route is going to be originated. store it in area's summary_table
*/ */
if (summary == NULL) { if (summary == NULL) {
@ -1134,39 +1164,6 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
return; return;
} }
/* Check import list */
if (IMPORT_NAME(oa)) {
if (IMPORT_LIST(oa) == NULL)
IMPORT_LIST(oa) =
access_list_lookup(AFI_IP6, IMPORT_NAME(oa));
if (IMPORT_LIST(oa))
if (access_list_apply(IMPORT_LIST(oa), &prefix)
== FILTER_DENY) {
if (is_debug)
zlog_debug(
"Prefix %pFX was denied by import-list",
&prefix);
if (old)
ospf6_route_remove(old, table);
return;
}
}
/* Check input prefix-list */
if (PREFIX_LIST_IN(oa)) {
if (prefix_list_apply(PREFIX_LIST_IN(oa), &prefix)
!= PREFIX_PERMIT) {
if (is_debug)
zlog_debug(
"Prefix %pFX was denied by prefix-list in",
&prefix);
if (old)
ospf6_route_remove(old, table);
return;
}
}
/* (5),(6): the path preference is handled by the sorting /* (5),(6): the path preference is handled by the sorting
in the routing table. Always install the path by substituting in the routing table. Always install the path by substituting
old route (if any). */ old route (if any). */
@ -1355,35 +1352,6 @@ void ospf6_abr_examin_brouter(uint32_t router_id, struct ospf6_route *route,
ospf6_abr_examin_summary(lsa, oa); ospf6_abr_examin_summary(lsa, oa);
} }
void ospf6_abr_reimport(struct ospf6_area *oa)
{
struct ospf6_lsa *lsa;
uint16_t type;
type = htons(OSPF6_LSTYPE_INTER_ROUTER);
for (ALL_LSDB_TYPED(oa->lsdb, type, lsa))
ospf6_abr_examin_summary(lsa, oa);
type = htons(OSPF6_LSTYPE_INTER_PREFIX);
for (ALL_LSDB_TYPED(oa->lsdb, type, lsa))
ospf6_abr_examin_summary(lsa, oa);
}
/* export filter removed so determine if we should reoriginate summary LSAs */
void ospf6_abr_reexport(struct ospf6_area *oa)
{
struct ospf6_route *route;
/* if not a ABR return success */
if (!ospf6_check_and_set_router_abr(oa->ospf6))
return;
/* Redo summaries if required */
for (route = ospf6_route_head(oa->ospf6->route_table); route;
route = ospf6_route_next(route))
ospf6_abr_originate_summary_to_area(route, oa);
}
void ospf6_abr_prefix_resummarize(struct ospf6 *o) void ospf6_abr_prefix_resummarize(struct ospf6 *o)
{ {
struct ospf6_route *route; struct ospf6_route *route;

View File

@ -73,8 +73,6 @@ extern void ospf6_abr_defaults_to_stub(struct ospf6 *ospf6);
extern void ospf6_abr_examin_brouter(uint32_t router_id, extern void ospf6_abr_examin_brouter(uint32_t router_id,
struct ospf6_route *route, struct ospf6_route *route,
struct ospf6 *ospf6); struct ospf6 *ospf6);
extern void ospf6_abr_reimport(struct ospf6_area *oa);
extern void ospf6_abr_reexport(struct ospf6_area *oa);
extern void ospf6_abr_range_reset_cost(struct ospf6 *ospf6); extern void ospf6_abr_range_reset_cost(struct ospf6 *ospf6);
extern void ospf6_abr_prefix_resummarize(struct ospf6 *ospf6); extern void ospf6_abr_prefix_resummarize(struct ospf6 *ospf6);
@ -88,7 +86,6 @@ extern void ospf6_abr_old_path_update(struct ospf6_route *old_route,
struct ospf6_route *route, struct ospf6_route *route,
struct ospf6_route_table *table); struct ospf6_route_table *table);
extern void ospf6_abr_init(void); extern void ospf6_abr_init(void);
extern void ospf6_abr_reexport(struct ospf6_area *oa);
extern void ospf6_abr_range_update(struct ospf6_route *range, extern void ospf6_abr_range_update(struct ospf6_route *range,
struct ospf6 *ospf6); struct ospf6 *ospf6);
extern void ospf6_abr_remove_unapproved_summaries(struct ospf6 *ospf6); extern void ospf6_abr_remove_unapproved_summaries(struct ospf6 *ospf6);

View File

@ -696,17 +696,17 @@ DEFUN (area_filter_list,
XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_IN(area)); XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_IN(area));
PREFIX_NAME_IN(area) = PREFIX_NAME_IN(area) =
XSTRDUP(MTYPE_OSPF6_PLISTNAME, plistname); XSTRDUP(MTYPE_OSPF6_PLISTNAME, plistname);
ospf6_abr_reimport(area);
} else { } else {
PREFIX_LIST_OUT(area) = plist; PREFIX_LIST_OUT(area) = plist;
XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_OUT(area)); XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_OUT(area));
PREFIX_NAME_OUT(area) = PREFIX_NAME_OUT(area) =
XSTRDUP(MTYPE_OSPF6_PLISTNAME, plistname); XSTRDUP(MTYPE_OSPF6_PLISTNAME, plistname);
/* Redo summaries if required */
ospf6_abr_reexport(area);
} }
/* Redo summaries if required */
if (ospf6_check_and_set_router_abr(area->ospf6))
ospf6_schedule_abr_task(ospf6);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -739,7 +739,6 @@ DEFUN (no_area_filter_list,
PREFIX_LIST_IN(area) = NULL; PREFIX_LIST_IN(area) = NULL;
XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_IN(area)); XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_IN(area));
ospf6_abr_reimport(area);
} else { } else {
if (PREFIX_NAME_OUT(area)) if (PREFIX_NAME_OUT(area))
if (!strmatch(PREFIX_NAME_OUT(area), plistname)) if (!strmatch(PREFIX_NAME_OUT(area), plistname))
@ -747,9 +746,12 @@ DEFUN (no_area_filter_list,
XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_OUT(area)); XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_OUT(area));
PREFIX_LIST_OUT(area) = NULL; PREFIX_LIST_OUT(area) = NULL;
ospf6_abr_reexport(area);
} }
/* Redo summaries if required */
if (ospf6_check_and_set_router_abr(area->ospf6))
ospf6_schedule_abr_task(ospf6);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -760,19 +762,30 @@ void ospf6_filter_update(struct access_list *access)
struct ospf6 *ospf6; struct ospf6 *ospf6;
for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) { for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
bool update = false;
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, n, oa)) { for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, n, oa)) {
if (IMPORT_NAME(oa) if (IMPORT_NAME(oa)
&& strcmp(IMPORT_NAME(oa), access->name) == 0) && strcmp(IMPORT_NAME(oa), access->name) == 0) {
ospf6_abr_reimport(oa); IMPORT_LIST(oa) = access_list_lookup(
AFI_IP6, IMPORT_NAME(oa));
update = true;
}
if (EXPORT_NAME(oa) if (EXPORT_NAME(oa)
&& strcmp(EXPORT_NAME(oa), access->name) == 0) && strcmp(EXPORT_NAME(oa), access->name) == 0) {
ospf6_abr_reexport(oa); EXPORT_LIST(oa) = access_list_lookup(
AFI_IP6, EXPORT_NAME(oa));
update = true;
}
} }
if (update && ospf6_check_and_set_router_abr(ospf6))
ospf6_schedule_abr_task(ospf6);
} }
} }
void ospf6_area_plist_update(struct prefix_list *plist, int add) void ospf6_plist_update(struct prefix_list *plist)
{ {
struct listnode *node, *nnode; struct listnode *node, *nnode;
struct ospf6_area *oa; struct ospf6_area *oa;
@ -780,19 +793,29 @@ void ospf6_area_plist_update(struct prefix_list *plist, int add)
const char *name = prefix_list_name(plist); const char *name = prefix_list_name(plist);
struct ospf6 *ospf6 = NULL; struct ospf6 *ospf6 = NULL;
if (prefix_list_afi(plist) != AFI_IP6)
return;
for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) { for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
bool update = false;
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, n, oa)) { for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, n, oa)) {
if (PREFIX_NAME_IN(oa) if (PREFIX_NAME_IN(oa)
&& !strcmp(PREFIX_NAME_IN(oa), name)) { && !strcmp(PREFIX_NAME_IN(oa), name)) {
PREFIX_LIST_IN(oa) = add ? plist : NULL; PREFIX_LIST_IN(oa) = prefix_list_lookup(
ospf6_abr_reexport(oa); AFI_IP6, PREFIX_NAME_IN(oa));
update = true;
} }
if (PREFIX_NAME_OUT(oa) if (PREFIX_NAME_OUT(oa)
&& !strcmp(PREFIX_NAME_OUT(oa), name)) { && !strcmp(PREFIX_NAME_OUT(oa), name)) {
PREFIX_LIST_OUT(oa) = add ? plist : NULL; PREFIX_LIST_OUT(oa) = prefix_list_lookup(
ospf6_abr_reexport(oa); AFI_IP6, PREFIX_NAME_OUT(oa));
update = true;
} }
} }
if (update && ospf6_check_and_set_router_abr(ospf6))
ospf6_schedule_abr_task(ospf6);
} }
} }
@ -822,7 +845,8 @@ DEFUN (area_import_list,
free(IMPORT_NAME(area)); free(IMPORT_NAME(area));
IMPORT_NAME(area) = strdup(argv[idx_name]->arg); IMPORT_NAME(area) = strdup(argv[idx_name]->arg);
ospf6_abr_reimport(area); if (ospf6_check_and_set_router_abr(area->ospf6))
ospf6_schedule_abr_task(ospf6);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -844,13 +868,14 @@ DEFUN (no_area_import_list,
OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, area, ospf6); OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, area, ospf6);
IMPORT_LIST(area) = 0; IMPORT_LIST(area) = NULL;
if (IMPORT_NAME(area)) if (IMPORT_NAME(area))
free(IMPORT_NAME(area)); free(IMPORT_NAME(area));
IMPORT_NAME(area) = NULL; IMPORT_NAME(area) = NULL;
ospf6_abr_reimport(area); if (ospf6_check_and_set_router_abr(area->ospf6))
ospf6_schedule_abr_task(ospf6);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -883,7 +908,8 @@ DEFUN (area_export_list,
EXPORT_NAME(area) = strdup(argv[idx_name]->arg); EXPORT_NAME(area) = strdup(argv[idx_name]->arg);
/* Redo summaries if required */ /* Redo summaries if required */
ospf6_abr_reexport(area); if (ospf6_check_and_set_router_abr(area->ospf6))
ospf6_schedule_abr_task(ospf6);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -905,13 +931,14 @@ DEFUN (no_area_export_list,
OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, area, ospf6); OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, area, ospf6);
EXPORT_LIST(area) = 0; EXPORT_LIST(area) = NULL;
if (EXPORT_NAME(area)) if (EXPORT_NAME(area))
free(EXPORT_NAME(area)); free(EXPORT_NAME(area));
EXPORT_NAME(area) = NULL; EXPORT_NAME(area) = NULL;
ospf6_abr_reexport(area); if (ospf6_check_and_set_router_abr(area->ospf6))
ospf6_schedule_abr_task(ospf6);
return CMD_SUCCESS; return CMD_SUCCESS;
} }

View File

@ -163,7 +163,7 @@ extern void ospf6_area_disable(struct ospf6_area *oa);
extern void ospf6_area_show(struct vty *vty, struct ospf6_area *oa, extern void ospf6_area_show(struct vty *vty, struct ospf6_area *oa,
json_object *json_areas, bool use_json); json_object *json_areas, bool use_json);
extern void ospf6_area_plist_update(struct prefix_list *plist, int add); extern void ospf6_plist_update(struct prefix_list *plist);
extern void ospf6_filter_update(struct access_list *access); extern void ospf6_filter_update(struct access_list *access);
extern void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6); extern void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6);
extern void ospf6_area_init(void); extern void ospf6_area_init(void);

View File

@ -1355,20 +1355,6 @@ DEFUN(show_ipv6_ospf6_linkstate_detail, show_ipv6_ospf6_linkstate_detail_cmd,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static void ospf6_plist_add(struct prefix_list *plist)
{
if (prefix_list_afi(plist) != AFI_IP6)
return;
ospf6_area_plist_update(plist, 1);
}
static void ospf6_plist_del(struct prefix_list *plist)
{
if (prefix_list_afi(plist) != AFI_IP6)
return;
ospf6_area_plist_update(plist, 0);
}
/* Install ospf related commands. */ /* Install ospf related commands. */
void ospf6_init(struct thread_master *master) void ospf6_init(struct thread_master *master)
{ {
@ -1387,8 +1373,8 @@ void ospf6_init(struct thread_master *master)
ospf6_gr_helper_config_init(); ospf6_gr_helper_config_init();
/* initialize hooks for modifying filter rules */ /* initialize hooks for modifying filter rules */
prefix_list_add_hook(ospf6_plist_add); prefix_list_add_hook(ospf6_plist_update);
prefix_list_delete_hook(ospf6_plist_del); prefix_list_delete_hook(ospf6_plist_update);
access_list_add_hook(ospf6_filter_update); access_list_add_hook(ospf6_filter_update);
access_list_delete_hook(ospf6_filter_update); access_list_delete_hook(ospf6_filter_update);

View File

@ -431,6 +431,75 @@ def test_nssa_no_summary():
assert result is None, assertmsg assert result is None, assertmsg
def test_area_filters():
"""
Test ABR import/export filters.
"""
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
#
# Configure import/export filters on r2 (ABR for area 1).
#
config = """
configure terminal
ipv6 access-list ACL_IMPORT seq 5 permit 2001:db8:2::/64
ipv6 access-list ACL_IMPORT seq 10 deny any
ipv6 access-list ACL_EXPORT seq 10 deny any
router ospf6
area 1 import-list ACL_IMPORT
area 1 export-list ACL_EXPORT
"""
tgen.gears["r2"].vtysh_cmd(config)
logger.info("Expecting inter-area routes to be removed on r1")
for route in ["::/0", "2001:db8:3::/64"]:
test_func = partial(dont_expect_route, "r1", route, type="inter-area")
_, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
assertmsg = "{}'s {} inter-area route still exists".format("r1", route)
assert result is None, assertmsg
logger.info("Expecting inter-area routes to be removed on r3")
for route in ["2001:db8:1::/64"]:
test_func = partial(dont_expect_route, "r3", route, type="inter-area")
_, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
assertmsg = "{}'s {} inter-area route still exists".format("r3", route)
assert result is None, assertmsg
#
# Update the ACLs used by the import/export filters.
#
config = """
configure terminal
ipv6 access-list ACL_IMPORT seq 6 permit 2001:db8:3::/64
ipv6 access-list ACL_EXPORT seq 5 permit 2001:db8:1::/64
"""
tgen.gears["r2"].vtysh_cmd(config)
logger.info("Expecting 2001:db8:3::/64 to be re-added on r1")
routes = {"2001:db8:3::/64": {}}
expect_ospfv3_routes("r1", routes, wait=30, type="inter-area")
logger.info("Expecting 2001:db8:1::/64 to be re-added on r3")
routes = {"2001:db8:1::/64": {}}
expect_ospfv3_routes("r3", routes, wait=30, type="inter-area")
#
# Unconfigure r2's ABR import/export filters.
#
config = """
configure terminal
router ospf6
no area 1 import-list ACL_IMPORT
no area 1 export-list ACL_EXPORT
"""
tgen.gears["r2"].vtysh_cmd(config)
logger.info("Expecting ::/0 to be re-added on r1")
routes = {"::/0": {}}
expect_ospfv3_routes("r1", routes, wait=30, type="inter-area")
def teardown_module(_mod): def teardown_module(_mod):
"Teardown the pytest environment" "Teardown the pytest environment"
tgen = get_topogen() tgen = get_topogen()