summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/user/ipv6.rst14
-rw-r--r--zebra/interface.c4
-rw-r--r--zebra/interface.h7
-rw-r--r--zebra/rtadv.c87
-rw-r--r--zebra/rtadv.h5
5 files changed, 111 insertions, 6 deletions
diff --git a/doc/user/ipv6.rst b/doc/user/ipv6.rst
index cc8fd18fee..f3f064b850 100644
--- a/doc/user/ipv6.rst
+++ b/doc/user/ipv6.rst
@@ -77,6 +77,20 @@ Router Advertisement
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)]
.. clicmd:: [no] ipv6 nd ra-lifetime [(0-9000)]
diff --git a/zebra/interface.c b/zebra/interface.c
index eea80652e5..64a7e9abc0 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -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;
}
diff --git a/zebra/interface.h b/zebra/interface.h
index 78ccbae623..b7e90a0c31 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -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 */
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 4903455a2b..f51c199f6b 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -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);
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index d692ef2417..f9bd2b1d39 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -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