]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: knob to make ra retransmit interval rfc compliant
authorDon Slice <dslice@cumulusnetworks.com>
Fri, 22 Nov 2019 17:31:29 +0000 (17:31 +0000)
committerDon Slice <dslice@cumulusnetworks.com>
Fri, 22 Nov 2019 18:40:20 +0000 (18:40 +0000)
Problem reported by testing facility that our sending of Router
Advertisements more frequently than once very three seconds is not
compliant with rfc4861. Added a knob to turn off fast retransmits
in order to meet the requirement of the RFC.

Ticket: CM-27063
Signed-off-by: Don Slice <dslice@cumulusnetworks.com>
doc/user/ipv6.rst
zebra/interface.c
zebra/interface.h
zebra/rtadv.c
zebra/rtadv.h

index cc8fd18fee5f8ec46713105294b6a9301cb41087..f3f064b850442c9444f76b5308e49db72789a9ab 100644 (file)
@@ -76,6 +76,20 @@ Router Advertisement
    advertisements from the interface, in milliseconds.
    Default: ``600000``
 
+.. index::
+   single: ipv6 nd ra-fast-retrans
+   single: no ipv6 nd ra-fast-retrans
+.. clicmd:: [no] ipv6 nd ra-fast-retrans
+
+   RFC4861 states that consecutive RA packets should be sent no more
+   frequently than three seconds apart. FRR by default allows faster
+   transmissions of RA packets in order to speed convergence and
+   neighbor establishment, particularly for unnumbered peering.  By
+   turning off ipv6 nd ra-fast-retrans, the implementation is
+   compliant with the RFC at the cost of slower convergence
+   and neighbor establishment.
+   Default: enabled
+
 .. index::
    single: ipv6 nd ra-lifetime (0-9000)
    single: no ipv6 nd ra-lifetime [(0-9000)]
index eea80652e57957e6e2d2a7b2067b0a722721e1f7..64a7e9abc0f418fbaf5424b2ca4f9b340617eab4 100644 (file)
@@ -161,6 +161,7 @@ static int if_zebra_new_hook(struct interface *ifp)
                rtadv->HomeAgentLifetime =
                        -1; /* derive from AdvDefaultLifetime */
                rtadv->AdvIntervalOption = 0;
+               rtadv->UseFastRexmit = true;
                rtadv->DefaultPreference = RTADV_PREF_MEDIUM;
 
                rtadv->AdvPrefixList = list_new();
@@ -1037,7 +1038,8 @@ void if_up(struct interface *ifp)
 #if defined(HAVE_RTADV)
        /* Enable fast tx of RA if enabled && RA interval is not in msecs */
        if (zif->rtadv.AdvSendAdvertisements
-           && (zif->rtadv.MaxRtrAdvInterval >= 1000)) {
+           && (zif->rtadv.MaxRtrAdvInterval >= 1000)
+           && zif->rtadv.UseFastRexmit) {
                zif->rtadv.inFastRexmit = 1;
                zif->rtadv.NumFastReXmitsRemain = RTADV_NUM_FAST_REXMITS;
        }
index 78ccbae6235d96e1320873454bfbc945d0746af7..b7e90a0c31edcbadbb9afd55f6872698fe606855 100644 (file)
@@ -189,6 +189,13 @@ struct rtadvconf {
         */
        struct list *AdvDNSSLList;
 
+       /*
+        * rfc4861 states RAs must be sent at least 3 seconds apart.
+        * We allow faster retransmits to speed up convergence but can
+        * turn that capability off to meet the rfc if needed.
+        */
+       bool UseFastRexmit; /* True if fast rexmits are enabled */
+
        uint8_t inFastRexmit; /* True if we're rexmits faster than usual */
 
        /* Track if RA was configured by BGP or by the Operator or both */
index 4903455a2b9b5a49d35e30cf90fcca2887371b12..f51c199f6b878c5b7f131b1a21aa059998273ace 100644 (file)
@@ -495,7 +495,8 @@ static int rtadv_timer(struct thread *thread)
                        zif = ifp->info;
 
                        if (zif->rtadv.AdvSendAdvertisements) {
-                               if (zif->rtadv.inFastRexmit) {
+                               if (zif->rtadv.inFastRexmit
+                                   && zif->rtadv.UseFastRexmit) {
                                        /* We assume we fast rexmit every sec so
                                         * no
                                         * additional vars */
@@ -535,9 +536,28 @@ static int rtadv_timer(struct thread *thread)
 static void rtadv_process_solicit(struct interface *ifp)
 {
        struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
+       struct zebra_if *zif;
 
        assert(zvrf);
-       rtadv_send_packet(rtadv_get_socket(zvrf), ifp);
+       zif = ifp->info;
+
+       /*
+        * If FastRetransmit is enabled, send the RA immediately.
+        * If not enabled but it has been more than MIN_DELAY_BETWEEN_RAS
+        * (3 seconds) since the last RA was sent, send it now and reset
+        * the timer to start at the max (configured) again.
+        * If not enabled and it is less than 3 seconds since the last
+        * RA packet was sent, set the timer for 3 seconds so the next
+        * one will be sent with a minimum of 3 seconds between RAs.
+        * RFC4861 sec 6.2.6
+        */
+       if ((zif->rtadv.UseFastRexmit)
+           || (zif->rtadv.AdvIntervalTimer <=
+               (zif->rtadv.MaxRtrAdvInterval - MIN_DELAY_BETWEEN_RAS))) {
+               rtadv_send_packet(rtadv_get_socket(zvrf), ifp);
+               zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
+       } else
+               zif->rtadv.AdvIntervalTimer = MIN_DELAY_BETWEEN_RAS;
 }
 
 /*
@@ -904,9 +924,12 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp,
                        zif->rtadv.AdvIntervalTimer = 0;
                        zvrf->rtadv.adv_if_count++;
 
-                       if (zif->rtadv.MaxRtrAdvInterval >= 1000) {
-                               /* Enable Fast RA only when RA interval is in
-                                * secs */
+                       if ((zif->rtadv.MaxRtrAdvInterval >= 1000)
+                           && zif->rtadv.UseFastRexmit) {
+                               /*
+                                * Enable Fast RA only when RA interval is in
+                                * secs and Fast RA retransmit is enabled
+                                */
                                zif->rtadv.inFastRexmit = 1;
                                zif->rtadv.NumFastReXmitsRemain =
                                        RTADV_NUM_FAST_REXMITS;
@@ -996,6 +1019,51 @@ void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS)
        zebra_interface_radv_set(client, hdr, msg, zvrf, 1);
 }
 
+DEFUN (ipv6_nd_ra_fast_retrans,
+       ipv6_nd_ra_fast_retrans_cmd,
+       "ipv6 nd ra-fast-retrans",
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Fast retransmit of RA packets\n")
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct zebra_if *zif = ifp->info;
+
+       if (if_is_loopback(ifp)
+           || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
+               vty_out(vty,
+                       "Cannot configure IPv6 Router Advertisements on this  interface\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       zif->rtadv.UseFastRexmit = true;
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_ra_fast_retrans,
+       no_ipv6_nd_ra_fast_retrans_cmd,
+       "no ipv6 nd ra-fast-retrans",
+       NO_STR
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Fast retransmit of RA packets\n")
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct zebra_if *zif = ifp->info;
+
+       if (if_is_loopback(ifp)
+           || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
+               vty_out(vty,
+                       "Cannot configure IPv6 Router Advertisements on this  interface\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       zif->rtadv.UseFastRexmit = false;
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (ipv6_nd_suppress_ra,
        ipv6_nd_suppress_ra_cmd,
        "ipv6 nd suppress-ra",
@@ -1954,6 +2022,10 @@ static int nd_dump_vty(struct vty *vty, struct interface *ifp)
                                "  ND router advertisements are sent every "
                                "%d seconds\n",
                                interval / 1000);
+               if (!rtadv->UseFastRexmit)
+                       vty_out(vty,
+                               "  ND router advertisements do not use fast retransmit\n");
+
                if (rtadv->AdvDefaultLifetime != -1)
                        vty_out(vty,
                                "  ND router advertisements live for %d seconds\n",
@@ -2025,6 +2097,9 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp)
        if (zif->rtadv.AdvIntervalOption)
                vty_out(vty, " ipv6 nd adv-interval-option\n");
 
+       if (!zif->rtadv.UseFastRexmit)
+               vty_out(vty, " no ipv6 nd ra-fast-retrans\n");
+
        if (zif->rtadv.AdvDefaultLifetime != -1)
                vty_out(vty, " ipv6 nd ra-lifetime %d\n",
                        zif->rtadv.AdvDefaultLifetime);
@@ -2173,6 +2248,8 @@ void rtadv_cmd_init(void)
        hook_register(zebra_if_extra_info, nd_dump_vty);
        hook_register(zebra_if_config_wr, rtadv_config_write);
 
+       install_element(INTERFACE_NODE, &ipv6_nd_ra_fast_retrans_cmd);
+       install_element(INTERFACE_NODE, &no_ipv6_nd_ra_fast_retrans_cmd);
        install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
        install_element(INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
        install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
index d692ef241748fcca6bc2a139b45f44abb4d02d3d..f9bd2b1d391cd228f509bdfab3497f426cfaafe9 100644 (file)
@@ -59,6 +59,11 @@ struct rtadv_prefix {
 #endif
 };
 
+/* RFC4861 minimum delay between RAs  */
+#ifndef MIN_DELAY_BETWEEN_RAS
+#define MIN_DELAY_BETWEEN_RAS        3000
+#endif
+
 /* RFC4584 Extension to Sockets API for Mobile IPv6 */
 
 #ifndef ND_OPT_ADV_INTERVAL