]> git.proxmox.com Git - mirror_frr.git/commitdiff
zebra: send RA lifetime of 0 before ceasing to advertise RAs
authorDon Slice <dslice@cumulusnetworks.com>
Tue, 3 Dec 2019 14:02:20 +0000 (14:02 +0000)
committerDon Slice <dslice@cumulusnetworks.com>
Tue, 3 Dec 2019 15:46:34 +0000 (15:46 +0000)
Problem reported by testing agency that RFC4861 section 6.2.5
states that a router should send an RA with a lifetime of 0
before ceasing to send RAs on the interface, or when the interace
is shutdown, or the router is shutdown.  This fix adds that capability.

Ticket: CM-27061
Signed-off-by: Don Slice <dslice@cumulusnetworks.com>
zebra/interface.c
zebra/main.c
zebra/rtadv.c
zebra/rtadv.h

index 20b05dfb32b9ace69e79d02b31f3021fd5483f70..bcb833b8d8f019b1ed7532533345b9a5bb2c4e42 100644 (file)
@@ -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");
index 731c4e161400e268fa7bf00cf0d0c04e4737d098..e0408c0bca83e4f7fe2a406a9c3eeabea9672ded 100644 (file)
@@ -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();
index 0adf654aaf72718098c64ba21c5550e3378c5914..5dd6012f6278daa753e7708403374ab1e47a4f40 100644 (file)
@@ -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);
index 409959d08d8f47abf308932ab2f2ba2be0430c37..63cec944341d90ffc9d3ebf7a49eb9831b15f326 100644 (file)
@@ -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);