]> git.puffer.fish Git - matthieu/frr.git/commitdiff
ospf6d: Handle Premature Aging of LSAs
authorChirag Shah <chirag@cumulusnetworks.com>
Fri, 26 Jan 2018 22:53:43 +0000 (14:53 -0800)
committerChirag Shah <chirag@cumulusnetworks.com>
Thu, 15 Feb 2018 01:37:34 +0000 (17:37 -0800)
RFC 2328 (14.1) Premature aging of LSAs from
routing domain :
When ospf6d is going away (router going down),
send MAXAGEd self originated LSAs to all
neighbors in routing domain to trigger
Premature aging to remove from resepective LSDBs.

Neighbor Router Reboot:
Upon receiving Self-originate MAXAGEd LSA, simply
discard, Current copy could be non maxaged latest.

For neighbor advertised LSA's (current copy in LSDB)
is set to MAXAGE but received new LSA with Non-MAXAGE
(with current age), discard the current MAXAGE LSA,
Send latest copy of LSA to neighbors and update the
LSDB with new LSA.

When a neighbor transition to FULL, trigger AS-External
LSAs update from external LSDB to new neighbor.

Testing:
R1 ---- DUT --- R5
| \
R2 R3
|
R4

Area 1: R5 and DUT
Area 0: DUT, R1, R2, R3
Area 2: R2 R4

Add IPv6 static routes at R5
Redistribute kernel routes at R5,
Validate routes at R4, redistributed via backbone
to area 2.
Stop n start frr.service at R5 and validated
MAXAGE LSAs then recent age LSAs in Database at DUT-R4.
Validated external routes installed DUT to R4.

Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
13 files changed:
ospf6d/ospf6_asbr.c
ospf6d/ospf6_flood.c
ospf6d/ospf6_flood.h
ospf6d/ospf6_interface.c
ospf6d/ospf6_interface.h
ospf6d/ospf6_intra.h
ospf6d/ospf6_lsa.c
ospf6d/ospf6_lsa.h
ospf6d/ospf6_lsdb.c
ospf6d/ospf6_message.c
ospf6d/ospf6_neighbor.c
ospf6d/ospf6_top.c
ospf6d/ospf6_top.h

index 02f8eb0b09ca6f2cd1b7e7accab7fb4d4fe1b497..11f9e7c7b6e4dfc2dfcdde6268a4a96e1d596525 100644 (file)
@@ -148,6 +148,32 @@ static void ospf6_as_external_lsa_originate(struct ospf6_route *route)
        ospf6_lsa_originate_process(lsa, ospf6);
 }
 
+int ospf6_orig_as_external_lsa(struct thread *thread)
+{
+       struct ospf6_interface *oi;
+       struct ospf6_lsa *lsa;
+       uint32_t type, adv_router;
+
+       oi = (struct ospf6_interface *)THREAD_ARG(thread);
+       oi->thread_as_extern_lsa = NULL;
+
+       if (oi->state == OSPF6_INTERFACE_DOWN)
+               return 0;
+
+       type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+       adv_router = oi->area->ospf6->router_id;
+       for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, adv_router, lsa)) {
+               if (IS_OSPF6_DEBUG_ASBR)
+                       zlog_debug("%s: Send update of AS-External LSA %s seq 0x%x",
+                                  __PRETTY_FUNCTION__, lsa->name,
+                                  ntohl(lsa->header->seqnum));
+
+               ospf6_flood_interface(NULL, lsa, oi);
+       }
+
+       return 0;
+}
+
 static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa)
 {
        struct ospf6_as_external_lsa *external;
index 42716fbc7fda9a65617449007345be013677381b..17733d6099fc257e0a3effaf295b1f1df07b8616 100644 (file)
@@ -192,10 +192,6 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
        struct timeval now;
        struct ospf6_lsa *old;
 
-       if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type)
-           || IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type))
-               zlog_debug("Install LSA: %s", lsa->name);
-
        /* Remove the old instance from all neighbors' Link state
           retransmission list (RFC2328 13.2 last paragraph) */
        old = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
@@ -237,6 +233,13 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
                ospf6_lsa_checksum(lsa->header);
        }
 
+       if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type)
+           || IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type))
+               zlog_debug("%s Install LSA: %s age %d seqnum %x in LSDB.",
+                          __PRETTY_FUNCTION__, lsa->name,
+                          ntohs(lsa->header->age),
+                          ntohl(lsa->header->seqnum));
+
        /* actually install */
        lsa->installed = now;
        ospf6_lsdb_add(lsa, lsa->lsdb);
@@ -246,7 +249,7 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
 
 /* RFC2740 section 3.5.2. Sending Link State Update packets */
 /* RFC2328 section 13.3 Next step in the flooding procedure */
-static void ospf6_flood_interface(struct ospf6_neighbor *from,
+void ospf6_flood_interface(struct ospf6_neighbor *from,
                                  struct ospf6_lsa *lsa,
                                  struct ospf6_interface *oi)
 {
@@ -343,15 +346,24 @@ static void ospf6_flood_interface(struct ospf6_neighbor *from,
                        continue;
                }
 
-               /* (d) add retrans-list, schedule retransmission */
-               if (is_debug)
-                       zlog_debug("Add retrans-list of this neighbor");
-               ospf6_increment_retrans_count(lsa);
-               ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list);
-               thread_add_timer(master, ospf6_lsupdate_send_neighbor, on,
-                                on->ospf6_if->rxmt_interval,
-                                &on->thread_send_lsupdate);
-               retrans_added++;
+               if (ospf6->inst_shutdown) {
+                       if (is_debug)
+                               zlog_debug("%s: Send LSA %s (age %d) update now",
+                                          __PRETTY_FUNCTION__, lsa->name,
+                                          ntohs(lsa->header->age));
+                       ospf6_lsupdate_send_neighbor_now(on, lsa);
+                       continue;
+               } else {
+                       /* (d) add retrans-list, schedule retransmission */
+                       if (is_debug)
+                               zlog_debug("Add retrans-list of this neighbor");
+                       ospf6_increment_retrans_count(lsa);
+                       ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list);
+                       thread_add_timer(master, ospf6_lsupdate_send_neighbor,
+                                        on, on->ospf6_if->rxmt_interval,
+                                        &on->thread_send_lsupdate);
+                       retrans_added++;
+               }
        }
 
        /* (2) examin next interface if not added to retrans-list */
@@ -806,6 +818,17 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
                                zlog_debug("Received is duplicated LSA");
                        SET_FLAG(new->flag, OSPF6_LSA_DUPLICATE);
                }
+               if (old->header->adv_router ==
+                   from->ospf6_if->area->ospf6->router_id
+                   && OSPF6_LSA_IS_MAXAGE(new)) {
+                       ospf6_acknowledge_lsa(new, ismore_recent, from);
+                       ospf6_lsa_delete(new);
+                       if (is_debug)
+                               zlog_debug("%s: Received is self orig MAXAGE LSA %s, discard (ismore_recent %d)",
+                                          __PRETTY_FUNCTION__, old->name,
+                                          ismore_recent);
+                       return;
+               }
        }
 
        /* if no database copy or received is more recent */
@@ -959,12 +982,34 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
                                        "Send back directly and then discard");
                        }
 
+                       /* Neighbor router sent recent age for LSA,
+                        * Router could be restarted while current copy is
+                        * MAXAGEd and not removed.*/
+                       if (OSPF6_LSA_IS_MAXAGE(old) &&
+                           !OSPF6_LSA_IS_MAXAGE(new)) {
+
+                               if (is_debug)
+                                       zlog_debug("%s: Current copy of LSA %s is MAXAGE, but new has recent Age.",
+                                                  old->name,
+                                          __PRETTY_FUNCTION__);
+
+                               ospf6_lsa_purge(old);
+                               if (new->header->adv_router
+                                               != from->ospf6_if->area->
+                                                       ospf6->router_id)
+                                       ospf6_flood(from, new);
+
+                               ospf6_install_lsa(new);
+                               return;
+                       }
+
                        /* XXX, MinLSArrival check !? RFC 2328 13 (8) */
 
                        ospf6_lsdb_add(ospf6_lsa_copy(old),
                                       from->lsupdate_list);
                        thread_add_event(master, ospf6_lsupdate_send_neighbor,
                                         from, 0, &from->thread_send_lsupdate);
+
                        ospf6_lsa_delete(new);
                        return;
                }
@@ -972,7 +1017,6 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
        }
 }
 
-
 DEFUN (debug_ospf6_flooding,
        debug_ospf6_flooding_cmd,
        "debug ospf6 flooding",
index 610eefc803b43047e1b21901692ff7bb3dc3b647..f5d33e2843aa3269a24e56c0fd6f20aab0ccb15b 100644 (file)
@@ -58,5 +58,10 @@ extern void ospf6_install_lsa(struct ospf6_lsa *lsa);
 
 extern int config_write_ospf6_debug_flood(struct vty *vty);
 extern void install_element_ospf6_debug_flood(void);
+extern void ospf6_flood_interface(struct ospf6_neighbor *from,
+                                 struct ospf6_lsa *lsa,
+                                 struct ospf6_interface *oi);
+extern int ospf6_lsupdate_send_neighbor_now(struct ospf6_neighbor *on,
+                                           struct ospf6_lsa *lsa);
 
 #endif /* OSPF6_FLOOD_H */
index fc6c46c7e75d417f87dc199198fcc734acd77d45..5eaf6177025321e1928380b2d8dbdc6bd32dab8e 100644 (file)
@@ -301,6 +301,7 @@ void ospf6_interface_disable(struct ospf6_interface *oi)
        THREAD_OFF(oi->thread_network_lsa);
        THREAD_OFF(oi->thread_link_lsa);
        THREAD_OFF(oi->thread_intra_prefix_lsa);
+       THREAD_OFF(oi->thread_as_extern_lsa);
 }
 
 static struct in6_addr *
@@ -532,6 +533,7 @@ static void ospf6_interface_state_change(u_char next_state,
                OSPF6_NETWORK_LSA_EXECUTE(oi);
                OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi);
                OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oi->area);
+               OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi);
        } else if (prev_state == OSPF6_INTERFACE_DR
                   || next_state == OSPF6_INTERFACE_DR) {
                OSPF6_NETWORK_LSA_SCHEDULE(oi);
index b67d9a9f2e6f55167f56159e3d577e3702db3118..9b9952beb68317f6215cd96d844bd60e632f089e 100644 (file)
@@ -108,6 +108,7 @@ struct ospf6_interface {
        struct thread *thread_network_lsa;
        struct thread *thread_link_lsa;
        struct thread *thread_intra_prefix_lsa;
+       struct thread *thread_as_extern_lsa;
 
        struct ospf6_route_table *route_connected;
 
index b511a92005342e302a81ae646d1997825e101b24..2ae17f07004b58472a4b1d5c76fd0e54ef9b10a1 100644 (file)
@@ -185,11 +185,21 @@ struct ospf6_intra_prefix_lsa {
                                0, &(oi)->thread_intra_prefix_lsa);            \
        } while (0)
 
+#define OSPF6_AS_EXTERN_LSA_SCHEDULE(oi)                                      \
+       do {                                                                   \
+               if (!CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE))          \
+                       thread_add_event(                                      \
+                               master,                                        \
+                               ospf6_orig_as_external_lsa, oi,                \
+                               0, &(oi)->thread_as_extern_lsa);               \
+       } while (0)
+
 #define OSPF6_NETWORK_LSA_EXECUTE(oi)                                          \
        do {                                                                   \
                THREAD_OFF((oi)->thread_network_lsa);                          \
                thread_execute(master, ospf6_network_lsa_originate, oi, 0);    \
        } while (0)
+
 #define OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi)                             \
        do {                                                                   \
                THREAD_OFF((oi)->thread_intra_prefix_lsa);                     \
@@ -198,6 +208,11 @@ struct ospf6_intra_prefix_lsa {
                               0);                                             \
        } while (0)
 
+#define OSPF6_AS_EXTERN_LSA_EXECUTE(oi)                                        \
+       do {                                                                   \
+               THREAD_OFF((oi)->thread_as_extern_lsa);                        \
+               thread_execute(master, ospf6_orig_as_external_lsa, oi, 0);     \
+       } while (0)
 
 /* Function Prototypes */
 extern char *ospf6_router_lsdesc_lookup(u_char type, u_int32_t interface_id,
@@ -215,7 +230,7 @@ extern int ospf6_intra_prefix_lsa_originate_transit(struct thread *);
 extern int ospf6_intra_prefix_lsa_originate_stub(struct thread *);
 extern void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa);
 extern void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa);
-
+extern int ospf6_orig_as_external_lsa(struct thread *thread);
 extern void ospf6_intra_route_calculation(struct ospf6_area *oa);
 extern void ospf6_intra_brouter_calculation(struct ospf6_area *oa);
 
index cca4616c163323b6385d967e5d93d2639c7770e9..4a1ba992e3de38770ff0d7dd805389acfdcc492f 100644 (file)
@@ -706,6 +706,37 @@ int ospf6_lsa_refresh(struct thread *thread)
        return 0;
 }
 
+void ospf6_flush_self_originated_lsas_now(void)
+{
+       struct listnode *node;
+       struct ospf6_area *oa;
+       struct ospf6_lsa *lsa;
+       const struct route_node *end = NULL;
+       uint32_t type, adv_router;
+
+       ospf6->inst_shutdown = 1;
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
+               end = ospf6_lsdb_head(oa->lsdb_self, 0, 0,
+                                     ospf6->router_id, &lsa);
+               while (lsa) {
+                       /* RFC 2328 (14.1):  Set MAXAGE */
+                       lsa->header->age = htons(OSPF_LSA_MAXAGE);
+                       /* Flood MAXAGE LSA*/
+                       ospf6_flood(NULL, lsa);
+
+                       lsa = ospf6_lsdb_next(end, lsa);
+               }
+       }
+
+       type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+       adv_router = ospf6->router_id;
+       for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, adv_router, lsa)) {
+               /* RFC 2328 (14.1):  Set MAXAGE */
+               lsa->header->age = htons(OSPF_LSA_MAXAGE);
+               ospf6_flood(NULL, lsa);
+       }
+}
 
 /* Fletcher Checksum -- Refer to RFC1008. */
 
index db446a328734f4ec95aec29afbbea974f01252bb..369b381faaed5f131b35a1a641ac4952c36624d9 100644 (file)
@@ -253,5 +253,6 @@ extern void ospf6_lsa_terminate(void);
 extern int config_write_ospf6_debug_lsa(struct vty *vty);
 extern void install_element_ospf6_debug_lsa(void);
 extern void ospf6_lsa_age_set(struct ospf6_lsa *lsa);
+extern void ospf6_flush_self_originated_lsas_now(void);
 
 #endif /* OSPF6_LSA_H */
index 418f858a3256a6684b240248a00d404289864fd7..152702391b6a3891dc92cf3318da419829a2c15c 100644 (file)
@@ -334,6 +334,7 @@ int ospf6_lsdb_maxage_remover(struct ospf6_lsdb *lsdb)
                }
                if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type))
                        zlog_debug("Remove MaxAge %s", lsa->name);
+
                if (CHECK_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED)) {
                        UNSET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED);
                        /*
index d76438ea5033aae81e6c89259946a5bbfdc7bd09..fe74ddc982ec00eab1310f27411a8db299080325 100644 (file)
@@ -2163,6 +2163,40 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread)
        return 0;
 }
 
+int ospf6_lsupdate_send_neighbor_now(struct ospf6_neighbor *on,
+                                    struct ospf6_lsa *lsa)
+{
+       struct ospf6_header *oh;
+       struct ospf6_lsupdate *lsupdate;
+       u_char *p;
+       int lsa_cnt = 0;
+
+       memset(sendbuf, 0, iobuflen);
+       oh = (struct ospf6_header *)sendbuf;
+       lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
+                                            + sizeof(struct ospf6_header));
+
+       p = (u_char *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
+       ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
+       memcpy(p, lsa->header, OSPF6_LSA_SIZE(lsa->header));
+       p += OSPF6_LSA_SIZE(lsa->header);
+       lsa_cnt++;
+
+       oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
+       oh->length = htons(p - sendbuf);
+       lsupdate->lsa_number = htonl(lsa_cnt);
+
+       if (IS_OSPF6_DEBUG_FLOODING ||
+           IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND))
+               zlog_debug("%s: Send lsupdate with lsa %s (age %u)",
+                  __PRETTY_FUNCTION__, lsa->name,
+                  ntohs(lsa->header->age));
+
+       ospf6_send_lsupdate(on, NULL, oh);
+
+       return 0;
+}
+
 int ospf6_lsupdate_send_interface(struct thread *thread)
 {
        struct ospf6_interface *oi;
index bde89f54a604b1be465f297c4d6caefec7d75d80..35d0b0a6462918af0861e457f05280b1947abb20 100644 (file)
@@ -189,6 +189,11 @@ static void ospf6_neighbor_state_change(u_char next_state,
                        OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(on->ospf6_if);
                }
                OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(on->ospf6_if->area);
+
+               if (prev_state == OSPF6_NEIGHBOR_LOADING &&
+                   next_state == OSPF6_NEIGHBOR_FULL) {
+                       OSPF6_AS_EXTERN_LSA_SCHEDULE(on->ospf6_if);
+               }
        }
 
        if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE
index 749873bcf8c753dae2232b3d2125e0b97df36b3c..db39420548c1785792bdca46b2ced064e0224978 100644 (file)
@@ -180,6 +180,8 @@ void ospf6_delete(struct ospf6 *o)
        struct ospf6_area *oa;
 
        QOBJ_UNREG(o);
+
+       ospf6_flush_self_originated_lsas_now();
        ospf6_disable(ospf6);
 
        for (ALL_LIST_ELEMENTS(o->area_list, node, nnode, oa))
index b39c25ba84c46472f9d4ba5dbd1e446a3f6bb830..8f99cc33f42a9a5aae5dc09719b4aedf6285f973 100644 (file)
@@ -94,6 +94,10 @@ struct ospf6 {
 
        struct route_table *distance_table;
 
+       /* Used during ospf instance going down send LSDB
+        * update to neighbors immediatly */
+       uint8_t inst_shutdown;
+
        QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(ospf6)