From f06c6e3ef91027205e653a4aa72a2bb8969466e9 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 20 Apr 2021 05:10:17 +0200 Subject: [PATCH 1/9] pimd: IGMP sockets need to be iface-bound too There's an IGMP socket per interface, so they should be bound to that interface. Which also makes IGMP work in VRFs. Fixes: #7889 Signed-off-by: David Lamparter --- pimd/pim_sock.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 504519c8a4..05b0f92a4b 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -112,17 +112,15 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp, } #ifdef SO_BINDTODEVICE - if (protocol == IPPROTO_PIM) { - int ret; + int ret; - ret = pim_socket_bind(fd, ifp); - if (ret) { - close(fd); - zlog_warn( - "Could not set fd: %d for interface: %s to device", - fd, ifp->name); - return PIM_SOCK_ERR_BIND; - } + ret = pim_socket_bind(fd, ifp); + if (ret) { + close(fd); + zlog_warn( + "Could not set fd: %d for interface: %s to device", + fd, ifp->name); + return PIM_SOCK_ERR_BIND; } #else /* XXX: use IP_PKTINFO / IP_RECVIF to emulate behaviour? Or change to From 2b6b16fc21d35693914231509c8710eff6a58c4a Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 20 Apr 2021 06:11:57 +0200 Subject: [PATCH 2/9] lib, pimd: add address match mode to prefix lists ... the PIM code is kinda misusing prefix lists to match addresses. Considering the weird semantics of access-lists, I can't fault it. However, prefix lists aren't great at matching addresses by default, since they try to match the prefix length too. So, here's an "address match mode" for prefix lists to get that to work more reasonably. Fixes: #8492 Signed-off-by: David Lamparter --- lib/plist.c | 20 ++++++++++++-------- lib/plist.h | 15 +++++++++++---- pimd/pim_rp.c | 33 +++++++++++++++++++++++++++------ 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/lib/plist.c b/lib/plist.c index 0ee02f8a0b..1ee855a594 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -750,7 +750,7 @@ static const char *prefix_list_type_str(struct prefix_list_entry *pentry) } static int prefix_list_entry_match(struct prefix_list_entry *pentry, - const struct prefix *p) + const struct prefix *p, bool address_mode) { int ret; @@ -761,6 +761,9 @@ static int prefix_list_entry_match(struct prefix_list_entry *pentry, if (!ret) return 0; + if (address_mode) + return 1; + /* In case of le nor ge is specified, exact match is performed. */ if (!pentry->le && !pentry->ge) { if (pentry->prefix.prefixlen != p->prefixlen) @@ -777,14 +780,15 @@ static int prefix_list_entry_match(struct prefix_list_entry *pentry, return 1; } -enum prefix_list_type prefix_list_apply_which_prefix( +enum prefix_list_type prefix_list_apply_ext( struct prefix_list *plist, - const struct prefix **which, - const void *object) + const struct prefix_list_entry **which, + union prefixconstptr object, + bool address_mode) { struct prefix_list_entry *pentry, *pbest = NULL; - const struct prefix *p = (const struct prefix *)object; + const struct prefix *p = object.p; const uint8_t *byte = p->u.val; size_t depth; size_t validbits = p->prefixlen; @@ -809,7 +813,7 @@ enum prefix_list_type prefix_list_apply_which_prefix( pentry = pentry->next_best) { if (pbest && pbest->seq < pentry->seq) continue; - if (prefix_list_entry_match(pentry, p)) + if (prefix_list_entry_match(pentry, p, address_mode)) pbest = pentry; } @@ -830,7 +834,7 @@ enum prefix_list_type prefix_list_apply_which_prefix( pentry = pentry->next_best) { if (pbest && pbest->seq < pentry->seq) continue; - if (prefix_list_entry_match(pentry, p)) + if (prefix_list_entry_match(pentry, p, address_mode)) pbest = pentry; } break; @@ -838,7 +842,7 @@ enum prefix_list_type prefix_list_apply_which_prefix( if (which) { if (pbest) - *which = &pbest->prefix; + *which = pbest; else *which = NULL; } diff --git a/lib/plist.h b/lib/plist.h index 57eb763a68..c9507df57c 100644 --- a/lib/plist.h +++ b/lib/plist.h @@ -37,6 +37,7 @@ enum prefix_list_type { }; struct prefix_list; +struct prefix_list_entry; struct orf_prefix { uint32_t seq; @@ -63,12 +64,18 @@ extern struct prefix_list *prefix_list_lookup(afi_t, const char *); * * If no pointer is sent in, do not return anything. * If it is a empty plist return a NULL pointer. + * + * address_mode = the "prefix" being passed in is really an address, match + * regardless of prefix length (i.e. ge/le are ignored.) prefix->prefixlen + * must be /32. */ extern enum prefix_list_type -prefix_list_apply_which_prefix(struct prefix_list *plist, - const struct prefix **which, - const void *object); -#define prefix_list_apply(A, B) prefix_list_apply_which_prefix((A), NULL, (B)) +prefix_list_apply_ext(struct prefix_list *plist, + const struct prefix_list_entry **matches, + union prefixconstptr prefix, + bool address_mode); +#define prefix_list_apply(A, B) \ + prefix_list_apply_ext((A), NULL, (B), false) extern struct prefix_list *prefix_bgp_orf_lookup(afi_t, const char *); extern struct stream *prefix_bgp_orf_entry(struct stream *, diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index b6521132f7..56e1927528 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -203,6 +203,26 @@ static struct rp_info *pim_rp_find_exact(struct pim_instance *pim, return NULL; } +/* + * XXX: long-term issue: we don't actually have a good "ip address-list" + * implementation. ("access-list XYZ" is the closest but honestly it's + * kinda garbage.) + * + * So it's using a prefix-list to match an address here, which causes very + * unexpected results for the user since prefix-lists by default only match + * when the prefix length is an exact match too. i.e. you'd have to add the + * "le 32" and do "ip prefix-list foo permit 10.0.0.0/24 le 32" + * + * To avoid this pitfall, this code uses "address_mode = true" for the prefix + * list match (this is the only user for that.) + * + * In the long run, we need to add a "ip address-list", but that's a wholly + * separate bag of worms, and existing configs using ip prefix-list would + * drop into the UX pitfall. + */ + +#include "lib/plist_int.h" + /* * Given a group, return the rp_info for that group */ @@ -213,7 +233,8 @@ struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, struct rp_info *best = NULL; struct rp_info *rp_info; struct prefix_list *plist; - const struct prefix *p, *bp; + const struct prefix *bp; + const struct prefix_list_entry *entry; struct route_node *rn; bp = NULL; @@ -221,19 +242,19 @@ struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, if (rp_info->plist) { plist = prefix_list_lookup(AFI_IP, rp_info->plist); - if (prefix_list_apply_which_prefix(plist, &p, group) - == PREFIX_DENY) + if (prefix_list_apply_ext(plist, &entry, group, true) + == PREFIX_DENY || !entry) continue; if (!best) { best = rp_info; - bp = p; + bp = &entry->prefix; continue; } - if (bp && bp->prefixlen < p->prefixlen) { + if (bp && bp->prefixlen < entry->prefix.prefixlen) { best = rp_info; - bp = p; + bp = &entry->prefix; } } } From 19cf3fc5abaeb633bacbda82d5fd6ad6d06d4849 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 20 Apr 2021 06:13:51 +0200 Subject: [PATCH 3/9] lib: add command to test prefix-list match While we do have `show ip prefix-list NAME A.B.C.D/M`, that doesn't actually run the prefix list matching code. While the result would hopefully be the same anyway, let's have a way to call the actual prefix list match code and get a result. (As an aside, this might be useful for scripting to do a quick "is this prefix in that prefix list" check.) Signed-off-by: David Lamparter --- doc/user/filter.rst | 9 +++++++++ lib/plist.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/doc/user/filter.rst b/doc/user/filter.rst index 1fb9beccdc..cbbcd47dc3 100644 --- a/doc/user/filter.rst +++ b/doc/user/filter.rst @@ -137,6 +137,15 @@ Showing ip prefix-list .. clicmd:: show ip prefix-list detail .. clicmd:: show ip prefix-list detail NAME +.. clicmd:: debug prefix-list NAME match [address-mode] + + Execute the prefix list matching code for the specified list and prefix. + Shows which entry matched, if any. (``address-mode`` is used for + PIM RP lookups and skips prefix length checks.) + + The return value from this command is success only if the prefix-list + result is to permit the prefix, so the command can be used in scripting. + Clear counter of ip prefix-list ------------------------------- diff --git a/lib/plist.c b/lib/plist.c index 1ee855a594..2b42c43764 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -1300,6 +1300,51 @@ DEFPY (clear_ipv6_prefix_list, return vty_clear_prefix_list(vty, AFI_IP6, prefix_list, prefix_str); } +DEFPY (debug_prefix_list_match, + debug_prefix_list_match_cmd, + "debug prefix-list WORD$prefix-list match " + " [address-mode$addr_mode]", + DEBUG_STR + "Prefix-list test access\n" + "Name of a prefix list\n" + "Test prefix for prefix list result\n" + "Prefix to test in ip prefix-list\n" + "Prefix to test in ipv6 prefix-list\n" + "Use address matching mode (PIM RP)\n") +{ + struct prefix_list *plist; + const struct prefix_list_entry *entry = NULL; + enum prefix_list_type ret; + + plist = prefix_list_lookup(family2afi(match->family), prefix_list); + if (!plist) { + vty_out(vty, "%% no prefix list named %s for AFI %s\n", + prefix_list, afi2str(family2afi(match->family))); + return CMD_WARNING; + } + + ret = prefix_list_apply_ext(plist, &entry, match, !!addr_mode); + + vty_out(vty, "%s prefix list %s yields %s for %pFX, ", + afi2str(family2afi(match->family)), prefix_list, + ret == PREFIX_DENY ? "DENY" : "PERMIT", match); + + if (!entry) + vty_out(vty, "no match found\n"); + else { + vty_out(vty, "matching entry #%"PRId64": %pFX", entry->seq, + &entry->prefix); + if (entry->ge) + vty_out(vty, " ge %d", entry->ge); + if (entry->le) + vty_out(vty, " le %d", entry->le); + vty_out(vty, "\n"); + } + + /* allow using this in scripts for quick prefix-list member tests */ + return (ret == PREFIX_PERMIT) ? CMD_SUCCESS : CMD_WARNING; +} + struct stream *prefix_bgp_orf_entry(struct stream *s, struct prefix_list *plist, uint8_t init_flag, uint8_t permit_flag, uint8_t deny_flag) @@ -1541,6 +1586,7 @@ static void prefix_list_init_ipv6(void) install_element(VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd); install_element(VIEW_NODE, &show_ipv6_prefix_list_summary_cmd); install_element(VIEW_NODE, &show_ipv6_prefix_list_detail_cmd); + install_element(VIEW_NODE, &debug_prefix_list_match_cmd); install_element(ENABLE_NODE, &clear_ipv6_prefix_list_cmd); } From f8f4aec3b0c976c6b933770cfac36b21ca7f06bb Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 20 Apr 2021 05:36:30 +0200 Subject: [PATCH 4/9] tests/lib/cli: allow using YANG modules Since the common CLI code calls nb_init, allow specifying some modules to load by overriding test_yang_models. Signed-off-by: David Lamparter --- tests/lib/cli/common_cli.c | 9 ++++++++- tests/lib/cli/common_cli.h | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c index 49bc0f4fb2..8be81cc4cb 100644 --- a/tests/lib/cli/common_cli.c +++ b/tests/lib/cli/common_cli.c @@ -59,10 +59,13 @@ static void vty_do_exit(int isexit) exit(0); } +const struct frr_yang_module_info *const *test_yang_modules = NULL; + /* main routine. */ int main(int argc, char **argv) { struct thread thread; + size_t yangcount; /* Set umask before anything for security */ umask(0027); @@ -79,7 +82,11 @@ int main(int argc, char **argv) vty_init(master, false); lib_cmd_init(); - nb_init(master, NULL, 0, false); + + for (yangcount = 0; test_yang_modules && test_yang_modules[yangcount]; + yangcount++) + ; + nb_init(master, test_yang_modules, yangcount, false); test_init(argc, argv); diff --git a/tests/lib/cli/common_cli.h b/tests/lib/cli/common_cli.h index 15abe3b855..3042ff5b12 100644 --- a/tests/lib/cli/common_cli.h +++ b/tests/lib/cli/common_cli.h @@ -25,6 +25,9 @@ #include "zebra.h" #include "vty.h" #include "command.h" +#include "northbound.h" + +extern const struct frr_yang_module_info *const *test_yang_modules; /* function to be implemented by test */ extern void test_init(int argc, char **argv); From fa8e714a6f45f1b1c74cb141310c21a1931c53de Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 20 Apr 2021 05:37:33 +0200 Subject: [PATCH 5/9] tests/lib: add a simple prefix list query tool Signed-off-by: David Lamparter --- tests/.gitignore | 1 + tests/lib/test_plist.c | 48 ++++++++++++++++++++++++++++++++++++++++++ tests/subdir.am | 5 +++++ 3 files changed, 54 insertions(+) create mode 100644 tests/lib/test_plist.c diff --git a/tests/.gitignore b/tests/.gitignore index 3fad1b0813..498d7dd0b7 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -36,6 +36,7 @@ /lib/test_nexthop /lib/test_nexthop_iter /lib/test_ntop +/lib/test_plist /lib/test_prefix2str /lib/test_printfrr /lib/test_privs diff --git a/tests/lib/test_plist.c b/tests/lib/test_plist.c new file mode 100644 index 0000000000..ee7a9ebf30 --- /dev/null +++ b/tests/lib/test_plist.c @@ -0,0 +1,48 @@ +/* + * Simple prefix list querying tool + * + * Copyright (C) 2021 by David Lamparter, + * for Open Source Routing / NetDEF, Inc. + * + * Quagga is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * Quagga is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "lib/plist.h" +#include "lib/filter.h" +#include "tests/lib/cli/common_cli.h" + +static const struct frr_yang_module_info *const my_yang_modules[] = { + &frr_filter_info, + NULL, +}; + +__attribute__((_CONSTRUCTOR(2000))) +static void test_yang_modules_set(void) +{ + test_yang_modules = my_yang_modules; +} + +void test_init(int argc, char **argv) +{ + prefix_list_init(); + filter_cli_init(); + + /* nothing else to do here, giving stand-alone access to the prefix + * list code's "debug prefix-list ..." command is the only purpose of + * this "test". + */ +} diff --git a/tests/subdir.am b/tests/subdir.am index c2153140f5..86c1aa4284 100644 --- a/tests/subdir.am +++ b/tests/subdir.am @@ -87,6 +87,7 @@ check_PROGRAMS = \ tests/lib/test_nexthop_iter \ tests/lib/test_nexthop \ tests/lib/test_ntop \ + tests/lib/test_plist \ tests/lib/test_prefix2str \ tests/lib/test_printfrr \ tests/lib/test_privs \ @@ -344,6 +345,10 @@ tests_lib_test_ntop_CFLAGS = $(TESTS_CFLAGS) tests_lib_test_ntop_CPPFLAGS = $(CPPFLAGS_BASE) # no assert override tests_lib_test_ntop_LDADD = # none tests_lib_test_ntop_SOURCES = tests/lib/test_ntop.c tests/helpers/c/prng.c +tests_lib_test_plist_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_plist_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_plist_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_plist_SOURCES = tests/lib/test_plist.c tests/lib/cli/common_cli.c tests_lib_test_prefix2str_CFLAGS = $(TESTS_CFLAGS) tests_lib_test_prefix2str_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_test_prefix2str_LDADD = $(ALL_TESTS_LDADD) From 80c5c45b0bc12d4fc5ca4b9d83a45db4798e7fac Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Mon, 3 May 2021 22:50:45 +0200 Subject: [PATCH 6/9] tests: fix hang during topology shutdown when CLI connection fails Signed-off-by: Martin Winter --- tests/topotests/lib/topotest.py | 37 ++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index d1f60bfe0d..4c0c6ab54a 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -1223,25 +1223,28 @@ class Router(Node): dmns = rundaemons.split("\n") # Exclude empty string at end of list for d in dmns[:-1]: - daemonpid = self.cmd("cat %s" % d.rstrip()).rstrip() - if daemonpid.isdigit() and pid_exists(int(daemonpid)): - daemonname = os.path.basename(d.rstrip().rsplit(".", 1)[0]) - logger.info("{}: stopping {}".format(self.name, daemonname)) - try: - os.kill(int(daemonpid), signal.SIGTERM) - except OSError as err: - if err.errno == errno.ESRCH: - logger.error( - "{}: {} left a dead pidfile (pid={})".format( - self.name, daemonname, daemonpid + # Only check if daemonfilepath starts with / + # Avoids hang on "-> Connection closed" in above self.cmd() + if d[0] == '/': + daemonpid = self.cmd("cat %s" % d.rstrip()).rstrip() + if daemonpid.isdigit() and pid_exists(int(daemonpid)): + daemonname = os.path.basename(d.rstrip().rsplit(".", 1)[0]) + logger.info("{}: stopping {}".format(self.name, daemonname)) + try: + os.kill(int(daemonpid), signal.SIGTERM) + except OSError as err: + if err.errno == errno.ESRCH: + logger.error( + "{}: {} left a dead pidfile (pid={})".format( + self.name, daemonname, daemonpid + ) ) - ) - else: - logger.info( - "{}: {} could not kill pid {}: {}".format( - self.name, daemonname, daemonpid, str(err) + else: + logger.info( + "{}: {} could not kill pid {}: {}".format( + self.name, daemonname, daemonpid, str(err) + ) ) - ) if not wait: return errors From fe3c85de1a3e167ecd5308efa448d127e78a9f7e Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Tue, 4 May 2021 04:04:37 +0200 Subject: [PATCH 7/9] tests: Add PIM ACL-based RP selection test Signed-off-by: Martin Winter --- tests/topotests/pim_acl/h1/zebra.conf | 10 + tests/topotests/pim_acl/h2/zebra.conf | 8 + .../topotests/pim_acl/r1/acl_1_pim_join.json | 21 + .../topotests/pim_acl/r1/acl_2_pim_join.json | 21 + .../topotests/pim_acl/r1/acl_3_pim_join.json | 21 + .../topotests/pim_acl/r1/acl_4_pim_join.json | 21 + .../topotests/pim_acl/r1/acl_5_pim_join.json | 21 + .../topotests/pim_acl/r1/acl_6_pim_join.json | 21 + tests/topotests/pim_acl/r1/ospf_neighbor.json | 59 +++ tests/topotests/pim_acl/r1/ospfd.conf | 16 + tests/topotests/pim_acl/r1/pim_neighbor.json | 31 ++ tests/topotests/pim_acl/r1/pimd.conf | 30 ++ tests/topotests/pim_acl/r1/zebra.conf | 18 + .../topotests/pim_acl/r11/acl_1_pim_join.json | 19 + tests/topotests/pim_acl/r11/ospfd.conf | 14 + tests/topotests/pim_acl/r11/pimd.conf | 16 + tests/topotests/pim_acl/r11/zebra.conf | 13 + .../topotests/pim_acl/r12/acl_2_pim_join.json | 19 + tests/topotests/pim_acl/r12/ospfd.conf | 14 + tests/topotests/pim_acl/r12/pimd.conf | 16 + tests/topotests/pim_acl/r12/zebra.conf | 13 + .../topotests/pim_acl/r13/acl_3_pim_join.json | 19 + tests/topotests/pim_acl/r13/ospfd.conf | 14 + tests/topotests/pim_acl/r13/pimd.conf | 16 + tests/topotests/pim_acl/r13/zebra.conf | 13 + .../topotests/pim_acl/r14/acl_4_pim_join.json | 19 + .../topotests/pim_acl/r14/acl_5_pim_join.json | 19 + tests/topotests/pim_acl/r14/ospfd.conf | 14 + tests/topotests/pim_acl/r14/pimd.conf | 17 + tests/topotests/pim_acl/r14/zebra.conf | 13 + .../topotests/pim_acl/r15/acl_6_pim_join.json | 19 + tests/topotests/pim_acl/r15/ospfd.conf | 14 + tests/topotests/pim_acl/r15/pimd.conf | 16 + tests/topotests/pim_acl/r15/zebra.conf | 13 + tests/topotests/pim_acl/test_pim_acl.py | 418 ++++++++++++++++++ 35 files changed, 1046 insertions(+) create mode 100644 tests/topotests/pim_acl/h1/zebra.conf create mode 100644 tests/topotests/pim_acl/h2/zebra.conf create mode 100644 tests/topotests/pim_acl/r1/acl_1_pim_join.json create mode 100644 tests/topotests/pim_acl/r1/acl_2_pim_join.json create mode 100644 tests/topotests/pim_acl/r1/acl_3_pim_join.json create mode 100644 tests/topotests/pim_acl/r1/acl_4_pim_join.json create mode 100644 tests/topotests/pim_acl/r1/acl_5_pim_join.json create mode 100644 tests/topotests/pim_acl/r1/acl_6_pim_join.json create mode 100644 tests/topotests/pim_acl/r1/ospf_neighbor.json create mode 100644 tests/topotests/pim_acl/r1/ospfd.conf create mode 100644 tests/topotests/pim_acl/r1/pim_neighbor.json create mode 100644 tests/topotests/pim_acl/r1/pimd.conf create mode 100644 tests/topotests/pim_acl/r1/zebra.conf create mode 100644 tests/topotests/pim_acl/r11/acl_1_pim_join.json create mode 100644 tests/topotests/pim_acl/r11/ospfd.conf create mode 100644 tests/topotests/pim_acl/r11/pimd.conf create mode 100644 tests/topotests/pim_acl/r11/zebra.conf create mode 100644 tests/topotests/pim_acl/r12/acl_2_pim_join.json create mode 100644 tests/topotests/pim_acl/r12/ospfd.conf create mode 100644 tests/topotests/pim_acl/r12/pimd.conf create mode 100644 tests/topotests/pim_acl/r12/zebra.conf create mode 100644 tests/topotests/pim_acl/r13/acl_3_pim_join.json create mode 100644 tests/topotests/pim_acl/r13/ospfd.conf create mode 100644 tests/topotests/pim_acl/r13/pimd.conf create mode 100644 tests/topotests/pim_acl/r13/zebra.conf create mode 100644 tests/topotests/pim_acl/r14/acl_4_pim_join.json create mode 100644 tests/topotests/pim_acl/r14/acl_5_pim_join.json create mode 100644 tests/topotests/pim_acl/r14/ospfd.conf create mode 100644 tests/topotests/pim_acl/r14/pimd.conf create mode 100644 tests/topotests/pim_acl/r14/zebra.conf create mode 100644 tests/topotests/pim_acl/r15/acl_6_pim_join.json create mode 100644 tests/topotests/pim_acl/r15/ospfd.conf create mode 100644 tests/topotests/pim_acl/r15/pimd.conf create mode 100644 tests/topotests/pim_acl/r15/zebra.conf create mode 100755 tests/topotests/pim_acl/test_pim_acl.py diff --git a/tests/topotests/pim_acl/h1/zebra.conf b/tests/topotests/pim_acl/h1/zebra.conf new file mode 100644 index 0000000000..3d6540d40c --- /dev/null +++ b/tests/topotests/pim_acl/h1/zebra.conf @@ -0,0 +1,10 @@ +! +hostname h1 +log file zebra.log +! +interface h1-eth0 + description connection to r1 via sw1 + ip address 192.168.100.10/24 +! +ip route 0.0.0.0/0 192.168.100.1 +! diff --git a/tests/topotests/pim_acl/h2/zebra.conf b/tests/topotests/pim_acl/h2/zebra.conf new file mode 100644 index 0000000000..95342f9e8a --- /dev/null +++ b/tests/topotests/pim_acl/h2/zebra.conf @@ -0,0 +1,8 @@ +hostname h2 +! +interface h2-eth0 + description connection to r1 via sw2 + ip address 192.168.101.2/24 +! +ip route 0.0.0.0/0 192.168.101.1 +! diff --git a/tests/topotests/pim_acl/r1/acl_1_pim_join.json b/tests/topotests/pim_acl/r1/acl_1_pim_join.json new file mode 100644 index 0000000000..1b44b2b5cf --- /dev/null +++ b/tests/topotests/pim_acl/r1/acl_1_pim_join.json @@ -0,0 +1,21 @@ +{ + "r1-eth0":{ + "name":"r1-eth0", + "state":"up", + "address":"192.168.100.1", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.1":{ + "*":{ + "source":"*", + "group":"239.100.0.1", + "upTime":"--:--:--", + "expire":"--:--", + "prune":"--:--", + "channelJoinName":"NOINFO", + "protocolIgmp":1 + } + } + } +} diff --git a/tests/topotests/pim_acl/r1/acl_2_pim_join.json b/tests/topotests/pim_acl/r1/acl_2_pim_join.json new file mode 100644 index 0000000000..c020a489a9 --- /dev/null +++ b/tests/topotests/pim_acl/r1/acl_2_pim_join.json @@ -0,0 +1,21 @@ +{ + "r1-eth0":{ + "name":"r1-eth0", + "state":"up", + "address":"192.168.100.1", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.17":{ + "*":{ + "source":"*", + "group":"239.100.0.17", + "upTime":"--:--:--", + "expire":"--:--", + "prune":"--:--", + "channelJoinName":"NOINFO", + "protocolIgmp":1 + } + } + } +} diff --git a/tests/topotests/pim_acl/r1/acl_3_pim_join.json b/tests/topotests/pim_acl/r1/acl_3_pim_join.json new file mode 100644 index 0000000000..6122f73992 --- /dev/null +++ b/tests/topotests/pim_acl/r1/acl_3_pim_join.json @@ -0,0 +1,21 @@ +{ + "r1-eth0":{ + "name":"r1-eth0", + "state":"up", + "address":"192.168.100.1", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.32":{ + "*":{ + "source":"*", + "group":"239.100.0.32", + "upTime":"--:--:--", + "expire":"--:--", + "prune":"--:--", + "channelJoinName":"NOINFO", + "protocolIgmp":1 + } + } + } +} diff --git a/tests/topotests/pim_acl/r1/acl_4_pim_join.json b/tests/topotests/pim_acl/r1/acl_4_pim_join.json new file mode 100644 index 0000000000..5f72256ba7 --- /dev/null +++ b/tests/topotests/pim_acl/r1/acl_4_pim_join.json @@ -0,0 +1,21 @@ +{ + "r1-eth0":{ + "name":"r1-eth0", + "state":"up", + "address":"192.168.100.1", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.255":{ + "*":{ + "source":"*", + "group":"239.100.0.255", + "upTime":"--:--:--", + "expire":"--:--", + "prune":"--:--", + "channelJoinName":"NOINFO", + "protocolIgmp":1 + } + } + } +} diff --git a/tests/topotests/pim_acl/r1/acl_5_pim_join.json b/tests/topotests/pim_acl/r1/acl_5_pim_join.json new file mode 100644 index 0000000000..70021bdbec --- /dev/null +++ b/tests/topotests/pim_acl/r1/acl_5_pim_join.json @@ -0,0 +1,21 @@ +{ + "r1-eth0":{ + "name":"r1-eth0", + "state":"up", + "address":"192.168.100.1", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.97":{ + "*":{ + "source":"*", + "group":"239.100.0.97", + "upTime":"--:--:--", + "expire":"--:--", + "prune":"--:--", + "channelJoinName":"NOINFO", + "protocolIgmp":1 + } + } + } +} diff --git a/tests/topotests/pim_acl/r1/acl_6_pim_join.json b/tests/topotests/pim_acl/r1/acl_6_pim_join.json new file mode 100644 index 0000000000..2baac6cb22 --- /dev/null +++ b/tests/topotests/pim_acl/r1/acl_6_pim_join.json @@ -0,0 +1,21 @@ +{ + "r1-eth0":{ + "name":"r1-eth0", + "state":"up", + "address":"192.168.100.1", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.70":{ + "*":{ + "source":"*", + "group":"239.100.0.70", + "upTime":"--:--:--", + "expire":"--:--", + "prune":"--:--", + "channelJoinName":"NOINFO", + "protocolIgmp":1 + } + } + } +} diff --git a/tests/topotests/pim_acl/r1/ospf_neighbor.json b/tests/topotests/pim_acl/r1/ospf_neighbor.json new file mode 100644 index 0000000000..a8fc093e90 --- /dev/null +++ b/tests/topotests/pim_acl/r1/ospf_neighbor.json @@ -0,0 +1,59 @@ +{ + "neighbors":{ + "192.168.0.11":[ + { + "priority":10, + "state":"Full\/Backup", + "address":"192.168.101.11", + "ifaceName":"r1-eth1:192.168.101.1", + "retransmitCounter":0, + "requestCounter":0, + "dbSummaryCounter":0 + } + ], + "192.168.0.12":[ + { + "priority":0, + "state":"Full\/DROther", + "address":"192.168.101.12", + "ifaceName":"r1-eth1:192.168.101.1", + "retransmitCounter":0, + "requestCounter":0, + "dbSummaryCounter":0 + } + ], + "192.168.0.13":[ + { + "priority":0, + "state":"Full\/DROther", + "address":"192.168.101.13", + "ifaceName":"r1-eth1:192.168.101.1", + "retransmitCounter":0, + "requestCounter":0, + "dbSummaryCounter":0 + } + ], + "192.168.0.14":[ + { + "priority":0, + "state":"Full\/DROther", + "address":"192.168.101.14", + "ifaceName":"r1-eth1:192.168.101.1", + "retransmitCounter":0, + "requestCounter":0, + "dbSummaryCounter":0 + } + ], + "192.168.0.15":[ + { + "priority":0, + "state":"Full\/DROther", + "address":"192.168.101.15", + "ifaceName":"r1-eth1:192.168.101.1", + "retransmitCounter":0, + "requestCounter":0, + "dbSummaryCounter":0 + } + ] + } +} diff --git a/tests/topotests/pim_acl/r1/ospfd.conf b/tests/topotests/pim_acl/r1/ospfd.conf new file mode 100644 index 0000000000..e1f47fb3b1 --- /dev/null +++ b/tests/topotests/pim_acl/r1/ospfd.conf @@ -0,0 +1,16 @@ +hostname r1 +! +debug ospf event +! +interface r1-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf priority 20 +! +router ospf + ospf router-id 192.168.0.1 + passive-interface r1-eth0 + network 192.168.0.1/32 area 0 + network 192.168.100.0/24 area 0 + network 192.168.101.0/24 area 0 + diff --git a/tests/topotests/pim_acl/r1/pim_neighbor.json b/tests/topotests/pim_acl/r1/pim_neighbor.json new file mode 100644 index 0000000000..ae95e8db14 --- /dev/null +++ b/tests/topotests/pim_acl/r1/pim_neighbor.json @@ -0,0 +1,31 @@ +{ + "r1-eth0":{ + }, + "r1-eth1":{ + "192.168.101.12":{ + "interface":"r1-eth1", + "neighbor":"192.168.101.12", + "drPriority":1 + }, + "192.168.101.15":{ + "interface":"r1-eth1", + "neighbor":"192.168.101.15", + "drPriority":1 + }, + "192.168.101.14":{ + "interface":"r1-eth1", + "neighbor":"192.168.101.14", + "drPriority":1 + }, + "192.168.101.11":{ + "interface":"r1-eth1", + "neighbor":"192.168.101.11", + "drPriority":1 + }, + "192.168.101.13":{ + "interface":"r1-eth1", + "neighbor":"192.168.101.13", + "drPriority":1 + } + } +} diff --git a/tests/topotests/pim_acl/r1/pimd.conf b/tests/topotests/pim_acl/r1/pimd.conf new file mode 100644 index 0000000000..72d28c9b02 --- /dev/null +++ b/tests/topotests/pim_acl/r1/pimd.conf @@ -0,0 +1,30 @@ +hostname r1 +! +debug igmp events +debug igmp packets +debug pim events +debug pim packets +debug pim trace +debug pim zebra +debug pim bsm +! +ip pim rp 192.168.0.11 prefix-list rp-pl-1 +ip pim rp 192.168.0.12 prefix-list rp-pl-2 +ip pim rp 192.168.0.13 prefix-list rp-pl-3 +ip pim rp 192.168.0.14 prefix-list rp-pl-4 +ip pim rp 192.168.0.15 prefix-list rp-pl-5 +! +interface r1-eth0 + ip igmp + ip igmp version 2 + ip pim +! +interface r1-eth1 + ip pim +! +ip prefix-list rp-pl-1 seq 10 permit 239.100.0.0/28 +ip prefix-list rp-pl-2 seq 10 permit 239.100.0.17/32 +ip prefix-list rp-pl-3 seq 10 permit 239.100.0.32/27 +ip prefix-list rp-pl-4 seq 10 permit 239.100.0.128/25 +ip prefix-list rp-pl-4 seq 20 permit 239.100.0.96/28 +ip prefix-list rp-pl-5 seq 10 permit 239.100.0.64/28 diff --git a/tests/topotests/pim_acl/r1/zebra.conf b/tests/topotests/pim_acl/r1/zebra.conf new file mode 100644 index 0000000000..74feb8f6a7 --- /dev/null +++ b/tests/topotests/pim_acl/r1/zebra.conf @@ -0,0 +1,18 @@ +! +hostname r1 +log file zebra.log +! +ip forwarding +ipv6 forwarding +! +interface lo + ip address 192.168.0.1/32 +! +interface r1-eth0 + description connection to h1 via sw1 + ip address 192.168.100.1/24 +! +interface r1-eth1 + description connection to r11/12/13/14/15 via sw2 + ip address 192.168.101.1/24 +! diff --git a/tests/topotests/pim_acl/r11/acl_1_pim_join.json b/tests/topotests/pim_acl/r11/acl_1_pim_join.json new file mode 100644 index 0000000000..289bf51e76 --- /dev/null +++ b/tests/topotests/pim_acl/r11/acl_1_pim_join.json @@ -0,0 +1,19 @@ +{ + "r11-eth0":{ + "name":"r11-eth0", + "state":"up", + "address":"192.168.101.11", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.1":{ + "*":{ + "source":"*", + "group":"239.100.0.1", + "prune":"--:--", + "channelJoinName":"JOIN", + "protocolPim":1 + } + } + } +} diff --git a/tests/topotests/pim_acl/r11/ospfd.conf b/tests/topotests/pim_acl/r11/ospfd.conf new file mode 100644 index 0000000000..e107220a4e --- /dev/null +++ b/tests/topotests/pim_acl/r11/ospfd.conf @@ -0,0 +1,14 @@ +hostname r11 +! +debug ospf event +! +interface r11-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf priority 10 +! +router ospf + ospf router-id 192.168.0.11 + network 192.168.0.11/32 area 0 + network 192.168.101.0/24 area 0 +! diff --git a/tests/topotests/pim_acl/r11/pimd.conf b/tests/topotests/pim_acl/r11/pimd.conf new file mode 100644 index 0000000000..05cd5ac911 --- /dev/null +++ b/tests/topotests/pim_acl/r11/pimd.conf @@ -0,0 +1,16 @@ +hostname r11 +! +debug pim events +debug pim packets +debug pim trace +debug pim zebra +debug pim bsm +! +ip pim rp 192.168.0.11 239.100.0.0/28 +! +interface lo + ip pim +! +interface r11-eth0 + ip pim +! diff --git a/tests/topotests/pim_acl/r11/zebra.conf b/tests/topotests/pim_acl/r11/zebra.conf new file mode 100644 index 0000000000..137706d245 --- /dev/null +++ b/tests/topotests/pim_acl/r11/zebra.conf @@ -0,0 +1,13 @@ +! +hostname r11 +log file zebra.log +! +interface lo + ip address 192.168.0.11/32 +! +interface r11-eth0 + description connection to r1 via sw1 + ip address 192.168.101.11/24 +! +ip route 0.0.0.0/0 192.168.101.1 +! diff --git a/tests/topotests/pim_acl/r12/acl_2_pim_join.json b/tests/topotests/pim_acl/r12/acl_2_pim_join.json new file mode 100644 index 0000000000..76ab7ee701 --- /dev/null +++ b/tests/topotests/pim_acl/r12/acl_2_pim_join.json @@ -0,0 +1,19 @@ +{ + "r12-eth0":{ + "name":"r12-eth0", + "state":"up", + "address":"192.168.101.12", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.17":{ + "*":{ + "source":"*", + "group":"239.100.0.17", + "prune":"--:--", + "channelJoinName":"JOIN", + "protocolPim":1 + } + } + } +} diff --git a/tests/topotests/pim_acl/r12/ospfd.conf b/tests/topotests/pim_acl/r12/ospfd.conf new file mode 100644 index 0000000000..f9203c78e4 --- /dev/null +++ b/tests/topotests/pim_acl/r12/ospfd.conf @@ -0,0 +1,14 @@ +hostname r12 +! +debug ospf event +! +interface r12-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf priority 0 +! +router ospf + ospf router-id 192.168.0.12 + network 192.168.0.12/32 area 0 + network 192.168.101.0/24 area 0 +! diff --git a/tests/topotests/pim_acl/r12/pimd.conf b/tests/topotests/pim_acl/r12/pimd.conf new file mode 100644 index 0000000000..cedde73c59 --- /dev/null +++ b/tests/topotests/pim_acl/r12/pimd.conf @@ -0,0 +1,16 @@ +hostname r12 +! +debug pim events +debug pim packets +debug pim trace +debug pim zebra +debug pim bsm +! +ip pim rp 192.168.0.12 239.100.0.17/32 +! +interface lo + ip pim +! +interface r12-eth0 + ip pim +! diff --git a/tests/topotests/pim_acl/r12/zebra.conf b/tests/topotests/pim_acl/r12/zebra.conf new file mode 100644 index 0000000000..bede104906 --- /dev/null +++ b/tests/topotests/pim_acl/r12/zebra.conf @@ -0,0 +1,13 @@ +! +hostname r12 +log file zebra.log +! +interface lo + ip address 192.168.0.12/32 +! +interface r12-eth0 + description connection to r1 via sw1 + ip address 192.168.101.12/24 +! +ip route 0.0.0.0/0 192.168.101.1 +! diff --git a/tests/topotests/pim_acl/r13/acl_3_pim_join.json b/tests/topotests/pim_acl/r13/acl_3_pim_join.json new file mode 100644 index 0000000000..48ad72cbe1 --- /dev/null +++ b/tests/topotests/pim_acl/r13/acl_3_pim_join.json @@ -0,0 +1,19 @@ +{ + "r13-eth0":{ + "name":"r13-eth0", + "state":"up", + "address":"192.168.101.13", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.32":{ + "*":{ + "source":"*", + "group":"239.100.0.32", + "prune":"--:--", + "channelJoinName":"JOIN", + "protocolPim":1 + } + } + } +} diff --git a/tests/topotests/pim_acl/r13/ospfd.conf b/tests/topotests/pim_acl/r13/ospfd.conf new file mode 100644 index 0000000000..830c5a14b6 --- /dev/null +++ b/tests/topotests/pim_acl/r13/ospfd.conf @@ -0,0 +1,14 @@ +hostname r13 +! +debug ospf event +! +interface r13-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf priority 0 +! +router ospf + ospf router-id 192.168.0.13 + network 192.168.0.13/32 area 0 + network 192.168.101.0/24 area 0 +! diff --git a/tests/topotests/pim_acl/r13/pimd.conf b/tests/topotests/pim_acl/r13/pimd.conf new file mode 100644 index 0000000000..2dab0cabec --- /dev/null +++ b/tests/topotests/pim_acl/r13/pimd.conf @@ -0,0 +1,16 @@ +hostname r13 +! +debug pim events +debug pim packets +debug pim trace +debug pim zebra +debug pim bsm +! +ip pim rp 192.168.0.13 239.100.0.32/27 +! +interface lo + ip pim +! +interface r13-eth0 + ip pim +! diff --git a/tests/topotests/pim_acl/r13/zebra.conf b/tests/topotests/pim_acl/r13/zebra.conf new file mode 100644 index 0000000000..f9ff27abac --- /dev/null +++ b/tests/topotests/pim_acl/r13/zebra.conf @@ -0,0 +1,13 @@ +! +hostname r13 +log file zebra.log +! +interface lo + ip address 192.168.0.13/32 +! +interface r13-eth0 + description connection to r1 via sw1 + ip address 192.168.101.13/24 +! +ip route 0.0.0.0/0 192.168.101.1 +! diff --git a/tests/topotests/pim_acl/r14/acl_4_pim_join.json b/tests/topotests/pim_acl/r14/acl_4_pim_join.json new file mode 100644 index 0000000000..46d86dd40d --- /dev/null +++ b/tests/topotests/pim_acl/r14/acl_4_pim_join.json @@ -0,0 +1,19 @@ +{ + "r14-eth0":{ + "name":"r14-eth0", + "state":"up", + "address":"192.168.101.14", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.255":{ + "*":{ + "source":"*", + "group":"239.100.0.255", + "prune":"--:--", + "channelJoinName":"JOIN", + "protocolPim":1 + } + } + } +} diff --git a/tests/topotests/pim_acl/r14/acl_5_pim_join.json b/tests/topotests/pim_acl/r14/acl_5_pim_join.json new file mode 100644 index 0000000000..2b291a8a0c --- /dev/null +++ b/tests/topotests/pim_acl/r14/acl_5_pim_join.json @@ -0,0 +1,19 @@ +{ + "r14-eth0":{ + "name":"r14-eth0", + "state":"up", + "address":"192.168.101.14", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.97":{ + "*":{ + "source":"*", + "group":"239.100.0.97", + "prune":"--:--", + "channelJoinName":"JOIN", + "protocolPim":1 + } + } + } +} diff --git a/tests/topotests/pim_acl/r14/ospfd.conf b/tests/topotests/pim_acl/r14/ospfd.conf new file mode 100644 index 0000000000..422e4c08b0 --- /dev/null +++ b/tests/topotests/pim_acl/r14/ospfd.conf @@ -0,0 +1,14 @@ +hostname r14 +! +debug ospf event +! +interface r14-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf priority 0 +! +router ospf + ospf router-id 192.168.0.14 + network 192.168.0.14/32 area 0 + network 192.168.101.0/24 area 0 +! diff --git a/tests/topotests/pim_acl/r14/pimd.conf b/tests/topotests/pim_acl/r14/pimd.conf new file mode 100644 index 0000000000..c6b949af16 --- /dev/null +++ b/tests/topotests/pim_acl/r14/pimd.conf @@ -0,0 +1,17 @@ +hostname r14 +! +debug pim events +debug pim packets +debug pim trace +debug pim zebra +debug pim bsm +! +ip pim rp 192.168.0.14 239.100.0.96/28 +ip pim rp 192.168.0.14 239.100.0.128/25 +! +interface lo + ip pim +! +interface r14-eth0 + ip pim +! diff --git a/tests/topotests/pim_acl/r14/zebra.conf b/tests/topotests/pim_acl/r14/zebra.conf new file mode 100644 index 0000000000..8761b46206 --- /dev/null +++ b/tests/topotests/pim_acl/r14/zebra.conf @@ -0,0 +1,13 @@ +! +hostname r14 +log file zebra.log +! +interface lo + ip address 192.168.0.14/32 +! +interface r14-eth0 + description connection to r1 via sw1 + ip address 192.168.101.14/24 +! +ip route 0.0.0.0/0 192.168.101.1 +! diff --git a/tests/topotests/pim_acl/r15/acl_6_pim_join.json b/tests/topotests/pim_acl/r15/acl_6_pim_join.json new file mode 100644 index 0000000000..05fed4ecc5 --- /dev/null +++ b/tests/topotests/pim_acl/r15/acl_6_pim_join.json @@ -0,0 +1,19 @@ +{ + "r15-eth0":{ + "name":"r15-eth0", + "state":"up", + "address":"192.168.101.15", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.70":{ + "*":{ + "source":"*", + "group":"239.100.0.70", + "prune":"--:--", + "channelJoinName":"JOIN", + "protocolPim":1 + } + } + } +} diff --git a/tests/topotests/pim_acl/r15/ospfd.conf b/tests/topotests/pim_acl/r15/ospfd.conf new file mode 100644 index 0000000000..cd4d7b3875 --- /dev/null +++ b/tests/topotests/pim_acl/r15/ospfd.conf @@ -0,0 +1,14 @@ +hostname r15 +! +debug ospf event +! +interface r15-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf priority 0 +! +router ospf + ospf router-id 192.168.0.15 + network 192.168.0.15/32 area 0 + network 192.168.101.0/24 area 0 +! diff --git a/tests/topotests/pim_acl/r15/pimd.conf b/tests/topotests/pim_acl/r15/pimd.conf new file mode 100644 index 0000000000..85c9c51e1e --- /dev/null +++ b/tests/topotests/pim_acl/r15/pimd.conf @@ -0,0 +1,16 @@ +hostname r15 +! +debug pim events +debug pim packets +debug pim trace +debug pim zebra +debug pim bsm +! +ip pim rp 192.168.0.15 239.100.0.64/28 +! +interface lo + ip pim +! +interface r15-eth0 + ip pim +! diff --git a/tests/topotests/pim_acl/r15/zebra.conf b/tests/topotests/pim_acl/r15/zebra.conf new file mode 100644 index 0000000000..f6909dd020 --- /dev/null +++ b/tests/topotests/pim_acl/r15/zebra.conf @@ -0,0 +1,13 @@ +! +hostname r15 +log file zebra.log +! +interface lo + ip address 192.168.0.15/32 +! +interface r15-eth0 + description connection to r1 via sw1 + ip address 192.168.101.15/24 +! +ip route 0.0.0.0/0 192.168.101.1 +! diff --git a/tests/topotests/pim_acl/test_pim_acl.py b/tests/topotests/pim_acl/test_pim_acl.py new file mode 100755 index 0000000000..848f7fa8ed --- /dev/null +++ b/tests/topotests/pim_acl/test_pim_acl.py @@ -0,0 +1,418 @@ +#!/usr/bin/env python + +# +# test_pim_acl.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_pim_acl.py: Test PIM with RP selection using ACLs +""" + +# Test PIM RP selection with ACLs +# +# Testing RP selection with ACLs. R1 uses multiple ACLs +# to select desired RPs (R11 to R15) +# +# Test steps: +# - setup_module() +# Create topology. Hosts are only using zebra/staticd, +# no PIM, no OSPF (using IGMPv2 for multicast) +# - test_ospf_convergence() +# Wait for OSPF convergence in each VRF. OSPF is run on +# R1 and R11 - R15. +# - test_pim_convergence() +# Wait for PIM convergence on all routers. PIM is run on +# R1 and R11 - R15. +# - test_mcast_acl_1(): +# Test 1st ACL entry 239.100.0.0/28 with 239.100.0.1 which +# should use R11 as RP +# Stop multicast after verification +# - test_mcast_acl_2(): +# Test 2nd ACL entry 239.100.0.17/32 with 239.100.0.17 which +# should use R12 as RP +# Stop multicast after verification +# - test_mcast_acl_3(): +# Test 3rd ACL entry 239.100.0.32/27 with 239.100.0.32 which +# should use R13 as RP +# Stop multicast after verification +# - test_mcast_acl_4(): +# Test 4th ACL entry 239.100.0.128/25 with 239.100.0.255 which +# should use R14 as RP +# Stop multicast after verification +# - test_mcast_acl_5(): +# Test 5th ACL entry 239.100.0.96/28 with 239.100.0.97 which +# should use R14 as RP +# Stop multicast after verification +# - test_mcast_acl_6(): +# Test 6th ACL entry 239.100.0.64/28 with 239.100.0.70 which +# should use R15 as RP +# Stop multicast after verification +# - teardown_module() +# shutdown topology +# + + +TOPOLOGY = """ + +----------+ + | Host H2 | + | Source | + +----------+ + .2 | + +-----------+ | +----------+ + | | .1 | .11 | Host R11 | ++---------+ | R1 |---------+--------| PIM RP | +| Host H1 | 192.168.100.0/24 | | 192.168.101.0/24 +----------+ +| receive |------------------| uses ACLs | | +----------+ +|IGMP JOIN| .10 .1 | to pick | | .12 | Host R12 | ++---------+ | RP | +--------| PIM RP | + | | | +----------+ + +-----------+ | +----------+ + | .13 | Host R13 | + +--------| PIM RP | + | +----------+ + | +----------+ + | .14 | Host R14 | + +--------| PIM RP | + | +----------+ + | +----------+ + | .15 | Host R15 | + +--------| PIM RP | + +----------+ +""" + +import json +import functools +import os +import sys +import pytest +import re +import time +from time import sleep +import socket + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +pytestmark = [pytest.mark.pimd] + + +# +# Test global variables: +# They are used to handle communicating with external application. +# +APP_SOCK_PATH = '/tmp/topotests/apps.sock' +HELPER_APP_PATH = os.path.join(CWD, "../lib/mcast-tester.py") +app_listener = None +app_clients = {} + +def listen_to_applications(): + "Start listening socket to connect with applications." + # Remove old socket. + try: + os.unlink(APP_SOCK_PATH) + except OSError: + pass + + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0) + sock.bind(APP_SOCK_PATH) + sock.listen(10) + global app_listener + app_listener = sock + +def accept_host(host): + "Accept connection from application running in hosts." + global app_listener, app_clients + conn = app_listener.accept() + app_clients[host] = { + 'fd': conn[0], + 'address': conn[1] + } + +def close_applications(): + "Signal applications to stop and close all sockets." + global app_listener, app_clients + + if app_listener: + # Close listening socket. + app_listener.close() + + # Remove old socket. + try: + os.unlink(APP_SOCK_PATH) + except OSError: + pass + + # Close all host connections. + for host in ["h1", "h2"]: + if app_clients.get(host) is None: + continue + app_clients[host]["fd"].close() + + # Reset listener and clients data struct + app_listener = None + app_clients = {} + + +class PIMACLTopo(Topo): + "PIM ACL Test Topology" + + def build(self): + tgen = get_topogen(self) + + # Create the hosts + for hostNum in range(1,3): + tgen.add_router("h{}".format(hostNum)) + + # Create the main router + tgen.add_router("r1") + + # Create the PIM RP routers + for rtrNum in range(11, 16): + tgen.add_router("r{}".format(rtrNum)) + + # Setup Switches and connections + for swNum in range(1, 3): + tgen.add_switch("sw{}".format(swNum)) + + # Add connections H1 to R1 switch sw1 + tgen.gears["h1"].add_link(tgen.gears["sw1"]) + tgen.gears["r1"].add_link(tgen.gears["sw1"]) + + # Add connections R1 to R1x switch sw2 + tgen.gears["r1"].add_link(tgen.gears["sw2"]) + tgen.gears["h2"].add_link(tgen.gears["sw2"]) + tgen.gears["r11"].add_link(tgen.gears["sw2"]) + tgen.gears["r12"].add_link(tgen.gears["sw2"]) + tgen.gears["r13"].add_link(tgen.gears["sw2"]) + tgen.gears["r14"].add_link(tgen.gears["sw2"]) + tgen.gears["r15"].add_link(tgen.gears["sw2"]) + + +##################################################### +# +# Tests starting +# +##################################################### + +def setup_module(module): + logger.info("PIM RP ACL Topology: \n {}".format(TOPOLOGY)) + + tgen = Topogen(PIMACLTopo, module.__name__) + tgen.start_topology() + + # Starting Routers + router_list = tgen.routers() + + for rname, router in router_list.items(): + logger.info("Loading router %s" % rname) + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + if rname[0] != 'h': + # Only load ospf on routers, not on end hosts + router.load_config( + TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_PIM, os.path.join(CWD, "{}/pimd.conf".format(rname)) + ) + tgen.start_router() + + +def teardown_module(module): + tgen = get_topogen() + tgen.stop_topology() + close_applications() + + +def test_ospf_convergence(): + "Test for OSPFv2 convergence" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Checking OSPFv2 convergence on router r1") + + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/ospf_neighbor.json") + expected = json.loads(open(reffile).read()) + + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip ospf neighbor json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "OSPF router R1 did not converge" + assert res is None, assertmsg + + +def test_pim_convergence(): + "Test for PIM convergence" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Checking PIM convergence on router r1") + + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/pim_neighbor.json") + expected = json.loads(open(reffile).read()) + + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip pim neighbor json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "PIM router R1 did not converge" + assert res is None, assertmsg + + + +def check_mcast_entry(entry, mcastaddr, pimrp): + "Helper function to check RP" + tgen = get_topogen() + + logger.info("Testing PIM RP selection for ACL {} entry using {}".format(entry, mcastaddr)); + + # Start applications socket. + listen_to_applications() + + tgen.gears["h2"].run("{} --send='0.7' '{}' '{}' '{}' &".format( + HELPER_APP_PATH, APP_SOCK_PATH, mcastaddr, 'h2-eth0')) + accept_host("h2") + + tgen.gears["h1"].run("{} '{}' '{}' '{}' &".format( + HELPER_APP_PATH, APP_SOCK_PATH, mcastaddr, 'h1-eth0')) + accept_host("h1") + + logger.info("mcast join and source for {} started".format(mcastaddr)) + + # tgen.mininet_cli() + + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/acl_{}_pim_join.json".format(entry)) + expected = json.loads(open(reffile).read()) + + logger.info("verifying pim join on r1 for {}".format(mcastaddr)) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip pim join json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "PIM router r1 did not show join status" + assert res is None, assertmsg + + logger.info("verifying pim join on PIM RP {} for {}".format(pimrp, mcastaddr)) + router = tgen.gears[pimrp] + reffile = os.path.join(CWD, "{}/acl_{}_pim_join.json".format(pimrp, entry)) + expected = json.loads(open(reffile).read()) + + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip pim join json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "PIM router {} did not get selected as the PIM RP".format(pimrp) + assert res is None, assertmsg + + close_applications() + return + + +def test_mcast_acl_1(): + "Test 1st ACL entry 239.100.0.0/28 with 239.100.0.1" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_mcast_entry(1, '239.100.0.1', 'r11') + + +def test_mcast_acl_2(): + "Test 2nd ACL entry 239.100.0.17/32 with 239.100.0.17" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_mcast_entry(2, '239.100.0.17', 'r12') + + +def test_mcast_acl_3(): + "Test 3rd ACL entry 239.100.0.32/27 with 239.100.0.32" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_mcast_entry(3, '239.100.0.32', 'r13') + + +def test_mcast_acl_4(): + "Test 4th ACL entry 239.100.0.128/25 with 239.100.0.255" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_mcast_entry(4, '239.100.0.255', 'r14') + + +def test_mcast_acl_5(): + "Test 5th ACL entry 239.100.0.96/28 with 239.100.0.97" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_mcast_entry(5, '239.100.0.97', 'r14') + + +def test_mcast_acl_6(): + "Test 6th ACL entry 239.100.0.64/28 with 239.100.0.70" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_mcast_entry(6, '239.100.0.70', 'r15') + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From 511184897b1ba45703f1a8b6503c6b4abc513482 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Tue, 4 May 2021 04:07:45 +0200 Subject: [PATCH 8/9] tests: Add IGMP/PIM VRF test Signed-off-by: Martin Winter --- tests/topotests/pim_igmp_vrf/h1/zebra.conf | 10 + tests/topotests/pim_igmp_vrf/h2/zebra.conf | 8 + tests/topotests/pim_igmp_vrf/h3/zebra.conf | 10 + tests/topotests/pim_igmp_vrf/h4/zebra.conf | 8 + .../pim_igmp_vrf/r1/ospf_blue_neighbor.json | 15 + .../pim_igmp_vrf/r1/ospf_red_neighbor.json | 16 + tests/topotests/pim_igmp_vrf/r1/ospfd.conf | 26 + .../pim_igmp_vrf/r1/pim_blue_join.json | 22 + .../pim_igmp_vrf/r1/pim_blue_neighbor.json | 13 + .../pim_igmp_vrf/r1/pim_blue_pimreg11.json | 14 + .../pim_igmp_vrf/r1/pim_red_join.json | 21 + .../pim_igmp_vrf/r1/pim_red_neighbor.json | 13 + .../pim_igmp_vrf/r1/pim_red_pimreg12.json | 14 + tests/topotests/pim_igmp_vrf/r1/pimd.conf | 26 + tests/topotests/pim_igmp_vrf/r1/zebra.conf | 30 ++ tests/topotests/pim_igmp_vrf/r11/ospfd.conf | 14 + .../pim_igmp_vrf/r11/pim_blue_join.json | 19 + tests/topotests/pim_igmp_vrf/r11/pimd.conf | 16 + tests/topotests/pim_igmp_vrf/r11/zebra.conf | 13 + tests/topotests/pim_igmp_vrf/r12/ospfd.conf | 14 + .../pim_igmp_vrf/r12/pim_red_join.json | 19 + tests/topotests/pim_igmp_vrf/r12/pimd.conf | 16 + tests/topotests/pim_igmp_vrf/r12/zebra.conf | 13 + tests/topotests/pim_igmp_vrf/test_pim_vrf.py | 462 ++++++++++++++++++ 24 files changed, 832 insertions(+) create mode 100644 tests/topotests/pim_igmp_vrf/h1/zebra.conf create mode 100644 tests/topotests/pim_igmp_vrf/h2/zebra.conf create mode 100644 tests/topotests/pim_igmp_vrf/h3/zebra.conf create mode 100644 tests/topotests/pim_igmp_vrf/h4/zebra.conf create mode 100644 tests/topotests/pim_igmp_vrf/r1/ospf_blue_neighbor.json create mode 100644 tests/topotests/pim_igmp_vrf/r1/ospf_red_neighbor.json create mode 100644 tests/topotests/pim_igmp_vrf/r1/ospfd.conf create mode 100644 tests/topotests/pim_igmp_vrf/r1/pim_blue_join.json create mode 100644 tests/topotests/pim_igmp_vrf/r1/pim_blue_neighbor.json create mode 100644 tests/topotests/pim_igmp_vrf/r1/pim_blue_pimreg11.json create mode 100644 tests/topotests/pim_igmp_vrf/r1/pim_red_join.json create mode 100644 tests/topotests/pim_igmp_vrf/r1/pim_red_neighbor.json create mode 100644 tests/topotests/pim_igmp_vrf/r1/pim_red_pimreg12.json create mode 100644 tests/topotests/pim_igmp_vrf/r1/pimd.conf create mode 100644 tests/topotests/pim_igmp_vrf/r1/zebra.conf create mode 100644 tests/topotests/pim_igmp_vrf/r11/ospfd.conf create mode 100644 tests/topotests/pim_igmp_vrf/r11/pim_blue_join.json create mode 100644 tests/topotests/pim_igmp_vrf/r11/pimd.conf create mode 100644 tests/topotests/pim_igmp_vrf/r11/zebra.conf create mode 100644 tests/topotests/pim_igmp_vrf/r12/ospfd.conf create mode 100644 tests/topotests/pim_igmp_vrf/r12/pim_red_join.json create mode 100644 tests/topotests/pim_igmp_vrf/r12/pimd.conf create mode 100644 tests/topotests/pim_igmp_vrf/r12/zebra.conf create mode 100755 tests/topotests/pim_igmp_vrf/test_pim_vrf.py diff --git a/tests/topotests/pim_igmp_vrf/h1/zebra.conf b/tests/topotests/pim_igmp_vrf/h1/zebra.conf new file mode 100644 index 0000000000..3d6540d40c --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/h1/zebra.conf @@ -0,0 +1,10 @@ +! +hostname h1 +log file zebra.log +! +interface h1-eth0 + description connection to r1 via sw1 + ip address 192.168.100.10/24 +! +ip route 0.0.0.0/0 192.168.100.1 +! diff --git a/tests/topotests/pim_igmp_vrf/h2/zebra.conf b/tests/topotests/pim_igmp_vrf/h2/zebra.conf new file mode 100644 index 0000000000..95342f9e8a --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/h2/zebra.conf @@ -0,0 +1,8 @@ +hostname h2 +! +interface h2-eth0 + description connection to r1 via sw2 + ip address 192.168.101.2/24 +! +ip route 0.0.0.0/0 192.168.101.1 +! diff --git a/tests/topotests/pim_igmp_vrf/h3/zebra.conf b/tests/topotests/pim_igmp_vrf/h3/zebra.conf new file mode 100644 index 0000000000..ef99b1cd8f --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/h3/zebra.conf @@ -0,0 +1,10 @@ +! +hostname h3 +log file zebra.log +! +interface h3-eth0 + description connection to r1 via sw3 + ip address 192.168.100.20/24 +! +ip route 0.0.0.0/0 192.168.100.1 +! diff --git a/tests/topotests/pim_igmp_vrf/h4/zebra.conf b/tests/topotests/pim_igmp_vrf/h4/zebra.conf new file mode 100644 index 0000000000..6a2e466000 --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/h4/zebra.conf @@ -0,0 +1,8 @@ +hostname h4 +! +interface h4-eth0 + description connection to r1 via sw4 + ip address 192.168.101.4/24 +! +ip route 0.0.0.0/0 192.168.101.1 +! diff --git a/tests/topotests/pim_igmp_vrf/r1/ospf_blue_neighbor.json b/tests/topotests/pim_igmp_vrf/r1/ospf_blue_neighbor.json new file mode 100644 index 0000000000..604d25fac1 --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r1/ospf_blue_neighbor.json @@ -0,0 +1,15 @@ +{ + "blue":{ + "vrfName":"blue", + "neighbors":{ + "192.168.0.11":[ + { + "priority":10, + "state":"Full\/Backup", + "address":"192.168.101.11", + "ifaceName":"r1-eth1:192.168.101.1" + } + ] + } + } +} diff --git a/tests/topotests/pim_igmp_vrf/r1/ospf_red_neighbor.json b/tests/topotests/pim_igmp_vrf/r1/ospf_red_neighbor.json new file mode 100644 index 0000000000..456bb87520 --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r1/ospf_red_neighbor.json @@ -0,0 +1,16 @@ +{ + "red":{ + "vrfName":"red", + "neighbors":{ + "192.168.0.12":[ + { + "priority":10, + "state":"Full\/Backup", + "address":"192.168.101.12", + "ifaceName":"r1-eth3:192.168.101.1" + } + ] + } + } +} + diff --git a/tests/topotests/pim_igmp_vrf/r1/ospfd.conf b/tests/topotests/pim_igmp_vrf/r1/ospfd.conf new file mode 100644 index 0000000000..263b5867cc --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r1/ospfd.conf @@ -0,0 +1,26 @@ +hostname r1 +! +debug ospf event +! +! +interface r1-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf priority 20 +! +interface r1-eth3 + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf priority 20 +! +router ospf vrf blue + ospf router-id 192.168.0.1 + network 192.168.0.1/32 area 0 + network 192.168.100.0/24 area 0 + network 192.168.101.0/24 area 0 +router ospf vrf red + ospf router-id 192.168.0.1 + network 192.168.0.1/32 area 0 + network 192.168.100.0/24 area 0 + network 192.168.101.0/24 area 0 +! diff --git a/tests/topotests/pim_igmp_vrf/r1/pim_blue_join.json b/tests/topotests/pim_igmp_vrf/r1/pim_blue_join.json new file mode 100644 index 0000000000..8568bae2bc --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r1/pim_blue_join.json @@ -0,0 +1,22 @@ +{ + "r1-eth0":{ + "name":"r1-eth0", + "state":"up", + "address":"192.168.100.1", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.1":{ + "*":{ + "source":"*", + "group":"239.100.0.1", + "upTime":"--:--:--", + "expire":"--:--", + "prune":"--:--", + "channelJoinName":"NOINFO", + "protocolIgmp":1 + } + } + } +} + diff --git a/tests/topotests/pim_igmp_vrf/r1/pim_blue_neighbor.json b/tests/topotests/pim_igmp_vrf/r1/pim_blue_neighbor.json new file mode 100644 index 0000000000..ea7d4aca6f --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r1/pim_blue_neighbor.json @@ -0,0 +1,13 @@ +{ + "blue":{ + }, + "r1-eth0":{ + }, + "r1-eth1":{ + "192.168.101.11":{ + "interface":"r1-eth1", + "neighbor":"192.168.101.11", + "drPriority":1 + } + } +} diff --git a/tests/topotests/pim_igmp_vrf/r1/pim_blue_pimreg11.json b/tests/topotests/pim_igmp_vrf/r1/pim_blue_pimreg11.json new file mode 100644 index 0000000000..d3642f854a --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r1/pim_blue_pimreg11.json @@ -0,0 +1,14 @@ +{ + "pimreg11":{ + "name":"pimreg11", + "state":"up", + "address":"0.0.0.0", + "flagAllMulticast":true, + "lanDelayEnabled":true, + "drAddress":"*", + "drPriority":1, + "drUptime":"--:--:--", + "drElections":0, + "drChanges":0 + } +} diff --git a/tests/topotests/pim_igmp_vrf/r1/pim_red_join.json b/tests/topotests/pim_igmp_vrf/r1/pim_red_join.json new file mode 100644 index 0000000000..d0037ca4b0 --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r1/pim_red_join.json @@ -0,0 +1,21 @@ +{ + "r1-eth2":{ + "name":"r1-eth2", + "state":"up", + "address":"192.168.100.1", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.1":{ + "*":{ + "source":"*", + "group":"239.100.0.1", + "upTime":"--:--:--", + "expire":"--:--", + "prune":"--:--", + "channelJoinName":"NOINFO", + "protocolIgmp":1 + } + } + } +} diff --git a/tests/topotests/pim_igmp_vrf/r1/pim_red_neighbor.json b/tests/topotests/pim_igmp_vrf/r1/pim_red_neighbor.json new file mode 100644 index 0000000000..e17b40854a --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r1/pim_red_neighbor.json @@ -0,0 +1,13 @@ +{ + "r1-eth2":{ + }, + "r1-eth3":{ + "192.168.101.12":{ + "interface":"r1-eth3", + "neighbor":"192.168.101.12", + "drPriority":1 + } + }, + "red":{ + } +} diff --git a/tests/topotests/pim_igmp_vrf/r1/pim_red_pimreg12.json b/tests/topotests/pim_igmp_vrf/r1/pim_red_pimreg12.json new file mode 100644 index 0000000000..45b6cd9645 --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r1/pim_red_pimreg12.json @@ -0,0 +1,14 @@ +{ + "pimreg12":{ + "name":"pimreg12", + "state":"up", + "address":"0.0.0.0", + "flagAllMulticast":true, + "lanDelayEnabled":true, + "drAddress":"*", + "drPriority":1, + "drUptime":"--:--:--", + "drElections":0, + "drChanges":0 + } +} diff --git a/tests/topotests/pim_igmp_vrf/r1/pimd.conf b/tests/topotests/pim_igmp_vrf/r1/pimd.conf new file mode 100644 index 0000000000..6ee264d3d0 --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r1/pimd.conf @@ -0,0 +1,26 @@ +hostname r1 +! +debug igmp events +debug igmp packets +debug pim events +debug pim packets +debug pim trace +debug pim zebra +debug pim bsm +! +interface r1-eth0 + ip igmp + ip igmp version 2 + ip pim +! +interface r1-eth1 + ip pim +! +interface r1-eth2 + ip igmp + ip igmp version 2 + ip pim +! +interface r1-eth3 + ip pim +! diff --git a/tests/topotests/pim_igmp_vrf/r1/zebra.conf b/tests/topotests/pim_igmp_vrf/r1/zebra.conf new file mode 100644 index 0000000000..9da9280945 --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r1/zebra.conf @@ -0,0 +1,30 @@ +! +hostname r1 +log file zebra.log +! +ip forwarding +ipv6 forwarding +! +interface blue vrf blue + ip address 192.168.0.1/32 +! +interface red vrf red + ip address 192.168.0.1/32 +! +interface r1-eth0 vrf blue + description connection to h1 via sw1 + ip address 192.168.100.1/24 +! +interface r1-eth1 vrf blue + description connection to r11 via sw2 + ip address 192.168.101.1/24 +! +interface r1-eth2 vrf red + description connection to h1 via sw3 + ip address 192.168.100.1/24 +! +interface r1-eth3 vrf red + description connection to r12 via sw4 + ip address 192.168.101.1/24 +! + diff --git a/tests/topotests/pim_igmp_vrf/r11/ospfd.conf b/tests/topotests/pim_igmp_vrf/r11/ospfd.conf new file mode 100644 index 0000000000..e107220a4e --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r11/ospfd.conf @@ -0,0 +1,14 @@ +hostname r11 +! +debug ospf event +! +interface r11-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf priority 10 +! +router ospf + ospf router-id 192.168.0.11 + network 192.168.0.11/32 area 0 + network 192.168.101.0/24 area 0 +! diff --git a/tests/topotests/pim_igmp_vrf/r11/pim_blue_join.json b/tests/topotests/pim_igmp_vrf/r11/pim_blue_join.json new file mode 100644 index 0000000000..289bf51e76 --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r11/pim_blue_join.json @@ -0,0 +1,19 @@ +{ + "r11-eth0":{ + "name":"r11-eth0", + "state":"up", + "address":"192.168.101.11", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.1":{ + "*":{ + "source":"*", + "group":"239.100.0.1", + "prune":"--:--", + "channelJoinName":"JOIN", + "protocolPim":1 + } + } + } +} diff --git a/tests/topotests/pim_igmp_vrf/r11/pimd.conf b/tests/topotests/pim_igmp_vrf/r11/pimd.conf new file mode 100644 index 0000000000..05cd5ac911 --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r11/pimd.conf @@ -0,0 +1,16 @@ +hostname r11 +! +debug pim events +debug pim packets +debug pim trace +debug pim zebra +debug pim bsm +! +ip pim rp 192.168.0.11 239.100.0.0/28 +! +interface lo + ip pim +! +interface r11-eth0 + ip pim +! diff --git a/tests/topotests/pim_igmp_vrf/r11/zebra.conf b/tests/topotests/pim_igmp_vrf/r11/zebra.conf new file mode 100644 index 0000000000..137706d245 --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r11/zebra.conf @@ -0,0 +1,13 @@ +! +hostname r11 +log file zebra.log +! +interface lo + ip address 192.168.0.11/32 +! +interface r11-eth0 + description connection to r1 via sw1 + ip address 192.168.101.11/24 +! +ip route 0.0.0.0/0 192.168.101.1 +! diff --git a/tests/topotests/pim_igmp_vrf/r12/ospfd.conf b/tests/topotests/pim_igmp_vrf/r12/ospfd.conf new file mode 100644 index 0000000000..03acc82c1d --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r12/ospfd.conf @@ -0,0 +1,14 @@ +hostname r12 +! +debug ospf event +! +interface r12-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf priority 10 +! +router ospf + ospf router-id 192.168.0.12 + network 192.168.0.12/32 area 0 + network 192.168.101.0/24 area 0 +! diff --git a/tests/topotests/pim_igmp_vrf/r12/pim_red_join.json b/tests/topotests/pim_igmp_vrf/r12/pim_red_join.json new file mode 100644 index 0000000000..6926246568 --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r12/pim_red_join.json @@ -0,0 +1,19 @@ +{ + "r12-eth0":{ + "name":"r12-eth0", + "state":"up", + "address":"192.168.101.12", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.100.0.1":{ + "*":{ + "source":"*", + "group":"239.100.0.1", + "prune":"--:--", + "channelJoinName":"JOIN", + "protocolPim":1 + } + } + } +} diff --git a/tests/topotests/pim_igmp_vrf/r12/pimd.conf b/tests/topotests/pim_igmp_vrf/r12/pimd.conf new file mode 100644 index 0000000000..531aec61ed --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r12/pimd.conf @@ -0,0 +1,16 @@ +hostname r12 +! +debug pim events +debug pim packets +debug pim trace +debug pim zebra +debug pim bsm +! +ip pim rp 192.168.0.12 239.100.0.0/28 +! +interface lo + ip pim +! +interface r12-eth0 + ip pim +! diff --git a/tests/topotests/pim_igmp_vrf/r12/zebra.conf b/tests/topotests/pim_igmp_vrf/r12/zebra.conf new file mode 100644 index 0000000000..bede104906 --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r12/zebra.conf @@ -0,0 +1,13 @@ +! +hostname r12 +log file zebra.log +! +interface lo + ip address 192.168.0.12/32 +! +interface r12-eth0 + description connection to r1 via sw1 + ip address 192.168.101.12/24 +! +ip route 0.0.0.0/0 192.168.101.1 +! diff --git a/tests/topotests/pim_igmp_vrf/test_pim_vrf.py b/tests/topotests/pim_igmp_vrf/test_pim_vrf.py new file mode 100755 index 0000000000..298adef9c6 --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/test_pim_vrf.py @@ -0,0 +1,462 @@ +#!/usr/bin/env python + +# +# test_pim_vrf.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_pim_vrf.py: Test PIM with VRFs. +""" + +# Tests PIM with VRF +# +# R1 is split into 2 VRF: Blue and Red, the others are normal +# routers and Hosts +# There are 2 similar topologies with overlapping IPs in each +# section. +# +# Test steps: +# - setup_module() +# Create topology. Hosts are only using zebra/staticd, +# no PIM, no OSPF (using IGMPv2 for multicast) +# - test_ospf_convergence() +# Wait for OSPF convergence in each VRF. OSPF is run on +# R1, R11 and R12. +# - test_pim_convergence() +# Wait for PIM convergence in each VRF. PIM is run on +# R1, R11 and R12. R11 is the RP for vrf blue, R12 is RP +# for vrf red. +# - test_vrf_pimreg_interfaces() +# Adding PIM RP in VRF information and verify pimreg +# interfaces in VRF blue and red +# - test_mcast_vrf_blue() +# Start multicast stream for group 239.100.0.1 from Host +# H2 and join from Host H1 on vrf blue +# Verify PIM JOIN status on R1 and R11 +# Stop multicast after verification +# - test_mcast_vrf_red() +# Start multicast stream for group 239.100.0.1 from Host +# H4 and join from Host H3 on vrf blue +# Verify PIM JOIN status on R1 and R12 +# Stop multicast after verification +# - teardown_module(module) +# shutdown topology +# + +TOPOLOGY = """ + +----------+ + | Host H2 | + | Source | + +----------+ + .2 | ++---------+ +------------+ | +---------+ +| Host H1 | 192.168.100.0/24 | | .1 | .11 | Host H2 | +| receive |------------------| VRF Blue |---------+--------| PIM RP | +|IGMP JOIN| .10 .1 | | 192.168.101.0/24 | | ++---------+ | | +---------+ + =| = = R1 = = |= ++---------+ | | +---------+ +| Host H3 | 192.168.100.0/24 | | 192.168.101.0/24 | Host H4 | +| receive |------------------| VRF Red |---------+--------| PIM RP | +|IGMP JOIN| .20 .1 | | .1 | .12 | | ++---------+ +------------+ | +---------+ + .4 | + +----------+ + | Host H4 | + | Source | + +----------+ +""" + +import json +import functools +import os +import sys +import pytest +import re +import time +from time import sleep +import socket + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from lib.topotest import iproute2_is_vrf_capable +from lib.common_config import ( + required_linux_kernel_version) + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +pytestmark = [pytest.mark.pimd] + + +# +# Test global variables: +# They are used to handle communicating with external application. +# +APP_SOCK_PATH = '/tmp/topotests/apps.sock' +HELPER_APP_PATH = os.path.join(CWD, "../lib/mcast-tester.py") +app_listener = None +app_clients = {} + +def listen_to_applications(): + "Start listening socket to connect with applications." + # Remove old socket. + try: + os.unlink(APP_SOCK_PATH) + except OSError: + pass + + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0) + sock.bind(APP_SOCK_PATH) + sock.listen(10) + global app_listener + app_listener = sock + +def accept_host(host): + "Accept connection from application running in hosts." + global app_listener, app_clients + conn = app_listener.accept() + app_clients[host] = { + 'fd': conn[0], + 'address': conn[1] + } + +def close_applications(): + "Signal applications to stop and close all sockets." + global app_listener, app_clients + + if app_listener: + # Close listening socket. + app_listener.close() + + # Remove old socket. + try: + os.unlink(APP_SOCK_PATH) + except OSError: + pass + + # Close all host connections. + for host in ["h1", "h2"]: + if app_clients.get(host) is None: + continue + app_clients[host]["fd"].close() + + # Reset listener and clients data struct + app_listener = None + app_clients = {} + + +class PIMVRFTopo(Topo): + "PIM VRF Test Topology" + + def build(self): + tgen = get_topogen(self) + + # Create the hosts + for hostNum in range(1,5): + tgen.add_router("h{}".format(hostNum)) + + # Create the main router + tgen.add_router("r1") + + # Create the PIM RP routers + for rtrNum in range(11, 13): + tgen.add_router("r{}".format(rtrNum)) + + # Setup Switches and connections + for swNum in range(1, 5): + tgen.add_switch("sw{}".format(swNum)) + + ################ + # 1st set of connections to routers for VRF red + ################ + + # Add connections H1 to R1 switch sw1 + tgen.gears["h1"].add_link(tgen.gears["sw1"]) + tgen.gears["r1"].add_link(tgen.gears["sw1"]) + + # Add connections R1 to R1x switch sw2 + tgen.gears["r1"].add_link(tgen.gears["sw2"]) + tgen.gears["h2"].add_link(tgen.gears["sw2"]) + tgen.gears["r11"].add_link(tgen.gears["sw2"]) + + ################ + # 2nd set of connections to routers for vrf blue + ################ + + # Add connections H1 to R1 switch sw1 + tgen.gears["h3"].add_link(tgen.gears["sw3"]) + tgen.gears["r1"].add_link(tgen.gears["sw3"]) + + # Add connections R1 to R1x switch sw2 + tgen.gears["r1"].add_link(tgen.gears["sw4"]) + tgen.gears["h4"].add_link(tgen.gears["sw4"]) + tgen.gears["r12"].add_link(tgen.gears["sw4"]) + +##################################################### +# +# Tests starting +# +##################################################### + +def setup_module(module): + logger.info("PIM IGMP VRF Topology: \n {}".format(TOPOLOGY)) + + tgen = Topogen(PIMVRFTopo, module.__name__) + tgen.start_topology() + + vrf_setup_cmds = [ + "ip link add name blue type vrf table 11", + "ip link add name red type vrf table 12", + "ip link set dev blue up", + "ip link set dev red up", + "ip link set dev r1-eth0 vrf blue up", + "ip link set dev r1-eth1 vrf blue up", + "ip link set dev r1-eth2 vrf red up", + "ip link set dev r1-eth3 vrf red up", + ] + + # Starting Routers + router_list = tgen.routers() + + # Create VRF on r2 first and add it's interfaces + for cmd in vrf_setup_cmds: + tgen.net["r1"].cmd(cmd) + + for rname, router in router_list.items(): + logger.info("Loading router %s" % rname) + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + if rname[0] != 'h': + # Only load ospf on routers, not on end hosts + router.load_config( + TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_PIM, os.path.join(CWD, "{}/pimd.conf".format(rname)) + ) + tgen.start_router() + + +def teardown_module(module): + tgen = get_topogen() + tgen.stop_topology() + close_applications() + + +def test_ospf_convergence(): + "Test for OSPFv2 convergence" + tgen = get_topogen() + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.15") + if result is not True: + pytest.skip("Kernel requirements are not met") + + # iproute2 needs to support VRFs for this suite to run. + if not iproute2_is_vrf_capable(): + pytest.skip("Installed iproute2 version does not support VRFs") + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Checking OSPFv2 convergence on router r1 for VRF blue") + + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/ospf_blue_neighbor.json") + expected = json.loads(open(reffile).read()) + + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip ospf vrf blue neighbor json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "OSPF router R1 did not converge on VRF blue" + assert res is None, assertmsg + + logger.info("Checking OSPFv2 convergence on router r1 for VRF red") + + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/ospf_red_neighbor.json") + expected = json.loads(open(reffile).read()) + + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip ospf vrf red neighbor json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = "OSPF router R1 did not converge on VRF red" + assert res is None, assertmsg + + +def test_pim_convergence(): + "Test for PIM convergence" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Checking PIM convergence on router r1 for VRF red") + + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/pim_red_neighbor.json") + expected = json.loads(open(reffile).read()) + + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip pim vrf red neighbor json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=30, wait=2) + assertmsg = "PIM router R1 did not converge for VRF red" + assert res is None, assertmsg + + logger.info("Checking PIM convergence on router r1 for VRF blue") + + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/pim_blue_neighbor.json") + expected = json.loads(open(reffile).read()) + + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip pim vrf blue neighbor json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=30, wait=2) + assertmsg = "PIM router R1 did not converge for VRF blue" + assert res is None, assertmsg + + +def test_vrf_pimreg_interfaces(): + "Adding PIM RP in VRF information and verify pimreg interfaces" + tgen = get_topogen() + + r1 = tgen.gears["r1"] + r1.vtysh_cmd("conf\ninterface blue\nip pim") + r1.vtysh_cmd("conf\nvrf blue\nip pim rp 192.168.0.11 239.100.0.1/32\nexit-vrf") + + # Check pimreg11 interface on R1, VRF blue + reffile = os.path.join(CWD, "r1/pim_blue_pimreg11.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, r1, "show ip pim vrf blue inter pimreg11 json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=5, wait=2) + assertmsg = "PIM router R1, VRF blue (table 11) pimreg11 interface missing or incorrect status" + assert res is None, assertmsg + + r1.vtysh_cmd("conf\ninterface red\nip pim") + r1.vtysh_cmd("conf\nvrf red\nip pim rp 192.168.0.12 239.100.0.1/32\nexit-vrf") + + # Check pimreg12 interface on R1, VRF red + reffile = os.path.join(CWD, "r1/pim_red_pimreg12.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, r1, "show ip pim vrf red inter pimreg12 json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=5, wait=2) + assertmsg = "PIM router R1, VRF red (table 12) pimreg12 interface missing or incorrect status" + assert res is None, assertmsg + + +################################## +### Test PIM / IGMP with VRF +################################## + +def check_mcast_entry(mcastaddr, pimrp, receiver, sender, vrf): + "Helper function to check RP" + tgen = get_topogen() + + logger.info("Testing PIM for VRF {} entry using {}".format(vrf, mcastaddr)); + + # Start applications socket. + listen_to_applications() + + tgen.gears[sender].run("{} --send='0.7' '{}' '{}' '{}' &".format( + HELPER_APP_PATH, APP_SOCK_PATH, mcastaddr, '{}-eth0'.format(sender))) + accept_host(sender) + + tgen.gears[receiver].run("{} '{}' '{}' '{}' &".format( + HELPER_APP_PATH, APP_SOCK_PATH, mcastaddr, '{}-eth0'.format(receiver))) + accept_host(receiver) + + logger.info("mcast join and source for {} started".format(mcastaddr)) + + # tgen.mininet_cli() + + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/pim_{}_join.json".format(vrf)) + expected = json.loads(open(reffile).read()) + + logger.info("verifying pim join on r1 for {} on VRF {}".format(mcastaddr, vrf)) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip pim vrf {} join json".format(vrf), + expected + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=2) + assertmsg = "PIM router r1 did not show join status on VRF".format(vrf) + assert res is None, assertmsg + + logger.info("verifying pim join on PIM RP {} for {}".format(pimrp, mcastaddr)) + router = tgen.gears[pimrp] + reffile = os.path.join(CWD, "{}/pim_{}_join.json".format(pimrp, vrf)) + expected = json.loads(open(reffile).read()) + + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip pim join json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=2) + assertmsg = "PIM router {} did not get selected as the PIM RP for VRF {}".format(pimrp, vrf) + assert res is None, assertmsg + + close_applications() + return + + +def test_mcast_vrf_blue(): + "Test vrf blue with 239.100.0.1" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_mcast_entry('239.100.0.1', 'r11', 'h1', 'h2', 'blue') + + +def test_mcast_vrf_red(): + "Test vrf red with 239.100.0.1" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_mcast_entry('239.100.0.1', 'r12', 'h3', 'h4', 'red') + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) From a2810d30256e8de250b9e0fdc274fc4852c7877c Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 18 May 2021 13:55:48 +0200 Subject: [PATCH 9/9] pimd: fix PtP address handling When we have a "192.0.2.1 peer 192.0.2.2/32" address on an interface, we need to (a) recognize the local address as being on the link for our own packets, and (b) do the IGMP socket lookup with the proper local address rather than the peer prefix. Fixes: efe6f18 ("pimd: fix IGMP receive handling") Cc: Nathan Bahr Signed-off-by: David Lamparter --- pimd/pim_iface.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 48b019c8c8..0b28a3e84c 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -1512,10 +1512,15 @@ struct prefix *pim_if_connected_to_source(struct interface *ifp, struct in_addr p.prefixlen = IPV4_MAX_BITLEN; for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { - if ((c->address->family == AF_INET) - && prefix_match(CONNECTED_PREFIX(c), &p)) { - return CONNECTED_PREFIX(c); - } + if (c->address->family != AF_INET) + continue; + if (prefix_match(c->address, &p)) + return c->address; + if (CONNECTED_PEER(c) && prefix_match(c->destination, &p)) + /* this is not a typo, on PtP we need to return the + * *local* address that lines up with src. + */ + return c->address; } return NULL;