]> git.puffer.fish Git - matthieu/frr.git/commitdiff
pimd: add IGMPv2/MLDv1 immediate-leave
authorDavid Lamparter <equinox@opensourcerouting.org>
Tue, 28 Sep 2021 12:40:23 +0000 (14:40 +0200)
committerRafael Zalamena <rzalamena@opensourcerouting.org>
Thu, 13 Feb 2025 15:45:47 +0000 (12:45 -0300)
(Somewhat) useful when dealing with an interface that has only one host
attached.  Only works for IGMPv2 and MLDv1, other protocol versions have
no leave message.

Co-authored-by: David Lamparter <equinox@opensourcerouting.org>
Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
pimd/pim6_cmd.c
pimd/pim6_mld.c
pimd/pim_cmd.c
pimd/pim_iface.h
pimd/pim_igmpv3.c
pimd/pim_nb.c
pimd/pim_nb.h
pimd/pim_nb_config.c
pimd/pim_vty.c
yang/frr-gmp.yang

index 40bd7caf7d68133952fb3e173c0101d710850705..50357ca1d06bc8bc8432e4c386248993438b716e 100644 (file)
@@ -1649,6 +1649,19 @@ ALIAS_YANG(interface_ipv6_mld_limits,
            "Limit number of MLDv2 sources to track\n"
            "Limit number of MLD group memberships to track\n")
 
+DEFPY_YANG(interface_ipv6_mld_immediate_leave,
+           interface_ipv6_mld_immediate_leave_cmd,
+           "[no] ipv6 mld immediate-leave",
+           NO_STR
+           IPV6_STR
+           IFACE_MLD_STR
+           "Immediately drop group memberships on receiving Leave (MLDv1 only)\n")
+{
+       nb_cli_enqueue_change(vty, "./immediate-leave", NB_OP_MODIFY, no ? "false" : "true");
+
+       return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, FRR_PIM_AF_XPATH_VAL);
+}
+
 DEFPY (interface_ipv6_mld_query_interval,
        interface_ipv6_mld_query_interval_cmd,
        "ipv6 mld query-interval (1-65535)$q_interval",
@@ -2944,6 +2957,7 @@ void pim_cmd_init(void)
        install_element(INTERFACE_NODE, &interface_ipv6_mld_static_group_cmd);
        install_element(INTERFACE_NODE, &interface_ipv6_mld_version_cmd);
        install_element(INTERFACE_NODE, &interface_no_ipv6_mld_version_cmd);
+       install_element(INTERFACE_NODE, &interface_ipv6_mld_immediate_leave_cmd);
        install_element(INTERFACE_NODE, &interface_ipv6_mld_query_interval_cmd);
        install_element(INTERFACE_NODE,
                        &interface_no_ipv6_mld_query_interval_cmd);
index d7e0314d3b251b7ccb08a7e0bb0e8059ce7bcf78..37c5309ba3104ba95ed03e3b606fa282b630e040 100644 (file)
@@ -448,18 +448,23 @@ static void gm_sg_update(struct gm_sg *sg, bool has_expired)
                    desired == GM_SG_NOPRUNE_EXPIRING) {
                        struct gm_query_timers timers;
 
-                       timers.qrv = gm_ifp->cur_qrv;
-                       timers.max_resp_ms = gm_ifp->cur_max_resp;
-                       timers.qqic_ms = gm_ifp->cur_query_intv_trig;
-                       timers.fuzz = gm_ifp->cfg_timing_fuzz;
+                       if (!pim_ifp->gmp_immediate_leave) {
+                               timers.qrv = gm_ifp->cur_qrv;
+                               timers.max_resp_ms = gm_ifp->cur_max_resp;
+                               timers.qqic_ms = gm_ifp->cur_query_intv_trig;
+                               timers.fuzz = gm_ifp->cfg_timing_fuzz;
+
+                               gm_expiry_calc(&timers);
+                       } else
+                               memset(&timers.expire_wait, 0, sizeof(timers.expire_wait));
 
-                       gm_expiry_calc(&timers);
                        gm_sg_timer_start(gm_ifp, sg, timers.expire_wait);
 
                        EVENT_OFF(sg->t_sg_query);
                        sg->query_sbit = false;
                        /* Trigger the specific queries only for querier. */
-                       if (IPV6_ADDR_SAME(&gm_ifp->querier, &pim_ifp->ll_lowest)) {
+                       if (!pim_ifp->gmp_immediate_leave &&
+                           IPV6_ADDR_SAME(&gm_ifp->querier, &pim_ifp->ll_lowest)) {
                                sg->n_query = gm_ifp->cur_lmqc;
                                gm_trigger_specific(sg);
                        }
@@ -1102,10 +1107,24 @@ static void gm_handle_v1_leave(struct gm_if *gm_ifp,
        if (grp) {
                old_grp = gm_packet_sg_find(grp, GM_SUB_POS, subscriber);
                if (old_grp) {
+                       const struct pim_interface *pim_ifp = gm_ifp->ifp->info;
+                       struct gm_packet_sg *item;
+
                        gm_packet_sg_drop(old_grp);
-                       gm_sg_update(grp, false);
 
-/* TODO "need S,G PRUNE => NO_INFO transition here" */
+                       /*
+                        * If immediate leave drop others subscribers and proceed
+                        * to expire the MLD join.
+                        */
+                       if (pim_ifp->gmp_immediate_leave) {
+                               frr_each_safe (gm_packet_sg_subs, grp->subs_positive, item) {
+                                       gm_packet_sg_drop(item);
+                               }
+                               gm_sg_update(grp, true);
+                       } else
+                               gm_sg_update(grp, false);
+
+                       /* TODO "need S,G PRUNE => NO_INFO transition here" */
 
                }
        }
index fa9c6f953793e9f4b62a488bf5645804e514a74b..4ad75a21e7f749e06da561eb6a393e3cfd8296b0 100644 (file)
@@ -5693,6 +5693,19 @@ ALIAS_YANG(interface_ip_igmp_limits,
            "Limit number of IGMPv3 sources to track\n"
            "Limit number of IGMP group memberships to track\n")
 
+DEFPY_YANG(interface_ip_igmp_immediate_leave,
+           interface_ip_igmp_immediate_leave_cmd,
+           "[no] ip igmp immediate-leave",
+           NO_STR
+           IP_STR
+           IFACE_IGMP_STR
+           "Immediately drop group memberships on receiving Leave (IGMPv2 only)\n")
+{
+       nb_cli_enqueue_change(vty, "./immediate-leave", NB_OP_MODIFY, no ? "false" : "true");
+
+       return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, FRR_PIM_AF_XPATH_VAL);
+}
+
 DEFUN (interface_ip_pim_drprio,
        interface_ip_pim_drprio_cmd,
        "ip pim drpriority (0-4294967295)",
@@ -9140,6 +9153,7 @@ void pim_cmd_init(void)
        install_element(INTERFACE_NODE, &interface_ip_igmp_proxy_cmd);
        install_element(INTERFACE_NODE, &interface_ip_igmp_limits_cmd);
        install_element(INTERFACE_NODE, &no_interface_ip_igmp_limits_cmd);
+       install_element(INTERFACE_NODE, &interface_ip_igmp_immediate_leave_cmd);
        install_element(INTERFACE_NODE, &interface_ip_pim_activeactive_cmd);
        install_element(INTERFACE_NODE, &interface_ip_pim_ssm_cmd);
        install_element(INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd);
index 0a7993fd27b6a53dd23bb6bdad99e9c6685dadb8..606fda6721269f175412a53d7901d97a39a614ce 100644 (file)
@@ -107,6 +107,9 @@ struct pim_interface {
 
        uint32_t gm_source_limit, gm_group_limit;
 
+       /* IGMPv2 only/MLDv1 only immediate leave */
+       bool gmp_immediate_leave;
+
        int pim_sock_fd;                /* PIM socket file descriptor */
        struct event *t_pim_sock_read;  /* thread for reading PIM socket */
        int64_t pim_sock_creation;      /* timestamp of PIM socket creation */
index 7cb168dc5dfe5c7deb3018649ee28f0c59acdf9b..2de2b32688775b153b0659c845317e20eb692176 100644 (file)
@@ -728,9 +728,25 @@ static void toin_incl(struct gm_group *group, int num_sources,
 static void toin_excl(struct gm_group *group, int num_sources,
                      struct in_addr *sources)
 {
+       struct listnode *src_node, *src_next;
+       struct pim_interface *pim_ifp = group->interface->info;
        int num_sources_tosend;
        int i;
 
+       if (group->igmp_version == 2 && pim_ifp->gmp_immediate_leave) {
+               struct gm_source *src;
+
+               if (PIM_DEBUG_GM_TRACE)
+                       zlog_debug("IGMP(v2) Immediate-leave group %pI4 on %s", &group->group_addr,
+                                  group->interface->name);
+
+               igmp_group_timer_on(group, 0, group->interface->name);
+
+               for (ALL_LIST_ELEMENTS(group->group_source_list, src_node, src_next, src))
+                       igmp_source_delete(src);
+               return;
+       }
+
        /* Set SEND flag for X (sources with timer > 0) */
        num_sources_tosend = source_mark_send_flag_by_timer(group);
 
@@ -1496,7 +1512,9 @@ void igmp_group_timer_lower_to_lmqt(struct gm_group *group)
        pim_ifp = ifp->info;
        ifname = ifp->name;
 
-       lmqi_dsec = pim_ifp->gm_specific_query_max_response_time_dsec;
+       lmqi_dsec = pim_ifp->gmp_immediate_leave
+                           ? 0
+                           : pim_ifp->gm_specific_query_max_response_time_dsec;
        lmqc = pim_ifp->gm_last_member_query_count;
        lmqt_msec = PIM_IGMP_LMQT_MSEC(
                lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */
@@ -1531,7 +1549,9 @@ void igmp_source_timer_lower_to_lmqt(struct gm_source *source)
        pim_ifp = ifp->info;
        ifname = ifp->name;
 
-       lmqi_dsec = pim_ifp->gm_specific_query_max_response_time_dsec;
+       lmqi_dsec = pim_ifp->gmp_immediate_leave
+                           ? 0
+                           : pim_ifp->gm_specific_query_max_response_time_dsec;
        lmqc = pim_ifp->gm_last_member_query_count;
        lmqt_msec = PIM_IGMP_LMQT_MSEC(
                lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */
index 62c5d531d91279c4e0f386ab7796af8cb4073ebe..3cd5c0f4e586e4a2a8d9bacb9bc844c74aa15dc1 100644 (file)
@@ -743,7 +743,13 @@ const struct frr_yang_module_info frr_gmp_info = {
                                .modify = lib_interface_gmp_address_family_proxy_modify,
                        }
                },
-{
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/immediate-leave",
+                       .cbs = {
+                               .modify = lib_interface_gmp_immediate_leave_modify,
+                       }
+               },
+               {
                        .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group",
                        .cbs = {
                                .create = lib_interface_gmp_address_family_static_group_create,
index 1656313fc240f51153985db0d3ed7a522bb3f6fd..ce7b5e43af3cb1039567079a859cd3b9cdfb4783 100644 (file)
@@ -289,6 +289,7 @@ int lib_interface_gmp_address_family_static_group_destroy(
                struct nb_cb_destroy_args *args);
 int lib_interface_gm_max_sources_modify(struct nb_cb_modify_args *args);
 int lib_interface_gm_max_groups_modify(struct nb_cb_modify_args *args);
+int lib_interface_gmp_immediate_leave_modify(struct nb_cb_modify_args *args);
 
 /*
  * Callback registered with routing_nb lib to validate only
index c9266966100ded8f971a76e05532f53322d79c0c..d671ea3b65125b649bcbfc960e26d4d22939922f 100644 (file)
@@ -4492,6 +4492,29 @@ int lib_interface_gmp_address_family_robustness_variable_modify(
        return NB_OK;
 }
 
+/*
+ * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/immediate-leave
+ */
+int lib_interface_gmp_immediate_leave_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_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               ifp = nb_running_get_entry(args->dnode, NULL, true);
+               pim_ifp = ifp->info;
+               pim_ifp->gmp_immediate_leave = yang_dnode_get_bool(args->dnode, NULL);
+               break;
+       }
+
+       return NB_OK;
+}
+
 /*
  * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/proxy
  */
index 64750a22f6d80a903020b4dbc1727c2b7091095d..b2525998a6f135364cdff231311b2435df004bf8 100644 (file)
@@ -471,6 +471,12 @@ int pim_config_write(struct vty *vty, int writes, struct interface *ifp,
                ++writes;
        }
 
+       /* IF ip/ipv6 igmp/mld immediate-leave */
+       if (pim_ifp->gmp_immediate_leave) {
+               vty_out(vty, " " PIM_AF_NAME " " GM_AF_DBG " immediate-leave\n");
+               ++writes;
+       }
+
        /* IF ip pim drpriority */
        if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) {
                vty_out(vty, " " PIM_AF_NAME " pim drpriority %u\n",
index 26b19501f9517d33c587eb713d1a9fc477d12eca..3843c88cff4113282cd0e130f6d1c25672c42c33 100644 (file)
@@ -186,6 +186,14 @@ module frr-gmp {
       }
     }
 
+    leaf immediate-leave {
+      type boolean;
+      default "false";
+      description
+        "Immediately drop group memberships on receiving IGMPv2/MLDv1 Leave.
+         Has no effect when IGMPv3/MLDv2 is in use.";
+    }
+
     list static-group {
       key "group-addr source-addr";
       description