diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 36c8b44aa4..f480c6bdc4 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 fc8778fd8d..af25d930d1 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -6628,18 +6628,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; } @@ -6700,6 +6700,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)", @@ -10798,6 +10818,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 347b0fc284..2cda628a90 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -69,6 +69,8 @@ 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_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 */ diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 19baecb9c2..7b0af89993 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,9 +386,36 @@ 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 (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) @@ -411,14 +437,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 +477,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 +487,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); } } diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 8a87dfbb55..72540903be 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -216,6 +216,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, 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)