summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zebra/interface.c2
-rw-r--r--zebra/main.c3
-rw-r--r--zebra/rtadv.c48
-rw-r--r--zebra/rtadv.h2
4 files changed, 50 insertions, 5 deletions
diff --git a/zebra/interface.c b/zebra/interface.c
index 20b05dfb32..bcb833b8d8 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -1977,6 +1977,8 @@ DEFUN (shutdown_if,
struct zebra_if *if_data;
if (ifp->ifindex != IFINDEX_INTERNAL) {
+ /* send RA lifetime of 0 before stopping. rfc4861/6.2.5 */
+ rtadv_stop_ra(ifp);
ret = if_unset_flags(ifp, IFF_UP);
if (ret < 0) {
vty_out(vty, "Can't shutdown interface\n");
diff --git a/zebra/main.c b/zebra/main.c
index 731c4e1614..e0408c0bca 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -145,6 +145,9 @@ static void sigint(void)
atomic_store_explicit(&zrouter.in_shutdown, true,
memory_order_relaxed);
+ /* send RA lifetime of 0 before stopping. rfc4861/6.2.5 */
+ rtadv_stop_ra_all();
+
frr_early_fini();
zebra_dplane_pre_finish();
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 0adf654aaf..5dd6012f62 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -166,7 +166,8 @@ static int rtadv_recv_packet(struct zebra_vrf *zvrf, int sock, uint8_t *buf,
#define RTADV_MSG_SIZE 4096
/* Send router advertisement packet. */
-static void rtadv_send_packet(int sock, struct interface *ifp)
+static void rtadv_send_packet(int sock, struct interface *ifp,
+ ipv6_nd_suppress_ra_status stop)
{
struct msghdr msg;
struct iovec iov;
@@ -252,7 +253,10 @@ static void rtadv_send_packet(int sock, struct interface *ifp)
zif->rtadv.AdvDefaultLifetime != -1
? zif->rtadv.AdvDefaultLifetime
: MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval);
- rtadv->nd_ra_router_lifetime = htons(pkt_RouterLifetime);
+
+ /* send RA lifetime of 0 before stopping. rfc4861/6.2.5 */
+ rtadv->nd_ra_router_lifetime =
+ (stop == RA_SUPPRESS) ? htons(0) : htons(pkt_RouterLifetime);
rtadv->nd_ra_reachable = htonl(zif->rtadv.AdvReachableTime);
rtadv->nd_ra_retransmit = htonl(0);
@@ -512,7 +516,7 @@ static int rtadv_timer(struct thread *thread)
ifp->name);
rtadv_send_packet(rtadv_get_socket(zvrf),
- ifp);
+ ifp, RA_ENABLE);
} else {
zif->rtadv.AdvIntervalTimer -= period;
if (zif->rtadv.AdvIntervalTimer <= 0) {
@@ -526,7 +530,7 @@ static int rtadv_timer(struct thread *thread)
.MaxRtrAdvInterval;
rtadv_send_packet(
rtadv_get_socket(zvrf),
- ifp);
+ ifp, RA_ENABLE);
}
}
}
@@ -556,7 +560,7 @@ static void rtadv_process_solicit(struct interface *ifp)
if ((zif->rtadv.UseFastRexmit)
|| (zif->rtadv.AdvIntervalTimer <=
(zif->rtadv.MaxRtrAdvInterval - MIN_DELAY_BETWEEN_RAS))) {
- rtadv_send_packet(rtadv_get_socket(zvrf), ifp);
+ rtadv_send_packet(rtadv_get_socket(zvrf), ifp, RA_ENABLE);
zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
} else
zif->rtadv.AdvIntervalTimer = MIN_DELAY_BETWEEN_RAS;
@@ -911,6 +915,8 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp,
if (status == RA_SUPPRESS) {
/* RA is currently enabled */
if (zif->rtadv.AdvSendAdvertisements) {
+ rtadv_send_packet(rtadv_get_socket(zvrf), ifp,
+ RA_SUPPRESS);
zif->rtadv.AdvSendAdvertisements = 0;
zif->rtadv.AdvIntervalTimer = 0;
zvrf->rtadv.adv_if_count--;
@@ -1012,6 +1018,38 @@ stream_failure:
return;
}
+/*
+ * send router lifetime value of zero in RAs on this interface since we're
+ * ceasing to advertise and want to let our neighbors know.
+ * RFC 4861 secion 6.2.5
+ */
+void rtadv_stop_ra(struct interface *ifp)
+{
+ struct zebra_if *zif;
+ struct zebra_vrf *zvrf;
+
+ zif = ifp->info;
+ zvrf = vrf_info_lookup(ifp->vrf_id);
+
+ if (zif->rtadv.AdvSendAdvertisements)
+ rtadv_send_packet(rtadv_get_socket(zvrf), ifp, RA_SUPPRESS);
+}
+
+/*
+ * send router lifetime value of zero in RAs on all interfaces since we're
+ * ceasing to advertise globally and want to let all of our neighbors know
+ * RFC 4861 secion 6.2.5
+ */
+void rtadv_stop_ra_all(void)
+{
+ struct vrf *vrf;
+ struct interface *ifp;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
+ FOR_ALL_INTERFACES (vrf, ifp)
+ rtadv_stop_ra(ifp);
+}
+
void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS)
{
zebra_interface_radv_set(client, hdr, msg, zvrf, 0);
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index 409959d08d..63cec94434 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -140,6 +140,8 @@ typedef enum {
extern void rtadv_init(struct zebra_vrf *zvrf);
extern void rtadv_terminate(struct zebra_vrf *zvrf);
+extern void rtadv_stop_ra(struct interface *ifp);
+extern void rtadv_stop_ra_all(void);
extern void rtadv_cmd_init(void);
extern void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS);
extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS);