From d2ee5625421cc292f6f320be4fb63076e91298c2 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 20 Feb 2020 08:42:00 -0500 Subject: [PATCH 1/5] pimd: the spt infinity prefix-list memory was not being freed On shutdown the string storing the prefix-list was not being properly freed. Signed-off-by: Donald Sharp --- pimd/pim_instance.c | 1 + 1 file changed, 1 insertion(+) diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 347b0fc284..1de873125a 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -69,6 +69,7 @@ static void pim_instance_terminate(struct pim_instance *pim) pim_msdp_exit(pim); + XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist); XFREE(MTYPE_PIM_PIM_INSTANCE, pim); } From 1c4e26bc06a3836ee2dff43d0691c53103ea40a4 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 20 Feb 2020 08:45:04 -0500 Subject: [PATCH 2/5] pimd: Rename the PIM_SPT_PLIST_NAME to PIM_PLIST_NAME The memory type PIM_SPT_PLIST_NAME is specific to SPT but we are going to store more prefix-list names in pim, make it generic to allow for less confusion in the future. Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 6 +++--- pimd/pim_instance.c | 2 +- pimd/pim_memory.c | 2 +- pimd/pim_memory.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index a3e5151a78..3633350a1d 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -6578,18 +6578,18 @@ static int pim_cmd_spt_switchover(struct pim_instance *pim, switch (pim->spt.switchover) { case PIM_SPT_IMMEDIATE: - XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist); + XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist); pim_upstream_add_lhr_star_pimreg(pim); break; case PIM_SPT_INFINITY: pim_upstream_remove_lhr_star_pimreg(pim, plist); - XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist); + XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist); if (plist) pim->spt.plist = - XSTRDUP(MTYPE_PIM_SPT_PLIST_NAME, plist); + XSTRDUP(MTYPE_PIM_PLIST_NAME, plist); break; } diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 1de873125a..795f79b351 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -69,7 +69,7 @@ static void pim_instance_terminate(struct pim_instance *pim) pim_msdp_exit(pim); - XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist); + XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist); XFREE(MTYPE_PIM_PIM_INSTANCE, pim); } diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c index 2bbab67e45..6bc8062c4b 100644 --- a/pimd/pim_memory.c +++ b/pimd/pim_memory.c @@ -51,5 +51,5 @@ DEFINE_MTYPE(PIMD, PIM_JP_AGG_SOURCE, "PIM JP AGG Source") DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE, "PIM global state") DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE, "PIM nexthop cache state") DEFINE_MTYPE(PIMD, PIM_SSM_INFO, "PIM SSM configuration") -DEFINE_MTYPE(PIMD, PIM_SPT_PLIST_NAME, "PIM SPT Prefix List Name") +DEFINE_MTYPE(PIMD, PIM_PLIST_NAME, "PIM Prefix List Names") DEFINE_MTYPE(PIMD, PIM_VXLAN_SG, "PIM VxLAN mroute cache") diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h index e5ca57a15d..6beeb60075 100644 --- a/pimd/pim_memory.h +++ b/pimd/pim_memory.h @@ -50,7 +50,7 @@ DECLARE_MTYPE(PIM_JP_AGG_SOURCE) DECLARE_MTYPE(PIM_PIM_INSTANCE) DECLARE_MTYPE(PIM_NEXTHOP_CACHE) DECLARE_MTYPE(PIM_SSM_INFO) -DECLARE_MTYPE(PIM_SPT_PLIST_NAME); +DECLARE_MTYPE(PIM_PLIST_NAME); DECLARE_MTYPE(PIM_VXLAN_SG) #endif /* _QUAGGA_PIM_MEMORY_H */ From 2ca35b64373e7efbe2541c77e0ebc07dfc1b25a5 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 20 Feb 2020 11:59:10 -0500 Subject: [PATCH 3/5] pimd: Add a pim pointer to register_recv We already use the pim pointer a bunch off of pim_ifp->pim just add another pim variable to allow us to shorten code a bit. Signed-off-by: Donald Sharp --- pimd/pim_register.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 19baecb9c2..3b58f6133c 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -324,14 +324,13 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, struct prefix_sg sg; uint32_t *bits; int i_am_rp = 0; - struct pim_interface *pim_ifp = NULL; - - pim_ifp = ifp->info; + struct pim_interface *pim_ifp = ifp->info; + struct pim_instance *pim = pim_ifp->pim; #define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4 ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN); - if (!pim_rp_check_is_my_ip_address(pim_ifp->pim, dest_addr)) { + if (!pim_rp_check_is_my_ip_address(pim, dest_addr)) { if (PIM_DEBUG_PIM_REG) { char dest[INET_ADDRSTRLEN]; @@ -375,7 +374,7 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, sg.src = ip_hdr->ip_src; sg.grp = ip_hdr->ip_dst; - i_am_rp = I_am_RP(pim_ifp->pim, sg.grp); + i_am_rp = I_am_RP(pim, sg.grp); if (PIM_DEBUG_PIM_REG) { char src_str[INET_ADDRSTRLEN]; @@ -387,7 +386,7 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, if (i_am_rp && (dest_addr.s_addr - == ((RP(pim_ifp->pim, sg.grp))->rpf_addr.u.prefix4.s_addr))) { + == ((RP(pim, sg.grp))->rpf_addr.u.prefix4.s_addr))) { sentRegisterStop = 0; if (*bits & PIM_REGISTER_BORDER_BIT) { @@ -411,14 +410,13 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, } } - struct pim_upstream *upstream = - pim_upstream_find(pim_ifp->pim, &sg); + struct pim_upstream *upstream = pim_upstream_find(pim, &sg); /* * If we don't have a place to send ignore the packet */ if (!upstream) { upstream = pim_upstream_add( - pim_ifp->pim, &sg, ifp, + pim, &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM, __func__, NULL); if (!upstream) { @@ -452,9 +450,8 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, } if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) - || ((SwitchToSptDesiredOnRp(pim_ifp->pim, &sg)) - && pim_upstream_inherited_olist(pim_ifp->pim, upstream) - == 0)) { + || ((SwitchToSptDesiredOnRp(pim, &sg)) + && pim_upstream_inherited_olist(pim, upstream) == 0)) { pim_register_stop_send(ifp, &sg, dest_addr, src_addr); sentRegisterStop = 1; } else { @@ -463,15 +460,13 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, upstream->sptbit); } if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) - || (SwitchToSptDesiredOnRp(pim_ifp->pim, &sg))) { + || (SwitchToSptDesiredOnRp(pim, &sg))) { if (sentRegisterStop) { pim_upstream_keep_alive_timer_start( - upstream, - pim_ifp->pim->rp_keep_alive_time); + upstream, pim->rp_keep_alive_time); } else { pim_upstream_keep_alive_timer_start( - upstream, - pim_ifp->pim->keep_alive_time); + upstream, pim->keep_alive_time); } } From f4e74bd0389c073d2940615b812bf397b9147dcc Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 20 Feb 2020 12:14:03 -0500 Subject: [PATCH 4/5] pimd: Add `ip pim register-accept-list PLIST` command When pim receives a register packet, we will apply the received source to the prefix list. If accepted normal processing continues. If denied we will send a register stop message to the source. Signed-off-by: Donald Sharp --- doc/user/pim.rst | 8 ++++++++ pimd/pim_cmd.c | 22 ++++++++++++++++++++++ pimd/pim_instance.c | 1 + pimd/pim_instance.h | 3 +++ pimd/pim_register.c | 27 +++++++++++++++++++++++++++ pimd/pim_vty.c | 5 +++++ 6 files changed, 66 insertions(+) diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 9876216736..5b566f4405 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -66,6 +66,14 @@ Certain signals have special meanings to *pimd*. prefix of group ranges covered. This command is vrf aware, to configure for a vrf, enter the vrf submode. +.. index:: ip pim register-accept-list PLIST +.. clicmd:: ip pim register-accept-list PLIST + + When pim receives a register packet the source of the packet will be compared + to the prefix-list specified, PLIST, and if a permit is received normal + processing continues. If a deny is returned for the source address of the + register packet a register stop message is sent to the source. + .. index:: ip pim spt-switchover infinity-and-beyond .. clicmd:: ip pim spt-switchover infinity-and-beyond diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 3633350a1d..137f68d72a 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -6650,6 +6650,26 @@ DEFUN (no_ip_pim_spt_switchover_infinity_plist, return pim_cmd_spt_switchover(pim, PIM_SPT_IMMEDIATE, NULL); } +DEFPY (pim_register_accept_list, + pim_register_accept_list_cmd, + "[no] ip pim register-accept-list WORD$word", + NO_STR + IP_STR + PIM_STR + "Only accept registers from a specific source prefix list\n" + "Prefix-List name\n") +{ + PIM_DECLVAR_CONTEXT(vrf, pim); + + if (no) + XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist); + else { + XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist); + pim->register_plist = XSTRDUP(MTYPE_PIM_PLIST_NAME, word); + } + return CMD_SUCCESS; +} + DEFUN (ip_pim_joinprune_time, ip_pim_joinprune_time_cmd, "ip pim join-prune-interval (60-600)", @@ -10743,6 +10763,8 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd); install_element(VRF_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd); + install_element(CONFIG_NODE, &pim_register_accept_list_cmd); + install_element(VRF_NODE, &pim_register_accept_list_cmd); install_element(CONFIG_NODE, &ip_pim_joinprune_time_cmd); install_element(VRF_NODE, &ip_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &no_ip_pim_joinprune_time_cmd); diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 795f79b351..2cda628a90 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -70,6 +70,7 @@ static void pim_instance_terminate(struct pim_instance *pim) pim_msdp_exit(pim); XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist); + XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist); XFREE(MTYPE_PIM_PIM_INSTANCE, pim); } diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h index 7b1fd2e172..48dc2d9530 100644 --- a/pimd/pim_instance.h +++ b/pimd/pim_instance.h @@ -135,6 +135,9 @@ struct pim_instance { char *plist; } spt; + /* The name of the register-accept prefix-list */ + char *register_plist; + struct hash *rpf_hash; void *ssm_info; /* per-vrf SSM configuration */ diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 3b58f6133c..7b0af89993 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -389,6 +389,33 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, == ((RP(pim, sg.grp))->rpf_addr.u.prefix4.s_addr))) { sentRegisterStop = 0; + if (pim->register_plist) { + struct prefix_list *plist; + struct prefix src; + + plist = prefix_list_lookup(AFI_IP, pim->register_plist); + + src.family = AF_INET; + src.prefixlen = IPV4_MAX_PREFIXLEN; + src.u.prefix4 = sg.src; + + if (prefix_list_apply(plist, &src) == PREFIX_DENY) { + pim_register_stop_send(ifp, &sg, dest_addr, + src_addr); + if (PIM_DEBUG_PIM_PACKETS) { + char src_str[INET_ADDRSTRLEN]; + + pim_inet4_dump("", src_addr, + src_str, + sizeof(src_str)); + zlog_debug("%s: Sending register-stop to %s for %pSG4 due to prefix-list denial, dropping packet", + __func__, src_str, &sg); + } + + return 0; + } + } + if (*bits & PIM_REGISTER_BORDER_BIT) { struct in_addr pimbr = pim_br_get_pmbr(&sg); if (PIM_DEBUG_PIM_PACKETS) diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index b5a5089ae7..f8fc09717e 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -211,6 +211,11 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) ssm->plist_name); ++writes; } + if (pim->register_plist) { + vty_out(vty, "%sip pim register-accept-list %s\n", spaces, + pim->register_plist); + ++writes; + } if (pim->spt.switchover == PIM_SPT_INFINITY) { if (pim->spt.plist) vty_out(vty, From c64d8d857780e59fd4fad6c6ffd1c712d097bca8 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 20 Feb 2020 15:38:33 -0500 Subject: [PATCH 5/5] tests: Add a test for the `ip pim register-accept-list PLIST` command Add a test to the pim-basic to ensure that the prefix-list works as expected. Signed-off-by: Donald Sharp --- tests/topotests/pim-basic/r1/pimd.conf | 4 ++++ tests/topotests/pim-basic/r1/zebra.conf | 3 +++ tests/topotests/pim-basic/r3/pimd.conf | 1 + tests/topotests/pim-basic/r3/zebra.conf | 8 ++++++++ tests/topotests/pim-basic/rp/pimd.conf | 3 +++ tests/topotests/pim-basic/test_pim.py | 13 ++++++++++++- 6 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/topotests/pim-basic/r3/pimd.conf create mode 100644 tests/topotests/pim-basic/r3/zebra.conf diff --git a/tests/topotests/pim-basic/r1/pimd.conf b/tests/topotests/pim-basic/r1/pimd.conf index cec765699d..f64a46deb3 100644 --- a/tests/topotests/pim-basic/r1/pimd.conf +++ b/tests/topotests/pim-basic/r1/pimd.conf @@ -7,6 +7,10 @@ interface r1-eth0 interface r1-eth1 ip pim ! +interface r1-eth2 + ip igmp + ip pim +! interface lo ip pim ! diff --git a/tests/topotests/pim-basic/r1/zebra.conf b/tests/topotests/pim-basic/r1/zebra.conf index b0a25f12aa..e43041758b 100644 --- a/tests/topotests/pim-basic/r1/zebra.conf +++ b/tests/topotests/pim-basic/r1/zebra.conf @@ -6,6 +6,9 @@ interface r1-eth0 interface r1-eth1 ip address 10.0.30.1/24 ! +interface r1-eth2 + ip address 10.0.40.1/24 +! interface lo ip address 10.254.0.1/32 ! diff --git a/tests/topotests/pim-basic/r3/pimd.conf b/tests/topotests/pim-basic/r3/pimd.conf new file mode 100644 index 0000000000..f94ee99930 --- /dev/null +++ b/tests/topotests/pim-basic/r3/pimd.conf @@ -0,0 +1 @@ +hostname r3 diff --git a/tests/topotests/pim-basic/r3/zebra.conf b/tests/topotests/pim-basic/r3/zebra.conf new file mode 100644 index 0000000000..8e58e8c66a --- /dev/null +++ b/tests/topotests/pim-basic/r3/zebra.conf @@ -0,0 +1,8 @@ +hostname r3 +! +interface r3-eth0 + ip address 10.0.40.4/24 +! +interface lo + ip address 10.254.0.4/32 +! diff --git a/tests/topotests/pim-basic/rp/pimd.conf b/tests/topotests/pim-basic/rp/pimd.conf index 3f1b4d65c9..6e35c97971 100644 --- a/tests/topotests/pim-basic/rp/pimd.conf +++ b/tests/topotests/pim-basic/rp/pimd.conf @@ -7,3 +7,6 @@ interface lo ip pim ! ip pim rp 10.254.0.3 +ip pim register-accept-list ACCEPT + +ip prefix-list ACCEPT seq 5 permit 10.0.20.0/24 le 32 diff --git a/tests/topotests/pim-basic/test_pim.py b/tests/topotests/pim-basic/test_pim.py index 0e0569e234..9101d7e035 100644 --- a/tests/topotests/pim-basic/test_pim.py +++ b/tests/topotests/pim-basic/test_pim.py @@ -46,14 +46,18 @@ class PIMTopo(Topo): "Build function" tgen = get_topogen(self) - for routern in range(1, 3): + for routern in range(1, 4): tgen.add_router('r{}'.format(routern)) tgen.add_router('rp') + # rp ------ r1 -------- r2 + # \ + # --------- r3 # r1 -> .1 # r2 -> .2 # rp -> .3 + # r3 -> .4 # loopback network is 10.254.0.X/32 # # r1 <- sw1 -> r2 @@ -70,6 +74,10 @@ class PIMTopo(Topo): sw.add_link(tgen.gears['r1']) sw.add_link(tgen.gears['rp']) + # 10.0.40.0/24 + sw = tgen.add_switch('sw3') + sw.add_link(tgen.gears['r1']) + sw.add_link(tgen.gears['r3']) def setup_module(mod): "Sets up the pytest environment" @@ -130,12 +138,15 @@ def test_pim_send_mcast_stream(): pytest.skip(tgen.errors) rp = tgen.gears['rp'] + r3 = tgen.gears['r3'] r2 = tgen.gears['r2'] r1 = tgen.gears['r1'] # Let's establish a S,G stream from r2 -> r1 CWD = os.path.dirname(os.path.realpath(__file__)) r2.run("{}/mcast-tx.py --ttl 5 --count 5 --interval 10 229.1.1.1 r2-eth0 > /tmp/bar".format(CWD)) + # And from r3 -> r1 + r3.run("{}/mcast-tx.py --ttl 5 --count 5 --interval 10 229.1.1.1 r3-eth0 > /tmp/bar".format(CWD)) # Let's see that it shows up and we have established some basic state out = r1.vtysh_cmd("show ip pim upstream json", isjson=True)