]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #10958 from patrasar/pim_passive
authorJafar Al-Gharaibeh <jafar@atcorp.com>
Fri, 13 May 2022 13:39:12 +0000 (08:39 -0500)
committerGitHub <noreply@github.com>
Fri, 13 May 2022 13:39:12 +0000 (08:39 -0500)
pimd: introduce ip pim passive command

22 files changed:
doc/user/pim.rst
doc/user/pimv6.rst
pimd/pim6_cmd.c
pimd/pim_assert.c
pimd/pim_bsm.c
pimd/pim_cmd.c
pimd/pim_cmd_common.c
pimd/pim_cmd_common.h
pimd/pim_hello.c
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_join.c
pimd/pim_nb.c
pimd/pim_nb.h
pimd/pim_nb_config.c
pimd/pim_pim.c
pimd/pim_pim.h
pimd/pim_register.c
pimd/pim_vty.c
tests/topotests/lib/pim.py
tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py
yang/frr-pim.yang

index dcea709503c1ca0a6863ab948c0aba61ce362b86..ae39f4220d0b701a484905661f2f1d6571f02c12 100644 (file)
@@ -234,6 +234,10 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
    and would like pim to use a specific source address associated with
    that interface.
 
+.. clicmd:: ip pim passive
+
+   Disable sending and receiving pim control packets on the interface.
+
 .. clicmd:: ip igmp
 
    Tell pim to receive IGMP reports and Query on this interface. The default
index 0456e77b21208239f61984d3144e4d2180f74ee2..c4d32e87513d81c1f17ba0fc198ef3aac6336aa9 100644 (file)
@@ -158,6 +158,10 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
    and would like pim to use a specific source address associated with
    that interface.
 
+.. clicmd:: ipv6 pim passive
+
+   Disable sending and receiving pim control packets on the interface.
+
 .. clicmd:: ipv6 mld
 
    Tell pim to receive MLD reports and Query on this interface. The default
index 6eeb778da9433afd7c6d35926763a38f67483b5f..ecff2173d4e92bae5df8800c5d17fc1e75141215 100644 (file)
@@ -41,7 +41,7 @@
 #include "pim_addr.h"
 #include "pim_nht.h"
 #include "pim_bsm.h"
-
+#include "pim_iface.h"
 
 #ifndef VTYSH_EXTRACT_PL
 #include "pimd/pim6_cmd_clippy.c"
@@ -216,20 +216,35 @@ DEFPY (no_ipv6_pim_register_suppress,
 
 DEFPY (interface_ipv6_pim,
        interface_ipv6_pim_cmd,
-       "ipv6 pim",
+       "ipv6 pim [passive$passive]",
        IPV6_STR
-       PIM_STR)
+       PIM_STR
+       "Disable exchange of protocol packets\n")
 {
-       return pim_process_ip_pim_cmd(vty);
+       int ret;
+
+       ret = pim_process_ip_pim_cmd(vty);
+
+       if (ret != NB_OK)
+               return ret;
+
+       if (passive)
+               return pim_process_ip_pim_passive_cmd(vty, true);
+
+       return CMD_SUCCESS;
 }
 
 DEFPY (interface_no_ipv6_pim,
        interface_no_ipv6_pim_cmd,
-       "no ipv6 pim",
+       "no ipv6 pim [passive$passive]",
        NO_STR
        IPV6_STR
-       PIM_STR)
+       PIM_STR
+       "Disable exchange of protocol packets\n")
 {
+       if (passive)
+               return pim_process_ip_pim_passive_cmd(vty, false);
+
        return pim_process_no_ip_pim_cmd(vty);
 }
 
index 6191f964689782ff8a2535439fc2fd60acc719eb..2cc98f73298b04dac3ee2dd9d41a158e429b2239 100644 (file)
@@ -303,6 +303,15 @@ int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh,
 
        pim_ifp = ifp->info;
        assert(pim_ifp);
+
+       if (pim_ifp->pim_passive_enable) {
+               if (PIM_DEBUG_PIM_PACKETS)
+                       zlog_debug(
+                               "skip receiving PIM message on passive interface %s",
+                               ifp->name);
+               return 0;
+       }
+
        ++pim_ifp->pim_ifstat_assert_recv;
 
        return dispatch_assert(ifp, msg_source_addr, sg.grp, msg_metric);
@@ -460,11 +469,12 @@ static int pim_assert_do(struct pim_ifchannel *ch,
                           metric.metric_preference, metric.route_metric,
                           PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
        }
-       ++pim_ifp->pim_ifstat_assert_send;
+       if (!pim_ifp->pim_passive_enable)
+               ++pim_ifp->pim_ifstat_assert_send;
 
        if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
                         qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
-                        ifp->name)) {
+                        ifp)) {
                zlog_warn("%s: could not send PIM message on interface %s",
                          __func__, ifp->name);
                return -3;
index 003ce47432c6f1a046ad33802343950bdb7a89e5..8ef3c43a99658a6a465ab470fe10169db8363e38 100644 (file)
@@ -704,13 +704,15 @@ static bool pim_bsm_send_intf(uint8_t *buf, int len, struct interface *ifp,
        }
 
        if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
-                        dst_addr, buf, len, ifp->name)) {
+                        dst_addr, buf, len, ifp)) {
                zlog_warn("%s: Could not send BSM message on interface: %s",
                          __func__, ifp->name);
                return false;
        }
 
-       pim_ifp->pim_ifstat_bsm_tx++;
+       if (!pim_ifp->pim_passive_enable)
+               pim_ifp->pim_ifstat_bsm_tx++;
+
        pim_ifp->pim->bsm_sent++;
        return true;
 }
@@ -1298,6 +1300,14 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
                return -1;
        }
 
+       if (pim_ifp->pim_passive_enable) {
+               if (PIM_DEBUG_PIM_PACKETS)
+                       zlog_debug(
+                               "skip receiving PIM message on passive interface %s",
+                               ifp->name);
+               return 0;
+       }
+
        pim_ifp->pim_ifstat_bsm_rx++;
        pim = pim_ifp->pim;
        pim->bsm_rcvd++;
index 55e58f2d9a892fbd2c065a0335a17603ae811a7c..7e9ce5f933773fbd3c54ed53cb0c904ff12af1b6 100644 (file)
@@ -5262,13 +5262,24 @@ DEFUN_HIDDEN (interface_ip_pim_sm,
        return pim_process_ip_pim_cmd(vty);
 }
 
-DEFUN (interface_ip_pim,
+DEFPY (interface_ip_pim,
        interface_ip_pim_cmd,
-       "ip pim",
+       "ip pim [passive$passive]",
        IP_STR
-       PIM_STR)
+       PIM_STR
+       "Disable exchange of protocol packets\n")
 {
-       return pim_process_ip_pim_cmd(vty);
+       int ret;
+
+       ret = pim_process_ip_pim_cmd(vty);
+
+       if (ret != NB_OK)
+               return ret;
+
+       if (passive)
+               return pim_process_ip_pim_passive_cmd(vty, true);
+
+       return CMD_SUCCESS;
 }
 
 DEFUN_HIDDEN (interface_no_ip_pim_ssm,
@@ -5293,13 +5304,17 @@ DEFUN_HIDDEN (interface_no_ip_pim_sm,
        return pim_process_no_ip_pim_cmd(vty);
 }
 
-DEFUN (interface_no_ip_pim,
+DEFPY (interface_no_ip_pim,
        interface_no_ip_pim_cmd,
-       "no ip pim",
+       "no ip pim [passive$passive]",
        NO_STR
        IP_STR
-       PIM_STR)
+       PIM_STR
+       "Disable exchange of protocol packets\n")
 {
+       if (passive)
+               return pim_process_ip_pim_passive_cmd(vty, false);
+
        return pim_process_no_ip_pim_cmd(vty);
 }
 
index cb98638107dba3fb4a6ce5235739844e27ba1131..6cff3a077e16e8bb9462ac5d2b223a9beaeb3b3f 100644 (file)
@@ -352,6 +352,19 @@ int pim_process_ip_pim_cmd(struct vty *vty)
                                    FRR_PIM_AF_XPATH_VAL);
 }
 
+int pim_process_ip_pim_passive_cmd(struct vty *vty, bool enable)
+{
+       if (enable)
+               nb_cli_enqueue_change(vty, "./pim-passive-enable", NB_OP_MODIFY,
+                                     "true");
+       else
+               nb_cli_enqueue_change(vty, "./pim-passive-enable", NB_OP_MODIFY,
+                                     "false");
+
+       return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
+                                   FRR_PIM_AF_XPATH_VAL);
+}
+
 int pim_process_no_ip_pim_cmd(struct vty *vty)
 {
        const struct lyd_node *mld_enable_dnode;
@@ -2110,6 +2123,10 @@ void pim_show_interfaces_single(struct pim_instance *pim, struct vty *vty,
                                                       sec_list);
                        }
 
+                       if (pim_ifp->pim_passive_enable)
+                               json_object_boolean_true_add(json_row,
+                                                            "passive");
+
                        /* PIM neighbors */
                        if (pim_ifp->pim_neighbor_list->count) {
                                json_pim_neighbors = json_object_new_object();
@@ -2276,6 +2293,12 @@ void pim_show_interfaces_single(struct pim_instance *pim, struct vty *vty,
                        } else {
                                vty_out(vty, "Address    : %pPAs\n", &ifaddr);
                        }
+
+                       if (pim_ifp->pim_passive_enable)
+                               vty_out(vty, "Passive    : %s\n",
+                                       (pim_ifp->pim_passive_enable) ? "yes"
+                                                                     : "no");
+
                        vty_out(vty, "\n");
 
                        /* PIM neighbors */
index 206a2248f8f6c6991007d09eb08817ea05c9fdad..4457ea57a97b232c003b4df6cf3b5d7b077810e8 100644 (file)
@@ -52,6 +52,7 @@ int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str,
 
 int pim_process_ip_pim_cmd(struct vty *vty);
 int pim_process_no_ip_pim_cmd(struct vty *vty);
+int pim_process_ip_pim_passive_cmd(struct vty *vty, bool enable);
 int pim_process_ip_pim_drprio_cmd(struct vty *vty, const char *drpriority_str);
 int pim_process_no_ip_pim_drprio_cmd(struct vty *vty);
 int pim_process_ip_pim_hello_cmd(struct vty *vty, const char *hello_str,
index a2f68acc78d2a9cef6087e89823544d76b4d839a..833103c27fc305e5bda46f3edd1ce7879f01c6f8 100644 (file)
@@ -125,6 +125,14 @@ int pim_hello_recv(struct interface *ifp, pim_addr src_addr, uint8_t *tlv_buf,
        pim_ifp = ifp->info;
        assert(pim_ifp);
 
+       if (pim_ifp->pim_passive_enable) {
+               if (PIM_DEBUG_PIM_PACKETS)
+                       zlog_debug(
+                               "skip receiving PIM message on passive interface %s",
+                               ifp->name);
+               return 0;
+       }
+
        ++pim_ifp->pim_ifstat_hello_recv;
 
        /*
index b98e64adfe91437e46505fc26c3cb34d708a4bf4..7d6f5603a4232b738a12f47811f75e4c8dd4977e 100644 (file)
@@ -150,6 +150,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
               pim_ifp->gm_default_query_interval);
 
        pim_ifp->pim_enable = pim;
+       pim_ifp->pim_passive_enable = false;
 #if PIM_IPV == 4
        pim_ifp->igmp_enable = igmp;
 #endif
index 45aecdd349fc756e01cf4fb42072f64b0f332568..529ce603e6bc74c5dce930a9467976e4ffb0fe6a 100644 (file)
@@ -71,6 +71,7 @@ struct pim_secondary_addr {
 struct pim_interface {
        bool pim_enable : 1;
        bool pim_can_disable_join_suppression : 1;
+       bool pim_passive_enable : 1;
 
        bool igmp_enable : 1;
 
index 58de2c4a86a9535822be09c93c49d482ebfc52ff..1b722382b919d67464eb7db19621f8d8b3982466 100644 (file)
@@ -164,6 +164,14 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
        pastend = tlv_buf + tlv_buf_size;
        pim_ifp = ifp->info;
 
+       if (pim_ifp->pim_passive_enable) {
+               if (PIM_DEBUG_PIM_PACKETS)
+                       zlog_debug(
+                               "skip receiving PIM message on passive interface %s",
+                               ifp->name);
+               return 0;
+       }
+
        /*
          Parse ucast addr
        */
@@ -497,7 +505,7 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
                                         pim_ifp->primary_address,
                                         qpim_all_pim_routers_addr, pim_msg,
                                         packet_size,
-                                        rpf->source_nexthop.interface->name)) {
+                                        rpf->source_nexthop.interface)) {
                                zlog_warn(
                                        "%s: could not send PIM message on interface %s",
                                        __func__,
@@ -535,8 +543,10 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
                packet_size += group_size;
                pim_msg_build_jp_groups(grp, group, group_size);
 
-               pim_ifp->pim_ifstat_join_send += ntohs(grp->joins);
-               pim_ifp->pim_ifstat_prune_send += ntohs(grp->prunes);
+               if (!pim_ifp->pim_passive_enable) {
+                       pim_ifp->pim_ifstat_join_send += ntohs(grp->joins);
+                       pim_ifp->pim_ifstat_prune_send += ntohs(grp->prunes);
+               }
 
                if (PIM_DEBUG_PIM_TRACE)
                        zlog_debug(
@@ -555,7 +565,7 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
                                         pim_ifp->primary_address,
                                         qpim_all_pim_routers_addr, pim_msg,
                                         packet_size,
-                                        rpf->source_nexthop.interface->name)) {
+                                        rpf->source_nexthop.interface)) {
                                zlog_warn(
                                        "%s: could not send PIM message on interface %s",
                                        __func__,
@@ -574,8 +584,7 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
                        pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE, false);
                if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
                                 qpim_all_pim_routers_addr, pim_msg,
-                                packet_size,
-                                rpf->source_nexthop.interface->name)) {
+                                packet_size, rpf->source_nexthop.interface)) {
                        zlog_warn(
                                "%s: could not send PIM message on interface %s",
                                __func__, rpf->source_nexthop.interface->name);
index 86dd8c490c8e6aa02111ba738f097f130b27b3b9..94696bb4c76ffa38ac021f497e3a69fc553bf421 100644 (file)
@@ -230,6 +230,12 @@ const struct frr_yang_module_info frr_pim_info = {
                                .modify = lib_interface_pim_address_family_pim_enable_modify,
                        }
                },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/pim-passive-enable",
+                       .cbs = {
+                               .modify = lib_interface_pim_address_family_pim_passive_enable_modify,
+                       }
+               },
                {
                        .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/dr-priority",
                        .cbs = {
index 273c7e8a6101ef56fdf34739538cdba69887af10..be3cab66ce5a5ddb3ce5fb28e000af5c7d805403 100644 (file)
@@ -106,6 +106,8 @@ int lib_interface_pim_address_family_create(struct nb_cb_create_args *args);
 int lib_interface_pim_address_family_destroy(struct nb_cb_destroy_args *args);
 int lib_interface_pim_address_family_pim_enable_modify(
        struct nb_cb_modify_args *args);
+int lib_interface_pim_address_family_pim_passive_enable_modify(
+       struct nb_cb_modify_args *args);
 int lib_interface_pim_address_family_hello_interval_modify(
        struct nb_cb_modify_args *args);
 int lib_interface_pim_address_family_hello_holdtime_modify(
index d174b8a0af7eb649cc758367c6de4b519556222b..34438120b9ab497b79916f065fae9e3f1b1985d1 100644 (file)
@@ -1623,6 +1623,32 @@ int lib_interface_pim_address_family_pim_enable_modify(struct nb_cb_modify_args
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-pim:pim/address-family/pim-passive-enable
+ */
+int lib_interface_pim_address_family_pim_passive_enable_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_ABORT:
+       case NB_EV_PREPARE:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               pim_ifp->pim_passive_enable =
+                       yang_dnode_get_bool(args->dnode, NULL);
+               break;
+       }
+
+       return NB_OK;
+}
+
 /*
  * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/hello-interval
  */
index 352f95c4735bc18f916e1adb52102274fa35edec..f0f4a7139b930343321c91cc8ed032fee0e9f895 100644 (file)
@@ -594,13 +594,24 @@ static int pim_msg_send_frame(int fd, char *buf, size_t len,
 }
 
 int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
-                int pim_msg_size, const char *ifname)
+                int pim_msg_size, struct interface *ifp)
 {
        socklen_t tolen;
        unsigned char buffer[10000];
        unsigned char *msg_start;
        uint8_t ttl;
        struct pim_msg_header *header;
+       struct pim_interface *pim_ifp;
+
+       pim_ifp = ifp->info;
+
+       if (pim_ifp->pim_passive_enable) {
+               if (PIM_DEBUG_PIM_PACKETS)
+                       zlog_debug(
+                               "skip sending PIM message on passive interface %s",
+                               ifp->name);
+               return 0;
+       }
 
        memset(buffer, 0, 10000);
 
@@ -673,7 +684,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
 
        if (PIM_DEBUG_PIM_PACKETS)
                zlog_debug("%s: to %pPA on %s: msg_size=%d checksum=%x",
-                          __func__, &dst, ifname, pim_msg_size,
+                          __func__, &dst, ifp->name, pim_msg_size,
                           header->checksum);
 
        if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
@@ -681,7 +692,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
        }
 
        pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to,
-                          tolen, ifname);
+                          tolen, ifp->name);
        return 0;
 }
 
@@ -726,7 +737,7 @@ static int hello_send(struct interface *ifp, uint16_t holdtime)
 
        if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
                         qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
-                        ifp->name)) {
+                        ifp)) {
                if (PIM_DEBUG_PIM_HELLO) {
                        zlog_debug(
                                "%s: could not send PIM message on interface %s",
@@ -755,8 +766,10 @@ int pim_hello_send(struct interface *ifp, uint16_t holdtime)
                return -1;
        }
 
-       ++pim_ifp->pim_ifstat_hello_sent;
-       PIM_IF_FLAG_SET_HELLO_SENT(pim_ifp->flags);
+       if (!pim_ifp->pim_passive_enable) {
+               ++pim_ifp->pim_ifstat_hello_sent;
+               PIM_IF_FLAG_SET_HELLO_SENT(pim_ifp->flags);
+       }
 
        return 0;
 }
index 822d8a18faf4fcbe13f5d7a06da840f28a209291..e2555eab8c216fd2453a22026f106fef4f5dc076 100644 (file)
@@ -58,7 +58,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
                   pim_sgaddr sg);
 
 int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
-                int pim_msg_size, const char *ifname);
+                int pim_msg_size, struct interface *ifp);
 
 int pim_hello_send(struct interface *ifp, uint16_t holdtime);
 #endif /* PIM_PIM_H */
index f86453f936b8cd17ce4889a20fd2f236b8b65c96..6b76f4c49b55c9364cf06af9ffea0973f454edb3 100644 (file)
@@ -100,14 +100,16 @@ void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg, pim_addr src,
                return;
        }
        if (pim_msg_send(pinfo->pim_sock_fd, src, originator, buffer,
-                        b1length + PIM_MSG_REGISTER_STOP_LEN, ifp->name)) {
+                        b1length + PIM_MSG_REGISTER_STOP_LEN, ifp)) {
                if (PIM_DEBUG_PIM_TRACE) {
                        zlog_debug(
                                "%s: could not send PIM register stop message on interface %s",
                                __func__, ifp->name);
                }
        }
-       ++pinfo->pim_ifstat_reg_stop_send;
+
+       if (!pinfo->pim_passive_enable)
+               ++pinfo->pim_ifstat_reg_stop_send;
 }
 
 static void pim_reg_stop_upstream(struct pim_instance *pim,
@@ -145,6 +147,14 @@ int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size)
        bool handling_star = false;
        int l;
 
+       if (pim_ifp->pim_passive_enable) {
+               if (PIM_DEBUG_PIM_PACKETS)
+                       zlog_debug(
+                               "skip receiving PIM message on passive interface %s",
+                               ifp->name);
+               return 0;
+       }
+
        ++pim_ifp->pim_ifstat_reg_stop_recv;
 
        memset(&sg, 0, sizeof(sg));
@@ -266,10 +276,11 @@ void pim_register_send(const uint8_t *buf, int buf_size, pim_addr src,
        pim_msg_build_header(src, dst, buffer, buf_size + PIM_MSG_REGISTER_LEN,
                             PIM_MSG_TYPE_REGISTER, false);
 
-       ++pinfo->pim_ifstat_reg_send;
+       if (!pinfo->pim_passive_enable)
+               ++pinfo->pim_ifstat_reg_send;
 
        if (pim_msg_send(pinfo->pim_sock_fd, src, dst, buffer,
-                        buf_size + PIM_MSG_REGISTER_LEN, ifp->name)) {
+                        buf_size + PIM_MSG_REGISTER_LEN, ifp)) {
                if (PIM_DEBUG_PIM_TRACE) {
                        zlog_debug(
                                "%s: could not send PIM register message on interface %s",
@@ -446,6 +457,14 @@ int pim_register_recv(struct interface *ifp, pim_addr dest_addr,
        struct pim_instance *pim = pim_ifp->pim;
        pim_addr rp_addr;
 
+       if (pim_ifp->pim_passive_enable) {
+               if (PIM_DEBUG_PIM_PACKETS)
+                       zlog_debug(
+                               "skip receiving PIM message on passive interface %s",
+                               ifp->name);
+               return 0;
+       }
+
 #define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
        ip_hdr = (tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
 
index d044aec510d5fc5ce4efa603f660b9b98326b291..eca5e4bbe598d8f2a5638785a057c96d6a58542b 100644 (file)
@@ -409,6 +409,11 @@ int pim_config_write(struct vty *vty, int writes, struct interface *ifp,
                ++writes;
        }
 
+       if (pim_ifp->pim_passive_enable) {
+               vty_out(vty, " " PIM_AF_NAME " pim passive\n");
+               ++writes;
+       }
+
        writes += pim_static_write_mroute(pim, vty, ifp);
        pim_bsm_write_config(vty, ifp);
        ++writes;
index 1423f3fecc56a41508901f1b29120a8894b4a954..47892a521875389bc66068e8a6dc27dfd3285dd3 100644 (file)
@@ -3550,6 +3550,69 @@ class McastTesterHelper(HostApplicationHelper):
 
         return True
 
+
+def verify_pim_interface_traffic(tgen, input_dict, return_stats=True):
+    """
+    Verify ip pim interface traffice by running
+    "show ip pim interface traffic" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `input_dict(dict)`: defines DUT, what and from which interfaces
+                          traffic needs to be verified
+    Usage
+    -----
+    input_dict = {
+        "r1": {
+            "r1-r0-eth0": {
+                "helloRx": 0,
+                "helloTx": 1,
+                "joinRx": 0,
+                "joinTx": 0
+            }
+        }
+    }
+
+    result = verify_pim_interface_traffic(tgen, input_dict)
+
+    Returns
+    -------
+    errormsg(str) or True
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    output_dict = {}
+    for dut in input_dict.keys():
+        if dut not in tgen.routers():
+            continue
+
+        rnode = tgen.routers()[dut]
+
+        logger.info("[DUT: %s]: Verifying pim interface traffic", dut)
+        show_pim_intf_traffic_json = run_frr_cmd(
+            rnode, "show ip pim interface traffic json", isjson=True
+        )
+
+        output_dict[dut] = {}
+        for intf, data in input_dict[dut].items():
+            interface_json = show_pim_intf_traffic_json[intf]
+            for state in data:
+
+                # Verify Tx/Rx
+                if state in interface_json:
+                    output_dict[dut][state] = interface_json[state]
+                else:
+                    errormsg = (
+                        "[DUT %s]: %s is not present"
+                        "for interface %s [FAILED]!! " % (dut, state, intf)
+                    )
+                    return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return True if return_stats == False else output_dict
+
     # def cleanup(self):
     #     super(McastTesterHelper, self).cleanup()
 
index cbd10906487aa0f400d3ff9ef2cf0deab765f51f..b71c2d65ebd2b7f7a1fc0883603911bf36cc790d 100755 (executable)
@@ -54,6 +54,7 @@ import sys
 import time
 import datetime
 import pytest
+from time import sleep
 
 pytestmark = pytest.mark.pimd
 
@@ -95,6 +96,7 @@ from lib.pim import (
     verify_pim_rp_info,
     verify_multicast_flag_state,
     McastTesterHelper,
+    verify_pim_interface_traffic,
 )
 from lib.topolog import logger
 from lib.topojson import build_config_from_json
@@ -354,6 +356,45 @@ def find_tos_in_tcpdump(tgen, router, message, cap_file):
     return True
 
 
+def verify_pim_stats_increament(stats_before, stats_after):
+    """
+    API to compare pim interface control plane traffic
+
+    Parameters
+    ----------
+    * `stats_before` : Stats dictionary for any particular instance
+    * `stats_after` : Stats dictionary for any particular instance
+    """
+
+    for router, stats_data in stats_before.items():
+        for stats, value in stats_data.items():
+            if stats_before[router][stats] >= stats_after[router][stats]:
+                errormsg = (
+                    "[DUT: %s]: state %s value has not"
+                    " incremented, Initial value: %s, "
+                    "Current value: %s [FAILED!!]"
+                    % (
+                        router,
+                        stats,
+                        stats_before[router][stats],
+                        stats_after[router][stats],
+                    )
+                )
+                return errormsg
+
+            logger.info(
+                "[DUT: %s]: State %s value is "
+                "incremented, Initial value: %s, Current value: %s"
+                " [PASSED!!]",
+                router,
+                stats,
+                stats_before[router][stats],
+                stats_after[router][stats],
+            )
+
+    return True
+
+
 def test_verify_oil_when_join_prune_sent_scenario_1_p1(request):
     """
     TC_21_1:
@@ -4490,6 +4531,259 @@ def test_verify_multicast_traffic_when_FHR_connected_to_RP_p1(request):
     write_test_footer(tc_name)
 
 
+def test_PIM_passive_p1(request):
+    """
+    TC Verify PIM passive functionality"
+    """
+
+    tgen = get_topogen()
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    app_helper.stop_all_hosts()
+    # Creating configuration from JSON
+    clear_mroute(tgen)
+    if tgen.routers_have_failure():
+        check_router_status(tgen)
+    reset_config_on_routers(tgen)
+    clear_pim_interface_traffic(tgen, topo)
+
+    step("Enable the PIM on all the interfaces of FRR1, FRR2, FRR3")
+    step(
+        "Enable IGMP of FRR1 interface and send IGMP joins "
+        " from FRR1 node for group range (225.1.1.1-5)"
+    )
+
+    intf_c1_i4 = topo["routers"]["c1"]["links"]["i4"]["interface"]
+
+    step(
+        "configure PIM passive on receiver interface to verify no impact on IGMP join"
+        "and multicast traffic on pim passive interface"
+    )
+
+    raw_config = {
+        "c1": {"raw_config": ["interface {}".format(intf_c1_i4), "ip pim passive"]}
+    }
+    result = apply_raw_config(tgen, raw_config)
+    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+    step("configure IGMPv2 and send IGMP joinon on PIM passive interface")
+    input_dict = {
+        "c1": {"igmp": {"interfaces": {intf_c1_i4: {"igmp": {"version": "2"}}}}}
+    }
+    result = create_igmp_config(tgen, topo, input_dict)
+    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+    input_join = {"i4": topo["routers"]["i4"]["links"]["c1"]["interface"]}
+    for recvr, recvr_intf in input_join.items():
+        result = app_helper.run_join(recvr, IGMP_JOIN_RANGE_1, join_intf=recvr_intf)
+        assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+    step("Configure static RP for (225.1.1.1-5) as R2")
+
+    input_dict = {
+        "r2": {
+            "pim": {
+                "rp": [
+                    {
+                        "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split(
+                            "/"
+                        )[0],
+                        "group_addr_range": GROUP_RANGE_1,
+                    }
+                ]
+            }
+        }
+    }
+
+    result = create_pim_config(tgen, topo, input_dict)
+    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+    step("Send Mcast traffic from C2 to all the groups ( 225.1.1.1 to 225.1.1.5)")
+
+    input_src = {"i5": topo["routers"]["i5"]["links"]["c2"]["interface"]}
+    for src, src_intf in input_src.items():
+        result = app_helper.run_traffic(src, IGMP_JOIN_RANGE_1, bind_intf=src_intf)
+        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+    source_i5 = topo["routers"]["i5"]["links"]["c2"]["ipv4"].split("/")[0]
+
+    input_dict_starg = [
+        {
+            "dut": "c1",
+            "src_address": "*",
+            "iif": topo["routers"]["c1"]["links"]["l1"]["interface"],
+            "oil": topo["routers"]["c1"]["links"]["i4"]["interface"],
+        }
+    ]
+
+    input_dict_sg = [
+        {
+            "dut": "c1",
+            "src_address": source_i5,
+            "iif": topo["routers"]["c1"]["links"]["c2"]["interface"],
+            "oil": topo["routers"]["c1"]["links"]["i4"]["interface"],
+        }
+    ]
+
+    step("(*,G) and (S,G) created on f1 and node verify using 'show ip mroute'")
+
+    for data in input_dict_sg:
+        result = verify_mroutes(
+            tgen,
+            data["dut"],
+            data["src_address"],
+            IGMP_JOIN_RANGE_1,
+            data["iif"],
+            data["oil"],
+        )
+        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+    for data in input_dict_sg:
+        result = verify_mroutes(
+            tgen,
+            data["dut"],
+            data["src_address"],
+            IGMP_JOIN_RANGE_1,
+            data["iif"],
+            data["oil"],
+        )
+        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+    for data in input_dict_starg:
+        result = verify_mroutes(
+            tgen,
+            data["dut"],
+            data["src_address"],
+            IGMP_JOIN_RANGE_1,
+            data["iif"],
+            data["oil"],
+        )
+        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+    intf_c1_c2 = topo["routers"]["c1"]["links"]["c2"]["interface"]
+    intf_c2_c1 = topo["routers"]["c2"]["links"]["c1"]["interface"]
+
+    step(
+        "configure PIM passive on upstream interface to verify"
+        "hello tx/rx counts are not incremented"
+    )
+
+    # Changing hello timer to 3sec for checking more number of packets
+
+    raw_config = {
+        "c1": {
+            "raw_config": [
+                "interface {}".format(intf_c1_c2),
+                "ip pim passive",
+                "ip pim hello 3",
+            ]
+        },
+        "c2": {"raw_config": ["interface {}".format(intf_c2_c1), "ip pim hello 3"]},
+    }
+    result = apply_raw_config(tgen, raw_config)
+    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+    step("verify PIM hello tx/rx stats on C1")
+    state_dict = {
+        "c1": {
+            intf_c1_c2: ["helloTx", "helloRx"],
+        }
+    }
+
+    logger.info("waiting for 5 sec config to get apply and hello count update")
+    sleep(5)
+
+    c1_state_before = verify_pim_interface_traffic(tgen, state_dict)
+    assert isinstance(
+        c1_state_before, dict
+    ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+        tc_name, result
+    )
+
+    logger.info(
+        "sleeping for 30 sec hello interval timer to verify count are not increamented"
+    )
+    sleep(35)
+
+    c1_state_after = verify_pim_interface_traffic(tgen, state_dict)
+    assert isinstance(
+        c1_state_after, dict
+    ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+        tc_name, result
+    )
+
+    step("verify stats not increamented on c1")
+    result = verify_pim_stats_increament(c1_state_before, c1_state_after)
+    assert (
+        result is not True
+    ), "Testcase{} : Failed Error: {}" "stats incremented".format(tc_name, result)
+
+    step("No impact observed on mroutes")
+    for data in input_dict_sg:
+        result = verify_mroutes(
+            tgen,
+            data["dut"],
+            data["src_address"],
+            IGMP_JOIN_RANGE_1,
+            data["iif"],
+            data["oil"],
+        )
+        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+    for data in input_dict_sg:
+        result = verify_mroutes(
+            tgen,
+            data["dut"],
+            data["src_address"],
+            IGMP_JOIN_RANGE_1,
+            data["iif"],
+            data["oil"],
+        )
+        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+    for data in input_dict_starg:
+        result = verify_mroutes(
+            tgen,
+            data["dut"],
+            data["src_address"],
+            IGMP_JOIN_RANGE_1,
+            data["iif"],
+            data["oil"],
+        )
+        assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+    step("remove PIM passive and verify hello tx/rx is increamented")
+    raw_config = {
+        "c1": {
+            "raw_config": [
+                "interface {}".format(intf_c1_c2),
+                "no ip pim passive",
+                "ip pim hello 3",
+            ]
+        }
+    }
+    result = apply_raw_config(tgen, raw_config)
+    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+    logger.info("waiting for 30 sec for pim hello to receive")
+    sleep(30)
+
+    c1_state_after = verify_pim_interface_traffic(tgen, state_dict)
+    assert isinstance(
+        c1_state_after, dict
+    ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+        tc_name, result
+    )
+
+    step("verify stats increamented on c1 after removing pim passive")
+    result = verify_pim_stats_increament(c1_state_before, c1_state_after)
+    assert result is True, "Testcase{} : Failed Error: {}" "stats incremented".format(
+        tc_name, result
+    )
+
+    write_test_footer(tc_name)
+
+
 if __name__ == "__main__":
     args = ["-s"] + sys.argv[1:]
     sys.exit(pytest.main(args))
index 08bc9ce0a6eb3eb23e706026bbd88e01d064ef80..9e40d786020f11f2d077b4e9bec75ce3c2ee5f97 100644 (file)
@@ -334,6 +334,13 @@ module frr-pim {
         "Enable PIM flag on the interface.";
     }
 
+    leaf pim-passive-enable {
+      type boolean;
+      default "false";
+      description
+        "Disable exchange of protocol packets.";
+    }
+
     leaf hello-interval {
       type uint8 {
         range "1..max";