summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/user/ospfd.rst26
-rw-r--r--ospfd/ospf_interface.c34
-rw-r--r--ospfd/ospf_interface.h7
-rw-r--r--ospfd/ospf_packet.c15
-rw-r--r--ospfd/ospf_vty.c89
-rw-r--r--ospfd/ospf_zebra.c14
-rw-r--r--tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py152
7 files changed, 323 insertions, 14 deletions
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 47f8fad17b..5652e34a43 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -757,6 +757,32 @@ Interfaces
optional IPv4 address is specified, the prefix suppression will apply
to the OSPF interface associated with the specified interface address.
+.. clicmd:: ip ospf neighbor-filter NAME [A.B.C.D]
+
+ Configure an IP prefix-list to use to filter packets received from
+ OSPF neighbors on the OSPF interface. The prefix-list should include rules
+ to permit or deny OSPF neighbors by IP source address. This is useful for
+ multi-access interfaces where adjacencies with only a subset of the
+ reachable neighbors are desired. Applications include testing partially
+ meshed topologies, OSPF Denial of Sevice (DoS) mitigation, and avoidance
+ of adjacencies with OSPF neighbors not meeting traffic engineering criteria.
+
+ Example:
+
+.. code-block:: frr
+
+ !
+ ! Prefix-list to block neighbor with source address 10.1.0.2
+ !
+ ip prefix-list nbr-filter seq 10 deny 10.1.0.2/32
+ ip prefix-list nbr-filter seq 200 permit any
+ !
+ ! Configure the neighbor filter prefix-list on interface eth0
+ !
+ interface eth0
+ ip ospf neighbor-filter nbr-filter
+ !
+
.. clicmd:: ip ospf area (A.B.C.D|(0-4294967295))
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index 319db1efe2..0b27501019 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -19,6 +19,7 @@
#include "zclient.h"
#include "bfd.h"
#include "ldp_sync.h"
+#include "plist.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_bfd.h"
@@ -67,6 +68,34 @@ int ospf_interface_neighbor_count(struct ospf_interface *oi)
return count;
}
+
+void ospf_intf_neighbor_filter_apply(struct ospf_interface *oi)
+{
+ struct route_node *rn;
+ struct ospf_neighbor *nbr = NULL;
+ struct prefix nbr_src_prefix = { AF_INET, IPV4_MAX_BITLEN, { 0 } };
+
+ if (!oi->nbr_filter)
+ return;
+
+ /*
+ * Kill neighbors that don't match the neighbor filter prefix-list
+ * excluding the neighbor for the router itself and any neighbors
+ * that are already down.
+ */
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
+ nbr = rn->info;
+ if (nbr && nbr != oi->nbr_self && nbr->state != NSM_Down) {
+ nbr_src_prefix.u.prefix4 = nbr->src;
+ if (prefix_list_apply(oi->nbr_filter,
+ (struct prefix *)&(
+ nbr_src_prefix)) !=
+ PREFIX_PERMIT)
+ OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr);
+ }
+ }
+}
+
int ospf_if_get_output_cost(struct ospf_interface *oi)
{
/* If all else fails, use default OSPF cost */
@@ -526,6 +555,7 @@ static struct ospf_if_params *ospf_new_if_params(void)
UNSET_IF_PARAM(oip, if_area);
UNSET_IF_PARAM(oip, opaque_capable);
UNSET_IF_PARAM(oip, keychain_name);
+ UNSET_IF_PARAM(oip, nbr_filter_name);
oip->auth_crypt = list_new();
@@ -544,6 +574,7 @@ static void ospf_del_if_params(struct interface *ifp,
{
list_delete(&oip->auth_crypt);
XFREE(MTYPE_OSPF_IF_PARAMS, oip->keychain_name);
+ XFREE(MTYPE_OSPF_IF_PARAMS, oip->nbr_filter_name);
ospf_interface_disable_bfd(ifp, oip);
ldp_sync_info_free(&(oip->ldp_sync_info));
XFREE(MTYPE_OSPF_IF_PARAMS, oip);
@@ -579,7 +610,8 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr)
!OSPF_IF_PARAM_CONFIGURED(oip, if_area) &&
!OSPF_IF_PARAM_CONFIGURED(oip, opaque_capable) &&
!OSPF_IF_PARAM_CONFIGURED(oip, prefix_suppression) &&
- !OSPF_IF_PARAM_CONFIGURED(oip, keychain_name) &&
+ !OSPF_IF_PARAM_CONFIGURED(oip, keychain_name) &&
+ !OSPF_IF_PARAM_CONFIGURED(oip, nbr_filter_name) &&
listcount(oip->auth_crypt) == 0) {
ospf_del_if_params(ifp, oip);
rn->info = NULL;
diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h
index 721ab1a9d7..2e53fbfbfa 100644
--- a/ospfd/ospf_interface.h
+++ b/ospfd/ospf_interface.h
@@ -124,6 +124,9 @@ struct ospf_if_params {
/* Opaque LSA capability at interface level (see RFC5250) */
DECLARE_IF_PARAM(bool, opaque_capable);
+
+ /* Name of prefix-list name for packet source address filtering. */
+ DECLARE_IF_PARAM(char *, nbr_filter_name);
};
enum { MEMBER_ALLROUTERS = 0,
@@ -242,6 +245,9 @@ struct ospf_interface {
/* List of configured NBMA neighbor. */
struct list *nbr_nbma;
+ /* Configured prefix-list for filtering neighbors. */
+ struct prefix_list *nbr_filter;
+
/* Graceful-Restart data. */
struct {
struct {
@@ -367,6 +373,7 @@ extern void ospf_crypt_key_add(struct list *list, struct crypt_key *key);
extern int ospf_crypt_key_delete(struct list *list, uint8_t key_id);
extern uint8_t ospf_default_iftype(struct interface *ifp);
extern int ospf_interface_neighbor_count(struct ospf_interface *oi);
+extern void ospf_intf_neighbor_filter_apply(struct ospf_interface *oi);
/* Set all multicast memberships appropriately based on the type and
state of the interface. */
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 60479ddcd1..87aaccad92 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -23,6 +23,7 @@
#endif
#include "vrf.h"
#include "lib_errors.h"
+#include "plist.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_network.h"
@@ -2747,6 +2748,20 @@ static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf)
oi = ospf_if_lookup_recv_if(ospf, iph->ip_src, ifp);
/*
+ * If a neighbor filter prefix-list is configured, apply it to the IP
+ * source address and ignore the packet if it doesn't match.
+ */
+ if (oi && oi->nbr_filter) {
+ struct prefix ip_src_prefix = { AF_INET, IPV4_MAX_BITLEN, { 0 } };
+
+ ip_src_prefix.u.prefix4 = iph->ip_src;
+ if (prefix_list_apply(oi->nbr_filter,
+ (struct prefix *)&(ip_src_prefix)) !=
+ PREFIX_PERMIT)
+ return OSPF_READ_CONTINUE;
+ }
+
+ /*
* ospf_verify_header() relies on a valid "oi" and thus can be called
* only after the passive/backbone/other checks below are passed.
* These checks in turn access the fields of unverified "ospfh"
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 4980cd3eca..e2f4f64d81 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -4085,6 +4085,31 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
if (use_json)
json_object_object_addf(json_ois, json_oi, "%pI4",
&oi->address->u.prefix4);
+
+ if (oi->nbr_filter) {
+ if (use_json) {
+ json_object_string_add(json_interface_sub,
+ "nbrFilterPrefixList",
+ prefix_list_name(
+ oi->nbr_filter));
+ json_object_string_add(json_oi,
+ "nbrFilterPrefixList",
+ prefix_list_name(
+ oi->nbr_filter));
+ } else
+ vty_out(vty,
+ " Neighbor filter prefix-list: %s\n",
+ prefix_list_name(oi->nbr_filter));
+ } else {
+ if (use_json) {
+ json_object_string_add(json_interface_sub,
+ "nbrFilterPrefixList",
+ "N/A");
+ json_object_string_add(json_oi,
+ "nbrFilterPrefixList",
+ "N/A");
+ }
+ }
}
}
@@ -9937,6 +9962,58 @@ DEFPY(ip_ospf_prefix_suppression, ip_ospf_prefix_suppression_addr_cmd,
return CMD_SUCCESS;
}
+DEFPY(ip_ospf_neighbor_filter, ip_ospf_neighbor_filter_addr_cmd,
+ "[no] ip ospf neighbor-filter ![PREFIXLIST4_NAME]$prefix_list [A.B.C.D]$ip_addr", NO_STR
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Filter OSPF neighbor packets\n"
+ "Prefix-List used for filtering\n"
+ "Address of interface\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf_if_params *params;
+ struct prefix_list *nbr_filter = NULL;
+ struct route_node *rn;
+
+ params = IF_DEF_PARAMS(ifp);
+
+ if (ip_addr.s_addr != INADDR_ANY) {
+ params = ospf_get_if_params(ifp, ip_addr);
+ ospf_if_update_params(ifp, ip_addr);
+ }
+
+ if (params->nbr_filter_name)
+ XFREE(MTYPE_OSPF_IF_PARAMS, params->nbr_filter_name);
+
+ if (no) {
+ UNSET_IF_PARAM(params, nbr_filter_name);
+ params->nbr_filter_name = NULL;
+ } else {
+ SET_IF_PARAM(params, nbr_filter_name);
+ params->nbr_filter_name = XSTRDUP(MTYPE_OSPF_IF_PARAMS,
+ prefix_list);
+ nbr_filter = prefix_list_lookup(AFI_IP, params->nbr_filter_name);
+ }
+
+ /*
+ * Determine if there is a change in neighbor filter prefix-list for the
+ * interface.
+ */
+ for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) {
+ struct ospf_interface *oi = rn->info;
+
+ if (oi &&
+ (ip_addr.s_addr == INADDR_ANY ||
+ IPV4_ADDR_SAME(&oi->address->u.prefix4, &ip_addr)) &&
+ oi->nbr_filter != nbr_filter) {
+ oi->nbr_filter = nbr_filter;
+ if (oi->nbr_filter)
+ ospf_intf_neighbor_filter_apply(oi);
+ }
+ }
+ return CMD_SUCCESS;
+}
+
DEFUN (ospf_max_metric_router_lsa_admin,
ospf_max_metric_router_lsa_admin_cmd,
"max-metric router-lsa administrative",
@@ -12360,6 +12437,15 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
vty_out(vty, "\n");
}
+ /* neighbor-filter print. */
+ if (OSPF_IF_PARAM_CONFIGURED(params, nbr_filter_name)) {
+ vty_out(vty, " ip ospf neighbor-filter %s",
+ params->nbr_filter_name);
+ if (params != IF_DEF_PARAMS(ifp) && rn)
+ vty_out(vty, " %pI4", &rn->p.u.prefix4);
+ vty_out(vty, "\n");
+ }
+
while (1) {
if (rn == NULL)
rn = route_top(IF_OIFS_PARAMS(ifp));
@@ -13176,6 +13262,9 @@ static void ospf_vty_if_init(void)
/* "ip ospf prefix-suppression" commands. */
install_element(INTERFACE_NODE, &ip_ospf_prefix_suppression_addr_cmd);
+ /* "ip ospf neighbor-filter" commands. */
+ install_element(INTERFACE_NODE, &ip_ospf_neighbor_filter_addr_cmd);
+
/* These commands are compatibitliy for previous version. */
install_element(INTERFACE_NODE, &ospf_authentication_key_cmd);
install_element(INTERFACE_NODE, &ospf_message_digest_key_cmd);
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index bb6cc3a89c..2c518f2c9e 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -1769,6 +1769,7 @@ static void ospf_prefix_list_update(struct prefix_list *plist)
int type;
int abr_inv = 0;
struct ospf_area *area;
+ struct ospf_interface *oi;
struct listnode *node, *n1;
/* If OSPF instatnce does not exist, return right now. */
@@ -1824,6 +1825,19 @@ static void ospf_prefix_list_update(struct prefix_list *plist)
}
}
+ /* Update interface neighbor-filter lists. */
+ for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
+ if (OSPF_IF_PARAM(oi, nbr_filter_name) &&
+ strcmp(OSPF_IF_PARAM(oi, nbr_filter_name),
+ prefix_list_name(plist)) == 0) {
+ oi->nbr_filter = prefix_list_lookup(
+ AFI_IP,
+ OSPF_IF_PARAM(oi, nbr_filter_name));
+ if (oi->nbr_filter)
+ ospf_intf_neighbor_filter_apply(oi);
+ }
+ }
+
/* Schedule ABR task. */
if (IS_OSPF_ABR(ospf) && abr_inv)
ospf_schedule_abr_task(ospf);
diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py
index 352180b7ce..1f0f87959a 100644
--- a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py
+++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py
@@ -118,17 +118,21 @@ def teardown_module(mod):
tgen.stop_topology()
-def verify_p2mp_interface(tgen):
+def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter):
"Verify the P2MP Configuration and interface settings"
- r1 = tgen.gears["r1"]
+ topo_router = tgen.gears[router]
step("Test running configuration for P2MP configuration")
rc = 0
- rc, _, _ = tgen.net["r1"].cmd_status(
+ rc, _, _ = tgen.net[router].cmd_status(
"show running ospfd | grep 'ip ospf network point-to-multipoint'", warn=False
)
- assertmsg = "'ip ospf network point-to-multipoint' applied, but not present in r1 configuration"
+ assertmsg = (
+ "'ip ospf network point-to-multipoint' applied, but not present in "
+ + router
+ + "configuration"
+ )
assert rc, assertmsg
step("Test OSPF interface for P2MP settings")
@@ -145,11 +149,11 @@ def verify_p2mp_interface(tgen):
"networkType": "POINTOMULTIPOINT",
"cost": 10,
"state": "Point-To-Point",
- "nbrCount": 3,
- "nbrAdjacentCount": 3,
+ "nbrCount": nbr_cnt,
+ "nbrAdjacentCount": nbr_adj_cnt,
"prefixSuppression": False,
"p2mpDelayReflood": False,
- "p2mpNonBroadcast": False,
+ "nbrFilterPrefixList": nbr_filter,
}
},
"ipAddress": "10.1.0.1",
@@ -161,16 +165,19 @@ def verify_p2mp_interface(tgen):
"cost": 10,
"state": "Point-To-Point",
"opaqueCapable": True,
- "nbrCount": 3,
- "nbrAdjacentCount": 3,
+ "nbrCount": nbr_cnt,
+ "nbrAdjacentCount": nbr_adj_cnt,
"prefixSuppression": False,
"p2mpDelayReflood": False,
- "p2mpNonBroadcast": False,
+ "nbrFilterPrefixList": nbr_filter,
}
}
}
test_func = partial(
- topotest.router_json_cmp, r1, "show ip ospf interface r1-eth0 json", input_dict
+ topotest.router_json_cmp,
+ topo_router,
+ "show ip ospf interface r1-eth0 json",
+ input_dict,
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "P2MP Interface Mismatch on router r1"
@@ -251,6 +258,23 @@ def verify_p2mp_neighbor(tgen, router, neighbor, state, intf_addr, interface):
assert result is None, assertmsg
+def verify_p2mp_neighbor_missing(tgen, router, neighbor):
+ topo_router = tgen.gears[router]
+
+ step("Verify neighbor " + neighbor + " missing")
+ input_dict = {"default": {}}
+ test_func = partial(
+ topotest.router_json_cmp,
+ topo_router,
+ "show ip ospf neighbor " + neighbor + " json",
+ input_dict,
+ True, # Require exact match for missing neighbor
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+ assertmsg = "P2MP Neighbor " + neighbor + " not missing"
+ assert result is None, assertmsg
+
+
def verify_p2mp_route(tgen, router, prefix, prefix_len, nexthop, interface):
topo_router = tgen.gears[router]
@@ -288,7 +312,7 @@ def test_p2mp_broadcast_interface():
pytest.skip("Skipped because of router(s) failure")
step("Verify router r1 interface r1-eth0 p2mp configuration")
- verify_p2mp_interface(tgen)
+ verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
step("Verify router r1 p2mp interface r1-eth0 neighbors")
verify_p2mp_neighbor(
@@ -313,7 +337,7 @@ def test_p2mp_broadcast_interface():
step("Verify router r1 interface r1-eth0 p2mp configuration application")
r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf network point-to-multipoint")
- verify_p2mp_interface(tgen)
+ verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
step("Verify restablishment of r1-eth0 p2mp neighbors")
verify_p2mp_neighbor(
@@ -332,6 +356,108 @@ def test_p2mp_broadcast_interface():
verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.4", "r1-eth0")
+def test_p2mp_broadcast_neighbor_filter():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip("Skipped because of router(s) failure")
+
+ step("Verify router r1 interface r1-eth0 p2mp configuration")
+ verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
+
+ step("Verify router r1 p2mp interface r1-eth0 neighbors")
+ verify_p2mp_neighbor(
+ tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1"
+ )
+ verify_p2mp_neighbor(
+ tgen, "r1", "3.3.3.3", "Full/DROther", "10.1.0.3", "r1-eth0:10.1.0.1"
+ )
+ verify_p2mp_neighbor(
+ tgen, "r1", "4.4.4.4", "Full/DROther", "10.1.0.4", "r1-eth0:10.1.0.1"
+ )
+
+ step("Add OSPF interface neighbor-filter to r1")
+ r1 = tgen.gears["r1"]
+ r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter")
+
+ step("Verify the R1 configuration of 'ip ospf neighbor-filter nbr-filter'")
+ neighbor_filter_cfg = (
+ tgen.net["r1"]
+ .cmd(
+ 'vtysh -c "show running ospfd" | grep "^ ip ospf neighbor-filter nbr-filter"'
+ )
+ .rstrip()
+ )
+ assertmsg = (
+ "'ip ospf neighbor-filter nbr-filter' applied, but not present in configuration"
+ )
+ assert neighbor_filter_cfg == " ip ospf neighbor-filter nbr-filter", assertmsg
+
+ step("Verify non-existent neighbor-filter is not applied to r1 interfaces")
+ verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
+
+ step("Add nbr-filter prefix-list configuration to r1")
+ r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 200 permit any")
+
+ step(
+ "Verify neighbor-filter is now applied to r1 interface and neighbors still adjacent"
+ )
+ verify_p2mp_interface(tgen, "r1", 3, 3, "nbr-filter")
+
+ step("Add nbr-filter prefix-list configuration to block r4")
+ r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.4/32")
+
+ step(
+ "Verify neighbor-filter is now applied to r1 interface and r4 is no longer adjacent"
+ )
+ verify_p2mp_interface(tgen, "r1", 2, 2, "nbr-filter")
+ verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4")
+
+ step("Verify route to r4 subnet is now through r2")
+ verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.2", "r1-eth0")
+
+ step("Add nbr-filter prefix-list configuration to block r2")
+ r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.2/32")
+
+ step(
+ "Verify neighbor-filter is now applied to r1 interface and r2 is no longer adjacent"
+ )
+ verify_p2mp_interface(tgen, "r1", 1, 1, "nbr-filter")
+ verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2")
+
+ step("Verify route to r4 and r2 subnet are now through r3")
+ verify_p2mp_route(tgen, "r1", "10.1.2.0/24", 24, "10.1.0.3", "r1-eth0")
+ verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.3", "r1-eth0")
+
+ step("Remove neighbor filter configuration and verify")
+ r1.vtysh_cmd("conf t\ninterface r1-eth0\nno ip ospf neighbor-filter")
+ rc, _, _ = tgen.net["r1"].cmd_status(
+ "show running ospfd | grep -q 'ip ospf neighbor-filter'", warn=False
+ )
+ assertmsg = "'ip ospf neighbor' not applied, but present in R1 configuration"
+ assert rc, assertmsg
+
+ step("Verify interface neighbor-filter is removed and neighbors present")
+ verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
+
+ step("Add neighbor filter configuration and verify neighbors are filtered")
+ r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter")
+ verify_p2mp_interface(tgen, "r1", 1, 1, "nbr-filter")
+ verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2")
+ verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4")
+
+ step("Remove nbr-filter prefix-list configuration to block r2 and verify neighbor")
+ r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter seq 20")
+ verify_p2mp_interface(tgen, "r1", 2, 2, "nbr-filter")
+ verify_p2mp_neighbor(
+ tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1"
+ )
+
+ step("Delete nbr-filter prefix-list and verify neighbors are present")
+ r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter")
+ verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
+
+
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()