]> git.proxmox.com Git - mirror_frr.git/commitdiff
isisd: Update TLVs processing for TE, RI & SR
authorOlivier Dugeon <olivier.dugeon@orange.com>
Fri, 26 Jul 2019 14:07:39 +0000 (16:07 +0200)
committerOlivier Dugeon <olivier.dugeon@orange.com>
Tue, 17 Sep 2019 15:35:50 +0000 (17:35 +0200)
In preparation to Segment Routing:
 - Update the management of Traffic Engineering subTLVs to the new tlvs parser
 - Add Router Capability TLV 242 as per RFC 4971 & 7981
 - Add Segment Routing subTLVs as per draft-isis-segment-routing-extension-25

Modified files:
 - isis_tlvs.h: add new structure to manage TE subTLVs, TLV 242 & SR subTLVs
 - isis_tlvs.c: add new functions (pack, copy, free, unpack & print) to process
   TE subTLVs, Router Capability TLV and SR subTLVs
 - isis_circuit.[c,h] & isis_lsp.[c,h]: update to new subTLVs & TLV processing
 - isis_te.[c,h]: remove all old TE structures and managment functions,
   and add hook call to set local and remote IP addresses as wellas update TE
   parameters
 - isis_zebra.[c,h]: add hook call when new interface is up
 - isis_mt.[c,h], isis_pdu.c & isis_northbound.c: adjust to new TE subTLVs
 - tests/isisd/test_fuzz_isis_tlv_tests.h.gz: adapte fuuz tests to new parser

Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
15 files changed:
isisd/isis_circuit.c
isisd/isis_circuit.h
isisd/isis_lsp.c
isisd/isis_mt.c
isisd/isis_mt.h
isisd/isis_northbound.c
isisd/isis_pdu.c
isisd/isis_te.c
isisd/isis_te.h
isisd/isis_tlvs.c
isisd/isis_tlvs.h
isisd/isis_zebra.c
isisd/isis_zebra.h
lib/mpls.h
tests/isisd/test_fuzz_isis_tlv_tests.h.gz

index 8d008d78bd4800d2e3618f1b3d66149d117e4f71..5da8e6ee9e2e97cff3d1ef0c589ccb2d385f7a4b 100644 (file)
@@ -135,8 +135,6 @@ struct isis_circuit *isis_circuit_new(void)
        }
 #endif /* ifndef FABRICD */
 
-       circuit->mtc = mpls_te_circuit_new();
-
        circuit_mt_init(circuit);
 
        QOBJ_REG(circuit, isis_circuit);
@@ -266,8 +264,11 @@ void isis_circuit_add_addr(struct isis_circuit *circuit,
                ipv4->prefix = connected->address->u.prefix4;
                listnode_add(circuit->ip_addrs, ipv4);
 
-               /* Update MPLS TE Local IP address parameter */
-               set_circuitparams_local_ipaddr(circuit->mtc, ipv4->prefix);
+               /* Update Local IP address parameter if MPLS TE is enable */
+               if (circuit->ext && IS_MPLS_TE(circuit->ext)) {
+                       circuit->ext->local_addr.s_addr = ipv4->prefix.s_addr;
+                       SET_SUBTLV(circuit->ext, EXT_LOCAL_ADDR);
+               }
 
                if (circuit->area)
                        lsp_regenerate_schedule(circuit->area, circuit->is_type,
@@ -478,6 +479,7 @@ void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp)
 
        for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, conn))
                isis_circuit_add_addr(circuit, conn);
+
 }
 
 void isis_circuit_if_del(struct isis_circuit *circuit, struct interface *ifp)
@@ -521,7 +523,6 @@ void isis_circuit_if_bind(struct isis_circuit *circuit, struct interface *ifp)
                assert(ifp->info == circuit);
        else
                ifp->info = circuit;
-       isis_link_params_update(circuit, ifp);
 }
 
 void isis_circuit_if_unbind(struct isis_circuit *circuit, struct interface *ifp)
index 2371c0b73a15c24444b05ef44de2fd847815ebd3..e3541644aa9052ec5d4a86f8da37406b7edb6840 100644 (file)
@@ -121,7 +121,7 @@ struct isis_circuit {
        uint16_t psnp_interval[2];    /* psnp-interval in seconds */
        uint8_t metric[2];
        uint32_t te_metric[2];
-       struct mpls_te_circuit *mtc; /* MPLS-TE parameters */
+       struct isis_ext_subtlvs *ext; /* Extended parameters (TE + Adj SID */
        int ip_router;  /* Route IP ? */
        int is_passive; /* Is Passive ? */
        struct list *mt_settings;   /* IS-IS MT Settings */
index 4b29e6dc7e0d7baee8faf159d5b7870b0741ebd3..061e7588314356098ce013214d924bf01895fcab 100644 (file)
@@ -52,9 +52,9 @@
 #include "isisd/isis_csm.h"
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_spf.h"
-#include "isisd/isis_te.h"
 #include "isisd/isis_mt.h"
 #include "isisd/isis_tlvs.h"
+#include "isisd/isis_te.h"
 #include "isisd/fabricd.h"
 #include "isisd/isis_tx_queue.h"
 
@@ -781,8 +781,8 @@ static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
                if (!rn->info)
                        continue;
                struct isis_ext_info *info = rn->info;
-
                struct prefix_ipv6 *p, *src_p;
+
                srcdest_rnode_prefixes(rn, (const struct prefix **)&p,
                                       (const struct prefix **)&src_p);
 
@@ -863,6 +863,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
        /* Protocols Supported */
        if (area->ip_circuits > 0 || area->ipv6_circuits > 0) {
                struct nlpids nlpids = {.count = 0};
+
                if (area->ip_circuits > 0) {
                        lsp_debug(
                                "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
@@ -908,10 +909,12 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                          area->area_tag);
        }
 
-       /* IPv4 address and TE router ID TLVs. In case of the first one we don't
-        * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put
-        * into
-        * LSP and this address is same as router id. */
+       /* IPv4 address and TE router ID TLVs.
+        * In case of the first one we don't follow "C" vendor,
+        * but "J" vendor behavior - one IPv4 address is put
+        * into LSP. TE router ID will be the same if MPLS-TE
+        * is not activate or MPLS-TE router-id not specified
+        */
        if (isis->router_id != 0) {
                struct in_addr id = {.s_addr = isis->router_id};
                inet_ntop(AF_INET, &id, buf, sizeof(buf));
@@ -919,11 +922,14 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                          area->area_tag, buf);
                isis_tlvs_add_ipv4_address(lsp->tlvs, &id);
 
-               /* Exactly same data is put into TE router ID TLV, but only if
-                * new style
-                * TLV's are in use. */
+               /* If new style TLV's are in use, add TE router ID TLV
+                * Check if MPLS-TE is activate and mpls-te router-id set
+                * otherwise add exactly same data as for IPv4 address
+                */
                if (area->newmetric) {
-
+                       if (IS_MPLS_TE(area->mta)
+                           && area->mta->router_id.s_addr != 0)
+                               id.s_addr = area->mta->router_id.s_addr;
                        lsp_debug(
                                "ISIS (%s): Adding router ID also as TE router ID tlv.",
                                area->area_tag);
@@ -1004,6 +1010,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                    && circuit->ipv6_non_link->count > 0) {
                        struct listnode *ipnode;
                        struct prefix_ipv6 *ipv6;
+
                        for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
                                                  ipnode, ipv6)) {
                                lsp_debug(
@@ -1036,25 +1043,10 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                                                        lsp->tlvs, ne_id,
                                                        metric);
                                        }
-                                       if (area->newmetric) {
-                                               uint8_t subtlvs[256];
-                                               uint8_t subtlv_len;
-
-                                               if (IS_MPLS_TE(area->mta)
-                                                   && circuit->interface
-                                                   && HAS_LINK_PARAMS(
-                                                              circuit->interface))
-                                                       subtlv_len = add_te_subtlvs(
-                                                               subtlvs,
-                                                               circuit->mtc);
-                                               else
-                                                       subtlv_len = 0;
-
+                                       if (area->newmetric)
                                                tlvs_add_mt_bcast(
                                                        lsp->tlvs, circuit,
-                                                       level, ne_id, metric,
-                                                       subtlvs, subtlv_len);
-                                       }
+                                                       level, ne_id, metric);
                                }
                        } else {
                                lsp_debug(
@@ -1079,36 +1071,6 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                                                lsp->tlvs, ne_id, metric);
                                }
                                if (area->newmetric) {
-                                       uint8_t subtlvs[256];
-                                       uint8_t subtlv_len;
-
-                                       if (IS_MPLS_TE(area->mta)
-                                           && circuit->interface != NULL
-                                           && HAS_LINK_PARAMS(
-                                                      circuit->interface))
-                                               /* Update Local and Remote IP
-                                                * address for MPLS TE circuit
-                                                * parameters */
-                                               /* NOTE sure that it is the
-                                                * pertinent place for that
-                                                * updates */
-                                               /* Local IP address could be
-                                                * updated in isis_circuit.c -
-                                                * isis_circuit_add_addr() */
-                                               /* But, where update remote IP
-                                                * address ? in isis_pdu.c -
-                                                * process_p2p_hello() ? */
-
-                                               /* Add SubTLVs & Adjust real
-                                                * size of SubTLVs */
-                                               subtlv_len = add_te_subtlvs(
-                                                       subtlvs, circuit->mtc);
-                                       else
-                                               /* Or keep only TE metric with
-                                                * no SubTLVs if MPLS_TE is off
-                                                */
-                                               subtlv_len = 0;
-
                                        uint32_t neighbor_metric;
                                        if (fabricd_tier(area) == 0) {
                                                neighbor_metric = 0xffe;
@@ -1117,8 +1079,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                                        }
 
                                        tlvs_add_mt_p2p(lsp->tlvs, circuit,
-                                                       ne_id, neighbor_metric,
-                                                       subtlvs, subtlv_len);
+                                                       ne_id, neighbor_metric);
                                }
                        } else {
                                lsp_debug(
@@ -1512,7 +1473,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
        }
        if (circuit->area->newmetric) {
                isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST,
-                                            ne_id, 0, NULL, 0);
+                                            ne_id, 0, circuit->ext);
                lsp_debug(
                        "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
                        area->area_tag, sysid_print(ne_id),
@@ -1554,7 +1515,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
                if (circuit->area->newmetric) {
                        isis_tlvs_add_extended_reach(lsp->tlvs,
                                                     ISIS_MT_IPV4_UNICAST,
-                                                    ne_id, 0, NULL, 0);
+                                                    ne_id, 0, circuit->ext);
                        lsp_debug(
                                "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
                                area->area_tag, sysid_print(ne_id),
index f7d4c7170f5c8a759a011e50e4d86d58c3ac5852..36413bac5949c8fe01b4a0cf5536b63d3c0b2f6d 100644 (file)
@@ -511,8 +511,8 @@ static uint16_t *circuit_bcast_mt_set(struct isis_circuit *circuit, int level,
 
 static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs,
                            unsigned int mt_count, uint16_t *mt_set,
-                           uint8_t *id, uint32_t metric, uint8_t *subtlvs,
-                           uint8_t subtlv_len)
+                           uint8_t *id, uint32_t metric,
+                           struct isis_ext_subtlvs *ext)
 {
        for (unsigned int i = 0; i < mt_count; i++) {
                uint16_t mtid = mt_set[i];
@@ -527,30 +527,27 @@ static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs,
                                area->area_tag, sysid_print(id),
                                LSP_PSEUDO_ID(id), isis_mtid2str(mtid));
                }
-               isis_tlvs_add_extended_reach(tlvs, mtid, id, metric, subtlvs,
-                                            subtlv_len);
+               isis_tlvs_add_extended_reach(tlvs, mtid, id, metric, ext);
        }
 }
 
 void tlvs_add_mt_bcast(struct isis_tlvs *tlvs, struct isis_circuit *circuit,
-                      int level, uint8_t *id, uint32_t metric,
-                      uint8_t *subtlvs, uint8_t subtlv_len)
+                      int level, uint8_t *id, uint32_t metric)
 {
        unsigned int mt_count;
        uint16_t *mt_set = circuit_bcast_mt_set(circuit, level, &mt_count);
 
        tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, id, metric,
-                       subtlvs, subtlv_len);
+                       circuit->ext);
 }
 
 void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit,
-                    uint8_t *id, uint32_t metric, uint8_t *subtlvs,
-                    uint8_t subtlv_len)
+                    uint8_t *id, uint32_t metric)
 {
        struct isis_adjacency *adj = circuit->u.p2p.neighbor;
 
        tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, id,
-                       metric, subtlvs, subtlv_len);
+                       metric, circuit->ext);
 }
 
 void mt_init(void)
index 515b63f50f024c7329c233c252600714db786f72..b40139c50a8419ff525cf3891816e503bf96c484 100644 (file)
@@ -116,10 +116,8 @@ bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable,
 bool adj_has_mt(struct isis_adjacency *adj, uint16_t mtid);
 void adj_mt_finish(struct isis_adjacency *adj);
 void tlvs_add_mt_bcast(struct isis_tlvs *tlvs, struct isis_circuit *circuit,
-                      int level, uint8_t *id, uint32_t metric,
-                      uint8_t *subtlvs, uint8_t subtlv_len);
+                      int level, uint8_t *id, uint32_t metric);
 void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit,
-                    uint8_t *id, uint32_t metric, uint8_t *subtlvs,
-                    uint8_t subtlv_len);
+                    uint8_t *id, uint32_t metric);
 void mt_init(void);
 #endif
index c1b630eb2db59a6396c360a1442ec0907460dc09..bd6191869782312eae9aaa5f5ee732e506261535 100644 (file)
@@ -1384,7 +1384,7 @@ static int isis_instance_mpls_te_create(enum nb_event event,
 
                struct mpls_te_area *new;
 
-               zlog_debug("ISIS MPLS-TE: Initialize area %s",
+               zlog_debug("ISIS-TE(%s): Initialize MPLS Traffic Engineering",
                        area->area_tag);
 
                new = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof(struct mpls_te_area));
@@ -1410,12 +1410,12 @@ static int isis_instance_mpls_te_create(enum nb_event event,
         * 2) MPLS-TE was once enabled then disabled, and now enabled again.
         */
        for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
-               if (circuit->mtc == NULL || IS_FLOOD_AS(circuit->mtc->type))
+               if (circuit->ext == NULL)
                        continue;
 
-               if (!IS_MPLS_TE(circuit->mtc)
+               if (!IS_EXT_TE(circuit->ext)
                    && HAS_LINK_PARAMS(circuit->interface))
-                       circuit->mtc->status = enable;
+                       isis_link_params_update(circuit, circuit->interface);
                else
                        continue;
 
@@ -1446,11 +1446,16 @@ static int isis_instance_mpls_te_destroy(enum nb_event event,
 
        /* Flush LSP if circuit engage */
        for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
-               if (circuit->mtc == NULL || (circuit->mtc->status == disable))
+               if (!IS_EXT_TE(circuit->ext))
                        continue;
 
-               /* disable MPLS_TE Circuit */
-               circuit->mtc->status = disable;
+               /* disable MPLS_TE Circuit keeping SR one's */
+               if (IS_SUBTLV(circuit->ext, EXT_ADJ_SID))
+                       circuit->ext->status = EXT_ADJ_SID;
+               else if (IS_SUBTLV(circuit->ext, EXT_LAN_ADJ_SID))
+                       circuit->ext->status = EXT_LAN_ADJ_SID;
+               else
+                       circuit->ext->status = 0;
 
                /* Re-originate circuit without STD_TE & GMPLS parameters */
                if (circuit->area)
@@ -1458,6 +1463,9 @@ static int isis_instance_mpls_te_destroy(enum nb_event event,
                                                0);
        }
 
+       zlog_debug("ISIS-TE(%s): Disabled MPLS Traffic Engineering",
+                  area->area_tag);
+
        return NB_OK;
 }
 
index 3d16d56016568ce53d40feb90aa676dec9a6bcf6..ecfce392ff5f61e55d858847d62b2776cde621b0 100644 (file)
@@ -199,13 +199,6 @@ static int process_p2p_hello(struct iih_info *iih)
        changed |= tlvs_to_adj_mt_set(iih->tlvs, iih->v4_usable, iih->v6_usable,
                                      adj);
 
-       /* Update MPLS TE Remote IP address parameter if possible */
-       if (IS_MPLS_TE(iih->circuit->area->mta)
-           && IS_MPLS_TE(iih->circuit->mtc)
-           && adj->ipv4_address_count)
-               set_circuitparams_rmt_ipaddr(iih->circuit->mtc,
-                                            adj->ipv4_addresses[0]);
-
        /* lets take care of the expiry */
        THREAD_TIMER_OFF(adj->t_expire);
        thread_add_timer(master, isis_adj_expire, adj, (long)adj->hold_time,
index 4ea6c2c60d657901cb6c8f9a8ea1252348ea1baa..44fa45d02b0a9b0bdd05f2b331f3bc15d762b068 100644 (file)
@@ -3,8 +3,9 @@
  *
  * This is an implementation of RFC5305 & RFC 7810
  *
- *      Copyright (C) 2014 Orange Labs
- *      http://www.orange.com
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ *
+ * Copyright (C) 2014 - 2019 Orange Labs http://www.orange.com
  *
  * This file is part of GNU Zebra.
  *
@@ -47,6 +48,7 @@
 #include "isisd/isis_common.h"
 #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
+#include "isisd/isis_adjacency.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_pdu.h"
@@ -56,6 +58,7 @@
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_spf.h"
 #include "isisd/isis_te.h"
+#include "isisd/isis_zebra.h"
 
 const char *mode2text[] = {"Disable", "Area", "AS", "Emulate"};
 
@@ -63,424 +66,6 @@ const char *mode2text[] = {"Disable", "Area", "AS", "Emulate"};
  * Followings are control functions for MPLS-TE parameters management.
  *------------------------------------------------------------------------*/
 
-/* Create new MPLS TE Circuit context */
-struct mpls_te_circuit *mpls_te_circuit_new(void)
-{
-       struct mpls_te_circuit *mtc;
-
-       zlog_debug("ISIS MPLS-TE: Create new MPLS TE Circuit context");
-
-       mtc = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof(struct mpls_te_circuit));
-
-       mtc->status = disable;
-       mtc->type = STD_TE;
-       mtc->length = 0;
-
-       return mtc;
-}
-
-/* Copy SUB TLVs parameters into a buffer - No space verification are performed
- */
-/* Caller must verify before that there is enough free space in the buffer */
-uint8_t add_te_subtlvs(uint8_t *buf, struct mpls_te_circuit *mtc)
-{
-       uint8_t size, *tlvs = buf;
-
-       zlog_debug("ISIS MPLS-TE: Add TE Sub TLVs to buffer");
-
-       if (mtc == NULL) {
-               zlog_debug(
-                       "ISIS MPLS-TE: Abort! No MPLS TE Circuit available has been specified");
-               return 0;
-       }
-
-       /* Create buffer if not provided */
-       if (buf == NULL) {
-               zlog_debug("ISIS MPLS-TE: Abort! No Buffer has been specified");
-               return 0;
-       }
-
-       /* TE_SUBTLV_ADMIN_GRP */
-       if (SUBTLV_TYPE(mtc->admin_grp) != 0) {
-               size = SUBTLV_SIZE(&(mtc->admin_grp.header));
-               memcpy(tlvs, &(mtc->admin_grp), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_LLRI */
-       if (SUBTLV_TYPE(mtc->llri) != 0) {
-               size = SUBTLV_SIZE(&(mtc->llri.header));
-               memcpy(tlvs, &(mtc->llri), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_LCLIF_IPADDR */
-       if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) {
-               size = SUBTLV_SIZE(&(mtc->local_ipaddr.header));
-               memcpy(tlvs, &(mtc->local_ipaddr), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_RMTIF_IPADDR */
-       if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) {
-               size = SUBTLV_SIZE(&(mtc->rmt_ipaddr.header));
-               memcpy(tlvs, &(mtc->rmt_ipaddr), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_MAX_BW */
-       if (SUBTLV_TYPE(mtc->max_bw) != 0) {
-               size = SUBTLV_SIZE(&(mtc->max_bw.header));
-               memcpy(tlvs, &(mtc->max_bw), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_MAX_RSV_BW */
-       if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0) {
-               size = SUBTLV_SIZE(&(mtc->max_rsv_bw.header));
-               memcpy(tlvs, &(mtc->max_rsv_bw), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_UNRSV_BW */
-       if (SUBTLV_TYPE(mtc->unrsv_bw) != 0) {
-               size = SUBTLV_SIZE(&(mtc->unrsv_bw.header));
-               memcpy(tlvs, &(mtc->unrsv_bw), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_TE_METRIC */
-       if (SUBTLV_TYPE(mtc->te_metric) != 0) {
-               size = SUBTLV_SIZE(&(mtc->te_metric.header));
-               memcpy(tlvs, &(mtc->te_metric), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_AV_DELAY */
-       if (SUBTLV_TYPE(mtc->av_delay) != 0) {
-               size = SUBTLV_SIZE(&(mtc->av_delay.header));
-               memcpy(tlvs, &(mtc->av_delay), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_MM_DELAY */
-       if (SUBTLV_TYPE(mtc->mm_delay) != 0) {
-               size = SUBTLV_SIZE(&(mtc->mm_delay.header));
-               memcpy(tlvs, &(mtc->mm_delay), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_DELAY_VAR */
-       if (SUBTLV_TYPE(mtc->delay_var) != 0) {
-               size = SUBTLV_SIZE(&(mtc->delay_var.header));
-               memcpy(tlvs, &(mtc->delay_var), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_PKT_LOSS */
-       if (SUBTLV_TYPE(mtc->pkt_loss) != 0) {
-               size = SUBTLV_SIZE(&(mtc->pkt_loss.header));
-               memcpy(tlvs, &(mtc->pkt_loss), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_RES_BW */
-       if (SUBTLV_TYPE(mtc->res_bw) != 0) {
-               size = SUBTLV_SIZE(&(mtc->res_bw.header));
-               memcpy(tlvs, &(mtc->res_bw), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_AVA_BW */
-       if (SUBTLV_TYPE(mtc->ava_bw) != 0) {
-               size = SUBTLV_SIZE(&(mtc->ava_bw.header));
-               memcpy(tlvs, &(mtc->ava_bw), size);
-               tlvs += size;
-       }
-
-       /* TE_SUBTLV_USE_BW */
-       if (SUBTLV_TYPE(mtc->use_bw) != 0) {
-               size = SUBTLV_SIZE(&(mtc->use_bw.header));
-               memcpy(tlvs, &(mtc->use_bw), size);
-               tlvs += size;
-       }
-
-       /* Add before this line any other parsing of TLV */
-       (void)tlvs;
-
-       /* Update SubTLVs length */
-       mtc->length = subtlvs_len(mtc);
-
-       zlog_debug("ISIS MPLS-TE: Add %d bytes length SubTLVs", mtc->length);
-
-       return mtc->length;
-}
-
-/* Compute total Sub-TLVs size */
-uint8_t subtlvs_len(struct mpls_te_circuit *mtc)
-{
-       int length = 0;
-
-       /* Sanity Check */
-       if (mtc == NULL)
-               return 0;
-
-       /* TE_SUBTLV_ADMIN_GRP */
-       if (SUBTLV_TYPE(mtc->admin_grp) != 0)
-               length += SUBTLV_SIZE(&(mtc->admin_grp.header));
-
-       /* TE_SUBTLV_LLRI */
-       if (SUBTLV_TYPE(mtc->llri) != 0)
-               length += SUBTLV_SIZE(&mtc->llri.header);
-
-       /* TE_SUBTLV_LCLIF_IPADDR */
-       if (SUBTLV_TYPE(mtc->local_ipaddr) != 0)
-               length += SUBTLV_SIZE(&mtc->local_ipaddr.header);
-
-       /* TE_SUBTLV_RMTIF_IPADDR */
-       if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0)
-               length += SUBTLV_SIZE(&mtc->rmt_ipaddr.header);
-
-       /* TE_SUBTLV_MAX_BW */
-       if (SUBTLV_TYPE(mtc->max_bw) != 0)
-               length += SUBTLV_SIZE(&mtc->max_bw.header);
-
-       /* TE_SUBTLV_MAX_RSV_BW */
-       if (SUBTLV_TYPE(mtc->max_rsv_bw) != 0)
-               length += SUBTLV_SIZE(&mtc->max_rsv_bw.header);
-
-       /* TE_SUBTLV_UNRSV_BW */
-       if (SUBTLV_TYPE(mtc->unrsv_bw) != 0)
-               length += SUBTLV_SIZE(&mtc->unrsv_bw.header);
-
-       /* TE_SUBTLV_TE_METRIC */
-       if (SUBTLV_TYPE(mtc->te_metric) != 0)
-               length += SUBTLV_SIZE(&mtc->te_metric.header);
-
-       /* TE_SUBTLV_AV_DELAY */
-       if (SUBTLV_TYPE(mtc->av_delay) != 0)
-               length += SUBTLV_SIZE(&mtc->av_delay.header);
-
-       /* TE_SUBTLV_MM_DELAY */
-       if (SUBTLV_TYPE(mtc->mm_delay) != 0)
-               length += SUBTLV_SIZE(&mtc->mm_delay.header);
-
-       /* TE_SUBTLV_DELAY_VAR */
-       if (SUBTLV_TYPE(mtc->delay_var) != 0)
-               length += SUBTLV_SIZE(&mtc->delay_var.header);
-
-       /* TE_SUBTLV_PKT_LOSS */
-       if (SUBTLV_TYPE(mtc->pkt_loss) != 0)
-               length += SUBTLV_SIZE(&mtc->pkt_loss.header);
-
-       /* TE_SUBTLV_RES_BW */
-       if (SUBTLV_TYPE(mtc->res_bw) != 0)
-               length += SUBTLV_SIZE(&mtc->res_bw.header);
-
-       /* TE_SUBTLV_AVA_BW */
-       if (SUBTLV_TYPE(mtc->ava_bw) != 0)
-               length += SUBTLV_SIZE(&mtc->ava_bw.header);
-
-       /* TE_SUBTLV_USE_BW */
-       if (SUBTLV_TYPE(mtc->use_bw) != 0)
-               length += SUBTLV_SIZE(&mtc->use_bw.header);
-
-       /* Check that length is lower than the MAXIMUM SUBTLV size i.e. 256 */
-       if (length > MAX_SUBTLV_SIZE) {
-               mtc->length = 0;
-               return 0;
-       }
-
-       mtc->length = (uint8_t)length;
-
-       return mtc->length;
-}
-
-/* Following are various functions to set MPLS TE parameters */
-static void set_circuitparams_admin_grp(struct mpls_te_circuit *mtc,
-                                       uint32_t admingrp)
-{
-       SUBTLV_TYPE(mtc->admin_grp) = TE_SUBTLV_ADMIN_GRP;
-       SUBTLV_LEN(mtc->admin_grp) = SUBTLV_DEF_SIZE;
-       mtc->admin_grp.value = htonl(admingrp);
-       return;
-}
-
-static void __attribute__((unused))
-set_circuitparams_llri(struct mpls_te_circuit *mtc, uint32_t local,
-                      uint32_t remote)
-{
-       SUBTLV_TYPE(mtc->llri) = TE_SUBTLV_LLRI;
-       SUBTLV_LEN(mtc->llri) = TE_SUBTLV_LLRI_SIZE;
-       mtc->llri.local = htonl(local);
-       mtc->llri.remote = htonl(remote);
-}
-
-void set_circuitparams_local_ipaddr(struct mpls_te_circuit *mtc,
-                                   struct in_addr addr)
-{
-
-       SUBTLV_TYPE(mtc->local_ipaddr) = TE_SUBTLV_LOCAL_IPADDR;
-       SUBTLV_LEN(mtc->local_ipaddr) = SUBTLV_DEF_SIZE;
-       mtc->local_ipaddr.value.s_addr = addr.s_addr;
-       return;
-}
-
-void set_circuitparams_rmt_ipaddr(struct mpls_te_circuit *mtc,
-                                 struct in_addr addr)
-{
-
-       SUBTLV_TYPE(mtc->rmt_ipaddr) = TE_SUBTLV_RMT_IPADDR;
-       SUBTLV_LEN(mtc->rmt_ipaddr) = SUBTLV_DEF_SIZE;
-       mtc->rmt_ipaddr.value.s_addr = addr.s_addr;
-       return;
-}
-
-static void set_circuitparams_max_bw(struct mpls_te_circuit *mtc, float fp)
-{
-       SUBTLV_TYPE(mtc->max_bw) = TE_SUBTLV_MAX_BW;
-       SUBTLV_LEN(mtc->max_bw) = SUBTLV_DEF_SIZE;
-       mtc->max_bw.value = htonf(fp);
-       return;
-}
-
-static void set_circuitparams_max_rsv_bw(struct mpls_te_circuit *mtc, float fp)
-{
-       SUBTLV_TYPE(mtc->max_rsv_bw) = TE_SUBTLV_MAX_RSV_BW;
-       SUBTLV_LEN(mtc->max_rsv_bw) = SUBTLV_DEF_SIZE;
-       mtc->max_rsv_bw.value = htonf(fp);
-       return;
-}
-
-static void set_circuitparams_unrsv_bw(struct mpls_te_circuit *mtc,
-                                      int priority, float fp)
-{
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_BW;
-       SUBTLV_LEN(mtc->unrsv_bw) = TE_SUBTLV_UNRSV_SIZE;
-       mtc->unrsv_bw.value[priority] = htonf(fp);
-       return;
-}
-
-static void set_circuitparams_te_metric(struct mpls_te_circuit *mtc,
-                                       uint32_t te_metric)
-{
-       SUBTLV_TYPE(mtc->te_metric) = TE_SUBTLV_TE_METRIC;
-       SUBTLV_LEN(mtc->te_metric) = TE_SUBTLV_TE_METRIC_SIZE;
-       mtc->te_metric.value[0] = (te_metric >> 16) & 0xFF;
-       mtc->te_metric.value[1] = (te_metric >> 8) & 0xFF;
-       mtc->te_metric.value[2] = te_metric & 0xFF;
-       return;
-}
-
-static void set_circuitparams_inter_as(struct mpls_te_circuit *mtc,
-                                      struct in_addr addr, uint32_t as)
-{
-
-       /* Set the Remote ASBR IP address and then the associated AS number */
-       SUBTLV_TYPE(mtc->rip) = TE_SUBTLV_RIP;
-       SUBTLV_LEN(mtc->rip) = SUBTLV_DEF_SIZE;
-       mtc->rip.value.s_addr = addr.s_addr;
-
-       SUBTLV_TYPE(mtc->ras) = TE_SUBTLV_RAS;
-       SUBTLV_LEN(mtc->ras) = SUBTLV_DEF_SIZE;
-       mtc->ras.value = htonl(as);
-}
-
-static void unset_circuitparams_inter_as(struct mpls_te_circuit *mtc)
-{
-
-       /* Reset the Remote ASBR IP address and then the associated AS number */
-       SUBTLV_TYPE(mtc->rip) = 0;
-       SUBTLV_LEN(mtc->rip) = 0;
-       mtc->rip.value.s_addr = 0;
-
-       SUBTLV_TYPE(mtc->ras) = 0;
-       SUBTLV_LEN(mtc->ras) = 0;
-       mtc->ras.value = 0;
-}
-
-static void set_circuitparams_av_delay(struct mpls_te_circuit *mtc,
-                                      uint32_t delay, uint8_t anormal)
-{
-       uint32_t tmp;
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->av_delay) = TE_SUBTLV_AV_DELAY;
-       SUBTLV_LEN(mtc->av_delay) = SUBTLV_DEF_SIZE;
-       tmp = delay & TE_EXT_MASK;
-       if (anormal)
-               tmp |= TE_EXT_ANORMAL;
-       mtc->av_delay.value = htonl(tmp);
-       return;
-}
-
-static void set_circuitparams_mm_delay(struct mpls_te_circuit *mtc,
-                                      uint32_t low, uint32_t high,
-                                      uint8_t anormal)
-{
-       uint32_t tmp;
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->mm_delay) = TE_SUBTLV_MM_DELAY;
-       SUBTLV_LEN(mtc->mm_delay) = TE_SUBTLV_MM_DELAY_SIZE;
-       tmp = low & TE_EXT_MASK;
-       if (anormal)
-               tmp |= TE_EXT_ANORMAL;
-       mtc->mm_delay.low = htonl(tmp);
-       mtc->mm_delay.high = htonl(high);
-       return;
-}
-
-static void set_circuitparams_delay_var(struct mpls_te_circuit *mtc,
-                                       uint32_t jitter)
-{
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->delay_var) = TE_SUBTLV_DELAY_VAR;
-       SUBTLV_LEN(mtc->delay_var) = SUBTLV_DEF_SIZE;
-       mtc->delay_var.value = htonl(jitter & TE_EXT_MASK);
-       return;
-}
-
-static void set_circuitparams_pkt_loss(struct mpls_te_circuit *mtc,
-                                      uint32_t loss, uint8_t anormal)
-{
-       uint32_t tmp;
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->pkt_loss) = TE_SUBTLV_PKT_LOSS;
-       SUBTLV_LEN(mtc->pkt_loss) = SUBTLV_DEF_SIZE;
-       tmp = loss & TE_EXT_MASK;
-       if (anormal)
-               tmp |= TE_EXT_ANORMAL;
-       mtc->pkt_loss.value = htonl(tmp);
-       return;
-}
-
-static void set_circuitparams_res_bw(struct mpls_te_circuit *mtc, float fp)
-{
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->res_bw) = TE_SUBTLV_RES_BW;
-       SUBTLV_LEN(mtc->res_bw) = SUBTLV_DEF_SIZE;
-       mtc->res_bw.value = htonf(fp);
-       return;
-}
-
-static void set_circuitparams_ava_bw(struct mpls_te_circuit *mtc, float fp)
-{
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->ava_bw) = TE_SUBTLV_AVA_BW;
-       SUBTLV_LEN(mtc->ava_bw) = SUBTLV_DEF_SIZE;
-       mtc->ava_bw.value = htonf(fp);
-       return;
-}
-
-static void set_circuitparams_use_bw(struct mpls_te_circuit *mtc, float fp)
-{
-       /* Note that TLV-length field is the size of array. */
-       SUBTLV_TYPE(mtc->use_bw) = TE_SUBTLV_USE_BW;
-       SUBTLV_LEN(mtc->use_bw) = SUBTLV_DEF_SIZE;
-       mtc->use_bw.value = htonf(fp);
-       return;
-}
-
 /* Main initialization / update function of the MPLS TE Circuit context */
 /* Call when interface TE Link parameters are modified */
 void isis_link_params_update(struct isis_circuit *circuit,
@@ -488,155 +73,223 @@ void isis_link_params_update(struct isis_circuit *circuit,
 {
        int i;
        struct prefix_ipv4 *addr;
-       struct mpls_te_circuit *mtc;
+       struct prefix_ipv6 *addr6;
+       struct isis_ext_subtlvs *ext;
+
+       /* Check if TE is enable or not */
+       if (!circuit->area || !IS_MPLS_TE(circuit->area->mta))
+               return;
 
        /* Sanity Check */
-       if ((circuit == NULL) || (ifp == NULL))
+       if ((circuit == NULL) || (ifp == NULL)
+           || (circuit->state != C_STATE_UP))
                return;
 
-       zlog_info("MPLS-TE: Initialize circuit parameters for interface %s",
-                 ifp->name);
+       zlog_debug("TE(%s): Update circuit parameters for interface %s",
+                  circuit->area->area_tag, ifp->name);
 
        /* Check if MPLS TE Circuit context has not been already created */
-       if (circuit->mtc == NULL)
-               circuit->mtc = mpls_te_circuit_new();
+       if (circuit->ext == NULL) {
+               circuit->ext = isis_alloc_ext_subtlvs();
+               zlog_debug("  |- Allocated new Ext-subTLVs for interface %s",
+                          ifp->name);
+       }
 
-       mtc = circuit->mtc;
+       ext = circuit->ext;
 
-       /* Fulfil MTC TLV from ifp TE Link parameters */
+       /* Fulfill Extended subTLVs from interface link parameters */
        if (HAS_LINK_PARAMS(ifp)) {
-               mtc->status = enable;
                /* STD_TE metrics */
-               if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP))
-                       set_circuitparams_admin_grp(
-                               mtc, ifp->link_params->admin_grp);
-               else
-                       SUBTLV_TYPE(mtc->admin_grp) = 0;
-
-               /* If not already set, register local IP addr from ip_addr list
-                * if it exists */
-               if (SUBTLV_TYPE(mtc->local_ipaddr) == 0) {
-                       if (circuit->ip_addrs != NULL
-                           && listcount(circuit->ip_addrs) != 0) {
-                               addr = (struct prefix_ipv4 *)listgetdata(
-                                       (struct listnode *)listhead(
-                                               circuit->ip_addrs));
-                               set_circuitparams_local_ipaddr(mtc,
-                                                              addr->prefix);
-                       }
-               }
-
-               /* If not already set, try to determine Remote IP addr if
-                * circuit is P2P */
-               if ((SUBTLV_TYPE(mtc->rmt_ipaddr) == 0)
-                   && (circuit->circ_type == CIRCUIT_T_P2P)) {
+               if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) {
+                       ext->adm_group = ifp->link_params->admin_grp;
+                       SET_SUBTLV(ext, EXT_ADM_GRP);
+               } else
+                       UNSET_SUBTLV(ext, EXT_ADM_GRP);
+
+               /* If known, register local IPv4 addr from ip_addr list */
+               if (circuit->ip_addrs != NULL
+                   && listcount(circuit->ip_addrs) != 0) {
+                       addr = (struct prefix_ipv4 *)listgetdata(
+                               (struct listnode *)listhead(circuit->ip_addrs));
+                       IPV4_ADDR_COPY(&ext->local_addr, &addr->prefix);
+                       SET_SUBTLV(ext, EXT_LOCAL_ADDR);
+               } else
+                       UNSET_SUBTLV(ext, EXT_LOCAL_ADDR);
+
+               /* Same for Remote IPv4 address */
+               if (circuit->circ_type == CIRCUIT_T_P2P) {
                        struct isis_adjacency *adj = circuit->u.p2p.neighbor;
+
                        if (adj && adj->adj_state == ISIS_ADJ_UP
                            && adj->ipv4_address_count) {
-                               set_circuitparams_rmt_ipaddr(
-                                       mtc, adj->ipv4_addresses[0]);
+                               IPV4_ADDR_COPY(&ext->neigh_addr,
+                                              &adj->ipv4_addresses[0]);
+                               SET_SUBTLV(ext, EXT_NEIGH_ADDR);
                        }
-               }
-
-               if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW))
-                       set_circuitparams_max_bw(mtc, ifp->link_params->max_bw);
-               else
-                       SUBTLV_TYPE(mtc->max_bw) = 0;
-
-               if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW))
-                       set_circuitparams_max_rsv_bw(
-                               mtc, ifp->link_params->max_rsv_bw);
-               else
-                       SUBTLV_TYPE(mtc->max_rsv_bw) = 0;
+               } else
+                       UNSET_SUBTLV(ext, EXT_NEIGH_ADDR);
+
+               /* If known, register local IPv6 addr from ip_addr list */
+               if (circuit->ipv6_non_link != NULL
+                   && listcount(circuit->ipv6_non_link) != 0) {
+                       addr6 = (struct prefix_ipv6 *)listgetdata(
+                               (struct listnode *)listhead(
+                                       circuit->ipv6_non_link));
+                       IPV6_ADDR_COPY(&ext->local_addr6, &addr6->prefix);
+                       SET_SUBTLV(ext, EXT_LOCAL_ADDR6);
+               } else
+                       UNSET_SUBTLV(ext, EXT_LOCAL_ADDR6);
+
+               /* Same for Remote IPv6 address */
+               if (circuit->circ_type == CIRCUIT_T_P2P) {
+                       struct isis_adjacency *adj = circuit->u.p2p.neighbor;
 
-               if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW))
+                       if (adj && adj->adj_state == ISIS_ADJ_UP
+                           && adj->ipv6_address_count) {
+                               IPV6_ADDR_COPY(&ext->neigh_addr6,
+                                              &adj->ipv6_addresses[0]);
+                               SET_SUBTLV(ext, EXT_NEIGH_ADDR6);
+                       }
+               } else
+                       UNSET_SUBTLV(ext, EXT_NEIGH_ADDR6);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) {
+                       ext->max_bw = ifp->link_params->max_bw;
+                       SET_SUBTLV(ext, EXT_MAX_BW);
+               } else
+                       UNSET_SUBTLV(ext, EXT_MAX_BW);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) {
+                       ext->max_rsv_bw = ifp->link_params->max_rsv_bw;
+                       SET_SUBTLV(ext, EXT_MAX_RSV_BW);
+               } else
+                       UNSET_SUBTLV(ext, EXT_MAX_RSV_BW);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) {
                        for (i = 0; i < MAX_CLASS_TYPE; i++)
-                               set_circuitparams_unrsv_bw(
-                                       mtc, i, ifp->link_params->unrsv_bw[i]);
-               else
-                       SUBTLV_TYPE(mtc->unrsv_bw) = 0;
-
-               if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC))
-                       set_circuitparams_te_metric(
-                               mtc, ifp->link_params->te_metric);
-               else
-                       SUBTLV_TYPE(mtc->te_metric) = 0;
-
-               /* TE metric Extensions */
-               if (IS_PARAM_SET(ifp->link_params, LP_DELAY))
-                       set_circuitparams_av_delay(
-                               mtc, ifp->link_params->av_delay, 0);
-               else
-                       SUBTLV_TYPE(mtc->av_delay) = 0;
+                               ext->unrsv_bw[i] =
+                                       ifp->link_params->unrsv_bw[i];
+                       SET_SUBTLV(ext, EXT_UNRSV_BW);
+               } else
+                       UNSET_SUBTLV(ext, EXT_UNRSV_BW);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC)) {
+                       ext->te_metric = ifp->link_params->te_metric;
+                       SET_SUBTLV(ext, EXT_TE_METRIC);
+               } else
+                       UNSET_SUBTLV(ext, EXT_TE_METRIC);
+
+               /* TE metric extensions */
+               if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) {
+                       ext->delay = ifp->link_params->av_delay;
+                       SET_SUBTLV(ext, EXT_DELAY);
+               } else
+                       UNSET_SUBTLV(ext, EXT_DELAY);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) {
+                       ext->min_delay = ifp->link_params->min_delay;
+                       ext->max_delay = ifp->link_params->max_delay;
+                       SET_SUBTLV(ext, EXT_MM_DELAY);
+               } else
+                       UNSET_SUBTLV(ext, EXT_MM_DELAY);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) {
+                       ext->delay_var = ifp->link_params->delay_var;
+                       SET_SUBTLV(ext, EXT_DELAY_VAR);
+               } else
+                       UNSET_SUBTLV(ext, EXT_DELAY_VAR);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) {
+                       ext->pkt_loss = ifp->link_params->pkt_loss;
+                       SET_SUBTLV(ext, EXT_PKT_LOSS);
+               } else
+                       UNSET_SUBTLV(ext, EXT_PKT_LOSS);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) {
+                       ext->res_bw = ifp->link_params->res_bw;
+                       SET_SUBTLV(ext, EXT_RES_BW);
+               } else
+                       UNSET_SUBTLV(ext, EXT_RES_BW);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) {
+                       ext->ava_bw = ifp->link_params->ava_bw;
+                       SET_SUBTLV(ext, EXT_AVA_BW);
+               } else
+                       UNSET_SUBTLV(ext, EXT_AVA_BW);
+
+               if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) {
+                       ext->use_bw = ifp->link_params->use_bw;
+                       SET_SUBTLV(ext, EXT_USE_BW);
+               } else
+                       UNSET_SUBTLV(ext, EXT_USE_BW);
 
-               if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY))
-                       set_circuitparams_mm_delay(
-                               mtc, ifp->link_params->min_delay,
-                               ifp->link_params->max_delay, 0);
-               else
-                       SUBTLV_TYPE(mtc->mm_delay) = 0;
-
-               if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR))
-                       set_circuitparams_delay_var(
-                               mtc, ifp->link_params->delay_var);
-               else
-                       SUBTLV_TYPE(mtc->delay_var) = 0;
-
-               if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS))
-                       set_circuitparams_pkt_loss(
-                               mtc, ifp->link_params->pkt_loss, 0);
+               /* INTER_AS */
+               if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS)) {
+                       ext->remote_as = ifp->link_params->rmt_as;
+                       ext->remote_ip = ifp->link_params->rmt_ip;
+                       SET_SUBTLV(ext, EXT_RMT_AS);
+                       SET_SUBTLV(ext, EXT_RMT_IP);
+               } else {
+                       /* reset inter-as TE params */
+                       UNSET_SUBTLV(ext, EXT_RMT_AS);
+                       UNSET_SUBTLV(ext, EXT_RMT_IP);
+               }
+               zlog_debug("  |- New MPLS-TE link parameters status 0x%x",
+                          ext->status);
+       } else {
+               zlog_debug("  |- Reset Extended subTLVs status 0x%x",
+                          ext->status);
+               /* Reset TE subTLVs keeping SR one's */
+               if (IS_SUBTLV(ext, EXT_ADJ_SID))
+                       ext->status = EXT_ADJ_SID;
+               else if (IS_SUBTLV(ext, EXT_LAN_ADJ_SID))
+                       ext->status = EXT_LAN_ADJ_SID;
                else
-                       SUBTLV_TYPE(mtc->pkt_loss) = 0;
+                       ext->status = 0;
+       }
 
-               if (IS_PARAM_SET(ifp->link_params, LP_RES_BW))
-                       set_circuitparams_res_bw(mtc, ifp->link_params->res_bw);
-               else
-                       SUBTLV_TYPE(mtc->res_bw) = 0;
+       return;
+}
 
-               if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW))
-                       set_circuitparams_ava_bw(mtc, ifp->link_params->ava_bw);
-               else
-                       SUBTLV_TYPE(mtc->ava_bw) = 0;
+static int isis_link_update_adj_hook(struct isis_adjacency *adj)
+{
 
-               if (IS_PARAM_SET(ifp->link_params, LP_USE_BW))
-                       set_circuitparams_use_bw(mtc, ifp->link_params->use_bw);
-               else
-                       SUBTLV_TYPE(mtc->use_bw) = 0;
+       struct isis_circuit *circuit = adj->circuit;
 
-               /* INTER_AS */
-               if (IS_PARAM_SET(ifp->link_params, LP_RMT_AS))
-                       set_circuitparams_inter_as(mtc,
-                                                  ifp->link_params->rmt_ip,
-                                                  ifp->link_params->rmt_as);
-               else
-                       /* reset inter-as TE params */
-                       unset_circuitparams_inter_as(mtc);
+       /* Update MPLS TE Remote IP address parameter if possible */
+       if (!IS_MPLS_TE(circuit->area->mta) || !IS_EXT_TE(circuit->ext))
+               return 0;
 
-               /* Compute total length of SUB TLVs */
-               mtc->length = subtlvs_len(mtc);
+       /* IPv4 first */
+       if (adj->ipv4_address_count > 0) {
+               IPV4_ADDR_COPY(&circuit->ext->neigh_addr,
+                              &adj->ipv4_addresses[0]);
+               SET_SUBTLV(circuit->ext, EXT_NEIGH_ADDR);
+       }
 
-       } else
-               mtc->status = disable;
+       /* and IPv6 */
+       if (adj->ipv6_address_count > 0) {
+               IPV6_ADDR_COPY(&circuit->ext->neigh_addr6,
+                              &adj->ipv6_addresses[0]);
+               SET_SUBTLV(circuit->ext, EXT_NEIGH_ADDR6);
+       }
 
-/* Finally Update LSP */
-#if 0
-  if (circuit->area && IS_MPLS_TE(circuit->area->mta))
-       lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
-#endif
-       return;
+       return 0;
 }
 
-void isis_mpls_te_update(struct interface *ifp)
+int isis_mpls_te_update(struct interface *ifp)
 {
        struct isis_circuit *circuit;
+       uint8_t rc = 1;
 
        /* Sanity Check */
        if (ifp == NULL)
-               return;
+               return rc;
 
        /* Get circuit context from interface */
-       if ((circuit = circuit_scan_by_ifp(ifp)) == NULL)
-               return;
+       circuit = circuit_scan_by_ifp(ifp);
+       if (circuit == NULL)
+               return rc;
 
        /* Update TE TLVs ... */
        isis_link_params_update(circuit, ifp);
@@ -645,418 +298,11 @@ void isis_mpls_te_update(struct interface *ifp)
        if (circuit->area && IS_MPLS_TE(circuit->area->mta))
                lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
 
-       return;
-}
-
-/*------------------------------------------------------------------------*
- * Followings are vty session control functions.
- *------------------------------------------------------------------------*/
-
-static uint8_t print_subtlv_admin_grp(struct sbuf *buf, int indent,
-                                     struct te_subtlv_admin_grp *tlv)
-{
-       sbuf_push(buf, indent, "Administrative Group: 0x%" PRIx32 "\n",
-                 ntohl(tlv->value));
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_llri(struct sbuf *buf, int indent,
-                                struct te_subtlv_llri *tlv)
-{
-       sbuf_push(buf, indent, "Link Local  ID: %" PRIu32 "\n",
-                 ntohl(tlv->local));
-       sbuf_push(buf, indent, "Link Remote ID: %" PRIu32 "\n",
-                 ntohl(tlv->remote));
-
-       return (SUBTLV_HDR_SIZE + TE_SUBTLV_LLRI_SIZE);
-}
-
-static uint8_t print_subtlv_local_ipaddr(struct sbuf *buf, int indent,
-                                        struct te_subtlv_local_ipaddr *tlv)
-{
-       sbuf_push(buf, indent, "Local Interface IP Address(es): %s\n",
-                 inet_ntoa(tlv->value));
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_rmt_ipaddr(struct sbuf *buf, int indent,
-                                      struct te_subtlv_rmt_ipaddr *tlv)
-{
-       sbuf_push(buf, indent, "Remote Interface IP Address(es): %s\n",
-                 inet_ntoa(tlv->value));
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_max_bw(struct sbuf *buf, int indent,
-                                  struct te_subtlv_max_bw *tlv)
-{
-       float fval;
-
-       fval = ntohf(tlv->value);
-
-       sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n", fval);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_max_rsv_bw(struct sbuf *buf, int indent,
-                                      struct te_subtlv_max_rsv_bw *tlv)
-{
-       float fval;
-
-       fval = ntohf(tlv->value);
-
-       sbuf_push(buf, indent, "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
-                 fval);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_unrsv_bw(struct sbuf *buf, int indent,
-                                    struct te_subtlv_unrsv_bw *tlv)
-{
-       float fval1, fval2;
-       int i;
-
-       sbuf_push(buf, indent, "Unreserved Bandwidth:\n");
-
-       for (i = 0; i < MAX_CLASS_TYPE; i += 2) {
-               fval1 = ntohf(tlv->value[i]);
-               fval2 = ntohf(tlv->value[i + 1]);
-               sbuf_push(buf, indent + 2,
-                         "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", i,
-                         fval1, i + 1, fval2);
-       }
-
-       return (SUBTLV_HDR_SIZE + TE_SUBTLV_UNRSV_SIZE);
-}
-
-static uint8_t print_subtlv_te_metric(struct sbuf *buf, int indent,
-                                     struct te_subtlv_te_metric *tlv)
-{
-       uint32_t te_metric;
-
-       te_metric = tlv->value[2] | tlv->value[1] << 8 | tlv->value[0] << 16;
-       sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n", te_metric);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_ras(struct sbuf *buf, int indent,
-                               struct te_subtlv_ras *tlv)
-{
-       sbuf_push(buf, indent, "Inter-AS TE Remote AS number: %" PRIu32 "\n",
-                 ntohl(tlv->value));
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_rip(struct sbuf *buf, int indent,
-                               struct te_subtlv_rip *tlv)
-{
-       sbuf_push(buf, indent, "Inter-AS TE Remote ASBR IP address: %s\n",
-                 inet_ntoa(tlv->value));
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
+       rc = 0;
+       return rc;
 }
 
-static uint8_t print_subtlv_av_delay(struct sbuf *buf, int indent,
-                                    struct te_subtlv_av_delay *tlv)
-{
-       uint32_t delay;
-       uint32_t A;
-
-       delay = (uint32_t)ntohl(tlv->value) & TE_EXT_MASK;
-       A = (uint32_t)ntohl(tlv->value) & TE_EXT_ANORMAL;
-
-       sbuf_push(buf, indent,
-                 "%s Average Link Delay: %" PRIu32 " (micro-sec)\n",
-                 A ? "Anomalous" : "Normal", delay);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_mm_delay(struct sbuf *buf, int indent,
-                                    struct te_subtlv_mm_delay *tlv)
-{
-       uint32_t low, high;
-       uint32_t A;
-
-       low = (uint32_t)ntohl(tlv->low) & TE_EXT_MASK;
-       A = (uint32_t)ntohl(tlv->low) & TE_EXT_ANORMAL;
-       high = (uint32_t)ntohl(tlv->high) & TE_EXT_MASK;
-
-       sbuf_push(buf, indent, "%s Min/Max Link Delay: %" PRIu32 " / %" PRIu32 " (micro-sec)\n",
-                 A ? "Anomalous" : "Normal", low, high);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_delay_var(struct sbuf *buf, int indent,
-                                     struct te_subtlv_delay_var *tlv)
-{
-       uint32_t jitter;
-
-       jitter = (uint32_t)ntohl(tlv->value) & TE_EXT_MASK;
-
-       sbuf_push(buf, indent, "Delay Variation: %" PRIu32 " (micro-sec)\n",
-                 jitter);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_pkt_loss(struct sbuf *buf, int indent,
-                                    struct te_subtlv_pkt_loss *tlv)
-{
-       uint32_t loss;
-       uint32_t A;
-       float fval;
-
-       loss = (uint32_t)ntohl(tlv->value) & TE_EXT_MASK;
-       fval = (float)(loss * LOSS_PRECISION);
-       A = (uint32_t)ntohl(tlv->value) & TE_EXT_ANORMAL;
-
-       sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n",
-                 A ? "Anomalous" : "Normal", fval);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_res_bw(struct sbuf *buf, int indent,
-                                  struct te_subtlv_res_bw *tlv)
-{
-       float fval;
-
-       fval = ntohf(tlv->value);
-
-       sbuf_push(buf, indent,
-                 "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n", fval);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_ava_bw(struct sbuf *buf, int indent,
-                                  struct te_subtlv_ava_bw *tlv)
-{
-       float fval;
-
-       fval = ntohf(tlv->value);
-
-       sbuf_push(buf, indent,
-                 "Unidirectional Available Bandwidth: %g (Bytes/sec)\n", fval);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_subtlv_use_bw(struct sbuf *buf, int indent,
-                                  struct te_subtlv_use_bw *tlv)
-{
-       float fval;
-
-       fval = ntohf(tlv->value);
-
-       sbuf_push(buf, indent,
-                 "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n", fval);
-
-       return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
-}
-
-static uint8_t print_unknown_tlv(struct sbuf *buf, int indent,
-                                struct subtlv_header *tlvh)
-{
-       int i, rtn;
-       uint8_t *v = (uint8_t *)tlvh;
-
-       if (tlvh->length != 0) {
-               sbuf_push(buf, indent,
-                         "Unknown TLV: [type(%#.2x), length(%#.2x)]\n",
-                         tlvh->type, tlvh->length);
-               sbuf_push(buf, indent + 2, "Dump: [00]");
-               rtn = 1; /* initialize end of line counter */
-               for (i = 0; i < tlvh->length; i++) {
-                       sbuf_push(buf, 0, " %#.2x", v[i]);
-                       if (rtn == 8) {
-                               sbuf_push(buf, 0, "\n");
-                               sbuf_push(buf, indent + 8, "[%.2x]", i + 1);
-                               rtn = 1;
-                       } else
-                               rtn++;
-               }
-               sbuf_push(buf, 0, "\n");
-       } else {
-               sbuf_push(buf, indent,
-                         "Unknown TLV: [type(%#.2x), length(%#.2x)]\n",
-                         tlvh->type, tlvh->length);
-       }
-
-       return SUBTLV_SIZE(tlvh);
-}
-
-/* Main Show function */
-void mpls_te_print_detail(struct sbuf *buf, int indent,
-                         uint8_t *subtlvs, uint8_t subtlv_len)
-{
-       struct subtlv_header *tlvh = (struct subtlv_header *)subtlvs;
-       uint16_t sum = 0;
-
-       for (; sum < subtlv_len;
-            tlvh = (struct subtlv_header *)(subtlvs + sum)) {
-               if (subtlv_len - sum < SUBTLV_SIZE(tlvh)) {
-                       sbuf_push(buf, indent, "Available data %" PRIu8 " is less than TLV size %u!\n",
-                                 subtlv_len - sum, SUBTLV_SIZE(tlvh));
-                       return;
-               }
-
-               switch (tlvh->type) {
-               case TE_SUBTLV_ADMIN_GRP:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Administrative Group!\n");
-                               return;
-                       }
-                       sum += print_subtlv_admin_grp(buf, indent,
-                               (struct te_subtlv_admin_grp *)tlvh);
-                       break;
-               case TE_SUBTLV_LLRI:
-                       if (tlvh->length != TE_SUBTLV_LLRI_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Link ID!\n");
-                               return;
-                       }
-                       sum += print_subtlv_llri(buf, indent,
-                                                (struct te_subtlv_llri *)tlvh);
-                       break;
-               case TE_SUBTLV_LOCAL_IPADDR:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Local IP address!\n");
-                               return;
-                       }
-                       sum += print_subtlv_local_ipaddr(buf, indent,
-                               (struct te_subtlv_local_ipaddr *)tlvh);
-                       break;
-               case TE_SUBTLV_RMT_IPADDR:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Remote Interface address!\n");
-                               return;
-                       }
-                       sum += print_subtlv_rmt_ipaddr(buf, indent,
-                               (struct te_subtlv_rmt_ipaddr *)tlvh);
-                       break;
-               case TE_SUBTLV_MAX_BW:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Maximum Bandwidth!\n");
-                               return;
-                       }
-                       sum += print_subtlv_max_bw(buf, indent,
-                               (struct te_subtlv_max_bw *)tlvh);
-                       break;
-               case TE_SUBTLV_MAX_RSV_BW:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Maximum Reservable Bandwidth!\n");
-                               return;
-                       }
-                       sum += print_subtlv_max_rsv_bw(buf, indent,
-                               (struct te_subtlv_max_rsv_bw *)tlvh);
-                       break;
-               case TE_SUBTLV_UNRSV_BW:
-                       if (tlvh->length != TE_SUBTLV_UNRSV_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Unreserved Bandwidth!\n");
-                               return;
-                       }
-                       sum += print_subtlv_unrsv_bw(buf, indent,
-                               (struct te_subtlv_unrsv_bw *)tlvh);
-                       break;
-               case TE_SUBTLV_TE_METRIC:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Traffic Engineering Metric!\n");
-                               return;
-                       }
-                       sum += print_subtlv_te_metric(buf, indent,
-                               (struct te_subtlv_te_metric *)tlvh);
-                       break;
-               case TE_SUBTLV_RAS:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Remote AS number!\n");
-                               return;
-                       }
-                       sum += print_subtlv_ras(buf, indent,
-                                               (struct te_subtlv_ras *)tlvh);
-                       break;
-               case TE_SUBTLV_RIP:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Remote ASBR IP Address!\n");
-                               return;
-                       }
-                       sum += print_subtlv_rip(buf, indent,
-                                               (struct te_subtlv_rip *)tlvh);
-                       break;
-               case TE_SUBTLV_AV_DELAY:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Average Link Delay!\n");
-                               return;
-                       }
-                       sum += print_subtlv_av_delay(buf, indent,
-                               (struct te_subtlv_av_delay *)tlvh);
-                       break;
-               case TE_SUBTLV_MM_DELAY:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Min/Max Link Delay!\n");
-                               return;
-                       }
-                       sum += print_subtlv_mm_delay(buf, indent,
-                               (struct te_subtlv_mm_delay *)tlvh);
-                       break;
-               case TE_SUBTLV_DELAY_VAR:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Delay Variation!\n");
-                               return;
-                       }
-                       sum += print_subtlv_delay_var(buf, indent,
-                               (struct te_subtlv_delay_var *)tlvh);
-                       break;
-               case TE_SUBTLV_PKT_LOSS:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Link Packet Loss!\n");
-                               return;
-                       }
-                       sum += print_subtlv_pkt_loss(buf, indent,
-                               (struct te_subtlv_pkt_loss *)tlvh);
-                       break;
-               case TE_SUBTLV_RES_BW:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n");
-                               return;
-                       }
-                       sum += print_subtlv_res_bw(buf, indent,
-                               (struct te_subtlv_res_bw *)tlvh);
-                       break;
-               case TE_SUBTLV_AVA_BW:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Unidirectional Available Bandwidth!\n");
-                               return;
-                       }
-                       sum += print_subtlv_ava_bw(buf, indent,
-                               (struct te_subtlv_ava_bw *)tlvh);
-                       break;
-               case TE_SUBTLV_USE_BW:
-                       if (tlvh->length != SUBTLV_DEF_SIZE) {
-                               sbuf_push(buf, indent, "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n");
-                               return;
-                       }
-                       sum += print_subtlv_use_bw(buf, indent,
-                               (struct te_subtlv_use_bw *)tlvh);
-                       break;
-               default:
-                       sum += print_unknown_tlv(buf, indent, tlvh);
-                       break;
-               }
-       }
-       return;
-}
-
-/*------------------------------------------------------------------------*
- * Followings are vty command functions.
- *------------------------------------------------------------------------*/
+/* Followings are vty command functions */
 #ifndef FABRICD
 
 DEFUN (show_isis_mpls_te_router,
@@ -1092,45 +338,104 @@ DEFUN (show_isis_mpls_te_router,
        return CMD_SUCCESS;
 }
 
-static void show_mpls_te_sub(struct vty *vty, char *name,
-                            struct mpls_te_circuit *mtc)
+static void show_ext_sub(struct vty *vty, char *name,
+                        struct isis_ext_subtlvs *ext)
 {
        struct sbuf buf;
+       char ibuf[PREFIX2STR_BUFFER];
 
        sbuf_init(&buf, NULL, 0);
 
-       if (mtc->status != enable)
+       if (!ext || ext->status == EXT_DISABLE)
                return;
 
        vty_out(vty, "-- MPLS-TE link parameters for %s --\n", name);
 
        sbuf_reset(&buf);
-       print_subtlv_admin_grp(&buf, 4, &mtc->admin_grp);
-
-       if (SUBTLV_TYPE(mtc->local_ipaddr) != 0)
-               print_subtlv_local_ipaddr(&buf, 4, &mtc->local_ipaddr);
-       if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0)
-               print_subtlv_rmt_ipaddr(&buf, 4, &mtc->rmt_ipaddr);
-
-       print_subtlv_max_bw(&buf, 4, &mtc->max_bw);
-       print_subtlv_max_rsv_bw(&buf, 4, &mtc->max_rsv_bw);
-       print_subtlv_unrsv_bw(&buf, 4, &mtc->unrsv_bw);
-       print_subtlv_te_metric(&buf, 4, &mtc->te_metric);
-
-       if (IS_INTER_AS(mtc->type)) {
-               if (SUBTLV_TYPE(mtc->ras) != 0)
-                       print_subtlv_ras(&buf, 4, &mtc->ras);
-               if (SUBTLV_TYPE(mtc->rip) != 0)
-                       print_subtlv_rip(&buf, 4, &mtc->rip);
-       }
 
-       print_subtlv_av_delay(&buf, 4, &mtc->av_delay);
-       print_subtlv_mm_delay(&buf, 4, &mtc->mm_delay);
-       print_subtlv_delay_var(&buf, 4, &mtc->delay_var);
-       print_subtlv_pkt_loss(&buf, 4, &mtc->pkt_loss);
-       print_subtlv_res_bw(&buf, 4, &mtc->res_bw);
-       print_subtlv_ava_bw(&buf, 4, &mtc->ava_bw);
-       print_subtlv_use_bw(&buf, 4, &mtc->use_bw);
+       if (IS_SUBTLV(ext, EXT_ADM_GRP))
+               sbuf_push(&buf, 4, "Administrative Group: 0x%" PRIx32 "\n",
+                       ext->adm_group);
+       if (IS_SUBTLV(ext, EXT_LLRI)) {
+               sbuf_push(&buf, 4, "Link Local  ID: %" PRIu32 "\n",
+                         ext->local_llri);
+               sbuf_push(&buf, 4, "Link Remote ID: %" PRIu32 "\n",
+                         ext->remote_llri);
+       }
+       if (IS_SUBTLV(ext, EXT_LOCAL_ADDR))
+               sbuf_push(&buf, 4, "Local Interface IP Address(es): %s\n",
+                         inet_ntoa(ext->local_addr));
+       if (IS_SUBTLV(ext, EXT_NEIGH_ADDR))
+               sbuf_push(&buf, 4, "Remote Interface IP Address(es): %s\n",
+                         inet_ntoa(ext->neigh_addr));
+       if (IS_SUBTLV(ext, EXT_LOCAL_ADDR6))
+               sbuf_push(&buf, 4, "Local Interface IPv6 Address(es): %s\n",
+                         inet_ntop(AF_INET6, &ext->local_addr6, ibuf,
+                                   PREFIX2STR_BUFFER));
+       if (IS_SUBTLV(ext, EXT_NEIGH_ADDR6))
+               sbuf_push(&buf, 4, "Remote Interface IPv6 Address(es): %s\n",
+                         inet_ntop(AF_INET6, &ext->local_addr6, ibuf,
+                                   PREFIX2STR_BUFFER));
+       if (IS_SUBTLV(ext, EXT_MAX_BW))
+               sbuf_push(&buf, 4, "Maximum Bandwidth: %g (Bytes/sec)\n",
+                         ext->max_bw);
+       if (IS_SUBTLV(ext, EXT_MAX_RSV_BW))
+               sbuf_push(&buf, 4,
+                         "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
+                         ext->max_rsv_bw);
+       if (IS_SUBTLV(ext, EXT_UNRSV_BW)) {
+               sbuf_push(&buf, 4, "Unreserved Bandwidth:\n");
+               for (int j = 0; j < MAX_CLASS_TYPE; j += 2) {
+                       sbuf_push(&buf, 4 + 2,
+                                 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
+                                 j, ext->unrsv_bw[j],
+                                 j + 1, ext->unrsv_bw[j + 1]);
+               }
+       }
+       if (IS_SUBTLV(ext, EXT_TE_METRIC))
+               sbuf_push(&buf, 4, "Traffic Engineering Metric: %u\n",
+                         ext->te_metric);
+       if (IS_SUBTLV(ext, EXT_RMT_AS))
+               sbuf_push(&buf, 4,
+                         "Inter-AS TE Remote AS number: %" PRIu32 "\n",
+                         ext->remote_as);
+       if (IS_SUBTLV(ext, EXT_RMT_IP))
+               sbuf_push(&buf, 4,
+                         "Inter-AS TE Remote ASBR IP address: %s\n",
+                         inet_ntoa(ext->remote_ip));
+       if (IS_SUBTLV(ext, EXT_DELAY))
+               sbuf_push(&buf, 4,
+                         "%s Average Link Delay: %" PRIu32 " (micro-sec)\n",
+                         IS_ANORMAL(ext->delay) ? "Anomalous" : "Normal",
+                         ext->delay);
+       if (IS_SUBTLV(ext, EXT_MM_DELAY)) {
+               sbuf_push(&buf, 4, "%s Min/Max Link Delay: %" PRIu32 " / %"
+                         PRIu32 " (micro-sec)\n",
+                         IS_ANORMAL(ext->min_delay) ? "Anomalous" : "Normal",
+                         ext->min_delay & TE_EXT_MASK,
+                         ext->max_delay & TE_EXT_MASK);
+       }
+       if (IS_SUBTLV(ext, EXT_DELAY_VAR))
+               sbuf_push(&buf, 4,
+                         "Delay Variation: %" PRIu32 " (micro-sec)\n",
+                         ext->delay_var & TE_EXT_MASK);
+       if (IS_SUBTLV(ext, EXT_PKT_LOSS))
+               sbuf_push(&buf, 4, "%s Link Packet Loss: %g (%%)\n",
+                         IS_ANORMAL(ext->pkt_loss) ? "Anomalous" : "Normal",
+                         (float)((ext->pkt_loss & TE_EXT_MASK)
+                                 * LOSS_PRECISION));
+       if (IS_SUBTLV(ext, EXT_RES_BW))
+               sbuf_push(&buf, 4,
+                         "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
+                         ext->res_bw);
+       if (IS_SUBTLV(ext, EXT_AVA_BW))
+               sbuf_push(&buf, 4,
+                         "Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
+                         ext->ava_bw);
+       if (IS_SUBTLV(ext, EXT_USE_BW))
+               sbuf_push(&buf, 4,
+                         "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
+                         ext->use_bw);
 
        vty_multiline(vty, "", "%s", sbuf_buf(&buf));
        vty_out(vty, "---------------\n\n");
@@ -1170,8 +475,8 @@ DEFUN (show_isis_mpls_te_interface,
 
                        for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode,
                                                  circuit))
-                               show_mpls_te_sub(vty, circuit->interface->name,
-                                                circuit->mtc);
+                               show_ext_sub(vty, circuit->interface->name,
+                                            circuit->ext);
                }
        } else {
                /* Interface name is specified. */
@@ -1185,7 +490,7 @@ DEFUN (show_isis_mpls_te_interface,
                                        "ISIS is not enabled on circuit %s\n",
                                        ifp->name);
                        else
-                               show_mpls_te_sub(vty, ifp->name, circuit->mtc);
+                               show_ext_sub(vty, ifp->name, circuit->ext);
                }
        }
 
@@ -1197,6 +502,11 @@ DEFUN (show_isis_mpls_te_interface,
 void isis_mpls_te_init(void)
 {
 
+       /* Register Circuit and Adjacency hook */
+       hook_register(isis_if_new_hook, isis_mpls_te_update);
+       hook_register(isis_adj_state_change_hook, isis_link_update_adj_hook);
+
+
 #ifndef FABRICD
        /* Register new VTY commands */
        install_element(VIEW_NODE, &show_isis_mpls_te_router_cmd);
index beb0c1836ff9b58c74529b9204514bed853207d4..2a6911d5006beaad1337376ba6b7ffe900bd362d 100644 (file)
@@ -3,8 +3,9 @@
  *
  * This is an implementation of RFC5305, RFC 5307 and RFC 7810
  *
- *      Copyright (C) 2014 Orange Labs
- *      http://www.orange.com
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ *
+ * Copyright (C) 2014 - 2019 Orange Labs http://www.orange.com
  *
  * This file is part of GNU Zebra.
  *
  * Remote AS number                  24   RFC5316
  * IPv4 Remote ASBR identifier       25   RFC5316
  *
+ * NOTE: RFC5316 is not fully supported in this version
+ * only subTLVs decoding is provided
  */
 
-/* NOTE: RFC5316 is not yet supported in this version */
-
 /* Following define the type of TE link regarding the various RFC */
 #define STD_TE                 0x01
 #define GMPLS                  0x02
 #define IS_INTER_AS_AS(x)      (x & INTER_AS & FLOOD_AS)
 
 /*
- * Following section defines subTLV (tag, length, value) structures,
- * used for Traffic Engineering.
+ * Note (since release 7.2), subTLVs definition, serialization
+ * and de-serialization have mode to isis_tlvs.[c,h]
  */
-struct subtlv_header {
-       uint8_t type;   /* sub_TLV_XXX type (see above) */
-       uint8_t length; /* Value portion only, in byte */
-};
-
-#define MAX_SUBTLV_SIZE 256
-
-#define SUBTLV_HDR_SIZE        2  /* (sizeof (struct sub_tlv_header)) */
-
-#define SUBTLV_SIZE(stlvh)     (SUBTLV_HDR_SIZE + (stlvh)->length)
-
-#define SUBTLV_HDR_TOP(lsph)   (struct subtlv_header *)((char *)(lsph) + ISIS_LSP_HEADER_SIZE)
-
-#define SUBTLV_HDR_NEXT(stlvh)         (struct subtlv_header *)((char *)(stlvh) + SUBTLV_SIZE(stlvh))
-
-#define SUBTLV_TYPE(stlvh)     stlvh.header.type
-#define SUBTLV_LEN(stlvh)      stlvh.header.length
-#define SUBTLV_VAL(stlvh)      stlvh.value
-#define SUBTLV_DATA(stlvh)     stlvh + SUBTLV_HDR_SIZE
-
-#define SUBTLV_DEF_SIZE                4
-
-/* Link Sub-TLV: Resource Class/Color - RFC 5305 */
-#define TE_SUBTLV_ADMIN_GRP    3
-struct te_subtlv_admin_grp {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       uint32_t value;              /* Admin. group membership. */
-} __attribute__((__packed__));
-
-/* Link Local/Remote Identifiers - RFC 5307 */
-#define TE_SUBTLV_LLRI         4
-#define TE_SUBTLV_LLRI_SIZE    8
-struct te_subtlv_llri {
-       struct subtlv_header header; /* Value length is 8 octets. */
-       uint32_t local;              /* Link Local Identifier */
-       uint32_t remote;             /* Link Remote Identifier */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Local Interface IP Address - RFC 5305 */
-#define TE_SUBTLV_LOCAL_IPADDR 6
-struct te_subtlv_local_ipaddr {
-       struct subtlv_header header; /* Value length is 4 x N octets. */
-       struct in_addr value;   /* Local IP address(es). */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Neighbor Interface IP Address - RFC 5305 */
-#define TE_SUBTLV_RMT_IPADDR   8
-struct te_subtlv_rmt_ipaddr {
-       struct subtlv_header header; /* Value length is 4 x N octets. */
-       struct in_addr value;   /* Neighbor's IP address(es). */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Maximum Bandwidth - RFC 5305 */
-#define TE_SUBTLV_MAX_BW       9
-struct te_subtlv_max_bw {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       float value;                 /* bytes/sec */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Maximum Reservable Bandwidth - RFC 5305 */
-#define TE_SUBTLV_MAX_RSV_BW   10
-struct te_subtlv_max_rsv_bw {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       float value;                 /* bytes/sec */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Unreserved Bandwidth - RFC 5305 */
-#define TE_SUBTLV_UNRSV_BW     11
-#define TE_SUBTLV_UNRSV_SIZE   32
-struct te_subtlv_unrsv_bw {
-       struct subtlv_header header; /* Value length is 32 octets. */
-       float value[8];              /* One for each priority level. */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Traffic Engineering Metric - RFC 5305 */
-#define TE_SUBTLV_TE_METRIC    18
-#define TE_SUBTLV_TE_METRIC_SIZE    3
-struct te_subtlv_te_metric {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       uint8_t value[3];           /* Link metric for TE purpose. */
-} __attribute__((__packed__));
-
-/* Remote AS Number sub-TLV - RFC5316 */
-#define TE_SUBTLV_RAS          24
-struct te_subtlv_ras {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       uint32_t value;              /* Remote AS number */
-} __attribute__((__packed__));
-
-/* IPv4 Remote ASBR ID Sub-TLV - RFC5316 */
-#define TE_SUBTLV_RIP          25
-struct te_subtlv_rip {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       struct in_addr value;   /* Remote ASBR IP address */
-} __attribute__((__packed__));
-
-
-/* TE Metric Extensions - RFC 7810 */
-/* Link Sub-TLV: Average Link Delay */
-#define TE_SUBTLV_AV_DELAY     33
-struct te_subtlv_av_delay {
-       struct subtlv_header header; /* Value length is 4 bytes. */
-       uint32_t value; /* Average delay in micro-seconds only 24 bits => 0 ...
-                           16777215
-                           with Anomalous Bit (A) as Upper most bit */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Low/High Link Delay */
-#define TE_SUBTLV_MM_DELAY      34
-#define TE_SUBTLV_MM_DELAY_SIZE    8
-struct te_subtlv_mm_delay {
-       struct subtlv_header header; /* Value length is 8 bytes. */
-       uint32_t low;  /* low delay in micro-seconds only 24 bits => 0 ...
-                          16777215
-                          with Anomalous Bit (A) as Upper most bit */
-       uint32_t high; /* high delay in micro-seconds only 24 bits => 0 ...
-                          16777215 */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Link Delay Variation i.e. Jitter */
-#define TE_SUBTLV_DELAY_VAR     35
-struct te_subtlv_delay_var {
-       struct subtlv_header header; /* Value length is 4 bytes. */
-       uint32_t value; /* interval in micro-seconds only 24 bits => 0 ...
-                           16777215 */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Routine Unidirectional Link Packet Loss */
-#define TE_SUBTLV_PKT_LOSS     36
-struct te_subtlv_pkt_loss {
-       struct subtlv_header header; /* Value length is 4 bytes. */
-       uint32_t
-               value; /* in percentage of total traffic only 24 bits (2^24 - 2)
-                         with Anomalous Bit (A) as Upper most bit */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Unidirectional Residual Bandwidth */ /* Optional */
-#define TE_SUBTLV_RES_BW       37
-struct te_subtlv_res_bw {
-       struct subtlv_header header; /* Value length is 4 bytes. */
-       float value; /* bandwidth in IEEE floating point format with units in
-                       bytes per second */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Unidirectional Available Bandwidth */ /* Optional */
-#define TE_SUBTLV_AVA_BW       38
-struct te_subtlv_ava_bw {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       float value; /* bandwidth in IEEE floating point format with units in
-                       bytes per second */
-} __attribute__((__packed__));
-
-/* Link Sub-TLV: Unidirectional Utilized Bandwidth */ /* Optional */
-#define TE_SUBTLV_USE_BW        39
-struct te_subtlv_use_bw {
-       struct subtlv_header header; /* Value length is 4 octets. */
-       float value; /* bandwidth in IEEE floating point format with units in
-                       bytes per second */
-} __attribute__((__packed__));
-
-#define TE_SUBTLV_MAX          40      /* Last SUBTLV + 1 */
 
 /* Following declaration concerns the MPLS-TE and LINk-TE management */
 typedef enum _status_t { disable, enable, learn } status_t;
@@ -244,7 +84,10 @@ typedef enum _status_t { disable, enable, learn } status_t;
 /* Mode for Inter-AS LSP */ /* TODO: Check how if LSP is flooded in RFC5316 */
 typedef enum _interas_mode_t { off, region, as, emulate } interas_mode_t;
 
-#define IS_MPLS_TE(m)    (m && m->status == enable)
+#define IS_EXT_TE(e)    (e && e->status != 0                   \
+                          && e->status != EXT_ADJ_SID          \
+                          && e->status != EXT_LAN_ADJ_SID)
+#define IS_MPLS_TE(a)  (a && a->status == enable)
 
 /* Per area MPLS-TE parameters */
 struct mpls_te_area {
@@ -262,56 +105,9 @@ struct mpls_te_area {
        struct in_addr router_id;
 };
 
-/* Per Circuit MPLS-TE parameters */
-struct mpls_te_circuit {
-
-       /* Status of MPLS-TE on this interface */
-       status_t status;
-
-       /* Type of MPLS-TE circuit: STD_TE(RFC5305), INTER_AS(RFC5316),
-        * INTER_AS_EMU(RFC5316 emulated) */
-       uint8_t type;
-
-       /* Total size of sub_tlvs */
-       uint8_t length;
-
-       /* Store subTLV in network byte order. */
-       /* RFC5305 */
-       struct te_subtlv_admin_grp admin_grp;
-       /* RFC5307 */
-       struct te_subtlv_llri llri;
-       /* RFC5305 */
-       struct te_subtlv_local_ipaddr local_ipaddr;
-       struct te_subtlv_rmt_ipaddr rmt_ipaddr;
-       struct te_subtlv_max_bw max_bw;
-       struct te_subtlv_max_rsv_bw max_rsv_bw;
-       struct te_subtlv_unrsv_bw unrsv_bw;
-       struct te_subtlv_te_metric te_metric;
-       /* RFC5316 */
-       struct te_subtlv_ras ras;
-       struct te_subtlv_rip rip;
-       /* RFC7810 */
-       struct te_subtlv_av_delay av_delay;
-       struct te_subtlv_mm_delay mm_delay;
-       struct te_subtlv_delay_var delay_var;
-       struct te_subtlv_pkt_loss pkt_loss;
-       struct te_subtlv_res_bw res_bw;
-       struct te_subtlv_ava_bw ava_bw;
-       struct te_subtlv_use_bw use_bw;
-};
-
 /* Prototypes. */
 void isis_mpls_te_init(void);
-struct mpls_te_circuit *mpls_te_circuit_new(void);
-struct sbuf;
-void mpls_te_print_detail(struct sbuf *buf, int indent, uint8_t *subtlvs,
-                         uint8_t subtlv_len);
-void set_circuitparams_local_ipaddr(struct mpls_te_circuit *, struct in_addr);
-void set_circuitparams_rmt_ipaddr(struct mpls_te_circuit *, struct in_addr);
-uint8_t subtlvs_len(struct mpls_te_circuit *);
-uint8_t add_te_subtlvs(uint8_t *, struct mpls_te_circuit *);
-uint8_t build_te_subtlvs(uint8_t *, struct isis_circuit *);
 void isis_link_params_update(struct isis_circuit *, struct interface *);
-void isis_mpls_te_update(struct interface *);
+int isis_mpls_te_update(struct interface *);
 
 #endif /* _ZEBRA_ISIS_MPLS_TE_H */
index bdf00b64cce15f3f98b909275148baeae27d46a9..442442152cbeb31f20b4b1c97b5330aba0ac2a90 100644 (file)
@@ -3,6 +3,8 @@
  *
  * Copyright (C) 2015,2017 Christian Franke
  *
+ * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR)
+ *
  * This file is part of FRR.
  *
  * FRR is free software; you can redistribute it and/or modify it
@@ -28,6 +30,7 @@
 #include "memory.h"
 #include "stream.h"
 #include "sbuf.h"
+#include "network.h"
 
 #include "isisd/isisd.h"
 #include "isisd/isis_memory.h"
@@ -98,7 +101,8 @@ static struct pack_order_entry pack_order[] = {
        PACK_ENTRY(EXTENDED_IP_REACH, ISIS_ITEMS, extended_ip_reach),
        PACK_ENTRY(MT_IP_REACH, ISIS_MT_ITEMS, mt_ip_reach),
        PACK_ENTRY(IPV6_REACH, ISIS_ITEMS, ipv6_reach),
-       PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach)};
+       PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach)
+};
 
 /* This is a forward definition. The table is actually initialized
  * in at the bottom. */
@@ -108,9 +112,683 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX];
 
 /* Prototypes */
 static void append_item(struct isis_item_list *dest, struct isis_item *item);
+static void init_item_list(struct isis_item_list *items);
 
-/* Functions for Sub-TLV 3 SR Prefix-SID */
+/* Functions for Extended IS Reachability SubTLVs a.k.a Traffic Engineering */
+struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void)
+{
+       struct isis_ext_subtlvs *ext;
+
+       ext = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_ext_subtlvs));
+       init_item_list(&ext->adj_sid);
+       init_item_list(&ext->lan_sid);
+
+       return ext;
+}
+
+/*
+ * mtid parameter is used to determine if Adjacency is related to IPv4 or IPv6.
+ * A negative value could be used to skip copy of Adjacency SID.
+ */
+static struct isis_ext_subtlvs *
+copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, int16_t mtid)
+{
+       struct isis_ext_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
+       struct isis_adj_sid *adj;
+       struct isis_lan_adj_sid *lan;
+
+       memcpy(rv, exts, sizeof(struct isis_ext_subtlvs));
+       init_item_list(&rv->adj_sid);
+       init_item_list(&rv->lan_sid);
+
+       UNSET_SUBTLV(rv, EXT_ADJ_SID);
+       UNSET_SUBTLV(rv, EXT_LAN_ADJ_SID);
+
+       /* Copy Adj SID and LAN Adj SID list for IPv4 if needed */
+       for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj != NULL;
+            adj = adj->next) {
+               if ((mtid != -1)
+                   && (((mtid == ISIS_MT_IPV4_UNICAST)
+                        && (adj->family != AF_INET))
+                       || ((mtid == ISIS_MT_IPV6_UNICAST)
+                           && (adj->family != AF_INET6))))
+                       continue;
+
+               struct isis_adj_sid *new;
+
+               new = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_adj_sid));
+               new->family = adj->family;
+               new->flags = adj->flags;
+               new->weight = adj->weight;
+               new->sid = adj->sid;
+               append_item(&rv->adj_sid, (struct isis_item *)new);
+               SET_SUBTLV(rv, EXT_ADJ_SID);
+       }
 
+       for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan != NULL;
+            lan = lan->next) {
+               if ((mtid != -1)
+                   && (((mtid == ISIS_MT_IPV4_UNICAST)
+                        && (lan->family != AF_INET))
+                       || ((mtid == ISIS_MT_IPV6_UNICAST)
+                           && (lan->family != AF_INET6))))
+                       continue;
+
+               struct isis_lan_adj_sid *new;
+
+               new = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_lan_adj_sid));
+               new->family = lan->family;
+               new->flags = lan->flags;
+               new->weight = lan->weight;
+               memcpy(new->neighbor_id, lan->neighbor_id, 6);
+               new->sid = lan->sid;
+               append_item(&rv->lan_sid, (struct isis_item *)new);
+               SET_SUBTLV(rv, EXT_LAN_ADJ_SID);
+       }
+
+       return rv;
+}
+
+/* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
+static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
+                                   struct sbuf *buf, int indent,
+                                   uint16_t mtid)
+{
+
+       char ibuf[PREFIX2STR_BUFFER];
+
+       /* Standard metrics */
+       if (IS_SUBTLV(exts, EXT_ADM_GRP))
+               sbuf_push(buf, indent, "Administrative Group: 0x%" PRIx32 "\n",
+                       exts->adm_group);
+       if (IS_SUBTLV(exts, EXT_LLRI)) {
+               sbuf_push(buf, indent, "Link Local  ID: %" PRIu32 "\n",
+                         exts->local_llri);
+               sbuf_push(buf, indent, "Link Remote ID: %" PRIu32 "\n",
+                         exts->remote_llri);
+       }
+       if (IS_SUBTLV(exts, EXT_LOCAL_ADDR))
+               sbuf_push(buf, indent, "Local Interface IP Address(es): %s\n",
+                         inet_ntoa(exts->local_addr));
+       if (IS_SUBTLV(exts, EXT_NEIGH_ADDR))
+               sbuf_push(buf, indent, "Remote Interface IP Address(es): %s\n",
+                         inet_ntoa(exts->neigh_addr));
+       if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6))
+               sbuf_push(buf, indent, "Local Interface IPv6 Address(es): %s\n",
+                       inet_ntop(AF_INET6, &exts->local_addr6, ibuf,
+                                 PREFIX2STR_BUFFER));
+       if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6))
+               sbuf_push(buf, indent, "Remote Interface IPv6 Address(es): %s\n",
+                       inet_ntop(AF_INET6, &exts->local_addr6, ibuf,
+                                 PREFIX2STR_BUFFER));
+       if (IS_SUBTLV(exts, EXT_MAX_BW))
+               sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n",
+                         exts->max_bw);
+       if (IS_SUBTLV(exts, EXT_MAX_RSV_BW))
+               sbuf_push(buf, indent,
+                         "Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
+                         exts->max_rsv_bw);
+       if (IS_SUBTLV(exts, EXT_UNRSV_BW)) {
+               sbuf_push(buf, indent, "Unreserved Bandwidth:\n");
+               for (int j = 0; j < MAX_CLASS_TYPE; j += 2) {
+                       sbuf_push(buf, indent + 2,
+                                 "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
+                                 j, exts->unrsv_bw[j],
+                                 j + 1, exts->unrsv_bw[j + 1]);
+               }
+       }
+       if (IS_SUBTLV(exts, EXT_TE_METRIC))
+               sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n",
+                         exts->te_metric);
+       if (IS_SUBTLV(exts, EXT_RMT_AS))
+               sbuf_push(buf, indent,
+                         "Inter-AS TE Remote AS number: %" PRIu32 "\n",
+                         exts->remote_as);
+       if (IS_SUBTLV(exts, EXT_RMT_IP))
+               sbuf_push(buf, indent,
+                         "Inter-AS TE Remote ASBR IP address: %s\n",
+                         inet_ntoa(exts->remote_ip));
+       /* Extended metrics */
+       if (IS_SUBTLV(exts, EXT_DELAY))
+               sbuf_push(buf, indent,
+                         "%s Average Link Delay: %" PRIu32 " (micro-sec)\n",
+                         IS_ANORMAL(exts->delay) ? "Anomalous" : "Normal",
+                         exts->delay);
+       if (IS_SUBTLV(exts, EXT_MM_DELAY)) {
+               sbuf_push(buf, indent, "%s Min/Max Link Delay: %" PRIu32 " / %"
+                         PRIu32 " (micro-sec)\n",
+                         IS_ANORMAL(exts->min_delay) ? "Anomalous" : "Normal",
+                         exts->min_delay & TE_EXT_MASK,
+                         exts->max_delay & TE_EXT_MASK);
+       }
+       if (IS_SUBTLV(exts, EXT_DELAY_VAR)) {
+               sbuf_push(buf, indent,
+                         "Delay Variation: %" PRIu32 " (micro-sec)\n",
+                         exts->delay_var & TE_EXT_MASK);
+       }
+       if (IS_SUBTLV(exts, EXT_PKT_LOSS))
+               sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n",
+                         IS_ANORMAL(exts->pkt_loss) ? "Anomalous" : "Normal",
+                         (float)((exts->pkt_loss & TE_EXT_MASK)
+                                 * LOSS_PRECISION));
+       if (IS_SUBTLV(exts, EXT_RES_BW))
+               sbuf_push(buf, indent,
+                         "Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
+                         exts->res_bw);
+       if (IS_SUBTLV(exts, EXT_AVA_BW))
+               sbuf_push(buf, indent,
+                         "Unidir. Available Bandwidth: %g (Bytes/sec)\n",
+                         exts->ava_bw);
+       if (IS_SUBTLV(exts, EXT_USE_BW))
+               sbuf_push(buf, indent,
+                         "Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
+                         exts->use_bw);
+       /* Segment Routing Adjacency */
+       if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
+               struct isis_adj_sid *adj;
+
+               for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj;
+                    adj = adj->next) {
+                       if (((mtid == ISIS_MT_IPV4_UNICAST)
+                            && (adj->family != AF_INET))
+                           || ((mtid == ISIS_MT_IPV6_UNICAST)
+                               && (adj->family != AF_INET6)))
+                               continue;
+                       sbuf_push(
+                               buf, indent,
+                               "Adjacency-SID: %" PRIu32 ", Weight: %" PRIu8
+                               ", Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n",
+                               adj->sid, adj->weight,
+                               adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? '1'
+                                                                         : '0',
+                               adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? '1'
+                                                                         : '0',
+                               adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? '1'
+                                                                         : '0',
+                               adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? '1'
+                                                                         : '0',
+                               adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? '1'
+                                                                         : '0',
+                               adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
+                                       ? '1'
+                                       : '0');
+               }
+       }
+       if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
+               struct isis_lan_adj_sid *lan;
+
+               for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head;
+                    lan; lan = lan->next) {
+                       if (((mtid == ISIS_MT_IPV4_UNICAST)
+                            && (lan->family != AF_INET))
+                           || ((mtid == ISIS_MT_IPV6_UNICAST)
+                               && (lan->family != AF_INET6)))
+                               continue;
+                       sbuf_push(buf, indent,
+                                 "Lan-Adjacency-SID: %" PRIu32
+                                 ", Weight: %" PRIu8
+                                 ", Flags: F:%c B:%c, V:%c, L:%c, S:%c, P:%c\n"
+                                 "  Neighbor-ID: %s\n",
+                                 lan->sid, lan->weight,
+                                 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG
+                                         ? '1'
+                                         : '0',
+                                 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG
+                                         ? '1'
+                                         : '0',
+                                 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG
+                                         ? '1'
+                                         : '0',
+                                 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG
+                                         ? '1'
+                                         : '0',
+                                 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG
+                                         ? '1'
+                                         : '0',
+                                 lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG
+                                         ? '1'
+                                         : '0',
+                                 isis_format_id(lan->neighbor_id, 6));
+               }
+       }
+}
+
+static void free_item_ext_subtlvs(struct  isis_ext_subtlvs *exts)
+{
+       struct isis_item *item, *next_item;
+
+       /* First, free Adj SID and LAN Adj SID list if needed */
+       for (item = exts->adj_sid.head; item; item = next_item) {
+               next_item = item->next;
+               XFREE(MTYPE_ISIS_SUBTLV, item);
+       }
+       for (item = exts->lan_sid.head; item; item = next_item) {
+               next_item = item->next;
+               XFREE(MTYPE_ISIS_SUBTLV, item);
+       }
+       XFREE(MTYPE_ISIS_SUBTLV, exts);
+}
+
+static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
+                                struct stream *s)
+{
+       uint8_t size;
+
+       if (STREAM_WRITEABLE(s) < ISIS_SUBTLV_MAX_SIZE)
+               return 1;
+
+       if (IS_SUBTLV(exts, EXT_ADM_GRP)) {
+               stream_putc(s, ISIS_SUBTLV_ADMIN_GRP);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putl(s, exts->adm_group);
+       }
+       if (IS_SUBTLV(exts, EXT_LLRI)) {
+               stream_putc(s, ISIS_SUBTLV_LLRI);
+               stream_putc(s, ISIS_SUBTLV_LLRI_SIZE);
+               stream_putl(s, exts->local_llri);
+               stream_putl(s, exts->remote_llri);
+       }
+       if (IS_SUBTLV(exts, EXT_LOCAL_ADDR)) {
+               stream_putc(s, ISIS_SUBTLV_LOCAL_IPADDR);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_put(s, &exts->local_addr.s_addr, 4);
+       }
+       if (IS_SUBTLV(exts, EXT_NEIGH_ADDR)) {
+               stream_putc(s, ISIS_SUBTLV_RMT_IPADDR);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_put(s, &exts->neigh_addr.s_addr, 4);
+       }
+       if (IS_SUBTLV(exts, EXT_LOCAL_ADDR6)) {
+               stream_putc(s, ISIS_SUBTLV_LOCAL_IPADDR6);
+               stream_putc(s, ISIS_SUBTLV_IPV6_ADDR_SIZE);
+               stream_put(s, &exts->local_addr6, 16);
+       }
+       if (IS_SUBTLV(exts, EXT_NEIGH_ADDR6)) {
+               stream_putc(s, ISIS_SUBTLV_RMT_IPADDR6);
+               stream_putc(s, ISIS_SUBTLV_IPV6_ADDR_SIZE);
+               stream_put(s, &exts->neigh_addr6, 16);
+       }
+       if (IS_SUBTLV(exts, EXT_MAX_BW)) {
+               stream_putc(s, ISIS_SUBTLV_MAX_BW);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putf(s, exts->max_bw);
+       }
+       if (IS_SUBTLV(exts, EXT_MAX_RSV_BW)) {
+               stream_putc(s, ISIS_SUBTLV_MAX_RSV_BW);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putf(s, exts->max_rsv_bw);
+       }
+       if (IS_SUBTLV(exts, EXT_UNRSV_BW)) {
+               stream_putc(s, ISIS_SUBTLV_UNRSV_BW);
+               stream_putc(s, ISIS_SUBTLV_UNRSV_BW_SIZE);
+               for (int j = 0; j < MAX_CLASS_TYPE; j++)
+                       stream_putf(s, exts->unrsv_bw[j]);
+       }
+       if (IS_SUBTLV(exts, EXT_TE_METRIC)) {
+               stream_putc(s, ISIS_SUBTLV_TE_METRIC);
+               stream_putc(s, ISIS_SUBTLV_TE_METRIC_SIZE);
+               stream_put3(s, exts->te_metric);
+       }
+       if (IS_SUBTLV(exts, EXT_RMT_AS)) {
+               stream_putc(s, ISIS_SUBTLV_RAS);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putl(s, exts->remote_as);
+       }
+       if (IS_SUBTLV(exts, EXT_RMT_IP)) {
+               stream_putc(s, ISIS_SUBTLV_RIP);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_put(s, &exts->remote_ip.s_addr, 4);
+       }
+       if (IS_SUBTLV(exts, EXT_DELAY)) {
+               stream_putc(s, ISIS_SUBTLV_AV_DELAY);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putl(s, exts->delay);
+       }
+       if (IS_SUBTLV(exts, EXT_MM_DELAY)) {
+               stream_putc(s, ISIS_SUBTLV_MM_DELAY);
+               stream_putc(s, ISIS_SUBTLV_MM_DELAY_SIZE);
+               stream_putl(s, exts->min_delay);
+               stream_putl(s, exts->max_delay);
+       }
+       if (IS_SUBTLV(exts, EXT_DELAY_VAR)) {
+               stream_putc(s, ISIS_SUBTLV_DELAY_VAR);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putl(s, exts->delay_var);
+       }
+       if (IS_SUBTLV(exts, EXT_PKT_LOSS)) {
+               stream_putc(s, ISIS_SUBTLV_PKT_LOSS);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putl(s, exts->pkt_loss);
+       }
+       if (IS_SUBTLV(exts, EXT_RES_BW)) {
+               stream_putc(s, ISIS_SUBTLV_RES_BW);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putf(s, exts->res_bw);
+       }
+       if (IS_SUBTLV(exts, EXT_AVA_BW)) {
+               stream_putc(s, ISIS_SUBTLV_AVA_BW);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putf(s, exts->ava_bw);
+       }
+       if (IS_SUBTLV(exts, EXT_USE_BW)) {
+               stream_putc(s, ISIS_SUBTLV_USE_BW);
+               stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
+               stream_putf(s, exts->use_bw);
+       }
+       if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
+               struct isis_adj_sid *adj;
+
+               for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj;
+                    adj = adj->next) {
+                       stream_putc(s, ISIS_SUBTLV_ADJ_SID);
+                       size = ISIS_SUBTLV_ADJ_SID_SIZE;
+                       if (!(adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG))
+                               size++;
+                       stream_putc(s, size);
+                       stream_putc(s, adj->flags);
+                       stream_putc(s, adj->weight);
+                       if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)
+                               stream_put3(s, adj->sid);
+                       else
+                               stream_putl(s, adj->sid);
+
+               }
+       }
+       if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
+               struct isis_lan_adj_sid *lan;
+
+               for (lan = (struct isis_lan_adj_sid *)exts->lan_sid.head; lan;
+                    lan = lan->next) {
+                       stream_putc(s, ISIS_SUBTLV_LAN_ADJ_SID);
+                       size = ISIS_SUBTLV_LAN_ADJ_SID_SIZE;
+                       if (!(lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG))
+                               size++;
+                       stream_putc(s, size);
+                       stream_putc(s, lan->flags);
+                       stream_putc(s, lan->weight);
+                       stream_put(s, lan->neighbor_id, 6);
+                       if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG)
+                               stream_put3(s, lan->sid);
+                       else
+                               stream_putl(s, lan->sid);
+               }
+       }
+
+       return 0;
+}
+
+static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s,
+                                  struct sbuf *log, void *dest, int indent)
+{
+       uint8_t sum = 0;
+       uint8_t subtlv_type;
+       uint8_t subtlv_len;
+
+       struct isis_extended_reach *rv = dest;
+       struct isis_ext_subtlvs *exts = isis_alloc_ext_subtlvs();
+
+       rv->subtlvs = exts;
+
+       /*
+        * Parse subTLVs until reach subTLV length
+        * Check that it remains at least 2 bytes: subTLV Type & Length
+        */
+       while (len > sum + 2) {
+               /* Read SubTLV Type and Length */
+               subtlv_type = stream_getc(s);
+               subtlv_len = stream_getc(s);
+               if (subtlv_len > len - sum) {
+                       sbuf_push(log, indent, "TLV %" PRIu8 ": Available data %" PRIu8 " is less than TLV size %u !\n",
+                                 subtlv_type, len - sum, subtlv_len);
+                       return 1;
+               }
+
+               switch (subtlv_type) {
+               /* Standard Metric as defined in RFC5305 */
+               case ISIS_SUBTLV_ADMIN_GRP:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Administrative Group!\n");
+                       } else {
+                               exts->adm_group = stream_getl(s);
+                               SET_SUBTLV(exts, EXT_ADM_GRP);
+                       }
+                       break;
+               case ISIS_SUBTLV_LLRI:
+                       if (subtlv_len != ISIS_SUBTLV_LLRI_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Link ID!\n");
+                       } else {
+                               exts->local_llri = stream_getl(s);
+                               exts->remote_llri = stream_getl(s);
+                               SET_SUBTLV(exts, EXT_LLRI);
+                       }
+                       break;
+               case ISIS_SUBTLV_LOCAL_IPADDR:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Local IP address!\n");
+                       } else {
+                               stream_get(&exts->local_addr.s_addr, s, 4);
+                               SET_SUBTLV(exts, EXT_LOCAL_ADDR);
+                       }
+                       break;
+               case ISIS_SUBTLV_RMT_IPADDR:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Remote IP address!\n");
+                       } else {
+                               stream_get(&exts->neigh_addr.s_addr, s, 4);
+                               SET_SUBTLV(exts, EXT_NEIGH_ADDR);
+                       }
+                       break;
+               case ISIS_SUBTLV_LOCAL_IPADDR6:
+                       if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Local IPv6 address!\n");
+                       } else {
+                               stream_get(&exts->local_addr6, s, 16);
+                               SET_SUBTLV(exts, EXT_LOCAL_ADDR6);
+                       }
+                       break;
+               case ISIS_SUBTLV_RMT_IPADDR6:
+                       if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Remote IPv6 address!\n");
+                       } else {
+                               stream_get(&exts->neigh_addr6, s, 16);
+                               SET_SUBTLV(exts, EXT_NEIGH_ADDR6);
+                       }
+                       break;
+               case ISIS_SUBTLV_MAX_BW:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Maximum Bandwidth!\n");
+                       } else {
+                               exts->max_bw = stream_getf(s);
+                               SET_SUBTLV(exts, EXT_MAX_BW);
+                       }
+                       break;
+               case ISIS_SUBTLV_MAX_RSV_BW:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Maximum Reservable Bandwidth!\n");
+                       } else {
+                               exts->max_rsv_bw = stream_getf(s);
+                               SET_SUBTLV(exts, EXT_MAX_RSV_BW);
+                       }
+                       break;
+               case ISIS_SUBTLV_UNRSV_BW:
+                       if (subtlv_len != ISIS_SUBTLV_UNRSV_BW_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Unreserved Bandwidth!\n");
+                       } else {
+                               for (int i = 0; i < MAX_CLASS_TYPE; i++)
+                                       exts->unrsv_bw[i] = stream_getf(s);
+                               SET_SUBTLV(exts, EXT_UNRSV_BW);
+                       }
+                       break;
+               case ISIS_SUBTLV_TE_METRIC:
+                       if (subtlv_len != ISIS_SUBTLV_TE_METRIC_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Traffic Engineering Metric!\n");
+                       } else {
+                               exts->te_metric = stream_get3(s);
+                               SET_SUBTLV(exts, EXT_TE_METRIC);
+                       }
+                       break;
+               case ISIS_SUBTLV_RAS:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Remote AS number!\n");
+                       } else {
+                               exts->remote_as = stream_getl(s);
+                               SET_SUBTLV(exts, EXT_RMT_AS);
+                       }
+                       break;
+               case ISIS_SUBTLV_RIP:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Remote ASBR IP Address!\n");
+                       } else {
+                               stream_get(&exts->remote_ip.s_addr, s, 4);
+                               SET_SUBTLV(exts, EXT_RMT_IP);
+                       }
+                       break;
+               /* Extended Metrics as defined in RFC 7810 */
+               case ISIS_SUBTLV_AV_DELAY:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Average Link Delay!\n");
+                       } else {
+                               exts->delay = stream_getl(s);
+                               SET_SUBTLV(exts, EXT_DELAY);
+                       }
+                       break;
+               case ISIS_SUBTLV_MM_DELAY:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Min/Max Link Delay!\n");
+                       } else {
+                               exts->min_delay = stream_getl(s);
+                               exts->max_delay = stream_getl(s);
+                               SET_SUBTLV(exts, EXT_MM_DELAY);
+                       }
+                       break;
+               case ISIS_SUBTLV_DELAY_VAR:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Delay Variation!\n");
+                       } else {
+                               exts->delay_var = stream_getl(s);
+                               SET_SUBTLV(exts, EXT_DELAY_VAR);
+                       }
+                       break;
+               case ISIS_SUBTLV_PKT_LOSS:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Link Packet Loss!\n");
+                       } else {
+                               exts->pkt_loss = stream_getl(s);
+                               SET_SUBTLV(exts, EXT_PKT_LOSS);
+                       }
+                       break;
+               case ISIS_SUBTLV_RES_BW:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n");
+                       } else {
+                               exts->res_bw = stream_getf(s);
+                               SET_SUBTLV(exts, EXT_RES_BW);
+                       }
+                       break;
+               case ISIS_SUBTLV_AVA_BW:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Unidirectional Available Bandwidth!\n");
+                       } else {
+                               exts->ava_bw = stream_getf(s);
+                               SET_SUBTLV(exts, EXT_AVA_BW);
+                       }
+                       break;
+               case ISIS_SUBTLV_USE_BW:
+                       if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n");
+                       } else {
+                               exts->use_bw = stream_getf(s);
+                               SET_SUBTLV(exts, EXT_USE_BW);
+                       }
+                       break;
+               /* Segment Routing Adjacency */
+               case ISIS_SUBTLV_ADJ_SID:
+                       if (subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE
+                           && subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE + 1) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for Adjacency SID!\n");
+                       } else {
+                               struct isis_adj_sid *adj;
+
+                               adj = XCALLOC(MTYPE_ISIS_SUBTLV,
+                                             sizeof(struct isis_adj_sid));
+                               adj->flags = stream_getc(s);
+                               adj->weight = stream_getc(s);
+                               if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) {
+                                       adj->sid = stream_get3(s);
+                                       adj->sid &= MPLS_LABEL_VALUE_MASK;
+                               } else {
+                                       adj->sid = stream_getl(s);
+                               }
+                               if (mtid == ISIS_MT_IPV4_UNICAST)
+                                       adj->family = AF_INET;
+                               if (mtid == ISIS_MT_IPV6_UNICAST)
+                                       adj->family = AF_INET6;
+                               append_item(&exts->adj_sid,
+                                           (struct isis_item *)adj);
+                               SET_SUBTLV(exts, EXT_ADJ_SID);
+                       }
+                       break;
+               case ISIS_SUBTLV_LAN_ADJ_SID:
+                       if (subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
+                           && subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE + 1) {
+                               sbuf_push(log, indent,
+                                         "TLV size does not match expected size for LAN-Adjacency SID!\n");
+                       } else {
+                               struct isis_lan_adj_sid *lan;
+
+                               lan = XCALLOC(MTYPE_ISIS_SUBTLV,
+                                             sizeof(struct isis_lan_adj_sid));
+                               lan->flags = stream_getc(s);
+                               lan->weight = stream_getc(s);
+                               stream_get(&(lan->neighbor_id), s,
+                                          ISIS_SYS_ID_LEN);
+                               if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) {
+                                       lan->sid = stream_get3(s);
+                                       lan->sid &= MPLS_LABEL_VALUE_MASK;
+                               } else {
+                                       lan->sid = stream_getl(s);
+                               }
+                               if (mtid == ISIS_MT_IPV4_UNICAST)
+                                       lan->family = AF_INET;
+                               if (mtid == ISIS_MT_IPV6_UNICAST)
+                                       lan->family = AF_INET6;
+                               append_item(&exts->lan_sid,
+                                           (struct isis_item *)lan);
+                               SET_SUBTLV(exts, EXT_LAN_ADJ_SID);
+                       }
+                       break;
+               default:
+                       /* Skip unknown TLV */
+                       stream_forward_getp(s, subtlv_len);
+                       break;
+               }
+               sum += subtlv_len + ISIS_SUBTLV_HDR_SIZE;
+       }
+
+       return 0;
+}
+
+/* Functions for Sub-TLV 3 SR Prefix-SID */
 static struct isis_item *copy_item_prefix_sid(struct isis_item *i)
 {
        struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
@@ -127,20 +805,22 @@ static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i,
 {
        struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
 
-       sbuf_push(buf, indent, "SR Prefix-SID:\n");
-       sbuf_push(buf, indent, "  Flags:%s%s%s%s%s%s\n",
-                 sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED" : "",
-                 sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "",
-                 sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO_PHP" : "",
-                 sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL" : "",
-                 sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "",
-                 sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : "");
-       sbuf_push(buf, indent, "  Algorithm: %" PRIu8 "\n", sid->algorithm);
+       sbuf_push(buf, indent, "SR Prefix-SID ");
        if (sid->flags & ISIS_PREFIX_SID_VALUE) {
-               sbuf_push(buf, indent,  "Label: %" PRIu32 "\n", sid->value);
+               sbuf_push(buf, 0, "Label: %" PRIu32 ", ", sid->value);
        } else {
-               sbuf_push(buf, indent,  "Index: %" PRIu32 "\n", sid->value);
+               sbuf_push(buf, 0, "Index: %" PRIu32 ", ", sid->value);
        }
+       sbuf_push(buf, 0, "Algorithm: %" PRIu8 ", ", sid->algorithm);
+       sbuf_push(buf, 0, "Flags:%s%s%s%s%s%s\n",
+                 sid->flags & ISIS_PREFIX_SID_READVERTISED ? " READVERTISED"
+                                                           : "",
+                 sid->flags & ISIS_PREFIX_SID_NODE ? " NODE" : "",
+                 sid->flags & ISIS_PREFIX_SID_NO_PHP ? " NO-PHP" : " PHP",
+                 sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL ? " EXPLICIT-NULL"
+                                                            : "",
+                 sid->flags & ISIS_PREFIX_SID_VALUE ? " VALUE" : "",
+                 sid->flags & ISIS_PREFIX_SID_LOCAL ? " LOCAL" : "");
 }
 
 static void free_item_prefix_sid(struct isis_item *i)
@@ -188,13 +868,15 @@ static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s,
        sid.flags = stream_getc(s);
        if (!!(sid.flags & ISIS_PREFIX_SID_VALUE)
            != !!(sid.flags & ISIS_PREFIX_SID_LOCAL)) {
-               sbuf_push(log, indent, "Flags inplausible: Local Flag needs to match Value Flag\n");
+               sbuf_push(log, indent, "Flags implausible: Local Flag needs to match Value Flag\n");
                return 1;
        }
 
        sid.algorithm = stream_getc(s);
 
-       uint8_t expected_size = (sid.flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6;
+       uint8_t expected_size = (sid.flags & ISIS_PREFIX_SID_VALUE)
+                                       ? ISIS_SUBTLV_PREFIX_SID_SIZE
+                                       : ISIS_SUBTLV_PREFIX_SID_SIZE + 1;
        if (len != expected_size) {
                sbuf_push(log, indent,
                          "TLV size differs from expected size. "
@@ -205,6 +887,7 @@ static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s,
 
        if (sid.flags & ISIS_PREFIX_SID_VALUE) {
                sid.value = stream_get3(s);
+               sid.value &= MPLS_LABEL_VALUE_MASK;
        } else {
                sid.value = stream_getl(s);
        }
@@ -276,7 +959,7 @@ static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context,
 
        p.prefixlen = stream_getc(s);
        if (p.prefixlen > 128) {
-               sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv6\n",
+               sbuf_push(log, indent, "Prefixlen %u is implausible for IPv6\n",
                          p.prefixlen);
                return 1;
        }
@@ -305,7 +988,7 @@ static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context,
        memcpy(subtlvs->source_prefix, &p, sizeof(p));
        return 0;
 }
-static void init_item_list(struct isis_item_list *items);
+
 static struct isis_item *copy_item(enum isis_tlv_context context,
                                   enum isis_tlv_type type,
                                   struct isis_item *item);
@@ -703,11 +1386,8 @@ static struct isis_item *copy_item_extended_reach(struct isis_item *i)
        memcpy(rv->id, r->id, 7);
        rv->metric = r->metric;
 
-       if (r->subtlvs && r->subtlv_len) {
-               rv->subtlvs = XCALLOC(MTYPE_ISIS_TLV, r->subtlv_len);
-               memcpy(rv->subtlvs, r->subtlvs, r->subtlv_len);
-               rv->subtlv_len = r->subtlv_len;
-       }
+       if (r->subtlvs)
+               rv->subtlvs = copy_item_ext_subtlvs(r->subtlvs, -1);
 
        return (struct isis_item *)rv;
 }
@@ -724,28 +1404,37 @@ static void format_item_extended_reach(uint16_t mtid, struct isis_item *i,
                sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
        sbuf_push(buf, 0, "\n");
 
-       if (r->subtlv_len && r->subtlvs)
-               mpls_te_print_detail(buf, indent + 2, r->subtlvs,
-                                    r->subtlv_len);
+       if (r->subtlvs)
+               format_item_ext_subtlvs(r->subtlvs, buf, indent + 2, mtid);
 }
 
 static void free_item_extended_reach(struct isis_item *i)
 {
        struct isis_extended_reach *item = (struct isis_extended_reach *)i;
-       XFREE(MTYPE_ISIS_TLV, item->subtlvs);
+       if (item->subtlvs != NULL)
+               free_item_ext_subtlvs(item->subtlvs);
        XFREE(MTYPE_ISIS_TLV, item);
 }
 
 static int pack_item_extended_reach(struct isis_item *i, struct stream *s)
 {
        struct isis_extended_reach *r = (struct isis_extended_reach *)i;
+       size_t len;
+       size_t len_pos;
 
-       if (STREAM_WRITEABLE(s) < 11 + (unsigned)r->subtlv_len)
+       if (STREAM_WRITEABLE(s) < 11 + ISIS_SUBTLV_MAX_SIZE)
                return 1;
+
        stream_put(s, r->id, sizeof(r->id));
        stream_put3(s, r->metric);
-       stream_putc(s, r->subtlv_len);
-       stream_put(s, r->subtlvs, r->subtlv_len);
+       len_pos = stream_get_endp(s);
+        /* Real length will be adjust after adding subTLVs */
+       stream_putc(s, 11);
+       if (r->subtlvs)
+               pack_item_ext_subtlvs(r->subtlvs, s);
+       /* Adjust length */
+       len = stream_get_endp(s) - len_pos - 1;
+       stream_putc_at(s, len_pos, len);
        return 0;
 }
 
@@ -780,9 +1469,6 @@ static int unpack_item_extended_reach(uint16_t mtid, uint8_t len,
        rv->metric = stream_get3(s);
        subtlv_len = stream_getc(s);
 
-       format_item_extended_reach(mtid, (struct isis_item *)rv, log,
-                                  indent + 2);
-
        if ((size_t)len < ((size_t)11) + subtlv_len) {
                sbuf_push(log, indent,
                          "Not enough data left for subtlv size %" PRIu8
@@ -795,20 +1481,14 @@ static int unpack_item_extended_reach(uint16_t mtid, uint8_t len,
                  subtlv_len);
 
        if (subtlv_len) {
-               size_t subtlv_start = stream_get_getp(s);
-
-               if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_NE_REACH, subtlv_len, s,
-                               log, NULL, indent + 4, NULL)) {
+               if (unpack_item_ext_subtlvs(mtid, subtlv_len, s, log, rv,
+                                           indent + 4)) {
                        goto out;
                }
-
-               stream_set_getp(s, subtlv_start);
-
-               rv->subtlvs = XCALLOC(MTYPE_ISIS_TLV, subtlv_len);
-               stream_get(rv->subtlvs, s, subtlv_len);
-               rv->subtlv_len = subtlv_len;
        }
 
+       format_item_extended_reach(mtid, (struct isis_item *)rv, log,
+                                  indent + 2);
        append_item(items, (struct isis_item *)rv);
        return 0;
 out:
@@ -1257,6 +1937,7 @@ static struct isis_item *copy_item_extended_ip_reach(struct isis_item *i)
        rv->metric = r->metric;
        rv->down = r->down;
        rv->prefix = r->prefix;
+       rv->subtlvs = copy_subtlvs(r->subtlvs);
 
        return (struct isis_item *)rv;
 }
@@ -1348,7 +2029,7 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len,
        rv->prefix.family = AF_INET;
        rv->prefix.prefixlen = control & 0x3f;
        if (rv->prefix.prefixlen > 32) {
-               sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv4\n",
+               sbuf_push(log, indent, "Prefixlen %u is implausible for IPv4\n",
                          rv->prefix.prefixlen);
                goto out;
        }
@@ -1834,7 +2515,7 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
        rv->prefix.family = AF_INET6;
        rv->prefix.prefixlen = stream_getc(s);
        if (rv->prefix.prefixlen > 128) {
-               sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv6\n",
+               sbuf_push(log, indent, "Prefixlen %u is implausible for IPv6\n",
                          rv->prefix.prefixlen);
                goto out;
        }
@@ -1848,6 +2529,7 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
        }
        stream_get(&rv->prefix.prefix.s6_addr, s, PSIZE(rv->prefix.prefixlen));
        struct in6_addr orig_prefix = rv->prefix.prefix;
+
        apply_mask_ipv6(&rv->prefix);
        if (memcmp(&orig_prefix, &rv->prefix.prefix, sizeof(orig_prefix)))
                sbuf_push(log, indent + 2,
@@ -1898,6 +2580,222 @@ out:
        return 1;
 }
 
+/* Functions related to TLV 242 Router Capability */
+static struct isis_router_cap *copy_tlv_router_cap(
+                              const struct isis_router_cap *router_cap)
+{
+       struct isis_router_cap *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       if (!router_cap)
+               return NULL;
+
+       memcpy(rv, router_cap, sizeof(*rv));
+
+       return rv;
+}
+
+static void format_tlv_router_cap(const struct isis_router_cap *router_cap,
+                                 struct sbuf *buf, int indent)
+{
+       char addrbuf[INET_ADDRSTRLEN];
+
+       if (!router_cap)
+               return;
+
+       /* Router ID and Flags */
+       inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf));
+       sbuf_push(buf, indent, "Router Capability:");
+       sbuf_push(buf, indent, " %s , D:%c, S:%c\n", addrbuf,
+                 router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? '1' : '0',
+                 router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? '1' : '0');
+
+       /* SR Global Block */
+       if (router_cap->srgb.range_size != 0)
+               sbuf_push(buf, indent,
+                       "  Segment Routing: I:%s V:%s, SRGB Base: %d Range: %d\n",
+                       IS_SR_IPV4(router_cap->srgb) ? "1" : "0",
+                       IS_SR_IPV6(router_cap->srgb) ? "1" : "0",
+                       router_cap->srgb.lower_bound,
+                       router_cap->srgb.range_size);
+
+       /* SR Algorithms */
+       if (router_cap->algo[0] != SR_ALGORITHM_UNSET) {
+               sbuf_push(buf, indent, "    Algorithm: %s",
+                         router_cap->algo[0] == 0 ? "0: SPF"
+                                                  : "0: Strict SPF");
+               for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
+                       if (router_cap->algo[i] != SR_ALGORITHM_UNSET)
+                               sbuf_push(buf, indent, " %s",
+                                         router_cap->algo[1] == 0
+                                                 ? "0: SPF"
+                                                 : "0: Strict SPF");
+               sbuf_push(buf, indent, "\n");
+       }
+
+       /* SR Node MSSD */
+       if (router_cap->msd != 0)
+               sbuf_push(buf, indent, "    Node MSD: %d\n", router_cap->msd);
+}
+
+static void free_tlv_router_cap(struct isis_router_cap *router_cap)
+{
+       XFREE(MTYPE_ISIS_TLV, router_cap);
+}
+
+static int pack_tlv_router_cap(const struct isis_router_cap *router_cap,
+                              struct stream *s)
+{
+       size_t tlv_len = ISIS_ROUTER_CAP_SIZE;
+       size_t len_pos;
+       uint8_t nb_algo;
+
+       if (!router_cap)
+               return 0;
+
+       /* Compute Maximum TLV size */
+       tlv_len += ISIS_SUBTLV_SID_LABEL_RANGE_SIZE
+               + ISIS_SUBTLV_HDR_SIZE
+               + ISIS_SUBTLV_ALGORITHM_SIZE
+               + ISIS_SUBTLV_NODE_MSD_SIZE;
+
+       if (STREAM_WRITEABLE(s) < (unsigned int)(2 + tlv_len))
+               return 1;
+
+       /* Add Router Capability TLV 242 with Router ID and Flags */
+       stream_putc(s, ISIS_TLV_ROUTER_CAPABILITY);
+       /* Real length will be adjusted later */
+       len_pos = stream_get_endp(s);
+       stream_putc(s, tlv_len);
+       stream_put_ipv4(s, router_cap->router_id.s_addr);
+       stream_putc(s, router_cap->flags);
+
+       /* Add SRGB if set */
+       if ((router_cap->srgb.range_size != 0)
+           && (router_cap->srgb.lower_bound != 0)) {
+               stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE);
+               stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE_SIZE);
+               stream_putc(s, router_cap->srgb.flags);
+               stream_put3(s, router_cap->srgb.range_size);
+               stream_putc(s, ISIS_SUBTLV_SID_LABEL);
+               stream_putc(s, ISIS_SUBTLV_SID_LABEL_SIZE);
+               stream_put3(s, router_cap->srgb.lower_bound);
+
+               /* Then SR Algorithm if set */
+               for (nb_algo = 0; nb_algo < SR_ALGORITHM_COUNT; nb_algo++)
+                       if (router_cap->algo[nb_algo] == SR_ALGORITHM_UNSET)
+                               break;
+               if (nb_algo > 0) {
+                       stream_putc(s, ISIS_SUBTLV_ALGORITHM);
+                       stream_putc(s, nb_algo);
+                       for (int i = 0; i < nb_algo; i++)
+                               stream_putc(s, router_cap->algo[i]);
+               }
+               /* And finish with MSD if set */
+               if (router_cap->msd != 0) {
+                       stream_putc(s, ISIS_SUBTLV_NODE_MSD);
+                       stream_putc(s, ISIS_SUBTLV_NODE_MSD_SIZE);
+                       stream_putc(s, MSD_TYPE_BASE_MPLS_IMPOSITION);
+                       stream_putc(s, router_cap->msd);
+               }
+       }
+
+       /* Adjust TLV length which depends on subTLVs presence */
+       tlv_len = stream_get_endp(s) - len_pos - 1;
+       stream_putc_at(s, len_pos, tlv_len);
+
+       return 0;
+}
+
+static int unpack_tlv_router_cap(enum isis_tlv_context context,
+                                      uint8_t tlv_type, uint8_t tlv_len,
+                                      struct stream *s, struct sbuf *log,
+                                      void *dest, int indent)
+{
+       struct isis_tlvs *tlvs = dest;
+       uint8_t type;
+       uint8_t length;
+       uint8_t subtlv_len;
+       uint8_t sid_len;
+
+       sbuf_push(log, indent, "Unpacking Router Capability TLV...\n");
+       if (tlv_len < ISIS_ROUTER_CAP_SIZE) {
+               sbuf_push(log, indent, "WARNING: Unexpected TLV size\n");
+               stream_forward_getp(s, tlv_len);
+               return 0;
+       }
+
+       if (tlvs->router_cap) {
+               sbuf_push(log, indent,
+                         "WARNING: Router Capability TLV present multiple times.\n");
+               stream_forward_getp(s, tlv_len);
+               return 0;
+       }
+
+       /* Allocate router cap structure and initialize SR Algorithms */
+       tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->router_cap));
+       for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
+               tlvs->router_cap->algo[i] = SR_ALGORITHM_UNSET;
+
+       /* Get Router ID and Flags */
+       tlvs->router_cap->router_id.s_addr = stream_get_ipv4(s);
+       tlvs->router_cap->flags = stream_getc(s);
+
+       /* Parse remaining part of the TLV if present */
+       subtlv_len = tlv_len - ISIS_ROUTER_CAP_SIZE;
+       while (subtlv_len > 2) {
+               struct isis_router_cap *rc = tlvs->router_cap;
+               uint8_t msd_type;
+
+               type = stream_getc(s);
+               length = stream_getc(s);
+               switch (type) {
+               case ISIS_SUBTLV_SID_LABEL_RANGE:
+                       rc->srgb.flags = stream_getc(s);
+                       rc->srgb.range_size = stream_get3(s);
+                       /* Skip Type and get Length of SID Label */
+                       stream_getc(s);
+                       sid_len = stream_getc(s);
+                       if (sid_len == ISIS_SUBTLV_SID_LABEL_SIZE)
+                               rc->srgb.lower_bound = stream_get3(s);
+                       else
+                               rc->srgb.lower_bound = stream_getl(s);
+
+                       /* SRGB sanity checks. */
+                       if (rc->srgb.range_size == 0
+                           || (rc->srgb.lower_bound <= MPLS_LABEL_RESERVED_MAX)
+                           || ((rc->srgb.lower_bound + rc->srgb.range_size - 1)
+                               > MPLS_LABEL_UNRESERVED_MAX)) {
+                               sbuf_push(log, indent, "Invalid label range. Reset SRGB\n");
+                               rc->srgb.lower_bound = 0;
+                               rc->srgb.range_size = 0;
+                       }
+                       break;
+               case ISIS_SUBTLV_ALGORITHM:
+                       /* Only 2 algorithms are supported: SPF & Strict SPF */
+                       stream_get(&rc->algo, s,
+                                  length > SR_ALGORITHM_COUNT
+                                          ? SR_ALGORITHM_COUNT
+                                          : length);
+                       if (length > SR_ALGORITHM_COUNT)
+                               stream_forward_getp(
+                                       s, length - SR_ALGORITHM_COUNT);
+                       break;
+               case ISIS_SUBTLV_NODE_MSD:
+                       msd_type = stream_getc(s);
+                       rc->msd = stream_getc(s);
+                       /* Only BMI-MSD type has been defined in RFC 8491 */
+                       if (msd_type != MSD_TYPE_BASE_MPLS_IMPOSITION)
+                               rc->msd = 0;
+                       break;
+               default:
+                       stream_forward_getp(s, length);
+                       break;
+               }
+               subtlv_len = subtlv_len - length - 2;
+       }
+       return 0;
+}
+
 /* Functions related to TLV 10 Authentication */
 static struct isis_item *copy_item_auth(struct isis_item *i)
 {
@@ -2318,6 +3216,39 @@ static void append_item(struct isis_item_list *dest, struct isis_item *item)
        dest->count++;
 }
 
+static void delete_item(struct isis_item_list *dest, struct isis_item *del)
+{
+       struct isis_item *item, *prev = NULL, *next;
+
+       /* Sanity Check */
+       if ((dest == NULL) || (del == NULL))
+               return;
+
+       /*
+        * TODO: delete is tricky because "dest" is a singly linked list.
+        * We need to switch a doubly linked list.
+        */
+       for (item = dest->head; item; item = next) {
+               if (item->next == del) {
+                       prev = item;
+                       break;
+               }
+               next = item->next;
+       }
+       if (prev)
+               prev->next = del->next;
+       if (dest->head == del)
+               dest->head = del->next;
+       if ((struct isis_item *)dest->tail == del) {
+               *dest->tail = prev;
+               if (prev)
+                       dest->tail = &(*dest->tail)->next;
+               else
+                       dest->tail = &dest->head;
+       }
+       dest->count--;
+}
+
 static struct isis_item *last_item(struct isis_item_list *list)
 {
        return container_of(list->tail, struct isis_item, next);
@@ -2596,6 +3527,8 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
 
        rv->threeway_adj = copy_tlv_threeway_adj(tlvs->threeway_adj);
 
+       rv->router_cap = copy_tlv_router_cap(tlvs->router_cap);
+
        rv->spine_leaf = copy_tlv_spine_leaf(tlvs->spine_leaf);
 
        return rv;
@@ -2631,6 +3564,7 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent)
 
        format_tlv_dynamic_hostname(tlvs->hostname, buf, indent);
        format_tlv_te_router_id(tlvs->te_router_id, buf, indent);
+       format_tlv_router_cap(tlvs->router_cap, buf, indent);
 
        format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
                     &tlvs->extended_reach, buf, indent);
@@ -2717,6 +3651,7 @@ void isis_free_tlvs(struct isis_tlvs *tlvs)
        free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
                      &tlvs->mt_ipv6_reach);
        free_tlv_threeway_adj(tlvs->threeway_adj);
+       free_tlv_router_cap(tlvs->router_cap);
        free_tlv_spine_leaf(tlvs->spine_leaf);
 
        XFREE(MTYPE_ISIS_TLV, tlvs);
@@ -2897,6 +3832,14 @@ static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
                fragment_tlvs->hostname =
                        copy_tlv_dynamic_hostname(tlvs->hostname);
 
+       rv = pack_tlv_router_cap(tlvs->router_cap, stream);
+       if (rv)
+               return rv;
+       if (fragment_tlvs) {
+               fragment_tlvs->router_cap =
+                       copy_tlv_router_cap(tlvs->router_cap);
+       }
+
        rv = pack_tlv_te_router_id(tlvs->te_router_id, stream);
        if (rv)
                return rv;
@@ -3131,6 +4074,7 @@ ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information");
 TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency");
 ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address");
 ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability");
+TLV_OPS(router_cap, "TLV 242 Router Capability");
 
 ITEM_SUBTLV_OPS(prefix_sid, "Sub-TLV 3 SR Prefix-SID");
 SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix");
@@ -3144,21 +4088,22 @@ static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
                [ISIS_TLV_AUTH] = &tlv_auth_ops,
                [ISIS_TLV_PURGE_ORIGINATOR] = &tlv_purge_originator_ops,
                [ISIS_TLV_EXTENDED_REACH] = &tlv_extended_reach_ops,
-               [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops,
                [ISIS_TLV_OLDSTYLE_IP_REACH] = &tlv_oldstyle_ip_reach_ops,
                [ISIS_TLV_PROTOCOLS_SUPPORTED] = &tlv_protocols_supported_ops,
                [ISIS_TLV_OLDSTYLE_IP_REACH_EXT] = &tlv_oldstyle_ip_reach_ops,
                [ISIS_TLV_IPV4_ADDRESS] = &tlv_ipv4_address_ops,
                [ISIS_TLV_TE_ROUTER_ID] = &tlv_te_router_id_ops,
                [ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops,
-               [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops,
                [ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops,
                [ISIS_TLV_SPINE_LEAF_EXT] = &tlv_spine_leaf_ops,
+               [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops,
                [ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops,
-               [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops,
                [ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops,
+               [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops,
                [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops,
                [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops,
+               [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops,
+               [ISIS_TLV_ROUTER_CAPABILITY] = &tlv_router_cap_ops,
        },
        [ISIS_CONTEXT_SUBTLV_NE_REACH] = {},
        [ISIS_CONTEXT_SUBTLV_IP_REACH] = {
@@ -3593,6 +4538,18 @@ void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs,
                tlvs->hostname = XSTRDUP(MTYPE_ISIS_TLV, hostname);
 }
 
+/* Set Router Capability TLV parameters */
+void isis_tlvs_set_router_capability(struct isis_tlvs *tlvs,
+                                    const struct isis_router_cap *cap)
+{
+       XFREE(MTYPE_ISIS_TLV, tlvs->router_cap);
+       if (!cap)
+               return;
+
+       tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->router_cap));
+       *tlvs->router_cap = *cap;
+}
+
 void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs,
                                const struct in_addr *id)
 {
@@ -3614,6 +4571,38 @@ void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
        append_item(&tlvs->oldstyle_ip_reach, (struct isis_item *)r);
 }
 
+void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts,
+                          struct isis_adj_sid *adj)
+{
+       append_item(&exts->adj_sid, (struct isis_item *)adj);
+       SET_SUBTLV(exts, EXT_ADJ_SID);
+}
+
+void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts,
+                          struct isis_adj_sid *adj)
+{
+       delete_item(&exts->adj_sid, (struct isis_item *)adj);
+       XFREE(MTYPE_ISIS_SUBTLV, adj);
+       if (exts->adj_sid.count == 0)
+               UNSET_SUBTLV(exts, EXT_ADJ_SID);
+}
+
+void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts,
+                              struct isis_lan_adj_sid *lan)
+{
+       append_item(&exts->lan_sid, (struct isis_item *)lan);
+       SET_SUBTLV(exts, EXT_LAN_ADJ_SID);
+}
+
+void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts,
+                              struct isis_lan_adj_sid *lan)
+{
+       delete_item(&exts->lan_sid, (struct isis_item *)lan);
+       XFREE(MTYPE_ISIS_SUBTLV, lan);
+       if (exts->lan_sid.count == 0)
+               UNSET_SUBTLV(exts, EXT_LAN_ADJ_SID);
+}
+
 void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
                                     struct prefix_ipv4 *dest, uint32_t metric)
 {
@@ -3668,17 +4657,14 @@ void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
 
 void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
                                  uint8_t *id, uint32_t metric,
-                                 uint8_t *subtlvs, uint8_t subtlv_len)
+                                 struct isis_ext_subtlvs *exts)
 {
        struct isis_extended_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
 
        memcpy(r->id, id, sizeof(r->id));
        r->metric = metric;
-       if (subtlvs && subtlv_len) {
-               r->subtlvs = XCALLOC(MTYPE_ISIS_TLV, subtlv_len);
-               memcpy(r->subtlvs, subtlvs, subtlv_len);
-               r->subtlv_len = subtlv_len;
-       }
+       if (exts)
+               r->subtlvs = copy_item_ext_subtlvs(exts, mtid);
 
        struct isis_item_list *l;
        if (mtid == ISIS_MT_IPV4_UNICAST)
index 4954d791d86e2fd5279e485623ada2b655f66bee..2948728e2b49b4dba369e5c961278dc7349990bb 100644 (file)
@@ -2,6 +2,8 @@
  * IS-IS TLV Serializer/Deserializer
  *
  * Copyright (C) 2015,2017 Christian Franke
+
+ * Copyright (C) 2019 Olivier Dugeon - Orange Labs (for TE and SR)
  *
  * This file is part of FRR.
  *
@@ -66,14 +68,14 @@ struct isis_lsp_entry {
 };
 
 struct isis_extended_reach;
+struct isis_ext_subtlvs;
 struct isis_extended_reach {
        struct isis_extended_reach *next;
 
        uint8_t id[7];
        uint32_t metric;
 
-       uint8_t *subtlvs;
-       uint8_t subtlv_len;
+       struct isis_ext_subtlvs *subtlvs;
 };
 
 struct isis_extended_ip_reach;
@@ -130,6 +132,95 @@ struct isis_threeway_adj {
        uint32_t neighbor_circuit_id;
 };
 
+/*
+ * Segment Routing subTLV's as per
+ * draft-ietf-isis-segment-routing-extension-25
+ */
+#define ISIS_SUBTLV_SRGB_FLAG_I                0x80
+#define ISIS_SUBTLV_SRGB_FLAG_V                0x40
+#define IS_SR_IPV4(srgb)               (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_I)
+#define IS_SR_IPV6(srgb)               (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_V)
+
+/* Structure aggregating SRGB info */
+struct isis_srgb {
+       uint8_t flags;
+       uint32_t range_size;
+       uint32_t lower_bound;
+};
+
+/* Prefix-SID sub-TLVs flags */
+#define ISIS_PREFIX_SID_READVERTISED  0x80
+#define ISIS_PREFIX_SID_NODE          0x40
+#define ISIS_PREFIX_SID_NO_PHP        0x20
+#define ISIS_PREFIX_SID_EXPLICIT_NULL 0x10
+#define ISIS_PREFIX_SID_VALUE         0x08
+#define ISIS_PREFIX_SID_LOCAL         0x04
+
+struct isis_prefix_sid;
+struct isis_prefix_sid {
+       struct isis_prefix_sid *next;
+
+       uint8_t flags;
+       uint8_t algorithm;
+       uint32_t value;
+};
+
+/* Adj-SID and LAN-Ajd-SID sub-TLVs flags */
+#define EXT_SUBTLV_LINK_ADJ_SID_FFLG   0x80
+#define EXT_SUBTLV_LINK_ADJ_SID_BFLG   0x40
+#define EXT_SUBTLV_LINK_ADJ_SID_VFLG   0x20
+#define EXT_SUBTLV_LINK_ADJ_SID_LFLG   0x10
+#define EXT_SUBTLV_LINK_ADJ_SID_SFLG   0x08
+#define EXT_SUBTLV_LINK_ADJ_SID_PFLG   0x04
+
+struct isis_adj_sid;
+struct isis_adj_sid {
+       struct isis_adj_sid *next;
+
+       uint8_t family;
+       uint8_t flags;
+       uint8_t weight;
+       uint32_t sid;
+};
+
+struct isis_lan_adj_sid;
+struct isis_lan_adj_sid {
+       struct isis_lan_adj_sid *next;
+
+       uint8_t family;
+       uint8_t flags;
+       uint8_t weight;
+       uint8_t neighbor_id[ISIS_SYS_ID_LEN];
+       uint32_t sid;
+};
+
+/* RFC 4971 & RFC 7981 */
+#define ISIS_ROUTER_CAP_FLAG_S 0x01
+#define ISIS_ROUTER_CAP_FLAG_D 0x02
+#define ISIS_ROUTER_CAP_SIZE   5
+
+/* Number of supported algorithm for Segment Routing.
+ * Right now only 2 have been standardized:
+ *  - 0: SPF
+ *  - 1: Strict SPF
+ */
+#define SR_ALGORITHM_COUNT     2
+#define SR_ALGORITHM_SPF       0
+#define SR_ALGORITHM_STRICT_SPF        1
+#define SR_ALGORITHM_UNSET     255
+
+struct isis_router_cap {
+       struct in_addr router_id;
+       uint8_t flags;
+
+       /* draft-ietf-segment-routing-extensions-25 */
+       struct isis_srgb srgb;
+       uint8_t algo[SR_ALGORITHM_COUNT];
+       /* RFC 8491 */
+#define MSD_TYPE_BASE_MPLS_IMPOSITION  0x01
+       uint8_t msd;
+};
+
 struct isis_item;
 struct isis_item {
        struct isis_item *next;
@@ -233,26 +324,10 @@ struct isis_tlvs {
        struct isis_item_list ipv6_reach;
        struct isis_mt_item_list mt_ipv6_reach;
        struct isis_threeway_adj *threeway_adj;
+       struct isis_router_cap *router_cap;
        struct isis_spine_leaf *spine_leaf;
 };
 
-#define ISIS_PREFIX_SID_READVERTISED  0x80
-#define ISIS_PREFIX_SID_NODE          0x40
-#define ISIS_PREFIX_SID_NO_PHP        0x20
-#define ISIS_PREFIX_SID_EXPLICIT_NULL 0x10
-#define ISIS_PREFIX_SID_VALUE         0x08
-#define ISIS_PREFIX_SID_LOCAL         0x04
-
-struct isis_prefix_sid;
-struct isis_prefix_sid {
-       struct isis_prefix_sid *next;
-
-       uint8_t flags;
-       uint8_t algorithm;
-
-       uint32_t value;
-};
-
 enum isis_tlv_context {
        ISIS_CONTEXT_LSP,
        ISIS_CONTEXT_SUBTLV_NE_REACH,
@@ -266,11 +341,12 @@ struct isis_subtlvs {
 
        /* draft-baker-ipv6-isis-dst-src-routing-06 */
        struct prefix_ipv6 *source_prefix;
-       /* draft-ietf-isis-segment-routing-extensions-16 */
+       /* draft-ietf-isis-segment-routing-extensions-25 */
        struct isis_item_list prefix_sids;
 };
 
 enum isis_tlv_type {
+       /* TLVs code point */
        ISIS_TLV_AREA_ADDRESSES = 1,
        ISIS_TLV_OLDSTYLE_REACH = 2,
        ISIS_TLV_LAN_NEIGHBORS = 6,
@@ -295,10 +371,149 @@ enum isis_tlv_type {
        ISIS_TLV_IPV6_REACH = 236,
        ISIS_TLV_MT_IPV6_REACH = 237,
        ISIS_TLV_THREE_WAY_ADJ = 240,
+       ISIS_TLV_ROUTER_CAPABILITY = 242,
        ISIS_TLV_MAX = 256,
 
+       /* subTLVs code point */
+       ISIS_SUBTLV_IPV6_SOURCE_PREFIX = 22,
+
+       /* RFC 5305 & RFC 6119 */
+       ISIS_SUBTLV_ADMIN_GRP = 3,
+       ISIS_SUBTLV_LOCAL_IPADDR = 6,
+       ISIS_SUBTLV_RMT_IPADDR = 8,
+       ISIS_SUBTLV_MAX_BW = 9,
+       ISIS_SUBTLV_MAX_RSV_BW = 10,
+       ISIS_SUBTLV_UNRSV_BW = 11,
+       ISIS_SUBTLV_LOCAL_IPADDR6 = 12,
+       ISIS_SUBTLV_RMT_IPADDR6 = 13,
+       ISIS_SUBTLV_TE_METRIC = 18,
+
+       /* RFC 5307 */
+       ISIS_SUBTLV_LLRI = 4,
+
+       /* RFC 5316 */
+       ISIS_SUBTLV_RAS = 24,
+       ISIS_SUBTLV_RIP = 25,
+
+       /* draft-isis-segment-routing-extension-25 */
+       ISIS_SUBTLV_SID_LABEL = 1,
+       ISIS_SUBTLV_SID_LABEL_RANGE = 2,
+       ISIS_SUBTLV_ALGORITHM = 19,
+       ISIS_SUBTLV_NODE_MSD = 23,
        ISIS_SUBTLV_PREFIX_SID = 3,
-       ISIS_SUBTLV_IPV6_SOURCE_PREFIX = 22
+       ISIS_SUBTLV_ADJ_SID = 31,
+       ISIS_SUBTLV_LAN_ADJ_SID = 32,
+
+       /* RFC 7810 */
+       ISIS_SUBTLV_AV_DELAY = 33,
+       ISIS_SUBTLV_MM_DELAY = 34,
+       ISIS_SUBTLV_DELAY_VAR = 35,
+       ISIS_SUBTLV_PKT_LOSS = 36,
+       ISIS_SUBTLV_RES_BW = 37,
+       ISIS_SUBTLV_AVA_BW = 38,
+       ISIS_SUBTLV_USE_BW = 39,
+
+       ISIS_SUBTLV_MAX = 40
+};
+
+/* subTLVs size for TE and SR */
+enum ext_subtlv_size {
+       ISIS_SUBTLV_LLRI_SIZE = 8,
+
+       ISIS_SUBTLV_UNRSV_BW_SIZE = 32,
+       ISIS_SUBTLV_TE_METRIC_SIZE = 3,
+       ISIS_SUBTLV_IPV6_ADDR_SIZE = 16,
+
+       /* draft-isis-segment-routing-extension-25 */
+       ISIS_SUBTLV_SID_LABEL_SIZE = 3,
+       ISIS_SUBTLV_SID_LABEL_RANGE_SIZE = 9,
+       ISIS_SUBTLV_ALGORITHM_SIZE = 4,
+       ISIS_SUBTLV_NODE_MSD_SIZE = 2,
+       ISIS_SUBTLV_ADJ_SID_SIZE = 5,
+       ISIS_SUBTLV_LAN_ADJ_SID_SIZE = 11,
+       ISIS_SUBTLV_PREFIX_SID_SIZE = 5,
+
+       ISIS_SUBTLV_MM_DELAY_SIZE = 8,
+
+       ISIS_SUBTLV_HDR_SIZE = 2,
+       ISIS_SUBTLV_DEF_SIZE = 4,
+
+       ISIS_SUBTLV_MAX_SIZE = 180
+};
+
+/* Macros to manage the optional presence of EXT subTLVs */
+#define SET_SUBTLV(s, t) ((s->status) |= (t))
+#define UNSET_SUBTLV(s, t) ((s->status) &= ~(t))
+#define IS_SUBTLV(s, t) (s->status & t)
+
+#define EXT_DISABLE            0x000000
+#define EXT_ADM_GRP            0x000001
+#define EXT_LLRI               0x000002
+#define EXT_LOCAL_ADDR         0x000004
+#define EXT_NEIGH_ADDR         0x000008
+#define EXT_LOCAL_ADDR6                0x000010
+#define EXT_NEIGH_ADDR6                0x000020
+#define EXT_MAX_BW             0x000040
+#define EXT_MAX_RSV_BW         0x000080
+#define EXT_UNRSV_BW           0x000100
+#define EXT_TE_METRIC          0x000200
+#define EXT_RMT_AS             0x000400
+#define EXT_RMT_IP             0x000800
+#define EXT_ADJ_SID            0x001000
+#define EXT_LAN_ADJ_SID                0x002000
+#define EXT_DELAY              0x004000
+#define EXT_MM_DELAY           0x008000
+#define EXT_DELAY_VAR          0x010000
+#define EXT_PKT_LOSS           0x020000
+#define EXT_RES_BW             0x040000
+#define EXT_AVA_BW             0x080000
+#define EXT_USE_BW             0x100000
+
+/*
+ * This structure groups all Extended IS Reachability subTLVs.
+ *
+ * Each bit of the status field indicates if a subTLVs is valid or not.
+ * SubTLVs values use following units:
+ *  - Bandwidth in bytes/sec following IEEE format,
+ *  - Delay in micro-seconds with only 24 bits significant
+ *  - Packet Loss in percentage of total traffic with only 24 bits (2^24 - 2)
+ *
+ * For Delay and packet Loss, upper bit (A) indicates if the value is
+ * normal (0) or anomalous (1).
+ */
+#define IS_ANORMAL(v) (v & 0x80000000)
+
+struct isis_ext_subtlvs {
+
+       uint32_t status;
+
+       uint32_t adm_group; /* Resource Class/Color - RFC 5305 */
+       /* Link Local/Remote Identifiers - RFC 5307 */
+       uint32_t local_llri;
+       uint32_t remote_llri;
+       struct in_addr local_addr; /* Local IP Address - RFC 5305 */
+       struct in_addr neigh_addr; /* Neighbor IP Address - RFC 5305 */
+       struct in6_addr local_addr6; /* Local IPv6 Address - RFC 6119 */
+       struct in6_addr neigh_addr6; /* Neighbor IPv6 Address - RFC 6119 */
+       float max_bw; /* Maximum Bandwidth - RFC 5305 */
+       float max_rsv_bw; /* Maximum Reservable Bandwidth - RFC 5305 */
+       float unrsv_bw[8]; /* Unreserved Bandwidth - RFC 5305 */
+       uint32_t te_metric; /* Traffic Engineering Metric - RFC 5305 */
+       uint32_t remote_as; /* Remote AS Number sub-TLV - RFC5316 */
+       struct in_addr remote_ip; /* IPv4 Remote ASBR ID Sub-TLV - RFC5316 */
+
+       uint32_t delay; /* Average Link Delay  - RFC 8570 */
+       uint32_t min_delay; /* Low Link Delay  - RFC 8570 */
+       uint32_t max_delay; /* High Link Delay  - RFC 8570 */
+       uint32_t delay_var; /* Link Delay Variation i.e. Jitter - RFC 8570 */
+       uint32_t pkt_loss; /* Unidirectional Link Packet Loss - RFC 8570 */
+       float res_bw; /* Unidirectional Residual Bandwidth - RFC 8570 */
+       float ava_bw; /* Unidirectional Available Bandwidth - RFC 8570 */
+       float use_bw; /* Unidirectional Utilized Bandwidth - RFC 8570 */
+
+       /* Segment Routing Adjacency & LAN Adjacency Segment ID */
+       struct isis_item_list adj_sid;
+       struct isis_item_list lan_sid;
 };
 
 #define IS_COMPAT_MT_TLV(tlv_type)                                             \
@@ -329,7 +544,6 @@ struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size);
 #define ISIS_MT_AT_MASK        0x4000
 #endif
 
-
 void isis_tlvs_add_auth(struct isis_tlvs *tlvs, struct isis_passwd *passwd);
 void isis_tlvs_add_area_addresses(struct isis_tlvs *tlvs,
                                  struct list *addresses);
@@ -359,6 +573,8 @@ void isis_tlvs_add_csnp_entries(struct isis_tlvs *tlvs, uint8_t *start_id,
                                struct isis_lsp **last_lsp);
 void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs,
                                    const char *hostname);
+void isis_tlvs_set_router_capability(struct isis_tlvs *tlvs,
+                     const struct isis_router_cap *cap);
 void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs,
                                const struct in_addr *id);
 void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
@@ -371,11 +587,21 @@ void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
                                     struct prefix_ipv6 *dest,
                                     struct prefix_ipv6 *src,
                                     uint32_t metric);
+struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void);
+void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts,
+                          struct isis_adj_sid *adj);
+void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts,
+                          struct isis_adj_sid *adj);
+void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts,
+                              struct isis_lan_adj_sid *lan);
+void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts,
+                              struct isis_lan_adj_sid *lan);
+
 void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
                                  uint8_t metric);
 void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
                                  uint8_t *id, uint32_t metric,
-                                 uint8_t *subtlvs, uint8_t subtlv_len);
+                                 struct isis_ext_subtlvs *subtlvs);
 
 const char *isis_threeway_state_name(enum isis_threeway_state state);
 
index d1bc20ba5a952ced2335c5ae109cb7fe3967d58f..39a2f6ef3502de674fe85e87cd8801c05ca863bd 100644 (file)
@@ -53,6 +53,8 @@
 
 struct zclient *zclient = NULL;
 
+DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp))
+
 /* Router-id update message from zebra. */
 static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
 {
@@ -82,6 +84,8 @@ static int isis_zebra_if_add(ZAPI_CALLBACK_ARGS)
                isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp),
                                      ifp);
 
+       hook_call(isis_if_new_hook, ifp);
+
        return 0;
 }
 
index d00f348c8e310da35360982c01d412c15608ee2d..83a32108eb13c74b642cc585b58b888df2845d5b 100644 (file)
@@ -24,6 +24,8 @@
 
 extern struct zclient *zclient;
 
+DECLARE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp));
+
 void isis_zebra_init(struct thread_master *);
 void isis_zebra_stop(void);
 
index 472ee9bc46671e9a616a5ad261d93c656f3575f9..635ecc77a1f962851c613bb63164f2dd85209ddf 100644 (file)
@@ -47,6 +47,7 @@ extern "C" {
 #define MPLS_LABEL_OAM_ALERT           14      /* [RFC3429] */
 #define MPLS_LABEL_EXTENSION           15      /* [RFC7274] */
 #define MPLS_LABEL_MAX                 1048575
+#define MPLS_LABEL_VALUE_MASK          0x000FFFFF
 #define MPLS_LABEL_NONE                0xFFFFFFFF /* for internal use only */
 
 /* Minimum and maximum label values */
index 6f8bc2218e2f7bcca388a9f7185bcb2816223ca9..46e45e5ee07abe69c86bb889e46916ff29187517 100644 (file)
Binary files a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz and b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz differ