]> git.proxmox.com Git - mirror_frr.git/blobdiff - isisd/isis_te.c
Merge pull request #5625 from qlyoung/fix-zapi-ipset-name-nullterm
[mirror_frr.git] / isisd / isis_te.c
index 4ea6c2c60d657901cb6c8f9a8ea1252348ea1baa..133707d61d28df5e3376ad4653b7565c75da1fc9 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"
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_spf.h"
 #include "isisd/isis_te.h"
-
-const char *mode2text[] = {"Disable", "Area", "AS", "Emulate"};
+#include "isisd/isis_zebra.h"
 
 /*------------------------------------------------------------------------*
  * 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 +71,222 @@ 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 ((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 +295,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 +335,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 +472,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 +487,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 +499,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);