]> git.proxmox.com Git - mirror_frr.git/blobdiff - isisd/isis_lsp.c
isisd: Add support for RFC6119 (IPv6 TE in IS-IS)
[mirror_frr.git] / isisd / isis_lsp.c
index d610495de683bd24920843521584073e646f058a..94353a5bc893df42fee679f729fc1032cf99ae30 100644 (file)
@@ -60,6 +60,8 @@
 #include "isisd/isis_tx_queue.h"
 #include "isisd/isis_nb.h"
 
+DEFINE_MTYPE_STATIC(ISISD, ISIS_LSP, "ISIS LSP");
+
 static int lsp_refresh(struct thread *thread);
 static int lsp_l1_refresh_pseudo(struct thread *thread);
 static int lsp_l2_refresh_pseudo(struct thread *thread);
@@ -399,93 +401,77 @@ static void lsp_seqno_update(struct isis_lsp *lsp0)
        return;
 }
 
-static bool isis_level2_adj_up(struct isis_area *curr_area)
+bool isis_level2_adj_up(struct isis_area *area)
 {
        struct listnode *node, *cnode;
        struct isis_circuit *circuit;
        struct list *adjdb;
        struct isis_adjacency *adj;
-       struct isis *isis = curr_area->isis;
-       struct isis_area *area;
 
-       /* lookup for a Level2 adjacency up in another area */
-       for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
-               if (area->area_tag
-                   && strcmp(area->area_tag, curr_area->area_tag) == 0)
-                       continue;
+       if (area->is_type == IS_LEVEL_1)
+               return false;
 
-               for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) {
-                       if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
-                               adjdb = circuit->u.bc.adjdb[1];
-                               if (!adjdb || !adjdb->count)
-                                       continue;
+       for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) {
+               if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+                       adjdb = circuit->u.bc.adjdb[1];
+                       if (!adjdb || !adjdb->count)
+                               continue;
 
-                               for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
-                                       if (adj->level != ISIS_ADJ_LEVEL1
-                                           && adj->adj_state == ISIS_ADJ_UP)
-                                               return true;
-                               }
-                       } else if (circuit->circ_type == CIRCUIT_T_P2P
-                                  && circuit->u.p2p.neighbor) {
-                               adj = circuit->u.p2p.neighbor;
+                       for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
                                if (adj->level != ISIS_ADJ_LEVEL1
                                    && adj->adj_state == ISIS_ADJ_UP)
                                        return true;
                        }
+               } else if (circuit->circ_type == CIRCUIT_T_P2P
+                          && circuit->u.p2p.neighbor) {
+                       adj = circuit->u.p2p.neighbor;
+                       if (adj->level != ISIS_ADJ_LEVEL1
+                           && adj->adj_state == ISIS_ADJ_UP)
+                               return true;
                }
        }
+
        return false;
 }
 
-static void isis_reset_attach_bit(struct isis_adjacency *curr_adj)
+static void isis_reset_attach_bit(struct isis_adjacency *adj)
 {
-       struct listnode *node;
-       struct isis_area *curr_area = curr_adj->circuit->area;
-       struct isis *isis = curr_area->isis;
-       struct isis_area *area;
+       struct isis_area *area = adj->circuit->area;
        struct lspdb_head *head;
        struct isis_lsp *lsp;
        uint8_t lspid[ISIS_SYS_ID_LEN + 2];
 
-       /* If new adjaceny is up and area is level2 or level1and2 verify if
-        * we have LSPs in other areas that should now set the attach bit.
-        *
-        * If adjacenty is down, verify if we no longer have another level2
-        * or level1and2 areas so that we should now remove the attach bit.
+       /*
+        * If an L2 adjacency changed its state in L-1-2 area, we have to:
+        * - set the attached bit in L1 LSPs if it's the first L2 adjacency
+        * - remove the attached bit in L1 LSPs if it's the last L2 adjacency
         */
-       if (curr_area->is_type == IS_LEVEL_1)
-               return;
 
-       for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
-               if (area->area_tag
-                   && strcmp(area->area_tag, curr_area->area_tag) == 0)
-                       continue;
+       if (area->is_type != IS_LEVEL_1_AND_2 || adj->level == ISIS_ADJ_LEVEL1)
+               return;
 
-               if (!area->attached_bit_send)
-                       continue;
+       if (!area->attached_bit_send)
+               return;
 
-               head = &area->lspdb[IS_LEVEL_1 - 1];
-               memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
-               memcpy(lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
+       head = &area->lspdb[IS_LEVEL_1 - 1];
+       memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
+       memcpy(lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
 
-               lsp = lsp_search(head, lspid);
-               if (!lsp)
-                       continue;
+       lsp = lsp_search(head, lspid);
+       if (!lsp)
+               return;
 
-               if (curr_adj->adj_state == ISIS_ADJ_UP
-                   && !(lsp->hdr.lsp_bits & LSPBIT_ATT)) {
-                       sched_debug(
-                               "ISIS (%s): adj going up regenerate lsp-bits",
-                               area->area_tag);
-                       lsp_regenerate_schedule(area, IS_LEVEL_1, 0);
-               } else if (curr_adj->adj_state == ISIS_ADJ_DOWN
-                          && lsp->hdr.lsp_bits & LSPBIT_ATT
-                          && !isis_level2_adj_up(area)) {
-                       sched_debug(
-                               "ISIS (%s): adj going down regenerate lsp-bits",
-                               area->area_tag);
-                       lsp_regenerate_schedule(area, IS_LEVEL_1, 0);
-               }
+       if (adj->adj_state == ISIS_ADJ_UP
+           && !(lsp->hdr.lsp_bits & LSPBIT_ATT)) {
+               sched_debug("ISIS (%s): adj going up regenerate lsp-bits",
+                           area->area_tag);
+               lsp_regenerate_schedule(area, IS_LEVEL_1, 0);
+       } else if (adj->adj_state == ISIS_ADJ_DOWN
+                  && (lsp->hdr.lsp_bits & LSPBIT_ATT)
+                  && !isis_level2_adj_up(area)) {
+               sched_debug("ISIS (%s): adj going down regenerate lsp-bits",
+                           area->area_tag);
+               lsp_regenerate_schedule(area, IS_LEVEL_1, 0);
        }
 }
 
@@ -493,7 +479,7 @@ static uint8_t lsp_bits_generate(int level, int overload_bit, int attached_bit,
                                 struct isis_area *area)
 {
        uint8_t lsp_bits = 0;
-       if (level == IS_LEVEL_1)
+       if (area->is_type == IS_LEVEL_1)
                lsp_bits = IS_LEVEL_1;
        else
                lsp_bits = IS_LEVEL_1_AND_2;
@@ -531,11 +517,11 @@ static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
 
        if (area->dynhostname && lsp->tlvs->hostname
            && lsp->hdr.rem_lifetime) {
-               isis_dynhn_insert(lsp->hdr.lsp_id, lsp->tlvs->hostname,
-                                 (lsp->hdr.lsp_bits & LSPBIT_IST)
-                                                 == IS_LEVEL_1_AND_2
-                                         ? IS_LEVEL_2
-                                         : IS_LEVEL_1);
+               isis_dynhn_insert(
+                       area->isis, lsp->hdr.lsp_id, lsp->tlvs->hostname,
+                       (lsp->hdr.lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2
+                               ? IS_LEVEL_2
+                               : IS_LEVEL_1);
        }
 
        return;
@@ -655,7 +641,7 @@ void lsp_insert(struct lspdb_head *head, struct isis_lsp *lsp)
 }
 
 /*
- * Build a list of LSPs with non-zero ht bounded by start and stop ids
+ * Build a list of LSPs with non-zero ht and seqno bounded by start and stop ids
  */
 void lsp_build_list_nonzero_ht(struct lspdb_head *head, const uint8_t *start_id,
                               const uint8_t *stop_id, struct list *list)
@@ -671,7 +657,7 @@ void lsp_build_list_nonzero_ht(struct lspdb_head *head, const uint8_t *start_id,
                           ISIS_SYS_ID_LEN + 2) > 0)
                        break;
 
-               if (lsp->hdr.rem_lifetime)
+               if (lsp->hdr.rem_lifetime && lsp->hdr.seqno)
                        listnode_add(list, lsp);
        }
 }
@@ -698,7 +684,7 @@ void lspid_print(uint8_t *lsp_id, char *dest, size_t dest_len, char dynhost,
        char id[SYSID_STRLEN];
 
        if (dynhost)
-               dyn = dynhn_find_by_id(lsp_id);
+               dyn = dynhn_find_by_id(isis, lsp_id);
        else
                dyn = NULL;
 
@@ -1081,6 +1067,14 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                          area->area_tag);
        }
 
+       if (IS_MPLS_TE(area->mta)
+           && !IN6_IS_ADDR_UNSPECIFIED(&area->mta->router_id_ipv6)) {
+               lsp_debug("ISIS (%s): Adding IPv6 TE Router ID tlv.",
+                         area->area_tag);
+               isis_tlvs_set_te_router_id_ipv6(lsp->tlvs,
+                                               &area->mta->router_id_ipv6);
+       }
+
        lsp_debug("ISIS (%s): Adding circuit specific information.",
                  area->area_tag);
 
@@ -1563,7 +1557,7 @@ int _lsp_regenerate_schedule(struct isis_area *area, int level,
                         */
                        if (area->bfd_signalled_down) {
                                sched_debug(
-                                       "ISIS (%s): Scheduling immediately due to BDF 'down' message.",
+                                       "ISIS (%s): Scheduling immediately due to BFD 'down' message.",
                                        area->area_tag);
                                area->bfd_signalled_down = false;
                                area->bfd_force_spf_refresh = true;
@@ -1615,6 +1609,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
        struct list *adj_list;
        struct listnode *node;
        struct isis_area *area = circuit->area;
+       uint16_t mtid;
 
        lsp_clear_data(lsp);
        lsp->tlvs = isis_alloc_tlvs();
@@ -1644,8 +1639,11 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
                        LSP_PSEUDO_ID(ne_id));
        }
        if (circuit->area->newmetric) {
-               isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST,
-                                            ne_id, 0, NULL);
+               if (area_is_mt(circuit->area))
+                       mtid = ISIS_MT_IPV4_UNICAST;
+               else
+                       mtid = ISIS_MT_DISABLE;
+               isis_tlvs_add_extended_reach(lsp->tlvs, mtid, ne_id, 0, NULL);
                lsp_debug(
                        "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
                        area->area_tag, sysid_print(ne_id),