]> git.proxmox.com Git - mirror_frr.git/commitdiff
isisd: send/receive LSPs with new parser
authorChristian Franke <chris@opensourcerouting.org>
Wed, 5 Jul 2017 16:37:36 +0000 (18:37 +0200)
committerChristian Franke <chris@opensourcerouting.org>
Thu, 3 Aug 2017 09:34:04 +0000 (11:34 +0200)
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
29 files changed:
isisd/Makefile.am
isisd/isis_adjacency.c
isisd/isis_circuit.c
isisd/isis_common.h
isisd/isis_csm.c
isisd/isis_dr.c
isisd/isis_dynhn.c
isisd/isis_dynhn.h
isisd/isis_events.c
isisd/isis_lsp.c
isisd/isis_lsp.h
isisd/isis_main.c
isisd/isis_misc.c
isisd/isis_misc.h
isisd/isis_mt.c
isisd/isis_mt.h
isisd/isis_pdu.c
isisd/isis_pdu.h
isisd/isis_redist.c
isisd/isis_route.c
isisd/isis_routemap.c
isisd/isis_spf.c
isisd/isis_te.c
isisd/isis_te.h
isisd/isis_tlv.c [deleted file]
isisd/isis_tlv.h [deleted file]
isisd/isis_zebra.c
isisd/isisd.c
isisd/iso_checksum.c

index 4e8665cd84a999589a2cf38b8307bd64d6fa8bda..ca212f5b44f7f4a843225e06e7e756e1c7185bc4 100644 (file)
@@ -13,7 +13,7 @@ sbin_PROGRAMS = isisd
 libisis_a_SOURCES = \
        isis_memory.c \
        isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \
-       isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \
+       isisd.c isis_misc.c isis_zebra.c isis_dr.c \
        isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \
        isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \
        isis_vty.c isis_mt.c \
@@ -22,7 +22,7 @@ libisis_a_SOURCES = \
 
 noinst_HEADERS = \
        isis_memory.h \
-       isisd.h isis_pdu.h isis_tlv.h isis_adjacency.h isis_constants.h \
+       isisd.h isis_pdu.h isis_adjacency.h isis_constants.h \
        isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \
        isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \
        iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \
index e13b3769ea6280d106b202eadb08cd3f5daad8da..0afa65d726914aba336a0074f0d02729860d6191 100644 (file)
@@ -43,7 +43,6 @@
 #include "isisd/isis_dr.h"
 #include "isisd/isis_dynhn.h"
 #include "isisd/isis_pdu.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_spf.h"
 #include "isisd/isis_events.h"
@@ -187,7 +186,7 @@ void isis_adj_state_change(struct isis_adjacency *adj,
 
                dyn = dynhn_find_by_id(adj->sysid);
                if (dyn)
-                       adj_name = (const char *)dyn->name.name;
+                       adj_name = dyn->hostname;
                else
                        adj_name = sysid_print(adj->sysid);
 
@@ -301,7 +300,7 @@ void isis_adj_print(struct isis_adjacency *adj)
                return;
        dyn = dynhn_find_by_id(adj->sysid);
        if (dyn)
-               zlog_debug("%s", dyn->name.name);
+               zlog_debug("%s", dyn->hostname);
 
        zlog_debug("SystemId %20s SNPA %s, level %d\nHolding Time %d",
                   sysid_print(adj->sysid), snpa_print(adj->snpa), adj->level,
@@ -355,7 +354,7 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
 
        dyn = dynhn_find_by_id(adj->sysid);
        if (dyn)
-               vty_out(vty, "  %-20s", dyn->name.name);
+               vty_out(vty, "  %-20s", dyn->hostname);
        else
                vty_out(vty, "  %-20s", sysid_print(adj->sysid));
 
@@ -416,8 +415,7 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
                    && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) {
                        dyn = dynhn_find_by_id(adj->lanid);
                        if (dyn)
-                               vty_out(vty, ", LAN id: %s.%02x",
-                                       dyn->name.name,
+                               vty_out(vty, ", LAN id: %s.%02x", dyn->hostname,
                                        adj->lanid[ISIS_SYS_ID_LEN]);
                        else
                                vty_out(vty, ", LAN id: %s.%02x",
index 72810532b01a83026a658b13a9869a16164362c6..c321677dee057e4626b9e36769d5e5298b0677de 100644 (file)
@@ -48,7 +48,6 @@
 #include "isisd/isis_common.h"
 #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_network.h"
index ba6c5f876d7f309ef9f9d98501a3e69ecfd567cc..b157bb18369f19a7cc2ec687c91b1ba942368f58 100644 (file)
@@ -46,16 +46,6 @@ struct isis_passwd {
        u_char passwd[255];
 };
 
-/*
- * (Dynamic) Hostname
- * one struct for cache list
- * one struct for LSP TLV
- */
-struct hostname {
-       u_char namelen;
-       u_char name[255];
-};
-
 /*
  * Supported Protocol IDs
  */
index b0ccdee769e24d68717504677430f66b1f359506..10870d5c50210c222d8ea40b9107ab540b28ef9f 100644 (file)
@@ -37,7 +37,6 @@
 #include "isisd/isis_common.h"
 #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_network.h"
index 3f532ecf84a1b757f49ae451ccf2684876f591ce..2db82719156373ccf048098571648b3fc8977141 100644 (file)
@@ -42,7 +42,6 @@
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_constants.h"
 #include "isisd/isis_pdu.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_dr.h"
 #include "isisd/isis_events.h"
index 9249ad6290677ebf4b8543d488ed0f0e62301f2a..6fa7988304263020e6829f82fa4402eb436f7995 100644 (file)
@@ -94,38 +94,26 @@ struct isis_dynhn *dynhn_find_by_name(const char *hostname)
        struct isis_dynhn *dyn = NULL;
 
        for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn))
-               if (strncmp((char *)dyn->name.name, hostname, 255) == 0)
+               if (strncmp(dyn->hostname, hostname, 255) == 0)
                        return dyn;
 
        return NULL;
 }
 
-void isis_dynhn_insert(const u_char *id, struct hostname *hostname, int level)
+void isis_dynhn_insert(const u_char *id, const char *hostname, int level)
 {
        struct isis_dynhn *dyn;
 
        dyn = dynhn_find_by_id(id);
-       if (dyn) {
-               memcpy(&dyn->name, hostname, hostname->namelen + 1);
-               memcpy(dyn->id, id, ISIS_SYS_ID_LEN);
-               dyn->refresh = time(NULL);
-               return;
-       }
-       dyn = XCALLOC(MTYPE_ISIS_DYNHN, sizeof(struct isis_dynhn));
        if (!dyn) {
-               zlog_warn("isis_dynhn_insert(): out of memory!");
-               return;
+               dyn = XCALLOC(MTYPE_ISIS_DYNHN, sizeof(struct isis_dynhn));
+               memcpy(dyn->id, id, ISIS_SYS_ID_LEN);
+               dyn->level = level;
+               listnode_add(dyn_cache, dyn);
        }
 
-       /* we also copy the length */
-       memcpy(&dyn->name, hostname, hostname->namelen + 1);
-       memcpy(dyn->id, id, ISIS_SYS_ID_LEN);
+       snprintf(dyn->hostname, sizeof(dyn->hostname), "%s", hostname);
        dyn->refresh = time(NULL);
-       dyn->level = level;
-
-       listnode_add(dyn_cache, dyn);
-
-       return;
 }
 
 void isis_dynhn_remove(const u_char *id)
@@ -137,7 +125,6 @@ void isis_dynhn_remove(const u_char *id)
                return;
        listnode_delete(dyn_cache, dyn);
        XFREE(MTYPE_ISIS_DYNHN, dyn);
-       return;
 }
 
 /*
@@ -155,7 +142,7 @@ void dynhn_print_all(struct vty *vty)
        for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn)) {
                vty_out(vty, "%-7d", dyn->level);
                vty_out(vty, "%-15s%-15s\n", sysid_print(dyn->id),
-                       dyn->name.name);
+                       dyn->hostname);
        }
 
        vty_out(vty, "     * %s %s\n", sysid_print(isis->sysid),
index f3ca94d40f9b6a2fb98d43e5eef1f495d65b6838..635d79f3f3f37f9602b8b94c9ae3c8aea993c6b6 100644 (file)
 
 struct isis_dynhn {
        u_char id[ISIS_SYS_ID_LEN];
-       struct hostname name;
+       char hostname[256];
        time_t refresh;
        int level;
 };
 
 void dyn_cache_init(void);
-void isis_dynhn_insert(const u_char *id, struct hostname *hostname, int level);
+void isis_dynhn_insert(const u_char *id, const char *hostname, int level);
 void isis_dynhn_remove(const u_char *id);
 struct isis_dynhn *dynhn_find_by_id(const u_char *id);
 struct isis_dynhn *dynhn_find_by_name(const char *hostname);
index 9af256ba3869eaaf0dd8844b6c526aaf8134c14a..1cc90d031c80874f205ba03d648c38117e8e8829 100644 (file)
@@ -37,7 +37,6 @@
 #include "isisd/isis_common.h"
 #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_network.h"
index 76022bdea2d7c3859b867f6e50c7efca500bfdf0..243853c977b8563cc024923d3639deaf7a16b0af 100644 (file)
@@ -44,7 +44,6 @@
 #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isisd.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_dynhn.h"
@@ -54,6 +53,7 @@
 #include "isisd/isis_spf.h"
 #include "isisd/isis_te.h"
 #include "isisd/isis_mt.h"
+#include "isisd/isis_tlvs2.h"
 
 /* staticly assigned vars for printing purposes */
 char lsp_bits_string[200]; /* FIXME: enough ? */
@@ -105,19 +105,8 @@ static void lsp_clear_data(struct isis_lsp *lsp)
        if (!lsp)
                return;
 
-       if (lsp->tlv_data.hostname)
-               isis_dynhn_remove(lsp->lsp_header->lsp_id);
-
-       if (lsp->own_lsp) {
-               if (lsp->tlv_data.nlpids)
-                       XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
-               if (lsp->tlv_data.hostname)
-                       XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
-               if (lsp->tlv_data.router_id)
-                       XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.router_id);
-       }
-
-       free_tlvs(&lsp->tlv_data);
+       isis_free_tlvs(lsp->tlvs);
+       lsp->tlvs = NULL;
 }
 
 static void lsp_destroy(struct isis_lsp *lsp)
@@ -146,7 +135,7 @@ static void lsp_destroy(struct isis_lsp *lsp)
 
        lsp_clear_data(lsp);
 
-       if (LSP_FRAGMENT(lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags) {
+       if (LSP_FRAGMENT(lsp->hdr.lsp_id) == 0 && lsp->lspu.frags) {
                list_delete(lsp->lspu.frags);
                lsp->lspu.frags = NULL;
        }
@@ -187,7 +176,7 @@ static void lsp_remove_frags(struct list *frags, dict_t *lspdb)
        struct isis_lsp *lsp;
 
        for (ALL_LIST_ELEMENTS(frags, lnode, lnnode, lsp)) {
-               dnode = dict_lookup(lspdb, lsp->lsp_header->lsp_id);
+               dnode = dict_lookup(lspdb, lsp->hdr.lsp_id);
                lsp_destroy(lsp);
                dnode_destroy(dict_delete(lspdb, dnode));
        }
@@ -209,7 +198,7 @@ void lsp_search_and_destroy(u_char *id, dict_t *lspdb)
                /*
                 * If this is a zero lsp, remove all the frags now
                 */
-               if (LSP_FRAGMENT(lsp->lsp_header->lsp_id) == 0) {
+               if (LSP_FRAGMENT(lsp->hdr.lsp_id) == 0) {
                        if (lsp->lspu.frags)
                                lsp_remove_frags(lsp->lspu.frags, lspdb);
                } else {
@@ -231,33 +220,25 @@ void lsp_search_and_destroy(u_char *id, dict_t *lspdb)
  * Compares a LSP to given values
  * Params are given in net order
  */
-int lsp_compare(char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
-               u_int16_t checksum, u_int16_t rem_lifetime)
+int lsp_compare(char *areatag, struct isis_lsp *lsp, uint32_t seqno,
+               uint16_t checksum, uint16_t rem_lifetime)
 {
-       seq_num = htonl(seq_num);
-       checksum = htons(checksum);
-       rem_lifetime = htons(rem_lifetime);
-
-       /* no point in double ntohl on seqnum */
-       if (lsp->lsp_header->seq_num == seq_num
-           && lsp->lsp_header->checksum == checksum &&
-           /*comparing with 0, no need to do ntohl */
-           ((lsp->lsp_header->rem_lifetime == 0 && rem_lifetime == 0)
-            || (lsp->lsp_header->rem_lifetime != 0 && rem_lifetime != 0))) {
+       if (lsp->hdr.seqno == seqno && lsp->hdr.checksum == checksum
+           && ((lsp->hdr.rem_lifetime == 0 && rem_lifetime == 0)
+               || (lsp->hdr.rem_lifetime != 0 && rem_lifetime != 0))) {
                if (isis->debugs & DEBUG_SNP_PACKETS) {
                        zlog_debug(
-                               "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
-                               " lifetime %us",
-                               areatag,
-                               rawlspid_print(lsp->lsp_header->lsp_id),
-                               ntohl(lsp->lsp_header->seq_num),
-                               ntohs(lsp->lsp_header->checksum),
-                               ntohs(lsp->lsp_header->rem_lifetime));
+                               "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
+                               ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                               "s",
+                               areatag, rawlspid_print(lsp->hdr.lsp_id),
+                               lsp->hdr.seqno, lsp->hdr.checksum,
+                               lsp->hdr.rem_lifetime);
                        zlog_debug(
-                               "ISIS-Snp (%s):         is equal to ours seq 0x%08x,"
-                               " cksum 0x%04x, lifetime %us",
-                               areatag, ntohl(seq_num), ntohs(checksum),
-                               ntohs(rem_lifetime));
+                               "ISIS-Snp (%s):         is equal to ours seq 0x%08" PRIx32
+                               ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                               "s",
+                               areatag, seqno, checksum, rem_lifetime);
                }
                return LSP_EQUAL;
        }
@@ -274,171 +255,136 @@ int lsp_compare(char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
         * as given
         *    in 7.3.16.2.
         */
-       if (ntohl(seq_num) > ntohl(lsp->lsp_header->seq_num)
-           || (ntohl(seq_num) == ntohl(lsp->lsp_header->seq_num)
-               && ((lsp->lsp_header->rem_lifetime != 0 && rem_lifetime == 0)
-                   || lsp->lsp_header->checksum != checksum))) {
+       if (seqno > lsp->hdr.seqno
+           || (seqno == lsp->hdr.seqno
+               && ((lsp->hdr.rem_lifetime != 0 && rem_lifetime == 0)
+                   || lsp->hdr.checksum != checksum))) {
                if (isis->debugs & DEBUG_SNP_PACKETS) {
                        zlog_debug(
-                               "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
-                               " lifetime %us",
-                               areatag,
-                               rawlspid_print(lsp->lsp_header->lsp_id),
-                               ntohl(seq_num), ntohs(checksum),
-                               ntohs(rem_lifetime));
+                               "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
+                               ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                               "s",
+                               areatag, rawlspid_print(lsp->hdr.lsp_id), seqno,
+                               checksum, rem_lifetime);
                        zlog_debug(
-                               "ISIS-Snp (%s):       is newer than ours seq 0x%08x, "
-                               "cksum 0x%04x, lifetime %us",
-                               areatag, ntohl(lsp->lsp_header->seq_num),
-                               ntohs(lsp->lsp_header->checksum),
-                               ntohs(lsp->lsp_header->rem_lifetime));
+                               "ISIS-Snp (%s):       is newer than ours seq 0x%08" PRIx32
+                               ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                               "s",
+                               areatag, lsp->hdr.seqno, lsp->hdr.checksum,
+                               lsp->hdr.rem_lifetime);
                }
                return LSP_NEWER;
        }
        if (isis->debugs & DEBUG_SNP_PACKETS) {
+               zlog_debug("ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
+                          ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 "s",
+                          areatag, rawlspid_print(lsp->hdr.lsp_id), seqno,
+                          checksum, rem_lifetime);
                zlog_debug(
-                       "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
-                       areatag, rawlspid_print(lsp->lsp_header->lsp_id),
-                       ntohl(seq_num), ntohs(checksum), ntohs(rem_lifetime));
-               zlog_debug(
-                       "ISIS-Snp (%s):       is older than ours seq 0x%08x,"
-                       " cksum 0x%04x, lifetime %us",
-                       areatag, ntohl(lsp->lsp_header->seq_num),
-                       ntohs(lsp->lsp_header->checksum),
-                       ntohs(lsp->lsp_header->rem_lifetime));
+                       "ISIS-Snp (%s):       is older than ours seq 0x%08" PRIx32
+                       ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 "s",
+                       areatag, lsp->hdr.seqno, lsp->hdr.checksum,
+                       lsp->hdr.rem_lifetime);
        }
 
        return LSP_OLDER;
 }
 
-static void lsp_auth_add(struct isis_lsp *lsp)
+static void put_lsp_hdr(struct isis_lsp *lsp, size_t *len_pointer)
 {
-       struct isis_passwd *passwd;
-       unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
-
-       /*
-        * Add the authentication info if its present
-        */
-       (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd)
-                                  : (passwd = &lsp->area->domain_passwd);
-       switch (passwd->type) {
-       /* Cleartext */
-       case ISIS_PASSWD_TYPE_CLEARTXT:
-               memcpy(&lsp->tlv_data.auth_info, passwd,
-                      sizeof(struct isis_passwd));
-               tlv_add_authinfo(passwd->type, passwd->len, passwd->passwd,
-                                lsp->pdu);
-               break;
-
-       /* HMAC MD5 */
-       case ISIS_PASSWD_TYPE_HMAC_MD5:
-               /* Remember where TLV is written so we can later
-                * overwrite the MD5 hash */
-               lsp->auth_tlv_offset = stream_get_endp(lsp->pdu);
-               memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
-               lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5;
-               lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE;
-               memcpy(&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
-                      ISIS_AUTH_MD5_SIZE);
-               tlv_add_authinfo(passwd->type, ISIS_AUTH_MD5_SIZE,
-                                hmac_md5_hash, lsp->pdu);
-               break;
-
-       default:
-               break;
-       }
+       uint8_t pdu_type =
+               (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE;
+       struct isis_lsp_hdr *hdr = &lsp->hdr;
+       struct stream *stream = lsp->pdu;
+
+       fill_fixed_hdr(pdu_type, stream);
+
+       if (len_pointer)
+               *len_pointer = stream_get_endp(stream);
+       stream_putw(stream, hdr->pdu_len);
+       stream_putw(stream, hdr->rem_lifetime);
+       stream_put(stream, hdr->lsp_id, sizeof(hdr->lsp_id));
+       stream_putl(stream, hdr->seqno);
+       stream_putw(stream, hdr->checksum);
+       stream_putc(stream, hdr->lsp_bits);
 }
 
-static void lsp_auth_update(struct isis_lsp *lsp)
+static void lsp_add_auth(struct isis_lsp *lsp)
 {
        struct isis_passwd *passwd;
-       unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
-       uint16_t checksum, rem_lifetime;
+       passwd = (lsp->level == IS_LEVEL_1) ? &lsp->area->area_passwd
+                                           : &lsp->area->domain_passwd;
+       isis_tlvs_add_auth(lsp->tlvs, passwd);
+}
 
-       /* For HMAC MD5 we need to recompute the md5 hash and store it */
-       (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd)
-                                  : (passwd = &lsp->area->domain_passwd);
-       if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5)
-               return;
+static void lsp_pack_pdu(struct isis_lsp *lsp)
+{
+       if (!lsp->tlvs)
+               lsp->tlvs = isis_alloc_tlvs();
 
-       /*
-        * In transient conditions (when net is configured where authentication
-        * config and lsp regenerate schedule is not yet run), there could be
-        * an own_lsp with auth_tlv_offset set to 0. In such a case, simply
-        * return, when lsp_regenerate is run, lsp will have auth tlv.
-        */
-       if (lsp->auth_tlv_offset == 0)
-               return;
+       lsp_add_auth(lsp);
 
-       /*
-        * RFC 5304 set auth value, checksum and remaining lifetime to zero
-        * before computation and reset to old values after computation.
-        */
-       checksum = lsp->lsp_header->checksum;
-       rem_lifetime = lsp->lsp_header->rem_lifetime;
-       lsp->lsp_header->checksum = 0;
-       lsp->lsp_header->rem_lifetime = 0;
-       /* Set the authentication value as well to zero */
-       memset(STREAM_DATA(lsp->pdu) + lsp->auth_tlv_offset + 3, 0,
-              ISIS_AUTH_MD5_SIZE);
-       /* Compute autentication value */
-       hmac_md5(STREAM_DATA(lsp->pdu), stream_get_endp(lsp->pdu),
-                (unsigned char *)&passwd->passwd, passwd->len,
-                (unsigned char *)&hmac_md5_hash);
-       /* Copy the hash into the stream */
-       memcpy(STREAM_DATA(lsp->pdu) + lsp->auth_tlv_offset + 3, hmac_md5_hash,
-              ISIS_AUTH_MD5_SIZE);
-       memcpy(&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
-              ISIS_AUTH_MD5_SIZE);
-       /* Copy back the checksum and remaining lifetime */
-       lsp->lsp_header->checksum = checksum;
-       lsp->lsp_header->rem_lifetime = rem_lifetime;
+       size_t len_pointer;
+       stream_reset(lsp->pdu);
+       put_lsp_hdr(lsp, &len_pointer);
+       isis_pack_tlvs(lsp->tlvs, lsp->pdu, len_pointer, false, true);
+
+       lsp->hdr.pdu_len = stream_get_endp(lsp->pdu);
+       lsp->hdr.checksum =
+               ntohs(fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
+                                       stream_get_endp(lsp->pdu) - 12, 12));
 }
 
-void lsp_inc_seqnum(struct isis_lsp *lsp, u_int32_t seq_num)
+void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno)
 {
-       u_int32_t newseq;
+       uint32_t newseq;
 
-       if (seq_num == 0 || ntohl(lsp->lsp_header->seq_num) > seq_num)
-               newseq = ntohl(lsp->lsp_header->seq_num) + 1;
+       if (seqno == 0 || lsp->hdr.seqno > seqno)
+               newseq = lsp->hdr.seqno + 1;
        else
-               newseq = seq_num + 1;
-
-       lsp->lsp_header->seq_num = htonl(newseq);
-
-       /* Recompute authentication and checksum information */
-       lsp_auth_update(lsp);
-       /* ISO 10589 - 7.3.11 Generation of the checksum
-        * The checksum shall be computed over all fields in the LSP which
-        * appear
-        * after the Remaining Lifetime field. This field (and those appearing
-        * before it) are excluded so that the LSP may be aged by systems
-        * without
-        * requiring recomputation.
-        */
-       fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
-                         ntohs(lsp->lsp_header->pdu_len) - 12, 12);
+               newseq = seqno + 1;
 
+       lsp->hdr.seqno = newseq;
+
+       lsp_pack_pdu(lsp);
        isis_spf_schedule(lsp->area, lsp->level);
+}
 
-       return;
+static void lsp_purge(struct isis_lsp *lsp, int level)
+{
+       /* reset stream */
+       lsp_clear_data(lsp);
+       stream_reset(lsp->pdu);
+
+       /* update header */
+       lsp->hdr.checksum = 0;
+       lsp->hdr.rem_lifetime = 0;
+       lsp->level = level;
+       lsp->age_out = lsp->area->max_lsp_lifetime[level - 1];
+
+       lsp_pack_pdu(lsp);
+       lsp_set_all_srmflags(lsp);
 }
 
 /*
- * Genetates checksum for LSP and its frags
+ * Generates checksum for LSP and its frags
  */
-static void lsp_seqnum_update(struct isis_lsp *lsp0)
+static void lsp_seqno_update(struct isis_lsp *lsp0)
 {
        struct isis_lsp *lsp;
        struct listnode *node;
 
-       lsp_inc_seqnum(lsp0, 0);
+       lsp_inc_seqno(lsp0, 0);
 
        if (!lsp0->lspu.frags)
                return;
 
-       for (ALL_LIST_ELEMENTS_RO(lsp0->lspu.frags, node, lsp))
-               lsp_inc_seqnum(lsp, 0);
+       for (ALL_LIST_ELEMENTS_RO(lsp0->lspu.frags, node, lsp)) {
+               if (lsp->tlvs)
+                       lsp_inc_seqno(lsp, 0);
+               else
+                       lsp_purge(lsp, lsp0->level);
+       }
 
        return;
 }
@@ -457,12 +403,10 @@ static u_int8_t lsp_bits_generate(int level, int overload_bit, int attached_bit)
        return lsp_bits;
 }
 
-static void lsp_update_data(struct isis_lsp *lsp, struct stream *stream,
+static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
+                           struct isis_tlvs *tlvs, struct stream *stream,
                            struct isis_area *area, int level)
 {
-       uint32_t expected = 0, found;
-       int retval;
-
        /* free the old lsp data */
        lsp_clear_data(lsp);
 
@@ -471,49 +415,17 @@ static void lsp_update_data(struct isis_lsp *lsp, struct stream *stream,
                stream_free(lsp->pdu);
        lsp->pdu = stream_dup(stream);
 
-       /* setting pointers to the correct place */
-       lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu)
-                                                        + ISIS_FIXED_HDR_LEN);
+       memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
        lsp->area = area;
        lsp->level = level;
        lsp->age_out = ZERO_AGE_LIFETIME;
        lsp->installed = time(NULL);
-       /*
-        * Get LSP data i.e. TLVs
-        */
-       expected |= TLVFLAG_AUTH_INFO;
-       expected |= TLVFLAG_AREA_ADDRS;
-       expected |= TLVFLAG_IS_NEIGHS;
-       expected |= TLVFLAG_NLPID;
-       if (area->dynhostname)
-               expected |= TLVFLAG_DYN_HOSTNAME;
-       if (area->newmetric) {
-               expected |= TLVFLAG_TE_IS_NEIGHS;
-               expected |= TLVFLAG_TE_IPV4_REACHABILITY;
-               expected |= TLVFLAG_TE_ROUTER_ID;
-       }
-       expected |= TLVFLAG_MT_ROUTER_INFORMATION;
-       expected |= TLVFLAG_IPV4_ADDR;
-       expected |= TLVFLAG_IPV4_INT_REACHABILITY;
-       expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
-       expected |= TLVFLAG_IPV6_ADDR;
-       expected |= TLVFLAG_IPV6_REACHABILITY;
-
-       retval = parse_tlvs(area->area_tag,
-                           STREAM_DATA(lsp->pdu) + ISIS_FIXED_HDR_LEN
-                                   + ISIS_LSP_HDR_LEN,
-                           ntohs(lsp->lsp_header->pdu_len) - ISIS_FIXED_HDR_LEN
-                                   - ISIS_LSP_HDR_LEN,
-                           &expected, &found, &lsp->tlv_data, NULL);
-       if (retval != ISIS_OK) {
-               zlog_warn("Could not parse LSP");
-               return;
-       }
 
-       if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname)) {
-               isis_dynhn_insert(lsp->lsp_header->lsp_id,
-                                 lsp->tlv_data.hostname,
-                                 (lsp->lsp_header->lsp_bits & LSPBIT_IST)
+       lsp->tlvs = tlvs;
+
+       if (area->dynhostname && lsp->tlvs->hostname) {
+               isis_dynhn_insert(lsp->hdr.lsp_id, lsp->tlvs->hostname,
+                                 (lsp->hdr.lsp_bits & LSPBIT_IST)
                                                  == IS_LEVEL_1_AND_2
                                          ? IS_LEVEL_2
                                          : IS_LEVEL_1);
@@ -522,7 +434,8 @@ static void lsp_update_data(struct isis_lsp *lsp, struct stream *stream,
        return;
 }
 
-void lsp_update(struct isis_lsp *lsp, struct stream *stream,
+void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
+               struct isis_tlvs *tlvs, struct stream *stream,
                struct isis_area *area, int level)
 {
        dnode_t *dnode = NULL;
@@ -530,36 +443,35 @@ void lsp_update(struct isis_lsp *lsp, struct stream *stream,
        /* Remove old LSP from database. This is required since the
         * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
         * and will update it with the new data in the stream. */
-       dnode = dict_lookup(area->lspdb[level - 1], lsp->lsp_header->lsp_id);
+       dnode = dict_lookup(area->lspdb[level - 1], lsp->hdr.lsp_id);
        if (dnode)
                dnode_destroy(dict_delete(area->lspdb[level - 1], dnode));
 
        if (lsp->own_lsp) {
                zlog_err(
                        "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
-                       area->area_tag,
-                       rawlspid_print(lsp->lsp_header->lsp_id));
+                       area->area_tag, rawlspid_print(lsp->hdr.lsp_id));
                lsp_clear_data(lsp);
                lsp->own_lsp = 0;
        }
 
        /* rebuild the lsp data */
-       lsp_update_data(lsp, stream, area, level);
+       lsp_update_data(lsp, hdr, tlvs, stream, area, level);
 
        /* insert the lsp back into the database */
        lsp_insert(lsp, area->lspdb[level - 1]);
 }
 
 /* creation of LSP directly from what we received */
-struct isis_lsp *lsp_new_from_stream_ptr(struct stream *stream,
-                                        u_int16_t pdu_len,
-                                        struct isis_lsp *lsp0,
-                                        struct isis_area *area, int level)
+struct isis_lsp *lsp_new_from_recv(struct isis_lsp_hdr *hdr,
+                                  struct isis_tlvs *tlvs,
+                                  struct stream *stream, struct isis_lsp *lsp0,
+                                  struct isis_area *area, int level)
 {
        struct isis_lsp *lsp;
 
        lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
-       lsp_update_data(lsp, stream, area, level);
+       lsp_update_data(lsp, hdr, tlvs, stream, area, level);
 
        if (lsp0 == NULL) {
                /*
@@ -579,12 +491,10 @@ struct isis_lsp *lsp_new_from_stream_ptr(struct stream *stream,
 }
 
 struct isis_lsp *lsp_new(struct isis_area *area, u_char *lsp_id,
-                        u_int16_t rem_lifetime, u_int32_t seq_num,
-                        u_int8_t lsp_bits, u_int16_t checksum, int level)
+                        uint16_t rem_lifetime, uint32_t seqno,
+                        uint8_t lsp_bits, uint16_t checksum, int level)
 {
        struct isis_lsp *lsp;
-       uint8_t pdu_type =
-               (level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE;
 
        lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
        lsp->area = area;
@@ -593,40 +503,31 @@ struct isis_lsp *lsp_new(struct isis_area *area, u_char *lsp_id,
        if (LSP_FRAGMENT(lsp_id) == 0)
                lsp->lspu.frags = list_new();
 
-       fill_fixed_hdr(pdu_type, lsp->pdu);
-
-       /* now for the LSP HEADER */
        /* Minimal LSP PDU size */
-       lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu)
-                                                        + ISIS_FIXED_HDR_LEN);
-       lsp->lsp_header->pdu_len = htons(ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-       memcpy(lsp->lsp_header->lsp_id, lsp_id, ISIS_SYS_ID_LEN + 2);
-       lsp->lsp_header->checksum = htons(checksum);
-       lsp->lsp_header->seq_num = htonl(seq_num);
-       lsp->lsp_header->rem_lifetime = htons(rem_lifetime);
-       lsp->lsp_header->lsp_bits = lsp_bits;
+       lsp->hdr.pdu_len = ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN;
+       memcpy(lsp->hdr.lsp_id, lsp_id, sizeof(lsp->hdr.lsp_id));
+       lsp->hdr.checksum = checksum;
+       lsp->hdr.seqno = seqno;
+       lsp->hdr.rem_lifetime = rem_lifetime;
+       lsp->hdr.lsp_bits = lsp_bits;
        lsp->level = level;
        lsp->age_out = ZERO_AGE_LIFETIME;
-
-       stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+       put_lsp_hdr(lsp, NULL);
 
        if (isis->debugs & DEBUG_EVENTS)
                zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
-                          sysid_print(lsp_id),
-                          LSP_PSEUDO_ID(lsp->lsp_header->lsp_id),
-                          LSP_FRAGMENT(lsp->lsp_header->lsp_id),
-                          ntohl(lsp->lsp_header->pdu_len),
-                          ntohl(lsp->lsp_header->seq_num));
+                          sysid_print(lsp_id), LSP_PSEUDO_ID(lsp->hdr.lsp_id),
+                          LSP_FRAGMENT(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
+                          lsp->hdr.seqno);
 
        return lsp;
 }
 
 void lsp_insert(struct isis_lsp *lsp, dict_t *lspdb)
 {
-       dict_alloc_insert(lspdb, lsp->lsp_header->lsp_id, lsp);
-       if (lsp->lsp_header->seq_num != 0) {
+       dict_alloc_insert(lspdb, lsp->hdr.lsp_id, lsp);
+       if (lsp->hdr.seqno)
                isis_spf_schedule(lsp->area, lsp->level);
-       }
 }
 
 /*
@@ -645,14 +546,13 @@ void lsp_build_list_nonzero_ht(u_char *start_id, u_char *stop_id,
 
        curr = first;
 
-       if (((struct isis_lsp *)(curr->dict_data))->lsp_header->rem_lifetime)
+       if (((struct isis_lsp *)(curr->dict_data))->hdr.rem_lifetime)
                listnode_add(list, first->dict_data);
 
        while (curr) {
                curr = dict_next(lspdb, curr);
                if (curr
-                   && ((struct isis_lsp *)(curr->dict_data))
-                              ->lsp_header->rem_lifetime)
+                   && ((struct isis_lsp *)(curr->dict_data))->hdr.rem_lifetime)
                        listnode_add(list, curr->dict_data);
                if (curr == last)
                        break;
@@ -665,14 +565,15 @@ static void lsp_set_time(struct isis_lsp *lsp)
 {
        assert(lsp);
 
-       if (lsp->lsp_header->rem_lifetime == 0) {
+       if (lsp->hdr.rem_lifetime == 0) {
                if (lsp->age_out > 0)
                        lsp->age_out--;
                return;
        }
 
-       lsp->lsp_header->rem_lifetime =
-               htons(ntohs(lsp->lsp_header->rem_lifetime) - 1);
+       lsp->hdr.rem_lifetime--;
+       if (lsp->pdu && stream_get_endp(lsp->pdu) >= 12)
+               stream_putw_at(lsp->pdu, 10, lsp->hdr.rem_lifetime);
 }
 
 static void lspid_print(u_char *lsp_id, u_char *trg, char dynhost, char frag)
@@ -686,7 +587,7 @@ static void lspid_print(u_char *lsp_id, u_char *trg, char dynhost, char frag)
                dyn = NULL;
 
        if (dyn)
-               sprintf((char *)id, "%.14s", dyn->name.name);
+               sprintf((char *)id, "%.14s", dyn->hostname);
        else if (!memcmp(isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
                sprintf((char *)id, "%.14s", unix_hostname());
        else
@@ -699,21 +600,21 @@ static void lspid_print(u_char *lsp_id, u_char *trg, char dynhost, char frag)
 }
 
 /* Convert the lsp attribute bits to attribute string */
-const char *lsp_bits2string(u_char *lsp_bits)
+static const char *lsp_bits2string(uint8_t lsp_bits)
 {
        char *pos = lsp_bits_string;
 
-       if (!*lsp_bits)
+       if (!lsp_bits)
                return " none";
 
        /* we only focus on the default metric */
        pos += sprintf(pos, "%d/",
-                      ISIS_MASK_LSP_ATT_DEFAULT_BIT(*lsp_bits) ? 1 : 0);
+                      ISIS_MASK_LSP_ATT_DEFAULT_BIT(lsp_bits) ? 1 : 0);
 
        pos += sprintf(pos, "%d/",
-                      ISIS_MASK_LSP_PARTITION_BIT(*lsp_bits) ? 1 : 0);
+                      ISIS_MASK_LSP_PARTITION_BIT(lsp_bits) ? 1 : 0);
 
-       pos += sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(*lsp_bits) ? 1 : 0);
+       pos += sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0);
 
        *(pos) = '\0';
 
@@ -726,276 +627,26 @@ void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost)
        u_char LSPid[255];
        char age_out[8];
 
-       lspid_print(lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
+       lspid_print(lsp->hdr.lsp_id, LSPid, dynhost, 1);
        vty_out(vty, "%-21s%c  ", LSPid, lsp->own_lsp ? '*' : ' ');
-       vty_out(vty, "%5u   ", ntohs(lsp->lsp_header->pdu_len));
-       vty_out(vty, "0x%08x  ", ntohl(lsp->lsp_header->seq_num));
-       vty_out(vty, "0x%04x  ", ntohs(lsp->lsp_header->checksum));
-       if (ntohs(lsp->lsp_header->rem_lifetime) == 0) {
-               snprintf(age_out, 8, "(%u)", lsp->age_out);
+       vty_out(vty, "%5" PRIu16 "   ", lsp->hdr.pdu_len);
+       vty_out(vty, "0x%08" PRIx32 "  ", lsp->hdr.seqno);
+       vty_out(vty, "0x%04" PRIx16 "  ", lsp->hdr.checksum);
+       if (lsp->hdr.rem_lifetime == 0) {
+               snprintf(age_out, 8, "(%d)", lsp->age_out);
                age_out[7] = '\0';
                vty_out(vty, "%7s   ", age_out);
        } else
-               vty_out(vty, " %5u    ", ntohs(lsp->lsp_header->rem_lifetime));
-       vty_out(vty, "%s\n", lsp_bits2string(&lsp->lsp_header->lsp_bits));
-}
-
-static void lsp_print_mt_reach(struct list *list, struct vty *vty, char dynhost,
-                              uint16_t mtid)
-{
-       struct listnode *node;
-       struct te_is_neigh *neigh;
-
-       for (ALL_LIST_ELEMENTS_RO(list, node, neigh)) {
-               u_char lspid[255];
-
-               lspid_print(neigh->neigh_id, lspid, dynhost, 0);
-               if (mtid == ISIS_MT_IPV4_UNICAST) {
-                       vty_out(vty,
-                               "  Metric      : %-8u IS-Extended   : %s\n",
-                               GET_TE_METRIC(neigh), lspid);
-               } else {
-                       vty_out(vty,
-                               "  Metric      : %-8u MT-Reach      : %s %s\n",
-                               GET_TE_METRIC(neigh), lspid,
-                               isis_mtid2str(mtid));
-               }
-               if (IS_MPLS_TE(isisMplsTE))
-                       mpls_te_print_detail(vty, neigh);
-       }
-}
-
-static void lsp_print_mt_ipv6_reach(struct list *list, struct vty *vty,
-                                   uint16_t mtid)
-{
-       struct listnode *node;
-       struct ipv6_reachability *ipv6_reach;
-       struct in6_addr in6;
-       u_char buff[BUFSIZ];
-
-       for (ALL_LIST_ELEMENTS_RO(list, node, ipv6_reach)) {
-               memset(&in6, 0, sizeof(in6));
-               memcpy(in6.s6_addr, ipv6_reach->prefix,
-                      PSIZE(ipv6_reach->prefix_len));
-               inet_ntop(AF_INET6, &in6, (char *)buff, BUFSIZ);
-               if (mtid == ISIS_MT_IPV4_UNICAST) {
-                       if ((ipv6_reach->control_info & CTRL_INFO_DISTRIBUTION)
-                           == DISTRIBUTION_INTERNAL)
-                               vty_out(vty, "  Metric      : %-8" PRIu32
-                                            " IPv6-Internal : %s/%d\n",
-                                       ntohl(ipv6_reach->metric), buff,
-                                       ipv6_reach->prefix_len);
-                       else
-                               vty_out(vty, "  Metric      : %-8" PRIu32
-                                            " IPv6-External : %s/%d\n",
-                                       ntohl(ipv6_reach->metric), buff,
-                                       ipv6_reach->prefix_len);
-               } else {
-                       if ((ipv6_reach->control_info & CTRL_INFO_DISTRIBUTION)
-                           == DISTRIBUTION_INTERNAL)
-                               vty_out(vty, "  Metric      : %-8" PRIu32
-                                            " IPv6-MT-Int   : %s/%d %s\n",
-                                       ntohl(ipv6_reach->metric), buff,
-                                       ipv6_reach->prefix_len,
-                                       isis_mtid2str(mtid));
-                       else
-                               vty_out(vty, "  Metric      : %-8" PRIu32
-                                            " IPv6-MT-Ext   : %s/%d %s\n",
-                                       ntohl(ipv6_reach->metric), buff,
-                                       ipv6_reach->prefix_len,
-                                       isis_mtid2str(mtid));
-               }
-       }
-}
-
-static void lsp_print_mt_ipv4_reach(struct list *list, struct vty *vty,
-                                   uint16_t mtid)
-{
-       struct listnode *node;
-       struct te_ipv4_reachability *te_ipv4_reach;
-
-       for (ALL_LIST_ELEMENTS_RO(list, node, te_ipv4_reach)) {
-               if (mtid == ISIS_MT_IPV4_UNICAST) {
-                       /* FIXME: There should be better way to output this
-                        * stuff. */
-                       vty_out(vty, "  Metric      : %-8" PRIu32
-                                    " IPv4-Extended : %s/%d\n",
-                               ntohl(te_ipv4_reach->te_metric),
-                               inet_ntoa(newprefix2inaddr(
-                                       &te_ipv4_reach->prefix_start,
-                                       te_ipv4_reach->control)),
-                               te_ipv4_reach->control & 0x3F);
-               } else {
-                       /* FIXME: There should be better way to output this
-                        * stuff. */
-                       vty_out(vty, "  Metric      : %-8" PRIu32
-                                    " IPv4-MT       : %s/%d %s\n",
-                               ntohl(te_ipv4_reach->te_metric),
-                               inet_ntoa(newprefix2inaddr(
-                                       &te_ipv4_reach->prefix_start,
-                                       te_ipv4_reach->control)),
-                               te_ipv4_reach->control & 0x3F,
-                               isis_mtid2str(mtid));
-               }
-       }
+               vty_out(vty, " %5" PRIu16 "    ", lsp->hdr.rem_lifetime);
+       vty_out(vty, "%s\n", lsp_bits2string(lsp->hdr.lsp_bits));
 }
 
 void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost)
 {
-       struct area_addr *area_addr;
-       int i;
-       struct listnode *lnode;
-       struct is_neigh *is_neigh;
-       struct ipv4_reachability *ipv4_reach;
-       struct in_addr *ipv4_addr;
-       struct mt_router_info *mt_router_info;
-       struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
-       struct tlv_mt_neighbors *mt_is_neigh;
-       struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
-       u_char LSPid[255];
-       u_char hostname[255];
-       u_char ipv4_reach_prefix[20];
-       u_char ipv4_reach_mask[20];
-       u_char ipv4_address[20];
-
-       lspid_print(lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
        lsp_print(lsp, vty, dynhost);
-
-       /* for all area address */
-       if (lsp->tlv_data.area_addrs)
-               for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.area_addrs, lnode,
-                                         area_addr)) {
-                       vty_out(vty, "  Area Address: %s\n",
-                               isonet_print(area_addr->area_addr,
-                                            area_addr->addr_len));
-               }
-
-       /* for the nlpid tlv */
-       if (lsp->tlv_data.nlpids) {
-               for (i = 0; i < lsp->tlv_data.nlpids->count; i++) {
-                       switch (lsp->tlv_data.nlpids->nlpids[i]) {
-                       case NLPID_IP:
-                       case NLPID_IPV6:
-                               vty_out(vty, "  NLPID       : 0x%X\n",
-                                       lsp->tlv_data.nlpids->nlpids[i]);
-                               break;
-                       default:
-                               vty_out(vty, "  NLPID       : %s\n", "unknown");
-                               break;
-                       }
-               }
-       }
-
-       for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_router_info, lnode,
-                                 mt_router_info)) {
-               vty_out(vty, "  MT          : %s%s\n",
-                       isis_mtid2str(mt_router_info->mtid),
-                       mt_router_info->overload ? " (overload)" : "");
-       }
-
-       /* for the hostname tlv */
-       if (lsp->tlv_data.hostname) {
-               bzero(hostname, sizeof(hostname));
-               memcpy(hostname, lsp->tlv_data.hostname->name,
-                      lsp->tlv_data.hostname->namelen);
-               vty_out(vty, "  Hostname    : %s\n", hostname);
-       }
-
-       /* authentication tlv */
-       if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED) {
-               if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5)
-                       vty_out(vty, "  Auth type   : md5\n");
-               else if (lsp->tlv_data.auth_info.type
-                        == ISIS_PASSWD_TYPE_CLEARTXT)
-                       vty_out(vty, "  Auth type   : clear text\n");
-       }
-
-       /* TE router id */
-       if (lsp->tlv_data.router_id) {
-               memcpy(ipv4_address, inet_ntoa(lsp->tlv_data.router_id->id),
-                      sizeof(ipv4_address));
-               vty_out(vty, "  Router ID   : %s\n", ipv4_address);
-       }
-
-       if (lsp->tlv_data.ipv4_addrs)
-               for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_addrs, lnode,
-                                         ipv4_addr)) {
-                       memcpy(ipv4_address, inet_ntoa(*ipv4_addr),
-                              sizeof(ipv4_address));
-                       vty_out(vty, "  IPv4 Address: %s\n", ipv4_address);
-               }
-
-       /* for the IS neighbor tlv */
-       if (lsp->tlv_data.is_neighs)
-               for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.is_neighs, lnode,
-                                         is_neigh)) {
-                       lspid_print(is_neigh->neigh_id, LSPid, dynhost, 0);
-                       vty_out(vty, "  Metric      : %-8" PRIu8
-                                    " IS            : %s\n",
-                               is_neigh->metrics.metric_default, LSPid);
-               }
-
-       /* for the internal reachable tlv */
-       if (lsp->tlv_data.ipv4_int_reachs)
-               for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_int_reachs, lnode,
-                                         ipv4_reach)) {
-                       memcpy(ipv4_reach_prefix, inet_ntoa(ipv4_reach->prefix),
-                              sizeof(ipv4_reach_prefix));
-                       memcpy(ipv4_reach_mask, inet_ntoa(ipv4_reach->mask),
-                              sizeof(ipv4_reach_mask));
-                       vty_out(vty, "  Metric      : %-8" PRIu8
-                                    " IPv4-Internal : %s %s\n",
-                               ipv4_reach->metrics.metric_default,
-                               ipv4_reach_prefix, ipv4_reach_mask);
-               }
-
-       /* for the external reachable tlv */
-       if (lsp->tlv_data.ipv4_ext_reachs)
-               for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_ext_reachs, lnode,
-                                         ipv4_reach)) {
-                       memcpy(ipv4_reach_prefix, inet_ntoa(ipv4_reach->prefix),
-                              sizeof(ipv4_reach_prefix));
-                       memcpy(ipv4_reach_mask, inet_ntoa(ipv4_reach->mask),
-                              sizeof(ipv4_reach_mask));
-                       vty_out(vty, "  Metric      : %-8" PRIu8
-                                    " IPv4-External : %s %s\n",
-                               ipv4_reach->metrics.metric_default,
-                               ipv4_reach_prefix, ipv4_reach_mask);
-               }
-
-       /* IPv6 tlv */
-       lsp_print_mt_ipv6_reach(lsp->tlv_data.ipv6_reachs, vty,
-                               ISIS_MT_IPV4_UNICAST);
-
-       /* MT IPv6 reachability tlv */
-       for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_ipv6_reachs, lnode,
-                                 mt_ipv6_reachs))
-               lsp_print_mt_ipv6_reach(mt_ipv6_reachs->list, vty,
-                                       mt_ipv6_reachs->mtid);
-
-       /* TE IS neighbor tlv */
-       lsp_print_mt_reach(lsp->tlv_data.te_is_neighs, vty, dynhost,
-                          ISIS_MT_IPV4_UNICAST);
-
-       /* MT IS neighbor tlv */
-       for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_is_neighs, lnode,
-                                 mt_is_neigh))
-               lsp_print_mt_reach(mt_is_neigh->list, vty, dynhost,
-                                  mt_is_neigh->mtid);
-
-       /* TE IPv4 tlv */
-       lsp_print_mt_ipv4_reach(lsp->tlv_data.te_ipv4_reachs, vty,
-                               ISIS_MT_IPV4_UNICAST);
-
-       /* MT IPv4 reachability tlv */
-       for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_ipv4_reachs, lnode,
-                                 mt_ipv4_reachs))
-               lsp_print_mt_ipv4_reach(mt_ipv4_reachs->list, vty,
-                                       mt_ipv4_reachs->mtid);
-
+       if (lsp->tlvs)
+               vty_multiline(vty, "  ", "%s", isis_format_tlvs(lsp->tlvs));
        vty_out(vty, "\n");
-
-       return;
 }
 
 /* print all the lsps info in the local lspdb */
@@ -1026,85 +677,6 @@ int lsp_print_all(struct vty *vty, dict_t *lspdb, char detail, char dynhost)
        return lsp_count;
 }
 
-static void _lsp_tlv_fit(struct isis_lsp *lsp, struct list **from,
-                        struct list **to, int frag_thold,
-                        unsigned int tlv_build_func(struct list *,
-                                                    struct stream *,
-                                                    void *arg),
-                        void *arg)
-{
-       while (*from && listcount(*from)) {
-               unsigned int count;
-
-               count = tlv_build_func(*from, lsp->pdu, arg);
-
-               if (listcount(*to) != 0 || count != listcount(*from)) {
-                       struct listnode *node, *nnode;
-                       void *elem;
-
-                       for (ALL_LIST_ELEMENTS(*from, node, nnode, elem)) {
-                               if (!count)
-                                       break;
-                               listnode_add(*to, elem);
-                               list_delete_node(*from, node);
-                               --count;
-                       }
-               } else {
-                       list_free(*to);
-                       *to = *from;
-                       *from = NULL;
-               }
-       }
-}
-
-#define FRAG_THOLD(S, T) ((STREAM_SIZE(S) * T) / 100)
-
-/* stream*, area->lsp_frag_threshold, increment */
-#define FRAG_NEEDED(S, T, I)                                                   \
-       (STREAM_SIZE(S) - STREAM_REMAIN(S) + (I) > FRAG_THOLD(S, T))
-
-/* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
- * variable length (TE TLVs, sub TLVs). */
-static void lsp_tlv_fit(struct isis_lsp *lsp, struct list **from,
-                       struct list **to, int tlvsize, int frag_thold,
-                       int tlv_build_func(struct list *, struct stream *))
-{
-       int count, i;
-
-       /* can we fit all ? */
-       if (!FRAG_NEEDED(lsp->pdu, frag_thold,
-                        listcount(*from) * tlvsize + 2)) {
-               tlv_build_func(*from, lsp->pdu);
-               if (listcount(*to) != 0) {
-                       struct listnode *node, *nextnode;
-                       void *elem;
-
-                       for (ALL_LIST_ELEMENTS(*from, node, nextnode, elem)) {
-                               listnode_add(*to, elem);
-                               list_delete_node(*from, node);
-                       }
-               } else {
-                       list_free(*to);
-                       *to = *from;
-                       *from = NULL;
-               }
-       } else if (!FRAG_NEEDED(lsp->pdu, frag_thold, tlvsize + 2)) {
-               /* fit all we can */
-               count = FRAG_THOLD(lsp->pdu, frag_thold) - 2
-                       - (STREAM_SIZE(lsp->pdu) - STREAM_REMAIN(lsp->pdu));
-               count = count / tlvsize;
-               if (count > (int)listcount(*from))
-                       count = listcount(*from);
-               for (i = 0; i < count; i++) {
-                       listnode_add(*to, listgetdata(listhead(*from)));
-                       listnode_delete(*from, listgetdata(listhead(*from)));
-               }
-               tlv_build_func(*to, lsp->pdu);
-       }
-       lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
-       return;
-}
-
 static u_int16_t lsp_rem_lifetime(struct isis_area *area, int level)
 {
        u_int16_t rem_lifetime;
@@ -1147,155 +719,90 @@ static u_int16_t lsp_refresh_time(struct isis_lsp *lsp, u_int16_t rem_lifetime)
        return refresh_time;
 }
 
-static struct isis_lsp *lsp_next_frag(u_char frag_num, struct isis_lsp *lsp0,
-                                     struct isis_area *area, int level)
-{
-       struct isis_lsp *lsp;
-       u_char frag_id[ISIS_SYS_ID_LEN + 2];
-
-       memcpy(frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
-       LSP_FRAGMENT(frag_id) = frag_num;
-       /* FIXME add authentication TLV for fragment LSPs */
-       lsp = lsp_search(frag_id, area->lspdb[level - 1]);
-       if (lsp) {
-               /* Clear the TLVs */
-               lsp_clear_data(lsp);
-               return lsp;
-       }
-       lsp = lsp_new(area, frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
-                     lsp_bits_generate(level, area->overload_bit,
-                                       area->attached_bit),
-                     0, level);
-       lsp->area = area;
-       lsp->own_lsp = 1;
-       lsp_insert(lsp, area->lspdb[level - 1]);
-       listnode_add(lsp0->lspu.frags, lsp);
-       lsp->lspu.zero_lsp = lsp0;
-       return lsp;
-}
-
 static void lsp_build_ext_reach_ipv4(struct isis_lsp *lsp,
-                                    struct isis_area *area,
-                                    struct tlvs *tlv_data)
+                                    struct isis_area *area)
 {
-       struct route_table *er_table;
-       struct route_node *rn;
-       struct prefix_ipv4 *ipv4;
-       struct isis_ext_info *info;
-       struct ipv4_reachability *ipreach;
-       struct te_ipv4_reachability *te_ipreach;
-
-       er_table = get_ext_reach(area, AF_INET, lsp->level);
+       struct route_table *er_table = get_ext_reach(area, AF_INET, lsp->level);
        if (!er_table)
                return;
 
-       for (rn = route_top(er_table); rn; rn = route_next(rn)) {
+       for (struct route_node *rn = route_top(er_table); rn;
+            rn = route_next(rn)) {
                if (!rn->info)
                        continue;
 
-               ipv4 = (struct prefix_ipv4 *)&rn->p;
-               info = rn->info;
-               if (area->oldmetric) {
-                       if (tlv_data->ipv4_ext_reachs == NULL) {
-                               tlv_data->ipv4_ext_reachs = list_new();
-                               tlv_data->ipv4_ext_reachs->del = free_tlv;
-                       }
-                       ipreach = XMALLOC(MTYPE_ISIS_TLV, sizeof(*ipreach));
-
-                       ipreach->prefix.s_addr = ipv4->prefix.s_addr;
-                       masklen2ip(ipv4->prefixlen, &ipreach->mask);
-                       ipreach->prefix.s_addr &= ipreach->mask.s_addr;
-
-                       if ((info->metric & 0x3f) != info->metric)
-                               ipreach->metrics.metric_default = 0x3f;
-                       else
-                               ipreach->metrics.metric_default = info->metric;
-                       ipreach->metrics.metric_expense = METRICS_UNSUPPORTED;
-                       ipreach->metrics.metric_error = METRICS_UNSUPPORTED;
-                       ipreach->metrics.metric_delay = METRICS_UNSUPPORTED;
-                       listnode_add(tlv_data->ipv4_ext_reachs, ipreach);
-               }
-               if (area->newmetric) {
-                       if (tlv_data->te_ipv4_reachs == NULL) {
-                               tlv_data->te_ipv4_reachs = list_new();
-                               tlv_data->te_ipv4_reachs->del = free_tlv;
-                       }
-                       te_ipreach = XCALLOC(MTYPE_ISIS_TLV,
-                                            sizeof(*te_ipreach) - 1
-                                                    + PSIZE(ipv4->prefixlen));
-                       if (info->metric > MAX_WIDE_PATH_METRIC)
-                               te_ipreach->te_metric =
-                                       htonl(MAX_WIDE_PATH_METRIC);
-                       else
-                               te_ipreach->te_metric = htonl(info->metric);
-                       te_ipreach->control = ipv4->prefixlen & 0x3f;
-                       memcpy(&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
-                              PSIZE(ipv4->prefixlen));
-                       listnode_add(tlv_data->te_ipv4_reachs, te_ipreach);
-               }
-       }
-}
+               struct prefix_ipv4 *ipv4 = (struct prefix_ipv4 *)&rn->p;
+               struct isis_ext_info *info = rn->info;
 
-static struct list *tlv_get_ipv6_reach_list(struct isis_area *area,
-                                           struct tlvs *tlv_data)
-{
-       uint16_t mtid = isis_area_ipv6_topology(area);
-       if (mtid == ISIS_MT_IPV4_UNICAST) {
-               if (!tlv_data->ipv6_reachs) {
-                       tlv_data->ipv6_reachs = list_new();
-                       tlv_data->ipv6_reachs->del = free_tlv;
-               }
-               return tlv_data->ipv6_reachs;
-       }
+               uint32_t metric = info->metric;
+               if (metric > MAX_WIDE_PATH_METRIC)
+                       metric = MAX_WIDE_PATH_METRIC;
+               if (area->oldmetric && metric > 0x3f)
+                       metric = 0x3f;
 
-       struct tlv_mt_ipv6_reachs *reachs =
-               tlvs_get_mt_ipv6_reachs(tlv_data, mtid);
-       return reachs->list;
+               if (area->oldmetric)
+                       isis_tlvs_add_oldstyle_ip_reach(lsp->tlvs, ipv4,
+                                                       metric);
+               if (area->newmetric)
+                       isis_tlvs_add_extended_ip_reach(lsp->tlvs, ipv4,
+                                                       metric);
+       }
 }
 
 static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
-                                    struct isis_area *area,
-                                    struct tlvs *tlv_data)
+                                    struct isis_area *area)
 {
-       struct route_table *er_table;
-       struct route_node *rn;
-       struct prefix_ipv6 *ipv6;
-       struct isis_ext_info *info;
-       struct ipv6_reachability *ip6reach;
-       struct list *reach_list = NULL;
-
-       er_table = get_ext_reach(area, AF_INET6, lsp->level);
+       struct route_table *er_table =
+               get_ext_reach(area, AF_INET6, lsp->level);
        if (!er_table)
                return;
 
-       for (rn = route_top(er_table); rn; rn = route_next(rn)) {
+       for (struct route_node *rn = route_top(er_table); rn;
+            rn = route_next(rn)) {
                if (!rn->info)
                        continue;
 
-               ipv6 = (struct prefix_ipv6 *)&rn->p;
-               info = rn->info;
+               struct prefix_ipv6 *ipv6 = (struct prefix_ipv6 *)&rn->p;
+               struct isis_ext_info *info = rn->info;
 
-               if (!reach_list)
-                       reach_list = tlv_get_ipv6_reach_list(area, tlv_data);
-
-               ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
+               uint32_t metric = info->metric;
                if (info->metric > MAX_WIDE_PATH_METRIC)
-                       ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
-               else
-                       ip6reach->metric = htonl(info->metric);
-               ip6reach->control_info = DISTRIBUTION_EXTERNAL;
-               ip6reach->prefix_len = ipv6->prefixlen;
-               memcpy(ip6reach->prefix, ipv6->prefix.s6_addr,
-                      sizeof(ip6reach->prefix));
-               listnode_add(reach_list, ip6reach);
+                       metric = MAX_WIDE_PATH_METRIC;
+               isis_tlvs_add_ipv6_reach(
+                       lsp->tlvs, isis_area_ipv6_topology(area), ipv6, metric);
        }
 }
 
-static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area,
-                               struct tlvs *tlv_data)
+static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area)
 {
-       lsp_build_ext_reach_ipv4(lsp, area, tlv_data);
-       lsp_build_ext_reach_ipv6(lsp, area, tlv_data);
+       lsp_build_ext_reach_ipv4(lsp, area);
+       lsp_build_ext_reach_ipv6(lsp, area);
+}
+
+static struct isis_lsp *lsp_next_frag(uint8_t frag_num, struct isis_lsp *lsp0,
+                                     struct isis_area *area, int level)
+{
+       struct isis_lsp *lsp;
+       uint8_t frag_id[ISIS_SYS_ID_LEN + 2];
+
+       memcpy(frag_id, lsp0->hdr.lsp_id, ISIS_SYS_ID_LEN + 1);
+       LSP_FRAGMENT(frag_id) = frag_num;
+
+       lsp = lsp_search(frag_id, area->lspdb[level - 1]);
+       if (lsp) {
+               lsp_clear_data(lsp);
+               return lsp;
+       }
+
+       lsp = lsp_new(area, frag_id, lsp0->hdr.rem_lifetime, 0,
+                     lsp_bits_generate(level, area->overload_bit,
+                                       area->attached_bit),
+                     0, level);
+       lsp->own_lsp = 1;
+       lsp_insert(lsp, area->lspdb[level - 1]);
+       listnode_add(lsp0->lspu.frags, lsp);
+       lsp->lspu.zero_lsp = lsp0;
+       return lsp;
 }
 
 /*
@@ -1304,126 +811,69 @@ static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area,
  */
 static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
 {
-       struct is_neigh *is_neigh;
-       struct te_is_neigh *te_is_neigh;
-       struct listnode *node, *ipnode;
        int level = lsp->level;
-       struct isis_circuit *circuit;
-       struct prefix_ipv4 *ipv4;
-       struct ipv4_reachability *ipreach;
-       struct te_ipv4_reachability *te_ipreach;
-       struct isis_adjacency *nei;
-       struct prefix_ipv6 *ipv6, ip6prefix;
-       struct list *ipv6_reachs = NULL;
-       struct ipv6_reachability *ip6reach;
-       struct tlvs tlv_data;
-       struct isis_lsp *lsp0 = lsp;
-       struct in_addr *routerid;
-       uint32_t expected = 0, found = 0;
-       uint32_t metric;
-       u_char zero_id[ISIS_SYS_ID_LEN + 1];
-       int retval = ISIS_OK;
-       char buf[BUFSIZ];
+       char buf[PREFIX2STR_BUFFER];
+       struct listnode *node;
+       struct isis_lsp *frag;
+
+       lsp_clear_data(lsp);
+       for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag))
+               lsp_clear_data(frag);
 
+       lsp->tlvs = isis_alloc_tlvs();
        lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
                  area->area_tag, level);
 
-       /*
-        * Building the zero lsp
-        */
-       memset(zero_id, 0, ISIS_SYS_ID_LEN + 1);
-
-       /* Reset stream endp. Stream is always there and on every LSP refresh
-        * only
-        * TLV part of it is overwritten. So we must seek past header we will
-        * not
-        * touch. */
-       stream_reset(lsp->pdu);
-       stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+       lsp->hdr.lsp_bits = lsp_bits_generate(level, area->overload_bit,
+                                             area->attached_bit);
 
-       /*
-        * Add the authentication info if its present
-        */
-       lsp_auth_add(lsp);
+       lsp_add_auth(lsp);
 
-       /*
-        * First add the tlvs related to area
-        */
-
-       /* Area addresses */
-       if (lsp->tlv_data.area_addrs == NULL)
-               lsp->tlv_data.area_addrs = list_new();
-       list_add_list(lsp->tlv_data.area_addrs, area->area_addrs);
-       if (listcount(lsp->tlv_data.area_addrs) > 0)
-               tlv_add_area_addrs(lsp->tlv_data.area_addrs, lsp->pdu);
+       isis_tlvs_add_area_addresses(lsp->tlvs, area->area_addrs);
 
        /* Protocols Supported */
        if (area->ip_circuits > 0 || area->ipv6_circuits > 0) {
-               lsp->tlv_data.nlpids =
-                       XCALLOC(MTYPE_ISIS_TLV, sizeof(struct nlpids));
-               lsp->tlv_data.nlpids->count = 0;
+               struct nlpids nlpids = {.count = 0};
                if (area->ip_circuits > 0) {
                        lsp_debug(
                                "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
                                area->area_tag);
-                       lsp->tlv_data.nlpids->count++;
-                       lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
+                       nlpids.nlpids[nlpids.count] = NLPID_IP;
+                       nlpids.count++;
                }
                if (area->ipv6_circuits > 0) {
                        lsp_debug(
                                "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
                                area->area_tag);
-                       lsp->tlv_data.nlpids->count++;
-                       lsp->tlv_data.nlpids
-                               ->nlpids[lsp->tlv_data.nlpids->count - 1] =
-                               NLPID_IPV6;
+                       nlpids.nlpids[nlpids.count] = NLPID_IPV6;
+                       nlpids.count++;
                }
-               tlv_add_nlpid(lsp->tlv_data.nlpids, lsp->pdu);
+               isis_tlvs_set_protocols_supported(lsp->tlvs, &nlpids);
        }
 
        if (area_is_mt(area)) {
                lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag);
-               lsp->tlv_data.mt_router_info = list_new();
-               lsp->tlv_data.mt_router_info->del = free_tlv;
 
                struct isis_area_mt_setting **mt_settings;
                unsigned int mt_count;
 
                mt_settings = area_mt_settings(area, &mt_count);
                for (unsigned int i = 0; i < mt_count; i++) {
-                       struct mt_router_info *info;
-
-                       info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
-                       info->mtid = mt_settings[i]->mtid;
-                       info->overload = mt_settings[i]->overload;
-                       listnode_add(lsp->tlv_data.mt_router_info, info);
+                       isis_tlvs_add_mt_router_info(
+                               lsp->tlvs, mt_settings[i]->mtid,
+                               mt_settings[i]->overload, false);
                        lsp_debug("ISIS (%s):   MT %s", area->area_tag,
-                                 isis_mtid2str(info->mtid));
+                                 isis_mtid2str(mt_settings[i]->mtid));
                }
-               tlv_add_mt_router_info(lsp->tlv_data.mt_router_info, lsp->pdu);
        } else {
                lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
                          area->area_tag);
        }
        /* Dynamic Hostname */
        if (area->dynhostname) {
-               const char *hostname = unix_hostname();
-               size_t hostname_len = strlen(hostname);
-
-               lsp->tlv_data.hostname =
-                       XMALLOC(MTYPE_ISIS_TLV, sizeof(struct hostname));
-
-               strncpy((char *)lsp->tlv_data.hostname->name, hostname,
-                       sizeof(lsp->tlv_data.hostname->name));
-               if (hostname_len <= MAX_TLV_LEN)
-                       lsp->tlv_data.hostname->namelen = hostname_len;
-               else
-                       lsp->tlv_data.hostname->namelen = MAX_TLV_LEN;
-
-               lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'",
-                         area->area_tag, lsp->tlv_data.hostname->namelen,
-                         lsp->tlv_data.hostname->name);
-               tlv_add_dynamic_hostname(lsp->tlv_data.hostname, lsp->pdu);
+               isis_tlvs_set_dynamic_hostname(lsp->tlvs, unix_hostname());
+               lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
+                         area->area_tag, unix_hostname());
        } else {
                lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
                          area->area_tag);
@@ -1434,45 +884,31 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
         * into
         * LSP and this address is same as router id. */
        if (isis->router_id != 0) {
-               inet_ntop(AF_INET, &isis->router_id, buf, sizeof(buf));
+               struct in_addr id = {.s_addr = isis->router_id};
+               inet_ntop(AF_INET, &id, buf, sizeof(buf));
                lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.",
                          area->area_tag, buf);
-               if (lsp->tlv_data.ipv4_addrs == NULL) {
-                       lsp->tlv_data.ipv4_addrs = list_new();
-                       lsp->tlv_data.ipv4_addrs->del = free_tlv;
-               }
-
-               routerid = XMALLOC(MTYPE_ISIS_TLV, sizeof(struct in_addr));
-               routerid->s_addr = isis->router_id;
-               listnode_add(lsp->tlv_data.ipv4_addrs, routerid);
-               tlv_add_in_addr(routerid, lsp->pdu, IPV4_ADDR);
+               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 (area->newmetric) {
+
                        lsp_debug(
                                "ISIS (%s): Adding router ID also as TE router ID tlv.",
                                area->area_tag);
-                       lsp->tlv_data.router_id =
-                               XMALLOC(MTYPE_ISIS_TLV, sizeof(struct in_addr));
-                       lsp->tlv_data.router_id->id.s_addr = isis->router_id;
-                       tlv_add_in_addr(&lsp->tlv_data.router_id->id, lsp->pdu,
-                                       TE_ROUTER_ID);
+                       isis_tlvs_set_te_router_id(lsp->tlvs, &id);
                }
        } else {
                lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
                          area->area_tag);
        }
 
-       memset(&tlv_data, 0, sizeof(struct tlvs));
-
        lsp_debug("ISIS (%s): Adding circuit specific information.",
                  area->area_tag);
 
-       /*
-        * Then build lists of tlvs related to circuits
-        */
+       struct isis_circuit *circuit;
        for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
                if (!circuit->interface)
                        lsp_debug(
@@ -1492,245 +928,94 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                        continue;
                }
 
-               /*
-                * Add IPv4 internal reachability of this circuit
-                */
+               uint32_t metric = area->oldmetric
+                                         ? circuit->metric[level - 1]
+                                         : circuit->te_metric[level - 1];
+
                if (circuit->ip_router && circuit->ip_addrs
                    && circuit->ip_addrs->count > 0) {
                        lsp_debug(
                                "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
                                area->area_tag);
-                       if (area->oldmetric) {
-                               if (tlv_data.ipv4_int_reachs == NULL) {
-                                       tlv_data.ipv4_int_reachs = list_new();
-                                       tlv_data.ipv4_int_reachs->del =
-                                               free_tlv;
-                               }
-                               for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs,
-                                                         ipnode, ipv4)) {
-                                       ipreach = XMALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct
-                                                      ipv4_reachability));
-                                       ipreach->metrics.metric_default =
-                                               circuit->metric[level - 1];
-                                       ipreach->metrics.metric_expense =
-                                               METRICS_UNSUPPORTED;
-                                       ipreach->metrics.metric_error =
-                                               METRICS_UNSUPPORTED;
-                                       ipreach->metrics.metric_delay =
-                                               METRICS_UNSUPPORTED;
-                                       masklen2ip(ipv4->prefixlen,
-                                                  &ipreach->mask);
-                                       ipreach->prefix.s_addr =
-                                               ((ipreach->mask.s_addr)
-                                                & (ipv4->prefix.s_addr));
-                                       inet_ntop(AF_INET,
-                                                 &ipreach->prefix.s_addr, buf,
-                                                 sizeof(buf));
+                       struct listnode *ipnode;
+                       struct prefix_ipv4 *ipv4;
+                       for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
+                                                 ipv4)) {
+                               if (area->oldmetric) {
                                        lsp_debug(
-                                               "ISIS (%s): Adding old-style IP reachability for %s/%d",
-                                               area->area_tag, buf,
-                                               ipv4->prefixlen);
-                                       listnode_add(tlv_data.ipv4_int_reachs,
-                                                    ipreach);
-                               }
-                       }
-                       if (area->newmetric) {
-                               if (tlv_data.te_ipv4_reachs == NULL) {
-                                       tlv_data.te_ipv4_reachs = list_new();
-                                       tlv_data.te_ipv4_reachs->del = free_tlv;
+                                               "ISIS (%s): Adding old-style IP reachability for %s",
+                                               area->area_tag,
+                                               prefix2str(ipv4, buf,
+                                                          sizeof(buf)));
+                                       isis_tlvs_add_oldstyle_ip_reach(
+                                               lsp->tlvs, ipv4, metric);
                                }
-                               for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs,
-                                                         ipnode, ipv4)) {
-                                       /* FIXME All this assumes that we have
-                                        * no sub TLVs. */
-                                       te_ipreach = XCALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct
-                                                      te_ipv4_reachability)
-                                                       + ((ipv4->prefixlen + 7)
-                                                          / 8)
-                                                       - 1);
-
-                                       if (area->oldmetric)
-                                               te_ipreach->te_metric = htonl(
-                                                       circuit->metric[level
-                                                                       - 1]);
-                                       else
-                                               te_ipreach->te_metric = htonl(
-                                                       circuit->te_metric
-                                                               [level - 1]);
-
-                                       te_ipreach->control =
-                                               (ipv4->prefixlen & 0x3F);
-                                       memcpy(&te_ipreach->prefix_start,
-                                              &ipv4->prefix.s_addr,
-                                              (ipv4->prefixlen + 7) / 8);
-                                       inet_ntop(AF_INET, &ipv4->prefix.s_addr,
-                                                 buf, sizeof(buf));
+
+                               if (area->newmetric) {
                                        lsp_debug(
-                                               "ISIS (%s): Adding te-style IP reachability for %s/%d",
-                                               area->area_tag, buf,
-                                               ipv4->prefixlen);
-                                       listnode_add(tlv_data.te_ipv4_reachs,
-                                                    te_ipreach);
+                                               "ISIS (%s): Adding te-style IP reachability for %s",
+                                               area->area_tag,
+                                               prefix2str(ipv4, buf,
+                                                          sizeof(buf)));
+                                       isis_tlvs_add_extended_ip_reach(
+                                               lsp->tlvs, ipv4, metric);
                                }
                        }
                }
 
-               /*
-                * Add IPv6 reachability of this circuit
-                */
                if (circuit->ipv6_router && circuit->ipv6_non_link
                    && circuit->ipv6_non_link->count > 0) {
-                       if (!ipv6_reachs)
-                               ipv6_reachs = tlv_get_ipv6_reach_list(
-                                       area, &tlv_data);
-
+                       struct listnode *ipnode;
+                       struct prefix_ipv6 *ipv6;
                        for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
                                                  ipnode, ipv6)) {
-                               ip6reach = XCALLOC(
-                                       MTYPE_ISIS_TLV,
-                                       sizeof(struct ipv6_reachability));
-
-                               if (area->oldmetric)
-                                       ip6reach->metric = htonl(
-                                               circuit->metric[level - 1]);
-                               else
-                                       ip6reach->metric = htonl(
-                                               circuit->te_metric[level - 1]);
-
-                               ip6reach->control_info = 0;
-                               ip6reach->prefix_len = ipv6->prefixlen;
-                               memcpy(&ip6prefix, ipv6, sizeof(ip6prefix));
-                               apply_mask_ipv6(&ip6prefix);
-
-                               inet_ntop(AF_INET6, &ip6prefix.prefix.s6_addr,
-                                         buf, sizeof(buf));
                                lsp_debug(
-                                       "ISIS (%s): Adding IPv6 reachability for %s/%d",
-                                       area->area_tag, buf, ipv6->prefixlen);
-
-                               memcpy(ip6reach->prefix,
-                                      ip6prefix.prefix.s6_addr,
-                                      sizeof(ip6reach->prefix));
-                               listnode_add(ipv6_reachs, ip6reach);
+                                       "ISIS (%s): Adding IPv6 reachability for %s",
+                                       area->area_tag,
+                                       prefix2str(ipv6, buf, sizeof(buf)));
+                               isis_tlvs_add_ipv6_reach(
+                                       lsp->tlvs,
+                                       isis_area_ipv6_topology(area), ipv6,
+                                       metric);
                        }
                }
 
                switch (circuit->circ_type) {
                case CIRCUIT_T_BROADCAST:
                        if (level & circuit->is_type) {
-                               if (area->oldmetric) {
-                                       if (tlv_data.is_neighs == NULL) {
-                                               tlv_data.is_neighs = list_new();
-                                               tlv_data.is_neighs->del =
-                                                       free_tlv;
-                                       }
-                                       is_neigh = XCALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct is_neigh));
-                                       if (level == IS_LEVEL_1)
-                                               memcpy(is_neigh->neigh_id,
-                                                      circuit->u.bc
-                                                              .l1_desig_is,
-                                                      ISIS_SYS_ID_LEN + 1);
-                                       else
-                                               memcpy(is_neigh->neigh_id,
-                                                      circuit->u.bc
-                                                              .l2_desig_is,
-                                                      ISIS_SYS_ID_LEN + 1);
-                                       is_neigh->metrics.metric_default =
-                                               circuit->metric[level - 1];
-                                       is_neigh->metrics.metric_expense =
-                                               METRICS_UNSUPPORTED;
-                                       is_neigh->metrics.metric_error =
-                                               METRICS_UNSUPPORTED;
-                                       is_neigh->metrics.metric_delay =
-                                               METRICS_UNSUPPORTED;
-                                       if (!memcmp(is_neigh->neigh_id, zero_id,
-                                                   ISIS_SYS_ID_LEN + 1)) {
-                                               XFREE(MTYPE_ISIS_TLV, is_neigh);
-                                               lsp_debug(
-                                                       "ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.",
-                                                       area->area_tag);
-                                       } else {
-                                               listnode_add(tlv_data.is_neighs,
-                                                            is_neigh);
+                               uint8_t *ne_id =
+                                       (level == IS_LEVEL_1)
+                                               ? circuit->u.bc.l1_desig_is
+                                               : circuit->u.bc.l2_desig_is;
+
+                               if (LSP_PSEUDO_ID(ne_id)) {
+                                       if (area->oldmetric) {
                                                lsp_debug(
                                                        "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
                                                        area->area_tag,
-                                                       sysid_print(
-                                                               is_neigh->neigh_id),
-                                                       LSP_PSEUDO_ID(
-                                                               is_neigh->neigh_id));
-                                       }
-                               }
-                               if (area->newmetric) {
-                                       if (tlv_data.te_is_neighs == NULL) {
-                                               tlv_data.te_is_neighs =
-                                                       list_new();
-                                               tlv_data.te_is_neighs->del =
-                                                       free_tlv;
+                                                       sysid_print(ne_id),
+                                                       LSP_PSEUDO_ID(ne_id));
+                                               isis_tlvs_add_oldstyle_reach(
+                                                       lsp->tlvs, ne_id,
+                                                       metric);
                                        }
-                                       te_is_neigh = XCALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct te_is_neigh));
-                                       if (level == IS_LEVEL_1)
-                                               memcpy(te_is_neigh->neigh_id,
-                                                      circuit->u.bc
-                                                              .l1_desig_is,
-                                                      ISIS_SYS_ID_LEN + 1);
-                                       else
-                                               memcpy(te_is_neigh->neigh_id,
-                                                      circuit->u.bc
-                                                              .l2_desig_is,
-                                                      ISIS_SYS_ID_LEN + 1);
-                                       if (area->oldmetric)
-                                               metric = circuit->metric[level
-                                                                        - 1];
-                                       else
-                                               metric =
-                                                       circuit->te_metric[level
-                                                                          - 1];
-                                       SET_TE_METRIC(te_is_neigh, metric);
-                                       if (!memcmp(te_is_neigh->neigh_id,
-                                                   zero_id,
-                                                   ISIS_SYS_ID_LEN + 1)) {
-                                               XFREE(MTYPE_ISIS_TLV,
-                                                     te_is_neigh);
-                                               lsp_debug(
-                                                       "ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.",
-                                                       area->area_tag);
-                                       } else {
-                                               /* Check if MPLS_TE is activate
-                                                */
+                                       if (area->newmetric) {
+                                               uint8_t subtlvs[256];
+                                               uint8_t subtlv_len;
+
                                                if (IS_MPLS_TE(isisMplsTE)
                                                    && HAS_LINK_PARAMS(
                                                               circuit->interface))
-                                                       /* Add SubTLVs & Adjust
-                                                        * real size of SubTLVs
-                                                        */
-                                                       te_is_neigh
-                                                               ->sub_tlvs_length = add_te_subtlvs(
-                                                               te_is_neigh
-                                                                       ->sub_tlvs,
+                                                       subtlv_len = add_te_subtlvs(
+                                                               subtlvs,
                                                                circuit->mtc);
                                                else
-                                                       /* Or keep only TE
-                                                        * metric with no
-                                                        * SubTLVs if MPLS_TE is
-                                                        * off */
-                                                       te_is_neigh
-                                                               ->sub_tlvs_length =
-                                                               0;
+                                                       subtlv_len = 0;
 
                                                tlvs_add_mt_bcast(
-                                                       &tlv_data, circuit,
-                                                       level, te_is_neigh);
-                                               XFREE(MTYPE_ISIS_TLV,
-                                                     te_is_neigh);
+                                                       lsp->tlvs, circuit,
+                                                       level, ne_id, metric,
+                                                       subtlvs, subtlv_len);
                                        }
                                }
                        } else {
@@ -1739,53 +1024,25 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                                        area->area_tag);
                        }
                        break;
-               case CIRCUIT_T_P2P:
-                       nei = circuit->u.p2p.neighbor;
+               case CIRCUIT_T_P2P: {
+                       struct isis_adjacency *nei = circuit->u.p2p.neighbor;
                        if (nei && (level & nei->circuit_t)) {
+                               uint8_t ne_id[7];
+                               memcpy(ne_id, nei->sysid, ISIS_SYS_ID_LEN);
+                               LSP_PSEUDO_ID(ne_id) = 0;
+
                                if (area->oldmetric) {
-                                       if (tlv_data.is_neighs == NULL) {
-                                               tlv_data.is_neighs = list_new();
-                                               tlv_data.is_neighs->del =
-                                                       free_tlv;
-                                       }
-                                       is_neigh = XCALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct is_neigh));
-                                       memcpy(is_neigh->neigh_id, nei->sysid,
-                                              ISIS_SYS_ID_LEN);
-                                       is_neigh->metrics.metric_default =
-                                               circuit->metric[level - 1];
-                                       is_neigh->metrics.metric_expense =
-                                               METRICS_UNSUPPORTED;
-                                       is_neigh->metrics.metric_error =
-                                               METRICS_UNSUPPORTED;
-                                       is_neigh->metrics.metric_delay =
-                                               METRICS_UNSUPPORTED;
-                                       listnode_add(tlv_data.is_neighs,
-                                                    is_neigh);
                                        lsp_debug(
                                                "ISIS (%s): Adding old-style is reach for %s",
                                                area->area_tag,
-                                               sysid_print(
-                                                       is_neigh->neigh_id));
+                                               sysid_print(ne_id));
+                                       isis_tlvs_add_oldstyle_reach(
+                                               lsp->tlvs, ne_id, metric);
                                }
                                if (area->newmetric) {
-                                       uint32_t metric;
+                                       uint8_t subtlvs[256];
+                                       uint8_t subtlv_len;
 
-                                       if (tlv_data.te_is_neighs == NULL) {
-                                               tlv_data.te_is_neighs =
-                                                       list_new();
-                                               tlv_data.te_is_neighs->del =
-                                                       free_tlv;
-                                       }
-                                       te_is_neigh = XCALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct te_is_neigh));
-                                       memcpy(te_is_neigh->neigh_id,
-                                              nei->sysid, ISIS_SYS_ID_LEN);
-                                       metric = circuit->te_metric[level - 1];
-                                       SET_TE_METRIC(te_is_neigh, metric);
-                                       /* Check if MPLS_TE is activate */
                                        if (IS_MPLS_TE(isisMplsTE)
                                            && HAS_LINK_PARAMS(
                                                       circuit->interface))
@@ -1804,28 +1061,24 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
 
                                                /* Add SubTLVs & Adjust real
                                                 * size of SubTLVs */
-                                               te_is_neigh->sub_tlvs_length =
-                                                       add_te_subtlvs(
-                                                               te_is_neigh
-                                                                       ->sub_tlvs,
-                                                               circuit->mtc);
+                                               subtlv_len = add_te_subtlvs(
+                                                       subtlvs, circuit->mtc);
                                        else
                                                /* Or keep only TE metric with
                                                 * no SubTLVs if MPLS_TE is off
                                                 */
-                                               te_is_neigh->sub_tlvs_length =
-                                                       0;
+                                               subtlv_len = 0;
 
-                                       tlvs_add_mt_p2p(&tlv_data, circuit,
-                                                       te_is_neigh);
-                                       XFREE(MTYPE_ISIS_TLV, te_is_neigh);
+                                       tlvs_add_mt_p2p(lsp->tlvs, circuit,
+                                                       ne_id, metric, subtlvs,
+                                                       subtlv_len);
                                }
                        } else {
                                lsp_debug(
                                        "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
                                        area->area_tag);
                        }
-                       break;
+               } break;
                case CIRCUIT_T_LOOPBACK:
                        break;
                default:
@@ -1833,169 +1086,36 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                }
        }
 
-       lsp_build_ext_reach(lsp, area, &tlv_data);
-
-       lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
-                 area->area_tag);
-
-       while (tlv_data.ipv4_int_reachs
-              && listcount(tlv_data.ipv4_int_reachs)) {
-               if (lsp->tlv_data.ipv4_int_reachs == NULL)
-                       lsp->tlv_data.ipv4_int_reachs = list_new();
-               lsp_tlv_fit(lsp, &tlv_data.ipv4_int_reachs,
-                           &lsp->tlv_data.ipv4_int_reachs, IPV4_REACH_LEN,
-                           area->lsp_frag_threshold, tlv_add_ipv4_int_reachs);
-               if (tlv_data.ipv4_int_reachs
-                   && listcount(tlv_data.ipv4_int_reachs))
-                       lsp = lsp_next_frag(
-                               LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
-                               area, level);
-       }
-
-       while (tlv_data.ipv4_ext_reachs
-              && listcount(tlv_data.ipv4_ext_reachs)) {
-               if (lsp->tlv_data.ipv4_ext_reachs == NULL)
-                       lsp->tlv_data.ipv4_ext_reachs = list_new();
-               lsp_tlv_fit(lsp, &tlv_data.ipv4_ext_reachs,
-                           &lsp->tlv_data.ipv4_ext_reachs, IPV4_REACH_LEN,
-                           area->lsp_frag_threshold, tlv_add_ipv4_ext_reachs);
-               if (tlv_data.ipv4_ext_reachs
-                   && listcount(tlv_data.ipv4_ext_reachs))
-                       lsp = lsp_next_frag(
-                               LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
-                               area, level);
-       }
-
-       while (tlv_data.te_ipv4_reachs && listcount(tlv_data.te_ipv4_reachs)) {
-               if (lsp->tlv_data.te_ipv4_reachs == NULL)
-                       lsp->tlv_data.te_ipv4_reachs = list_new();
-               _lsp_tlv_fit(lsp, &tlv_data.te_ipv4_reachs,
-                            &lsp->tlv_data.te_ipv4_reachs,
-                            area->lsp_frag_threshold, tlv_add_te_ipv4_reachs,
-                            NULL);
-               if (tlv_data.te_ipv4_reachs
-                   && listcount(tlv_data.te_ipv4_reachs))
-                       lsp = lsp_next_frag(
-                               LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
-                               area, level);
-       }
-
-       struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
-       for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv4_reachs, node,
-                                 mt_ipv4_reachs)) {
-               while (mt_ipv4_reachs->list
-                      && listcount(mt_ipv4_reachs->list)) {
-                       struct tlv_mt_ipv4_reachs *frag_mt_ipv4_reachs;
-
-                       frag_mt_ipv4_reachs = tlvs_get_mt_ipv4_reachs(
-                               &lsp->tlv_data, mt_ipv4_reachs->mtid);
-                       _lsp_tlv_fit(lsp, &mt_ipv4_reachs->list,
-                                    &frag_mt_ipv4_reachs->list,
-                                    area->lsp_frag_threshold,
-                                    tlv_add_te_ipv4_reachs,
-                                    &mt_ipv4_reachs->mtid);
-                       if (mt_ipv4_reachs->list
-                           && listcount(mt_ipv4_reachs->list))
-                               lsp = lsp_next_frag(
-                                       LSP_FRAGMENT(lsp->lsp_header->lsp_id)
-                                               + 1,
-                                       lsp0, area, level);
-               }
-       }
-
-       while (tlv_data.ipv6_reachs && listcount(tlv_data.ipv6_reachs)) {
-               if (lsp->tlv_data.ipv6_reachs == NULL)
-                       lsp->tlv_data.ipv6_reachs = list_new();
-               _lsp_tlv_fit(
-                       lsp, &tlv_data.ipv6_reachs, &lsp->tlv_data.ipv6_reachs,
-                       area->lsp_frag_threshold, tlv_add_ipv6_reachs, NULL);
-               if (tlv_data.ipv6_reachs && listcount(tlv_data.ipv6_reachs))
-                       lsp = lsp_next_frag(
-                               LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
-                               area, level);
-       }
+       lsp_build_ext_reach(lsp, area);
 
-       struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
-       for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv6_reachs, node,
-                                 mt_ipv6_reachs)) {
-               while (mt_ipv6_reachs->list
-                      && listcount(mt_ipv6_reachs->list)) {
-                       struct tlv_mt_ipv6_reachs *frag_mt_ipv6_reachs;
-
-                       frag_mt_ipv6_reachs = tlvs_get_mt_ipv6_reachs(
-                               &lsp->tlv_data, mt_ipv6_reachs->mtid);
-                       _lsp_tlv_fit(lsp, &mt_ipv6_reachs->list,
-                                    &frag_mt_ipv6_reachs->list,
-                                    area->lsp_frag_threshold,
-                                    tlv_add_ipv6_reachs,
-                                    &mt_ipv6_reachs->mtid);
-                       if (mt_ipv6_reachs->list
-                           && listcount(mt_ipv6_reachs->list))
-                               lsp = lsp_next_frag(
-                                       LSP_FRAGMENT(lsp->lsp_header->lsp_id)
-                                               + 1,
-                                       lsp0, area, level);
-               }
-       }
+       struct isis_tlvs *tlvs = lsp->tlvs;
+       lsp->tlvs = NULL;
 
-       while (tlv_data.is_neighs && listcount(tlv_data.is_neighs)) {
-               if (lsp->tlv_data.is_neighs == NULL)
-                       lsp->tlv_data.is_neighs = list_new();
-               lsp_tlv_fit(lsp, &tlv_data.is_neighs, &lsp->tlv_data.is_neighs,
-                           IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
-                           tlv_add_is_neighs);
-               if (tlv_data.is_neighs && listcount(tlv_data.is_neighs))
-                       lsp = lsp_next_frag(
-                               LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
-                               area, level);
-       }
+       lsp_pack_pdu(lsp);
+       size_t tlv_space = STREAM_WRITEABLE(lsp->pdu) - LLC_LEN;
+       lsp_clear_data(lsp);
 
-       while (tlv_data.te_is_neighs && listcount(tlv_data.te_is_neighs)) {
-               if (lsp->tlv_data.te_is_neighs == NULL)
-                       lsp->tlv_data.te_is_neighs = list_new();
-               _lsp_tlv_fit(lsp, &tlv_data.te_is_neighs,
-                            &lsp->tlv_data.te_is_neighs,
-                            area->lsp_frag_threshold, tlv_add_te_is_neighs,
-                            NULL);
-               if (tlv_data.te_is_neighs && listcount(tlv_data.te_is_neighs))
-                       lsp = lsp_next_frag(
-                               LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
-                               area, level);
+       struct list *fragments = isis_fragment_tlvs(tlvs, tlv_space);
+       if (!fragments) {
+               zlog_warn("BUG: could not fragment own LSP:");
+               log_multiline(LOG_WARNING, "    ", "%s", isis_format_tlvs(tlvs));
+               isis_free_tlvs(tlvs);
+               return;
        }
+       isis_free_tlvs(tlvs);
 
-       struct tlv_mt_neighbors *mt_neighs;
-       for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_is_neighs, node, mt_neighs)) {
-               while (mt_neighs->list && listcount(mt_neighs->list)) {
-                       struct tlv_mt_neighbors *frag_mt_neighs;
-
-                       frag_mt_neighs = tlvs_get_mt_neighbors(&lsp->tlv_data,
-                                                              mt_neighs->mtid);
-                       _lsp_tlv_fit(lsp, &mt_neighs->list,
-                                    &frag_mt_neighs->list,
-                                    area->lsp_frag_threshold,
-                                    tlv_add_te_is_neighs, &mt_neighs->mtid);
-                       if (mt_neighs->list && listcount(mt_neighs->list))
-                               lsp = lsp_next_frag(
-                                       LSP_FRAGMENT(lsp->lsp_header->lsp_id)
-                                               + 1,
-                                       lsp0, area, level);
+       frag = lsp;
+       for (ALL_LIST_ELEMENTS_RO(fragments, node, tlvs)) {
+               if (node != listhead(fragments)) {
+                       frag = lsp_next_frag(LSP_FRAGMENT(frag->hdr.lsp_id) + 1,
+                                            lsp, area, level);
                }
+               frag->tlvs = tlvs;
        }
 
-
-       lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
-
-       free_tlvs(&tlv_data);
-
-       /* Validate the LSP */
-       retval = parse_tlvs(area->area_tag,
-                           STREAM_DATA(lsp->pdu) + ISIS_FIXED_HDR_LEN
-                                   + ISIS_LSP_HDR_LEN,
-                           stream_get_endp(lsp->pdu) - ISIS_FIXED_HDR_LEN
-                                   - ISIS_LSP_HDR_LEN,
-                           &expected, &found, &tlv_data, NULL);
-       assert(retval == ISIS_OK);
-
+       list_delete(fragments);
+       lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
+                 area->area_tag);
        return;
 }
 
@@ -2019,8 +1139,8 @@ int lsp_generate(struct isis_area *area, int level)
        oldlsp = lsp_search(lspid, area->lspdb[level - 1]);
        if (oldlsp) {
                /* FIXME: we should actually initiate a purge */
-               seq_num = ntohl(oldlsp->lsp_header->seq_num);
-               lsp_search_and_destroy(oldlsp->lsp_header->lsp_id,
+               seq_num = oldlsp->hdr.seqno;
+               lsp_search_and_destroy(oldlsp->hdr.lsp_id,
                                       area->lspdb[level - 1]);
        }
        rem_lifetime = lsp_rem_lifetime(area, level);
@@ -2035,7 +1155,7 @@ int lsp_generate(struct isis_area *area, int level)
        /* build_lsp_data (newlsp, area); */
        lsp_build(newlsp, area);
        /* time to calculate our checksum */
-       lsp_seqnum_update(newlsp);
+       lsp_seqno_update(newlsp);
        newlsp->last_generated = time(NULL);
        lsp_set_all_srmflags(newlsp);
 
@@ -2051,15 +1171,14 @@ int lsp_generate(struct isis_area *area, int level)
                                 &area->t_lsp_refresh[level - 1]);
 
        if (isis->debugs & DEBUG_UPDATE_PACKETS) {
-               zlog_debug(
-                       "ISIS-Upd (%s): Building L%d LSP %s, len %d, "
-                       "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
-                       area->area_tag, level,
-                       rawlspid_print(newlsp->lsp_header->lsp_id),
-                       ntohl(newlsp->lsp_header->pdu_len),
-                       ntohl(newlsp->lsp_header->seq_num),
-                       ntohs(newlsp->lsp_header->checksum),
-                       ntohs(newlsp->lsp_header->rem_lifetime), refresh_time);
+               zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %" PRIu16
+                          ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
+                          ", lifetime %" PRIu16 "s refresh %" PRIu16 "s",
+                          area->area_tag, level,
+                          rawlspid_print(newlsp->hdr.lsp_id),
+                          newlsp->hdr.pdu_len, newlsp->hdr.seqno,
+                          newlsp->hdr.checksum, newlsp->hdr.rem_lifetime,
+                          refresh_time);
        }
        sched_debug(
                "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
@@ -2097,24 +1216,21 @@ static int lsp_regenerate(struct isis_area *area, int level)
 
        lsp_clear_data(lsp);
        lsp_build(lsp, area);
-       lsp->lsp_header->lsp_bits = lsp_bits_generate(level, area->overload_bit,
-                                                     area->attached_bit);
        rem_lifetime = lsp_rem_lifetime(area, level);
-       lsp->lsp_header->rem_lifetime = htons(rem_lifetime);
-       lsp_seqnum_update(lsp);
-
+       lsp->hdr.rem_lifetime = rem_lifetime;
        lsp->last_generated = time(NULL);
        lsp_set_all_srmflags(lsp);
        for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
-               frag->lsp_header->lsp_bits = lsp_bits_generate(
+               frag->hdr.lsp_bits = lsp_bits_generate(
                        level, area->overload_bit, area->attached_bit);
                /* Set the lifetime values of all the fragments to the same
                 * value,
                 * so that no fragment expires before the lsp is refreshed.
                 */
-               frag->lsp_header->rem_lifetime = htons(rem_lifetime);
+               frag->hdr.rem_lifetime = rem_lifetime;
                lsp_set_all_srmflags(frag);
        }
+       lsp_seqno_update(lsp);
 
        refresh_time = lsp_refresh_time(lsp, rem_lifetime);
        if (level == IS_LEVEL_1)
@@ -2127,14 +1243,12 @@ static int lsp_regenerate(struct isis_area *area, int level)
 
        if (isis->debugs & DEBUG_UPDATE_PACKETS) {
                zlog_debug(
-                       "ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
-                       "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
-                       area->area_tag, level,
-                       rawlspid_print(lsp->lsp_header->lsp_id),
-                       ntohl(lsp->lsp_header->pdu_len),
-                       ntohl(lsp->lsp_header->seq_num),
-                       ntohs(lsp->lsp_header->checksum),
-                       ntohs(lsp->lsp_header->rem_lifetime), refresh_time);
+                       "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %" PRIu16
+                       ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
+                       ", lifetime %" PRIu16 "s refresh %" PRIu16 "s",
+                       area->area_tag, level, rawlspid_print(lsp->hdr.lsp_id),
+                       lsp->hdr.pdu_len, lsp->hdr.seqno, lsp->hdr.checksum,
+                       lsp->hdr.rem_lifetime, refresh_time);
        }
        sched_debug(
                "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
@@ -2294,164 +1408,89 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
                             int level)
 {
        struct isis_adjacency *adj;
-       struct is_neigh *is_neigh;
-       struct te_is_neigh *te_is_neigh;
-       struct es_neigh *es_neigh;
        struct list *adj_list;
        struct listnode *node;
        struct isis_area *area = circuit->area;
 
+       lsp_clear_data(lsp);
+       lsp->tlvs = isis_alloc_tlvs();
        lsp_debug(
                "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
-               area->area_tag, rawlspid_print(lsp->lsp_header->lsp_id),
+               area->area_tag, rawlspid_print(lsp->hdr.lsp_id),
                circuit->interface->name, level);
 
        lsp->level = level;
        /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
-       lsp->lsp_header->lsp_bits =
+       lsp->hdr.lsp_bits =
                lsp_bits_generate(level, 0, circuit->area->attached_bit);
 
        /*
         * add self to IS neighbours
         */
-       if (circuit->area->oldmetric) {
-               if (lsp->tlv_data.is_neighs == NULL) {
-                       lsp->tlv_data.is_neighs = list_new();
-                       lsp->tlv_data.is_neighs->del = free_tlv;
-               }
-               is_neigh = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct is_neigh));
+       uint8_t ne_id[ISIS_SYS_ID_LEN + 1];
+
+       memcpy(ne_id, isis->sysid, ISIS_SYS_ID_LEN);
+       LSP_PSEUDO_ID(ne_id) = 0;
 
-               memcpy(&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
-               listnode_add(lsp->tlv_data.is_neighs, is_neigh);
+       if (circuit->area->oldmetric) {
+               isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
                lsp_debug(
                        "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
-                       area->area_tag, sysid_print(is_neigh->neigh_id),
-                       LSP_PSEUDO_ID(is_neigh->neigh_id));
+                       area->area_tag, sysid_print(ne_id),
+                       LSP_PSEUDO_ID(ne_id));
        }
        if (circuit->area->newmetric) {
-               if (lsp->tlv_data.te_is_neighs == NULL) {
-                       lsp->tlv_data.te_is_neighs = list_new();
-                       lsp->tlv_data.te_is_neighs->del = free_tlv;
-               }
-               te_is_neigh =
-                       XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh));
-
-               memcpy(&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
-               listnode_add(lsp->tlv_data.te_is_neighs, te_is_neigh);
+               isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST,
+                                            ne_id, 0, NULL, 0);
                lsp_debug(
                        "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
-                       area->area_tag, sysid_print(te_is_neigh->neigh_id),
-                       LSP_PSEUDO_ID(te_is_neigh->neigh_id));
+                       area->area_tag, sysid_print(ne_id),
+                       LSP_PSEUDO_ID(ne_id));
        }
 
        adj_list = list_new();
        isis_adj_build_up_list(circuit->u.bc.adjdb[level - 1], adj_list);
 
        for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) {
-               if (adj->level & level) {
-                       if ((level == IS_LEVEL_1
-                            && adj->sys_type == ISIS_SYSTYPE_L1_IS)
-                           || (level == IS_LEVEL_1
-                               && adj->sys_type == ISIS_SYSTYPE_L2_IS
-                               && adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
-                           || (level == IS_LEVEL_2
-                               && adj->sys_type == ISIS_SYSTYPE_L2_IS)) {
-                               /* an IS neighbour -> add it */
-                               if (circuit->area->oldmetric) {
-                                       is_neigh = XCALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct is_neigh));
-
-                                       memcpy(&is_neigh->neigh_id, adj->sysid,
-                                              ISIS_SYS_ID_LEN);
-                                       listnode_add(lsp->tlv_data.is_neighs,
-                                                    is_neigh);
-                                       lsp_debug(
-                                               "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
-                                               area->area_tag,
-                                               sysid_print(is_neigh->neigh_id),
-                                               LSP_PSEUDO_ID(
-                                                       is_neigh->neigh_id));
-                               }
-                               if (circuit->area->newmetric) {
-                                       te_is_neigh = XCALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct te_is_neigh));
-                                       memcpy(&te_is_neigh->neigh_id,
-                                              adj->sysid, ISIS_SYS_ID_LEN);
-                                       listnode_add(lsp->tlv_data.te_is_neighs,
-                                                    te_is_neigh);
-                                       lsp_debug(
-                                               "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
-                                               area->area_tag,
-                                               sysid_print(
-                                                       te_is_neigh->neigh_id),
-                                               LSP_PSEUDO_ID(
-                                                       te_is_neigh->neigh_id));
-                               }
-                       } else if (level == IS_LEVEL_1
-                                  && adj->sys_type == ISIS_SYSTYPE_ES) {
-                               /* an ES neigbour add it, if we are building
-                                * level 1 LSP */
-                               /* FIXME: the tlv-format is hard to use here */
-                               if (lsp->tlv_data.es_neighs == NULL) {
-                                       lsp->tlv_data.es_neighs = list_new();
-                                       lsp->tlv_data.es_neighs->del = free_tlv;
-                               }
-                               es_neigh = XCALLOC(MTYPE_ISIS_TLV,
-                                                  sizeof(struct es_neigh));
-
-                               memcpy(&es_neigh->first_es_neigh, adj->sysid,
-                                      ISIS_SYS_ID_LEN);
-                               listnode_add(lsp->tlv_data.es_neighs, es_neigh);
-                               lsp_debug(
-                                       "ISIS (%s): Adding %s as ES neighbor (peer)",
-                                       area->area_tag,
-                                       sysid_print(es_neigh->first_es_neigh));
-                       } else {
-                               lsp_debug(
-                                       "ISIS (%s): Ignoring neighbor %s, level does not match",
-                                       area->area_tag,
-                                       sysid_print(adj->sysid));
-                       }
-               } else {
+               if (!(adj->level & level)) {
                        lsp_debug(
                                "ISIS (%s): Ignoring neighbor %s, level does not intersect",
                                area->area_tag, sysid_print(adj->sysid));
+                       continue;
                }
-       }
-       list_delete(adj_list);
-
-       lsp_debug("ISIS (%s): Pseudo LSP construction is complete.",
-                 area->area_tag);
-
-       /* Reset endp of stream to overwrite only TLV part of it. */
-       stream_reset(lsp->pdu);
-       stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
 
-       /*
-        * Add the authentication info if it's present
-        */
-       lsp_auth_add(lsp);
-
-       if (lsp->tlv_data.is_neighs && listcount(lsp->tlv_data.is_neighs) > 0)
-               tlv_add_is_neighs(lsp->tlv_data.is_neighs, lsp->pdu);
-
-       if (lsp->tlv_data.te_is_neighs
-           && listcount(lsp->tlv_data.te_is_neighs) > 0)
-               tlv_add_te_is_neighs(lsp->tlv_data.te_is_neighs, lsp->pdu,
-                                    NULL);
-
-       if (lsp->tlv_data.es_neighs && listcount(lsp->tlv_data.es_neighs) > 0)
-               tlv_add_is_neighs(lsp->tlv_data.es_neighs, lsp->pdu);
-
-       lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
-
-       /* Recompute authentication and checksum information */
-       lsp_auth_update(lsp);
-       fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
-                         ntohs(lsp->lsp_header->pdu_len) - 12, 12);
+               if (!(level == IS_LEVEL_1
+                     && adj->sys_type == ISIS_SYSTYPE_L1_IS)
+                   && !(level == IS_LEVEL_1
+                        && adj->sys_type == ISIS_SYSTYPE_L2_IS
+                        && adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
+                   && !(level == IS_LEVEL_2
+                        && adj->sys_type == ISIS_SYSTYPE_L2_IS)) {
+                       lsp_debug(
+                               "ISIS (%s): Ignoring neighbor %s, level does not match",
+                               area->area_tag, sysid_print(adj->sysid));
+                       continue;
+               }
 
+               memcpy(ne_id, adj->sysid, ISIS_SYS_ID_LEN);
+               if (circuit->area->oldmetric) {
+                       isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
+                       lsp_debug(
+                               "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
+                               area->area_tag, sysid_print(ne_id),
+                               LSP_PSEUDO_ID(ne_id));
+               }
+               if (circuit->area->newmetric) {
+                       isis_tlvs_add_extended_reach(lsp->tlvs,
+                                                    ISIS_MT_IPV4_UNICAST,
+                                                    ne_id, 0, NULL, 0);
+                       lsp_debug(
+                               "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
+                               area->area_tag, sysid_print(ne_id),
+                               LSP_PSEUDO_ID(ne_id));
+               }
+       }
+       list_delete(adj_list);
        return;
 }
 
@@ -2486,7 +1525,7 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
        lsp->area = circuit->area;
 
        lsp_build_pseudo(lsp, circuit, level);
-
+       lsp_pack_pdu(lsp);
        lsp->own_lsp = 1;
        lsp_insert(lsp, lspdb);
        lsp_set_all_srmflags(lsp);
@@ -2505,14 +1544,13 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
 
        if (isis->debugs & DEBUG_UPDATE_PACKETS) {
                zlog_debug(
-                       "ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
-                       "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
+                       "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %" PRIu16
+                       ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
+                       ", lifetime %" PRIu16 "s, refresh %" PRIu16 "s",
                        circuit->area->area_tag, level,
-                       rawlspid_print(lsp->lsp_header->lsp_id),
-                       ntohl(lsp->lsp_header->pdu_len),
-                       ntohl(lsp->lsp_header->seq_num),
-                       ntohs(lsp->lsp_header->checksum),
-                       ntohs(lsp->lsp_header->rem_lifetime), refresh_time);
+                       rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
+                       lsp->hdr.seqno, lsp->hdr.checksum,
+                       lsp->hdr.rem_lifetime, refresh_time);
        }
 
        return ISIS_OK;
@@ -2542,16 +1580,11 @@ static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
                         rawlspid_print(lsp_id));
                return ISIS_ERROR;
        }
-       lsp_clear_data(lsp);
 
-       lsp_build_pseudo(lsp, circuit, level);
-
-       /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
-       lsp->lsp_header->lsp_bits =
-               lsp_bits_generate(level, 0, circuit->area->attached_bit);
        rem_lifetime = lsp_rem_lifetime(circuit->area, level);
-       lsp->lsp_header->rem_lifetime = htons(rem_lifetime);
-       lsp_inc_seqnum(lsp, 0);
+       lsp->hdr.rem_lifetime = rem_lifetime;
+       lsp_build_pseudo(lsp, circuit, level);
+       lsp_inc_seqno(lsp, 0);
        lsp->last_generated = time(NULL);
        lsp_set_all_srmflags(lsp);
 
@@ -2567,14 +1600,13 @@ static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
 
        if (isis->debugs & DEBUG_UPDATE_PACKETS) {
                zlog_debug(
-                       "ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
-                       "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
+                       "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %" PRIu16
+                       ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
+                       ", lifetime %" PRIu16 "s, refresh %" PRIu16 "s",
                        circuit->area->area_tag, level,
-                       rawlspid_print(lsp->lsp_header->lsp_id),
-                       ntohl(lsp->lsp_header->pdu_len),
-                       ntohl(lsp->lsp_header->seq_num),
-                       ntohs(lsp->lsp_header->checksum),
-                       ntohs(lsp->lsp_header->rem_lifetime), refresh_time);
+                       rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
+                       lsp->hdr.seqno, lsp->hdr.checksum,
+                       lsp->hdr.rem_lifetime, refresh_time);
        }
 
        return ISIS_OK;
@@ -2771,8 +1803,7 @@ int lsp_tick(struct thread *thread)
                                 * when
                                 * the first time rem_lifetime becomes 0.
                                 */
-                               rem_lifetime =
-                                       ntohs(lsp->lsp_header->rem_lifetime);
+                               rem_lifetime = lsp->hdr.rem_lifetime;
                                lsp_set_time(lsp);
 
                                /*
@@ -2782,8 +1813,7 @@ int lsp_tick(struct thread *thread)
                                 * time.
                                 * ISO 10589 - 7.3.16.4 first paragraph.
                                 */
-                               if (rem_lifetime == 1
-                                   && lsp->lsp_header->seq_num != 0) {
+                               if (rem_lifetime == 1 && lsp->hdr.seqno != 0) {
                                        /* 7.3.16.4 a) set SRM flags on all */
                                        lsp_set_all_srmflags(lsp);
                                        /* 7.3.16.4 b) retain only the header
@@ -2800,13 +1830,11 @@ int lsp_tick(struct thread *thread)
 
                                if (lsp->age_out == 0) {
                                        zlog_debug(
-                                               "ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
+                                               "ISIS-Upd (%s): L%u LSP %s seq "
+                                               "0x%08" PRIx32 " aged out",
                                                area->area_tag, lsp->level,
-                                               rawlspid_print(
-                                                       lsp->lsp_header
-                                                               ->lsp_id),
-                                               ntohl(lsp->lsp_header
-                                                             ->seq_num));
+                                               rawlspid_print(lsp->hdr.lsp_id),
+                                               lsp->hdr.seqno);
                                        lsp_destroy(lsp);
                                        lsp = NULL;
                                        dict_delete_free(area->lspdb[level],
@@ -2867,56 +1895,22 @@ int lsp_tick(struct thread *thread)
 void lsp_purge_pseudo(u_char *id, struct isis_circuit *circuit, int level)
 {
        struct isis_lsp *lsp;
-       u_int16_t seq_num;
-       u_int8_t lsp_bits;
 
        lsp = lsp_search(id, circuit->area->lspdb[level - 1]);
        if (!lsp)
                return;
 
-       /* store old values */
-       seq_num = lsp->lsp_header->seq_num;
-       lsp_bits = lsp->lsp_header->lsp_bits;
-
-       /* reset stream */
-       lsp_clear_data(lsp);
-       stream_reset(lsp->pdu);
-
-       /* update header */
-       lsp->lsp_header->pdu_len = htons(ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-       memcpy(lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2);
-       lsp->lsp_header->checksum = 0;
-       lsp->lsp_header->seq_num = seq_num;
-       lsp->lsp_header->rem_lifetime = 0;
-       lsp->lsp_header->lsp_bits = lsp_bits;
-       lsp->level = level;
-       lsp->age_out = lsp->area->max_lsp_lifetime[level - 1];
-       stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-
-       /*
-        * Add and update the authentication info if its present
-        */
-       lsp_auth_add(lsp);
-       lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
-       lsp_auth_update(lsp);
-       fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
-                         ntohs(lsp->lsp_header->pdu_len) - 12, 12);
-
-       lsp_set_all_srmflags(lsp);
-
-       return;
+       lsp_purge(lsp, level);
 }
 
 /*
  * Purge own LSP that is received and we don't have.
  * -> Do as in 7.3.16.4
  */
-void lsp_purge_non_exist(int level, struct isis_link_state_hdr *lsp_hdr,
+void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr,
                         struct isis_area *area)
 {
        struct isis_lsp *lsp;
-       uint8_t pdu_type =
-               (level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE;
 
        /*
         * We need to create the LSP to be purged
@@ -2925,37 +1919,14 @@ void lsp_purge_non_exist(int level, struct isis_link_state_hdr *lsp_hdr,
        lsp->area = area;
        lsp->level = level;
        lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
-       fill_fixed_hdr(pdu_type, lsp->pdu);
-
-       lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu)
-                                                        + ISIS_FIXED_HDR_LEN);
-       memcpy(lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
-       stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-
-       /*
-        * Set the remaining lifetime to 0
-        */
-       lsp->lsp_header->rem_lifetime = 0;
+       lsp->age_out = ZERO_AGE_LIFETIME;
 
-       /*
-        * Add and update the authentication info if its present
-        */
-       lsp_auth_add(lsp);
-       lsp_auth_update(lsp);
+       memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
+       lsp->hdr.rem_lifetime = 0;
 
-       /*
-        * Update the PDU length to header plus any authentication TLV.
-        */
-       lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
+       lsp_pack_pdu(lsp);
 
-       /*
-        * Put the lsp into LSPdb
-        */
        lsp_insert(lsp, area->lspdb[lsp->level - 1]);
-
-       /*
-        * Send in to whole area
-        */
        lsp_set_all_srmflags(lsp);
 
        return;
index 429cd194239b0bdb59dff75facbd23d750a9d8c4..8b62ed5513e0e14751023db3c2bf4372737f8945 100644 (file)
 #ifndef _ZEBRA_ISIS_LSP_H
 #define _ZEBRA_ISIS_LSP_H
 
+#include "isisd/isis_pdu.h"
+
 /* Structure for isis_lsp, this structure will only support the fixed
  * System ID (Currently 6) (atleast for now). In order to support more
  * We will have to split the header into two parts, and for readability
  * sake it should better be avoided */
 struct isis_lsp {
-       struct isis_link_state_hdr *lsp_header; /* pdu + isis_header_len */
-       struct stream *pdu;                     /* full pdu lsp */
+       struct isis_lsp_hdr hdr;
+       struct stream *pdu; /* full pdu lsp */
        union {
                struct list *frags;
                struct isis_lsp *zero_lsp;
        } lspu;
-       u_int32_t auth_tlv_offset; /* authentication TLV position in the pdu */
        u_int32_t SRMflags[ISIS_MAX_CIRCUITS];
        u_int32_t SSNflags[ISIS_MAX_CIRCUITS];
        int level;     /* L1 or L2? */
@@ -46,7 +47,7 @@ struct isis_lsp {
        /* used for 60 second counting when rem_lifetime is zero */
        int age_out;
        struct isis_area *area;
-       struct tlvs tlv_data; /* Simplifies TLV access */
+       struct isis_tlvs *tlvs;
 };
 
 dict_t *lsp_db_init(void);
@@ -58,13 +59,13 @@ int lsp_regenerate_schedule(struct isis_area *area, int level, int all_pseudo);
 int lsp_generate_pseudo(struct isis_circuit *circuit, int level);
 int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level);
 
-struct isis_lsp *lsp_new(struct isis_area *area, u_char *lsp_id,
-                        u_int16_t rem_lifetime, u_int32_t seq_num,
-                        u_int8_t lsp_bits, u_int16_t checksum, int level);
-struct isis_lsp *lsp_new_from_stream_ptr(struct stream *stream,
-                                        u_int16_t pdu_len,
-                                        struct isis_lsp *lsp0,
-                                        struct isis_area *area, int level);
+struct isis_lsp *lsp_new(struct isis_area *area, uint8_t *lsp_id,
+                        uint16_t rem_lifetime, uint32_t seq_num,
+                        uint8_t lsp_bits, uint16_t checksum, int level);
+struct isis_lsp *lsp_new_from_recv(struct isis_lsp_hdr *hdr,
+                                  struct isis_tlvs *tlvs,
+                                  struct stream *stream, struct isis_lsp *lsp0,
+                                  struct isis_area *area, int level);
 void lsp_insert(struct isis_lsp *lsp, dict_t *lspdb);
 struct isis_lsp *lsp_search(u_char *id, dict_t *lspdb);
 
@@ -74,7 +75,7 @@ void lsp_build_list_nonzero_ht(u_char *start_id, u_char *stop_id,
                               struct list *list, dict_t *lspdb);
 void lsp_search_and_destroy(u_char *id, dict_t *lspdb);
 void lsp_purge_pseudo(u_char *id, struct isis_circuit *circuit, int level);
-void lsp_purge_non_exist(int level, struct isis_link_state_hdr *lsp_hdr,
+void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr,
                         struct isis_area *area);
 
 #define LSP_EQUAL 1
@@ -88,16 +89,15 @@ void lsp_purge_non_exist(int level, struct isis_link_state_hdr *lsp_hdr,
        (I)[ISIS_SYS_ID_LEN] = 0;                                              \
        (I)[ISIS_SYS_ID_LEN + 1] = 0
 int lsp_id_cmp(u_char *id1, u_char *id2);
-int lsp_compare(char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
-               u_int16_t checksum, u_int16_t rem_lifetime);
-void lsp_update(struct isis_lsp *lsp, struct stream *stream,
+int lsp_compare(char *areatag, struct isis_lsp *lsp, uint32_t seqno,
+               uint16_t checksum, uint16_t rem_lifetime);
+void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
+               struct isis_tlvs *tlvs, struct stream *stream,
                struct isis_area *area, int level);
-void lsp_inc_seqnum(struct isis_lsp *lsp, u_int32_t seq_num);
+void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno);
 void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost);
 void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost);
 int lsp_print_all(struct vty *vty, dict_t *lspdb, char detail, char dynhost);
-const char *lsp_bits2string(u_char *);
-
 /* sets SRMflags for all active circuits of an lsp */
 void lsp_set_all_srmflags(struct isis_lsp *lsp);
 
index 463e3abcf3471ad788594868c8c532f35635f8f5..40ceb99fb259ff647461f90d4b2eae3863ebd22a 100644 (file)
@@ -52,7 +52,6 @@
 #include "isisd/isis_route.h"
 #include "isisd/isis_routemap.h"
 #include "isisd/isis_zebra.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_te.h"
 
 /* Default configuration file name */
index cf6558c13ad6f85c4ff318106445831942d8874b..4d7b4c381af99dbc2d2948a5bc1dec6cb5f07396 100644 (file)
@@ -39,7 +39,6 @@
 #include "isisd/isisd.h"
 #include "isisd/isis_misc.h"
 
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_constants.h"
 #include "isisd/isis_adjacency.h"
@@ -215,25 +214,6 @@ char *nlpid2string(struct nlpids *nlpids)
        return nlpidstring;
 }
 
-/*
- *  supports the given af ?
- */
-int speaks(struct nlpids *nlpids, int family)
-{
-       int i, speaks = 0;
-
-       if (nlpids == (struct nlpids *)NULL)
-               return speaks;
-       for (i = 0; i < nlpids->count; i++) {
-               if (family == AF_INET && nlpids->nlpids[i] == NLPID_IP)
-                       speaks = 1;
-               if (family == AF_INET6 && nlpids->nlpids[i] == NLPID_IPV6)
-                       speaks = 1;
-       }
-
-       return speaks;
-}
-
 /*
  * Returns 0 on error, IS-IS Circuit Type on ok
  */
@@ -486,7 +466,7 @@ const char *print_sys_hostname(const u_char *sysid)
 
        dyn = dynhn_find_by_id(sysid);
        if (dyn)
-               return (const char *)dyn->name.name;
+               return dyn->hostname;
 
        return sysid_print(sysid);
 }
index 0ff33f831d8e85314965e66c5e0eec8a148e7b20..7de534ec7b26047101f146cd91a15151c26a5f8a 100644 (file)
@@ -55,7 +55,6 @@ void zlog_dump_data(void *data, int len);
 /*
  * misc functions
  */
-int speaks(struct nlpids *nlpids, int family);
 unsigned long isis_jitter(unsigned long timer, unsigned long jitter);
 const char *unix_hostname(void);
 
index ff0b95487fde58b1077a21d18d8fd2ca1eb5d57a..e1ff81e2384591360a452bc3c62df496bed863ce 100644 (file)
@@ -24,7 +24,6 @@
 #include "isisd/isis_memory.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_adjacency.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_mt.h"
 DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
 DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
 DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
-DEFINE_MTYPE_STATIC(ISISD, MT_NEIGHBORS, "ISIS MT Neighbors for TLV")
-DEFINE_MTYPE_STATIC(ISISD, MT_IPV4_REACHS,
-                   "ISIS MT IPv4 Reachabilities for TLV")
-DEFINE_MTYPE_STATIC(ISISD, MT_IPV6_REACHS,
-                   "ISIS MT IPv6 Reachabilities for TLV")
 
 uint16_t isis_area_ipv6_topology(struct isis_area *area)
 {
@@ -389,7 +383,8 @@ bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable,
 
        mt_settings = circuit_mt_settings(adj->circuit, &circuit_mt_count);
        for (unsigned int i = 0; i < circuit_mt_count; i++) {
-               if (tlvs->mt_router_info.count && !tlvs->mt_router_info_empty) {
+               if (!tlvs->mt_router_info.count
+                   && !tlvs->mt_router_info_empty) {
                        /* Other end does not have MT enabled */
                        if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST
                            && v4_usable)
@@ -459,153 +454,6 @@ void adj_mt_finish(struct isis_adjacency *adj)
        adj->mt_count = 0;
 }
 
-/* TLV Router info api */
-struct mt_router_info *tlvs_lookup_mt_router_info(struct tlvs *tlvs,
-                                                 uint16_t mtid)
-{
-       return lookup_mt_setting(tlvs->mt_router_info, mtid);
-}
-
-/* TLV MT Neighbors api */
-struct tlv_mt_neighbors *tlvs_lookup_mt_neighbors(struct tlvs *tlvs,
-                                                 uint16_t mtid)
-{
-       return lookup_mt_setting(tlvs->mt_is_neighs, mtid);
-}
-
-static struct tlv_mt_neighbors *tlvs_new_mt_neighbors(uint16_t mtid)
-{
-       struct tlv_mt_neighbors *rv;
-
-       rv = XCALLOC(MTYPE_MT_NEIGHBORS, sizeof(*rv));
-       rv->mtid = mtid;
-       rv->list = list_new();
-
-       return rv;
-};
-
-static void tlvs_free_mt_neighbors(void *arg)
-{
-       struct tlv_mt_neighbors *neighbors = arg;
-
-       if (neighbors && neighbors->list)
-               list_delete(neighbors->list);
-       XFREE(MTYPE_MT_NEIGHBORS, neighbors);
-}
-
-static void tlvs_add_mt_neighbors(struct tlvs *tlvs,
-                                 struct tlv_mt_neighbors *neighbors)
-{
-       add_mt_setting(&tlvs->mt_is_neighs, neighbors);
-       tlvs->mt_is_neighs->del = tlvs_free_mt_neighbors;
-}
-
-struct tlv_mt_neighbors *tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
-{
-       struct tlv_mt_neighbors *neighbors;
-
-       neighbors = tlvs_lookup_mt_neighbors(tlvs, mtid);
-       if (!neighbors) {
-               neighbors = tlvs_new_mt_neighbors(mtid);
-               tlvs_add_mt_neighbors(tlvs, neighbors);
-       }
-       return neighbors;
-}
-
-/* TLV MT IPv4 reach api */
-struct tlv_mt_ipv4_reachs *tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs,
-                                                     uint16_t mtid)
-{
-       return lookup_mt_setting(tlvs->mt_ipv4_reachs, mtid);
-}
-
-static struct tlv_mt_ipv4_reachs *tlvs_new_mt_ipv4_reachs(uint16_t mtid)
-{
-       struct tlv_mt_ipv4_reachs *rv;
-
-       rv = XCALLOC(MTYPE_MT_IPV4_REACHS, sizeof(*rv));
-       rv->mtid = mtid;
-       rv->list = list_new();
-
-       return rv;
-};
-
-static void tlvs_free_mt_ipv4_reachs(void *arg)
-{
-       struct tlv_mt_ipv4_reachs *reachs = arg;
-
-       if (reachs && reachs->list)
-               list_delete(reachs->list);
-       XFREE(MTYPE_MT_IPV4_REACHS, reachs);
-}
-
-static void tlvs_add_mt_ipv4_reachs(struct tlvs *tlvs,
-                                   struct tlv_mt_ipv4_reachs *reachs)
-{
-       add_mt_setting(&tlvs->mt_ipv4_reachs, reachs);
-       tlvs->mt_ipv4_reachs->del = tlvs_free_mt_ipv4_reachs;
-}
-
-struct tlv_mt_ipv4_reachs *tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs,
-                                                  uint16_t mtid)
-{
-       struct tlv_mt_ipv4_reachs *reachs;
-
-       reachs = tlvs_lookup_mt_ipv4_reachs(tlvs, mtid);
-       if (!reachs) {
-               reachs = tlvs_new_mt_ipv4_reachs(mtid);
-               tlvs_add_mt_ipv4_reachs(tlvs, reachs);
-       }
-       return reachs;
-}
-
-/* TLV MT IPv6 reach api */
-struct tlv_mt_ipv6_reachs *tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs,
-                                                     uint16_t mtid)
-{
-       return lookup_mt_setting(tlvs->mt_ipv6_reachs, mtid);
-}
-
-static struct tlv_mt_ipv6_reachs *tlvs_new_mt_ipv6_reachs(uint16_t mtid)
-{
-       struct tlv_mt_ipv6_reachs *rv;
-
-       rv = XCALLOC(MTYPE_MT_IPV6_REACHS, sizeof(*rv));
-       rv->mtid = mtid;
-       rv->list = list_new();
-
-       return rv;
-};
-
-static void tlvs_free_mt_ipv6_reachs(void *arg)
-{
-       struct tlv_mt_ipv6_reachs *reachs = arg;
-
-       if (reachs && reachs->list)
-               list_delete(reachs->list);
-       XFREE(MTYPE_MT_IPV6_REACHS, reachs);
-}
-
-static void tlvs_add_mt_ipv6_reachs(struct tlvs *tlvs,
-                                   struct tlv_mt_ipv6_reachs *reachs)
-{
-       add_mt_setting(&tlvs->mt_ipv6_reachs, reachs);
-       tlvs->mt_ipv6_reachs->del = tlvs_free_mt_ipv6_reachs;
-}
-
-struct tlv_mt_ipv6_reachs *tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs,
-                                                  uint16_t mtid)
-{
-       struct tlv_mt_ipv6_reachs *reachs;
-
-       reachs = tlvs_lookup_mt_ipv6_reachs(tlvs, mtid);
-       if (!reachs) {
-               reachs = tlvs_new_mt_ipv6_reachs(mtid);
-               tlvs_add_mt_ipv6_reachs(tlvs, reachs);
-       }
-       return reachs;
-}
-
 static void mt_set_add(uint16_t **mt_set, unsigned int *size,
                       unsigned int *index, uint16_t mtid)
 {
@@ -650,51 +498,46 @@ static uint16_t *circuit_bcast_mt_set(struct isis_circuit *circuit, int level,
        return rv;
 }
 
-static void tlvs_add_mt_set(struct isis_area *area, struct tlvs *tlvs,
+static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs,
                            unsigned int mt_count, uint16_t *mt_set,
-                           struct te_is_neigh *neigh)
+                           uint8_t *id, uint32_t metric, uint8_t *subtlvs,
+                           uint8_t subtlv_len)
 {
        for (unsigned int i = 0; i < mt_count; i++) {
                uint16_t mtid = mt_set[i];
-               struct te_is_neigh *ne_copy;
-
-               ne_copy = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ne_copy));
-               memcpy(ne_copy, neigh, sizeof(*ne_copy));
-
                if (mt_set[i] == ISIS_MT_IPV4_UNICAST) {
-                       listnode_add(tlvs->te_is_neighs, ne_copy);
                        lsp_debug(
                                "ISIS (%s): Adding %s.%02x as te-style neighbor",
-                               area->area_tag, sysid_print(ne_copy->neigh_id),
-                               LSP_PSEUDO_ID(ne_copy->neigh_id));
+                               area->area_tag, sysid_print(id),
+                               LSP_PSEUDO_ID(id));
                } else {
-                       struct tlv_mt_neighbors *neighbors;
-
-                       neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
-                       neighbors->list->del = free_tlv;
-                       listnode_add(neighbors->list, ne_copy);
                        lsp_debug(
                                "ISIS (%s): Adding %s.%02x as mt-style neighbor for %s",
-                               area->area_tag, sysid_print(ne_copy->neigh_id),
-                               LSP_PSEUDO_ID(ne_copy->neigh_id),
-                               isis_mtid2str(mtid));
+                               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);
        }
 }
 
-void tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
-                      int level, struct te_is_neigh *neigh)
+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)
 {
        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, neigh);
+       tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, id, metric,
+                       subtlvs, subtlv_len);
 }
 
-void tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
-                    struct te_is_neigh *neigh)
+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)
 {
        struct isis_adjacency *adj = circuit->u.p2p.neighbor;
 
-       tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, neigh);
+       tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, id,
+                       metric, subtlvs, subtlv_len);
 }
index 496da8558c5bfaa9f10b1b28e7745289fad35627..95aa99dba0bd6be1b87be4bb9028020b24512e70 100644 (file)
@@ -65,21 +65,6 @@ struct isis_circuit_mt_setting {
        bool enabled;
 };
 
-struct tlv_mt_neighbors {
-       ISIS_MT_INFO_FIELDS
-       struct list *list;
-};
-
-struct tlv_mt_ipv4_reachs {
-       ISIS_MT_INFO_FIELDS
-       struct list *list;
-};
-
-struct tlv_mt_ipv6_reachs {
-       ISIS_MT_INFO_FIELDS
-       struct list *list;
-};
-
 const char *isis_mtid2str(uint16_t mtid);
 uint16_t isis_str2mtid(const char *name);
 
@@ -92,24 +77,6 @@ struct isis_tlvs;
 
 uint16_t isis_area_ipv6_topology(struct isis_area *area);
 
-struct mt_router_info *tlvs_lookup_mt_router_info(struct tlvs *tlvs,
-                                                 uint16_t mtid);
-
-struct tlv_mt_neighbors *tlvs_lookup_mt_neighbors(struct tlvs *tlvs,
-                                                 uint16_t mtid);
-struct tlv_mt_neighbors *tlvs_get_mt_neighbors(struct tlvs *tlvs,
-                                              uint16_t mtid);
-
-struct tlv_mt_ipv4_reachs *tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs,
-                                                     uint16_t mtid);
-struct tlv_mt_ipv4_reachs *tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs,
-                                                  uint16_t mtid);
-
-struct tlv_mt_ipv6_reachs *tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs,
-                                                     uint16_t mtid);
-struct tlv_mt_ipv6_reachs *tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs,
-                                                  uint16_t mtid);
-
 struct isis_area_mt_setting *area_lookup_mt_setting(struct isis_area *area,
                                                    uint16_t mtid);
 struct isis_area_mt_setting *area_new_mt_setting(struct isis_area *area,
@@ -143,8 +110,10 @@ bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable,
                        struct isis_adjacency *adj);
 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 tlvs *tlvs, struct isis_circuit *circuit,
-                      int level, struct te_is_neigh *neigh);
-void tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
-                    struct te_is_neigh *neigh);
+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);
+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);
 #endif
index 5ab5a1e992da7a66eeff2f8fde6a2fe99f0d961c..aee2cf3811e74ff3f91a9c56a51abbdd802fba53 100644 (file)
@@ -44,7 +44,6 @@
 #include "isisd/isis_network.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_dr.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_dynhn.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_mt.h"
 #include "isisd/isis_tlvs2.h"
 
-#define ISIS_MINIMUM_FIXED_HDR_LEN 15
-#define ISIS_MIN_PDU_LEN           13  /* partial seqnum pdu with id_len=2 */
-
-#ifndef PNBBY
-#define PNBBY 8
-#endif /* PNBBY */
-
-/*
- * HELPER FUNCS
- */
-
-/*
- * Checks whether we should accept a PDU of given level
- */
-static int accept_level(int level, int circuit_t)
-{
-       int retval = ((circuit_t & level) == level); /* simple approach */
-
-       return retval;
-}
-
-/*
- * Verify authentication information
- * Support cleartext and HMAC MD5 authentication
- */
-static int authentication_check(struct isis_passwd *remote,
-                               struct isis_passwd *local,
-                               struct stream *stream, uint32_t auth_tlv_offset)
+static int ack_lsp(struct isis_lsp_hdr *hdr, struct isis_circuit *circuit,
+                  int level)
 {
-       unsigned char digest[ISIS_AUTH_MD5_SIZE];
-
-       /* Auth fail () - passwd type mismatch */
-       if (local->type != remote->type)
-               return ISIS_ERROR;
-
-       switch (local->type) {
-       /* No authentication required */
-       case ISIS_PASSWD_TYPE_UNUSED:
-               break;
-
-       /* Cleartext (ISO 10589) */
-       case ISIS_PASSWD_TYPE_CLEARTXT:
-               /* Auth fail () - passwd len mismatch */
-               if (remote->len != local->len)
-                       return ISIS_ERROR;
-               return memcmp(local->passwd, remote->passwd, local->len);
-
-       /* HMAC MD5 (RFC 3567) */
-       case ISIS_PASSWD_TYPE_HMAC_MD5:
-               /* Auth fail () - passwd len mismatch */
-               if (remote->len != ISIS_AUTH_MD5_SIZE)
-                       return ISIS_ERROR;
-               /* Set the authentication value to 0 before the check */
-               memset(STREAM_DATA(stream) + auth_tlv_offset + 3, 0,
-                      ISIS_AUTH_MD5_SIZE);
-               /* Compute the digest */
-               hmac_md5(STREAM_DATA(stream), stream_get_endp(stream),
-                        (unsigned char *)&(local->passwd), local->len,
-                        (unsigned char *)&digest);
-               /* Copy back the authentication value after the check */
-               memcpy(STREAM_DATA(stream) + auth_tlv_offset + 3,
-                      remote->passwd, ISIS_AUTH_MD5_SIZE);
-               return memcmp(digest, remote->passwd, ISIS_AUTH_MD5_SIZE);
-
-       default:
-               zlog_err("Unsupported authentication type");
-               return ISIS_ERROR;
-       }
+       unsigned long lenp;
+       int retval;
+       u_int16_t length;
+       uint8_t pdu_type =
+               (level == IS_LEVEL_1) ? L1_PARTIAL_SEQ_NUM : L2_PARTIAL_SEQ_NUM;
 
-       /* Authentication pass when no authentication is configured */
-       return ISIS_OK;
-}
+       isis_circuit_stream(circuit, &circuit->snd_stream);
 
-static int lsp_authentication_check(struct stream *stream,
-                                   struct isis_area *area, int level,
-                                   struct isis_passwd *passwd)
-{
-       struct isis_link_state_hdr *hdr;
-       uint32_t expected = 0, found = 0, auth_tlv_offset = 0;
-       uint16_t checksum, rem_lifetime, pdu_len;
-       struct tlvs tlvs;
-       int retval = ISIS_OK;
+       fill_fixed_hdr(pdu_type, circuit->snd_stream);
 
-       hdr = (struct isis_link_state_hdr *)(STREAM_PNT(stream));
-       pdu_len = ntohs(hdr->pdu_len);
-       expected |= TLVFLAG_AUTH_INFO;
-       auth_tlv_offset = stream_get_getp(stream) + ISIS_LSP_HDR_LEN;
-       retval = parse_tlvs(area->area_tag,
-                           STREAM_PNT(stream) + ISIS_LSP_HDR_LEN,
-                           pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
-                           &expected, &found, &tlvs, &auth_tlv_offset);
+       lenp = stream_get_endp(circuit->snd_stream);
+       stream_putw(circuit->snd_stream, 0); /* PDU length  */
+       stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
+       stream_putc(circuit->snd_stream, circuit->idx);
+       stream_putc(circuit->snd_stream, 9);  /* code */
+       stream_putc(circuit->snd_stream, 16); /* len */
 
-       if (retval != ISIS_OK) {
-               zlog_err(
-                       "ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, "
-                       "cksum 0x%04x, lifetime %us, len %u",
-                       area->area_tag, level, rawlspid_print(hdr->lsp_id),
-                       ntohl(hdr->seq_num), ntohs(hdr->checksum),
-                       ntohs(hdr->rem_lifetime), pdu_len);
-               if ((isis->debugs & DEBUG_UPDATE_PACKETS)
-                   && (isis->debugs & DEBUG_PACKET_DUMP))
-                       zlog_dump_data(STREAM_DATA(stream),
-                                      stream_get_endp(stream));
-               return retval;
-       }
-
-       if (!(found & TLVFLAG_AUTH_INFO)) {
-               zlog_err("No authentication tlv in LSP");
-               return ISIS_ERROR;
-       }
+       stream_putw(circuit->snd_stream, hdr->rem_lifetime);
+       stream_put(circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2);
+       stream_putl(circuit->snd_stream, hdr->seqno);
+       stream_putw(circuit->snd_stream, hdr->checksum);
 
-       if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT
-           && tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5) {
-               zlog_err("Unknown authentication type in LSP");
-               return ISIS_ERROR;
-       }
+       length = (u_int16_t)stream_get_endp(circuit->snd_stream);
+       /* Update PDU length */
+       stream_putw_at(circuit->snd_stream, lenp, length);
 
-       /*
-        * RFC 5304 set checksum and remaining lifetime to zero before
-        * verification and reset to old values after verification.
-        */
-       checksum = hdr->checksum;
-       rem_lifetime = hdr->rem_lifetime;
-       hdr->checksum = 0;
-       hdr->rem_lifetime = 0;
-       retval = authentication_check(&tlvs.auth_info, passwd, stream,
-                                     auth_tlv_offset);
-       hdr->checksum = checksum;
-       hdr->rem_lifetime = rem_lifetime;
+       retval = circuit->tx(circuit, level);
+       if (retval != ISIS_OK)
+               zlog_err("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
+                        circuit->area->area_tag, level,
+                        circuit->interface->name);
 
        return retval;
 }
@@ -670,7 +574,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
                        return ISIS_WARNING;
                }
 
-               if (!accept_level(level, circuit->is_type)) {
+               if (!(circuit->is_type & level)) {
                        if (isis->debugs & DEBUG_ADJ_PACKETS) {
                                zlog_debug(
                                        "ISIS-Adj (%s): Interface level mismatch, %s",
@@ -731,7 +635,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
        }
 
        if (!isis_tlvs_auth_is_valid(iih.tlvs, &circuit->passwd,
-                                    circuit->rcv_stream)) {
+                                    circuit->rcv_stream, false)) {
                isis_event_auth_failure(circuit->area->area_tag,
                                        "IIH authentication failure",
                                        iih.sys_id);
@@ -780,17 +684,10 @@ out:
  * ISO - 10589
  * Section 7.3.15.1 - Action on receipt of a link state PDU
  */
-static int process_lsp(int level, struct isis_circuit *circuit,
+static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit,
                       const u_char *ssnpa)
 {
-       struct isis_link_state_hdr *hdr;
-       struct isis_adjacency *adj = NULL;
-       struct isis_lsp *lsp, *lsp0 = NULL;
-       int retval = ISIS_OK, comp = 0;
-       u_char lspid[ISIS_SYS_ID_LEN + 2];
-       struct isis_passwd *passwd;
-       uint16_t pdu_len;
-       int lsp_confusion;
+       int level = (pdu_type == L1_LINK_STATE) ? ISIS_LEVEL1 : ISIS_LEVEL2;
 
        if (isis->debugs & DEBUG_UPDATE_PACKETS) {
                zlog_debug(
@@ -804,65 +701,50 @@ static int process_lsp(int level, struct isis_circuit *circuit,
                                       stream_get_endp(circuit->rcv_stream));
        }
 
-       if ((stream_get_endp(circuit->rcv_stream)
-            - stream_get_getp(circuit->rcv_stream))
-           < ISIS_LSP_HDR_LEN) {
-               zlog_warn("Packet too short");
-               return ISIS_WARNING;
-       }
-
-       /* Reference the header   */
-       hdr = (struct isis_link_state_hdr *)STREAM_PNT(circuit->rcv_stream);
-       pdu_len = ntohs(hdr->pdu_len);
+       struct isis_lsp_hdr hdr = {};
 
-       /* lsp length check */
-       if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN)
-           || pdu_len > ISO_MTU(circuit)
-           || pdu_len > stream_get_endp(circuit->rcv_stream)) {
-               zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP length %d",
-                          circuit->area->area_tag, rawlspid_print(hdr->lsp_id),
-                          pdu_len);
+       hdr.pdu_len = stream_getw(circuit->rcv_stream);
+       hdr.rem_lifetime = stream_getw(circuit->rcv_stream);
+       stream_get(hdr.lsp_id, circuit->rcv_stream, sizeof(hdr.lsp_id));
+       hdr.seqno = stream_getl(circuit->rcv_stream);
+       hdr.checksum = stream_getw(circuit->rcv_stream);
+       hdr.lsp_bits = stream_getc(circuit->rcv_stream);
 
+       if (pdu_len_validate(hdr.pdu_len, circuit)) {
+               zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP length %" PRIu16,
+                          circuit->area->area_tag, rawlspid_print(hdr.lsp_id),
+                          hdr.pdu_len);
                return ISIS_WARNING;
        }
 
-       /*
-        * Set the stream endp to PDU length, ignoring additional padding
-        * introduced by transport chips.
-        */
-       if (pdu_len < stream_get_endp(circuit->rcv_stream))
-               stream_set_endp(circuit->rcv_stream, pdu_len);
-
        if (isis->debugs & DEBUG_UPDATE_PACKETS) {
-               zlog_debug(
-                       "ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
-                       "lifetime %us, len %u, on %s",
-                       circuit->area->area_tag, level,
-                       rawlspid_print(hdr->lsp_id), ntohl(hdr->seq_num),
-                       ntohs(hdr->checksum), ntohs(hdr->rem_lifetime), pdu_len,
-                       circuit->interface->name);
+               zlog_debug("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08" PRIx32
+                          ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                          "s, len %" PRIu16 ", on %s",
+                          circuit->area->area_tag, level,
+                          rawlspid_print(hdr.lsp_id), hdr.seqno, hdr.checksum,
+                          hdr.rem_lifetime, hdr.pdu_len,
+                          circuit->interface->name);
        }
 
        /* lsp is_type check */
-       if ((hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1
-           && (hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1_AND_2) {
-               zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP is type %x",
-                          circuit->area->area_tag, rawlspid_print(hdr->lsp_id),
-                          hdr->lsp_bits);
+       if ((hdr.lsp_bits & IS_LEVEL_1) != IS_LEVEL_1) {
+               zlog_debug(
+                       "ISIS-Upd (%s): LSP %s invalid LSP is type 0x%" PRIx8,
+                       circuit->area->area_tag, rawlspid_print(hdr.lsp_id),
+                       hdr.lsp_bits & IS_LEVEL_1_AND_2);
                /* continue as per RFC1122 Be liberal in what you accept, and
                 * conservative in what you send */
        }
 
        /* Checksum sanity check - FIXME: move to correct place */
        /* 12 = sysid+pdu+remtime */
-       if (iso_csum_verify(STREAM_PNT(circuit->rcv_stream) + 4, pdu_len - 12,
-                           hdr->checksum,
-                           offsetof(struct isis_link_state_hdr, checksum)
-                                   - 4)) {
-               zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
-                          circuit->area->area_tag, rawlspid_print(hdr->lsp_id),
-                          ntohs(hdr->checksum));
-
+       if (iso_csum_verify(STREAM_DATA(circuit->rcv_stream) + 12,
+                           hdr.pdu_len - 12, hdr.checksum, 12)) {
+               zlog_debug(
+                       "ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04" PRIx16,
+                       circuit->area->area_tag, rawlspid_print(hdr.lsp_id),
+                       hdr.checksum);
                return ISIS_WARNING;
        }
 
@@ -871,47 +753,56 @@ static int process_lsp(int level, struct isis_circuit *circuit,
                zlog_debug(
                        "ISIS-Upd (%s): LSP %s received at level %d over circuit with "
                        "externalDomain = true",
-                       circuit->area->area_tag, rawlspid_print(hdr->lsp_id),
+                       circuit->area->area_tag, rawlspid_print(hdr.lsp_id),
                        level);
-
                return ISIS_WARNING;
        }
 
        /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
-       if (!accept_level(level, circuit->is_type)) {
+       if (!(circuit->is_type & level)) {
                zlog_debug(
                        "ISIS-Upd (%s): LSP %s received at level %d over circuit of"
                        " type %s",
-                       circuit->area->area_tag, rawlspid_print(hdr->lsp_id),
+                       circuit->area->area_tag, rawlspid_print(hdr.lsp_id),
                        level, circuit_t2string(circuit->is_type));
-
                return ISIS_WARNING;
        }
 
+       struct isis_tlvs *tlvs = NULL;
+       int retval = ISIS_WARNING;
+       const char *error_log;
+
+       if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream),
+                            circuit->rcv_stream, &tlvs, &error_log)) {
+               zlog_warn("Something went wrong unpacking the LSP: %s",
+                         error_log);
+               goto out;
+       }
+
        /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
 
        /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use
         * 3 */
 
        /* 7.3.15.1 a) 7 - password check */
-       (level == IS_LEVEL_1) ? (passwd = &circuit->area->area_passwd)
-                             : (passwd = &circuit->area->domain_passwd);
-       if (passwd->type) {
-               if (lsp_authentication_check(circuit->rcv_stream, circuit->area,
-                                            level, passwd)) {
-                       isis_event_auth_failure(circuit->area->area_tag,
-                                               "LSP authentication failure",
-                                               hdr->lsp_id);
-                       return ISIS_WARNING;
-               }
+       struct isis_passwd *passwd = (level == ISIS_LEVEL1)
+                                            ? &circuit->area->area_passwd
+                                            : &circuit->area->domain_passwd;
+       if (!isis_tlvs_auth_is_valid(tlvs, passwd, circuit->rcv_stream, true)) {
+               isis_event_auth_failure(circuit->area->area_tag,
+                                       "LSP authentication failure",
+                                       hdr.lsp_id);
+               goto out;
        }
+
        /* Find the LSP in our database and compare it to this Link State header
         */
-       lsp = lsp_search(hdr->lsp_id, circuit->area->lspdb[level - 1]);
+       struct isis_lsp *lsp =
+               lsp_search(hdr.lsp_id, circuit->area->lspdb[level - 1]);
+       int comp = 0;
        if (lsp)
-               comp = lsp_compare(circuit->area->area_tag, lsp,
-                                  ntohl(hdr->seq_num), ntohs(hdr->checksum),
-                                  ntohs(hdr->rem_lifetime));
+               comp = lsp_compare(circuit->area->area_tag, lsp, hdr.seqno,
+                                  hdr.checksum, hdr.rem_lifetime);
        if (lsp && (lsp->own_lsp))
                goto dontcheckadj;
 
@@ -920,25 +811,24 @@ static int process_lsp(int level, struct isis_circuit *circuit,
        /* for broadcast circuits, snpa should be compared */
 
        if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
-               adj = isis_adj_lookup_snpa(ssnpa,
-                                          circuit->u.bc.adjdb[level - 1]);
-               if (!adj) {
-                       zlog_debug(
-                               "(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
-                               "lifetime %us on %s",
-                               circuit->area->area_tag,
-                               rawlspid_print(hdr->lsp_id),
-                               ntohl(hdr->seq_num), ntohs(hdr->checksum),
-                               ntohs(hdr->rem_lifetime),
-                               circuit->interface->name);
-                       return ISIS_WARNING; /* Silently discard */
+               if (!isis_adj_lookup_snpa(ssnpa,
+                                         circuit->u.bc.adjdb[level - 1])) {
+                       zlog_debug("(%s): DS ======= LSP %s, seq 0x%08" PRIx32
+                                  ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                                  "s on %s",
+                                  circuit->area->area_tag,
+                                  rawlspid_print(hdr.lsp_id), hdr.seqno,
+                                  hdr.checksum, hdr.rem_lifetime,
+                                  circuit->interface->name);
+                       goto out; /* Silently discard */
                }
        }
        /* for non broadcast, we just need to find same level adj */
        else {
                /* If no adj, or no sharing of level */
                if (!circuit->u.p2p.neighbor) {
-                       return ISIS_OK; /* Silently discard */
+                       retval = ISIS_OK;
+                       goto out;
                } else {
                        if (((level == IS_LEVEL_1)
                             && (circuit->u.p2p.neighbor->adj_usage
@@ -946,10 +836,12 @@ static int process_lsp(int level, struct isis_circuit *circuit,
                            || ((level == IS_LEVEL_2)
                                && (circuit->u.p2p.neighbor->adj_usage
                                    == ISIS_ADJ_LEVEL1)))
-                               return ISIS_WARNING; /* Silently discard */
+                               goto out;
                }
        }
 
+       bool lsp_confusion;
+
 dontcheckadj:
        /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented  */
 
@@ -961,33 +853,35 @@ dontcheckadj:
        /* 7.3.16.2 - If this is an LSP from another IS with identical seq_num
         * but
         *            wrong checksum, initiate a purge. */
-       if (lsp && (lsp->lsp_header->seq_num == hdr->seq_num)
-           && (lsp->lsp_header->checksum != hdr->checksum)) {
-               zlog_warn(
-                       "ISIS-Upd (%s): LSP %s seq 0x%08x with confused checksum received.",
-                       circuit->area->area_tag, rawlspid_print(hdr->lsp_id),
-                       ntohl(hdr->seq_num));
-               hdr->rem_lifetime = 0;
-               lsp_confusion = 1;
+       if (lsp && (lsp->hdr.seqno == hdr.seqno)
+           && (lsp->hdr.checksum != hdr.checksum)) {
+               zlog_warn("ISIS-Upd (%s): LSP %s seq 0x%08" PRIx32
+                         " with confused checksum received.",
+                         circuit->area->area_tag, rawlspid_print(hdr.lsp_id),
+                         hdr.seqno);
+               hdr.rem_lifetime = 0;
+               lsp_confusion = true;
        } else
-               lsp_confusion = 0;
+               lsp_confusion = false;
 
        /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */
-       if (hdr->rem_lifetime == 0) {
+       if (hdr.rem_lifetime == 0) {
                if (!lsp) {
                        /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't
                         * save */
                        /* only needed on explicit update, eg - p2p */
                        if (circuit->circ_type == CIRCUIT_T_P2P)
-                               ack_lsp(hdr, circuit, level);
-                       return retval; /* FIXME: do we need a purge? */
+                               ack_lsp(&hdr, circuit, level);
+                       goto out; /* FIXME: do we need a purge? */
                } else {
-                       if (memcmp(hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) {
+                       if (memcmp(hdr.lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) {
                                /* LSP by some other system -> do 7.3.16.4 b) */
                                /* 7.3.16.4 b) 1)  */
                                if (comp == LSP_NEWER) {
-                                       lsp_update(lsp, circuit->rcv_stream,
+                                       lsp_update(lsp, &hdr, tlvs,
+                                                  circuit->rcv_stream,
                                                   circuit->area, level);
+                                       tlvs = NULL;
                                        /* ii */
                                        lsp_set_all_srmflags(lsp);
                                        /* v */
@@ -1028,11 +922,10 @@ dontcheckadj:
                                        ISIS_SET_FLAG(lsp->SRMflags, circuit);
                                        ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
                                }
-                       } else if (lsp->lsp_header->rem_lifetime != 0) {
+                       } else if (lsp->hdr.rem_lifetime != 0) {
                                /* our own LSP -> 7.3.16.4 c) */
                                if (comp == LSP_NEWER) {
-                                       lsp_inc_seqnum(lsp,
-                                                      ntohl(hdr->seq_num));
+                                       lsp_inc_seqno(lsp, hdr.seqno);
                                        lsp_set_all_srmflags(lsp);
                                } else {
                                        ISIS_SET_FLAG(lsp->SRMflags, circuit);
@@ -1040,23 +933,22 @@ dontcheckadj:
                                }
                                if (isis->debugs & DEBUG_UPDATE_PACKETS)
                                        zlog_debug(
-                                               "ISIS-Upd (%s): (1) re-originating LSP %s new "
-                                               "seq 0x%08x",
+                                               "ISIS-Upd (%s): (1) re-originating LSP %s new seq 0x%08" PRIx32,
                                                circuit->area->area_tag,
-                                               rawlspid_print(hdr->lsp_id),
-                                               ntohl(lsp->lsp_header
-                                                             ->seq_num));
+                                               rawlspid_print(hdr.lsp_id),
+                                               lsp->hdr.seqno);
                        }
                }
-               return retval;
+               goto out;
        }
        /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
         * purge */
-       if (memcmp(hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0) {
+       if (memcmp(hdr.lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0) {
                if (!lsp) {
                        /* 7.3.16.4: initiate a purge */
-                       lsp_purge_non_exist(level, hdr, circuit->area);
-                       return ISIS_OK;
+                       lsp_purge_non_exist(level, &hdr, circuit->area);
+                       retval = ISIS_OK;
+                       goto out;
                }
                /* 7.3.15.1 d) - If this is our own lsp and we have it */
 
@@ -1066,16 +958,15 @@ dontcheckadj:
                 * is
                 * "greater" than that held by S, ... */
 
-               if (ntohl(hdr->seq_num) > ntohl(lsp->lsp_header->seq_num)) {
+               if (hdr.seqno > lsp->hdr.seqno) {
                        /* 7.3.16.1  */
-                       lsp_inc_seqnum(lsp, ntohl(hdr->seq_num));
+                       lsp_inc_seqno(lsp, hdr.seqno);
                        if (isis->debugs & DEBUG_UPDATE_PACKETS)
                                zlog_debug(
-                                       "ISIS-Upd (%s): (2) re-originating LSP %s new seq "
-                                       "0x%08x",
+                                       "ISIS-Upd (%s): (2) re-originating LSP %s new seq 0x%08" PRIx32,
                                        circuit->area->area_tag,
-                                       rawlspid_print(hdr->lsp_id),
-                                       ntohl(lsp->lsp_header->seq_num));
+                                       rawlspid_print(hdr.lsp_id),
+                                       lsp->hdr.seqno);
                }
                /* If the received LSP is older or equal,
                 * resend the LSP which will act as ACK */
@@ -1090,8 +981,10 @@ dontcheckadj:
                         * If this lsp is a frag, need to see if we have zero
                         * lsp present
                         */
-                       if (LSP_FRAGMENT(hdr->lsp_id) != 0) {
-                               memcpy(lspid, hdr->lsp_id, ISIS_SYS_ID_LEN + 1);
+                       struct isis_lsp *lsp0 = NULL;
+                       if (LSP_FRAGMENT(hdr.lsp_id) != 0) {
+                               uint8_t lspid[ISIS_SYS_ID_LEN + 2];
+                               memcpy(lspid, hdr.lsp_id, ISIS_SYS_ID_LEN + 1);
                                LSP_FRAGMENT(lspid) = 0;
                                lsp0 = lsp_search(
                                        lspid, circuit->area->lspdb[level - 1]);
@@ -1103,15 +996,17 @@ dontcheckadj:
                        }
                        /* i */
                        if (!lsp) {
-                               lsp = lsp_new_from_stream_ptr(
-                                       circuit->rcv_stream, pdu_len, lsp0,
+                               lsp = lsp_new_from_recv(
+                                       &hdr, tlvs, circuit->rcv_stream, lsp0,
                                        circuit->area, level);
+                               tlvs = NULL;
                                lsp_insert(lsp,
                                           circuit->area->lspdb[level - 1]);
                        } else /* exists, so we overwrite */
                        {
-                               lsp_update(lsp, circuit->rcv_stream,
+                               lsp_update(lsp, &hdr, tlvs, circuit->rcv_stream,
                                           circuit->area, level);
+                               tlvs = NULL;
                        }
                        /* ii */
                        lsp_set_all_srmflags(lsp);
@@ -1126,8 +1021,9 @@ dontcheckadj:
                /* 7.3.15.1 e) 2) LSP equal to the one in db */
                else if (comp == LSP_EQUAL) {
                        ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
-                       lsp_update(lsp, circuit->rcv_stream, circuit->area,
-                                  level);
+                       lsp_update(lsp, &hdr, tlvs, circuit->rcv_stream,
+                                  circuit->area, level);
+                       tlvs = NULL;
                        if (circuit->circ_type != CIRCUIT_T_BROADCAST)
                                ISIS_SET_FLAG(lsp->SSNflags, circuit);
                }
@@ -1137,6 +1033,11 @@ dontcheckadj:
                        ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
                }
        }
+
+       retval = ISIS_OK;
+
+out:
+       isis_free_tlvs(tlvs);
        return retval;
 }
 
@@ -1202,8 +1103,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
        }
 
        /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
-       if (!accept_level(level, circuit->is_type)) {
-
+       if (!(circuit->is_type & level)) {
                zlog_debug(
                        "ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
                        "skipping: circuit type %s does not match level %d",
@@ -1264,7 +1164,8 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
                                             ? &circuit->area->area_passwd
                                             : &circuit->area->domain_passwd;
        if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV)
-           && !isis_tlvs_auth_is_valid(tlvs, passwd, circuit->rcv_stream)) {
+           && !isis_tlvs_auth_is_valid(tlvs, passwd, circuit->rcv_stream,
+                                       false)) {
                isis_event_auth_failure(circuit->area->area_tag,
                                        "SNP authentication failure",
                                        rem_sys_id);
@@ -1317,7 +1218,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
                           on p2p */
                        else {
                                if (own_lsp) {
-                                       lsp_inc_seqnum(lsp, entry->seqno);
+                                       lsp_inc_seqno(lsp, entry->seqno);
                                        ISIS_SET_FLAG(lsp->SRMflags, circuit);
                                } else {
                                        ISIS_SET_FLAG(lsp->SSNflags, circuit);
@@ -1362,8 +1263,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
                for (struct isis_lsp_entry *entry = entry_head; entry;
                     entry = entry->next) {
                        for (ALL_LIST_ELEMENTS(lsp_list, node, nnode, lsp)) {
-                               if (lsp_id_cmp(lsp->lsp_header->lsp_id,
-                                              entry->id)
+                               if (lsp_id_cmp(lsp->hdr.lsp_id, entry->id)
                                    == 0) {
                                        list_delete_node(lsp_list, node);
                                        break;
@@ -1506,10 +1406,8 @@ static int isis_handle_pdu(struct isis_circuit *circuit, u_char *ssnpa)
                retval = process_hello(pdu_type, circuit, ssnpa);
                break;
        case L1_LINK_STATE:
-               retval = process_lsp(ISIS_LEVEL1, circuit, ssnpa);
-               break;
        case L2_LINK_STATE:
-               retval = process_lsp(ISIS_LEVEL2, circuit, ssnpa);
+               retval = process_lsp(pdu_type, circuit, ssnpa);
                break;
        case L1_COMPLETE_SEQ_NUM:
        case L2_COMPLETE_SEQ_NUM:
@@ -1669,7 +1567,7 @@ int send_hello(struct isis_circuit *circuit, int level)
                isis_tlvs_add_ipv6_addresses(tlvs, circuit->ipv6_link);
 
        if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer,
-                          circuit->pad_hellos)) {
+                          circuit->pad_hellos, false)) {
                isis_free_tlvs(tlvs);
                return ISIS_WARNING; /* XXX: Maybe Log TLV structure? */
        }
@@ -1782,6 +1680,7 @@ int send_p2p_hello(struct thread *thread)
 /*
  * Count the maximum number of lsps that can be accomodated by a given size.
  */
+#define LSP_ENTRIES_LEN (10 + ISIS_SYS_ID_LEN)
 static uint16_t get_max_lsp_count(uint16_t size)
 {
        uint16_t tlv_count;
@@ -1832,7 +1731,8 @@ int send_csnp(struct isis_circuit *circuit, int level)
                isis_tlvs_add_auth(tlvs, passwd);
 
        size_t tlv_start = stream_get_endp(circuit->snd_stream);
-       if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer, false)) {
+       if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer, false,
+                          false)) {
                isis_free_tlvs(tlvs);
                return ISIS_WARNING;
        }
@@ -1862,8 +1762,7 @@ int send_csnp(struct isis_circuit *circuit, int level)
                if (tlvs->lsp_entries.count < num_lsps) {
                        memset(stop, 0xff, ISIS_SYS_ID_LEN + 2);
                } else {
-                       memcpy(stop, last_lsp->lsp_header->lsp_id,
-                              ISIS_SYS_ID_LEN + 2);
+                       memcpy(stop, last_lsp->hdr.lsp_id, sizeof(stop));
                }
 
                memcpy(STREAM_DATA(circuit->snd_stream) + start_pointer, start,
@@ -1872,7 +1771,7 @@ int send_csnp(struct isis_circuit *circuit, int level)
                       ISIS_SYS_ID_LEN + 2);
                stream_set_endp(circuit->snd_stream, tlv_start);
                if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer,
-                                  false)) {
+                                  false, false)) {
                        isis_free_tlvs(tlvs);
                        return ISIS_WARNING;
                }
@@ -2001,7 +1900,8 @@ static int send_psnp(int level, struct isis_circuit *circuit)
                isis_tlvs_add_auth(tlvs, passwd);
 
        size_t tlv_start = stream_get_endp(circuit->snd_stream);
-       if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer, false)) {
+       if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer, false,
+                          false)) {
                isis_free_tlvs(tlvs);
                return ISIS_WARNING;
        }
@@ -2035,7 +1935,7 @@ static int send_psnp(int level, struct isis_circuit *circuit)
 
                stream_set_endp(circuit->snd_stream, tlv_start);
                if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer,
-                                  false)) {
+                                  false, false)) {
                        isis_free_tlvs(tlvs);
                        return ISIS_WARNING;
                }
@@ -2183,14 +2083,12 @@ int send_lsp(struct thread *thread)
         * the circuit's MTU. So handle and log this case here. */
        if (stream_get_endp(lsp->pdu) > stream_get_size(circuit->snd_stream)) {
                zlog_err(
-                       "ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08x,"
-                       " cksum 0x%04x, lifetime %us on %s. LSP Size is %zu"
-                       " while interface stream size is %zu.",
+                       "ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08" PRIx32
+                       ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                       "s on %s. LSP Size is %zu while interface stream size is %zu.",
                        circuit->area->area_tag, lsp->level,
-                       rawlspid_print(lsp->lsp_header->lsp_id),
-                       ntohl(lsp->lsp_header->seq_num),
-                       ntohs(lsp->lsp_header->checksum),
-                       ntohs(lsp->lsp_header->rem_lifetime),
+                       rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.seqno,
+                       lsp->hdr.checksum, lsp->hdr.rem_lifetime,
                        circuit->interface->name, stream_get_endp(lsp->pdu),
                        stream_get_size(circuit->snd_stream));
                if (isis->debugs & DEBUG_PACKET_DUMP)
@@ -2204,15 +2102,13 @@ int send_lsp(struct thread *thread)
        stream_copy(circuit->snd_stream, lsp->pdu);
 
        if (isis->debugs & DEBUG_UPDATE_PACKETS) {
-               zlog_debug(
-                       "ISIS-Upd (%s): Sending L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
-                       " lifetime %us on %s",
-                       circuit->area->area_tag, lsp->level,
-                       rawlspid_print(lsp->lsp_header->lsp_id),
-                       ntohl(lsp->lsp_header->seq_num),
-                       ntohs(lsp->lsp_header->checksum),
-                       ntohs(lsp->lsp_header->rem_lifetime),
-                       circuit->interface->name);
+               zlog_debug("ISIS-Upd (%s): Sending L%d LSP %s, seq 0x%08" PRIx32
+                          ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                          "s on %s",
+                          circuit->area->area_tag, lsp->level,
+                          rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.seqno,
+                          lsp->hdr.checksum, lsp->hdr.rem_lifetime,
+                          circuit->interface->name);
                if (isis->debugs & DEBUG_PACKET_DUMP)
                        zlog_dump_data(STREAM_DATA(circuit->snd_stream),
                                       stream_get_endp(circuit->snd_stream));
@@ -2246,41 +2142,3 @@ out:
 
        return retval;
 }
-
-int ack_lsp(struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,
-           int level)
-{
-       unsigned long lenp;
-       int retval;
-       u_int16_t length;
-       uint8_t pdu_type =
-               (level == IS_LEVEL_1) ? L1_PARTIAL_SEQ_NUM : L2_PARTIAL_SEQ_NUM;
-
-       isis_circuit_stream(circuit, &circuit->snd_stream);
-
-       fill_fixed_hdr(pdu_type, circuit->snd_stream);
-
-       lenp = stream_get_endp(circuit->snd_stream);
-       stream_putw(circuit->snd_stream, 0); /* PDU length  */
-       stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
-       stream_putc(circuit->snd_stream, circuit->idx);
-       stream_putc(circuit->snd_stream, 9);  /* code */
-       stream_putc(circuit->snd_stream, 16); /* len */
-
-       stream_putw(circuit->snd_stream, ntohs(hdr->rem_lifetime));
-       stream_put(circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2);
-       stream_putl(circuit->snd_stream, ntohl(hdr->seq_num));
-       stream_putw(circuit->snd_stream, ntohs(hdr->checksum));
-
-       length = (u_int16_t)stream_get_endp(circuit->snd_stream);
-       /* Update PDU length */
-       stream_putw_at(circuit->snd_stream, lenp, length);
-
-       retval = circuit->tx(circuit, level);
-       if (retval != ISIS_OK)
-               zlog_err("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
-                        circuit->area->area_tag, level,
-                        circuit->interface->name);
-
-       return retval;
-}
index 985fc56adfe25640cd0b18ac602cf454e35a9ff5..7096761879394591f830f7554d30f6d6707ed5ca 100644 (file)
@@ -125,30 +125,14 @@ struct isis_p2p_hello_hdr {
 
 #define L1_LINK_STATE        18
 #define L2_LINK_STATE        20
-/*
- *              L1 and L2 IS to IS link state PDU header
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * +                        PDU Length                             + 2
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * +                        Remaining Lifetime                     + 2
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |                        LSP ID                                 | id_len + 2
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * +                        Sequence Number                        + 4
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * +                        Checksum                               + 2
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |   P   |              ATT              |LSPDBOL|    ISTYPE     |
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- */
-struct isis_link_state_hdr {
-       u_int16_t pdu_len;
-       u_int16_t rem_lifetime;
-       u_char lsp_id[ISIS_SYS_ID_LEN + 2];
-       u_int32_t seq_num;
-       u_int16_t checksum;
-       u_int8_t lsp_bits;
-} __attribute__((packed));
+struct isis_lsp_hdr {
+       uint16_t pdu_len;
+       uint16_t rem_lifetime;
+       uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
+       uint32_t seqno;
+       uint16_t checksum;
+       uint8_t lsp_bits;
+};
 #define ISIS_LSP_HDR_LEN 19
 
 /*
@@ -229,8 +213,6 @@ int send_l2_csnp(struct thread *thread);
 int send_l1_psnp(struct thread *thread);
 int send_l2_psnp(struct thread *thread);
 int send_lsp(struct thread *thread);
-int ack_lsp(struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,
-           int level);
 void fill_fixed_hdr(uint8_t pdu_type, struct stream *stream);
 int send_hello(struct isis_circuit *circuit, int level);
 
index 8e329494dd5b9e903cf6c91c41d2456e1514bbb0..ea94b6580544b6550fa37edd90e727cb0eedf84c 100644 (file)
@@ -37,7 +37,6 @@
 #include "isisd/isis_flags.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_circuit.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_route.h"
index 8cb5aa9ed6130eacc831cf2046f7d25de80353b6..267e72002f041f352c63ae0c2990986a9f25b241 100644 (file)
@@ -42,7 +42,6 @@
 #include "isis_misc.h"
 #include "isis_adjacency.h"
 #include "isis_circuit.h"
-#include "isis_tlv.h"
 #include "isis_pdu.h"
 #include "isis_lsp.h"
 #include "isis_spf.h"
index 44d7fa0403d63a1dbaf714347b7510ed22422892..d92207d57c6b7a60dcc7e6958c4102869b2482b7 100644 (file)
@@ -42,7 +42,6 @@
 #include "isis_misc.h"
 #include "isis_adjacency.h"
 #include "isis_circuit.h"
-#include "isis_tlv.h"
 #include "isis_pdu.h"
 #include "isis_lsp.h"
 #include "isis_spf.h"
index 615c2eeaa2c89ccfb00344e264ef52026e36fd8f..ffe6bf2fbdcfe0636e84e758c145bc34a2ecbacc 100644 (file)
@@ -44,7 +44,6 @@
 #include "isis_misc.h"
 #include "isis_adjacency.h"
 #include "isis_circuit.h"
-#include "isis_tlv.h"
 #include "isis_pdu.h"
 #include "isis_lsp.h"
 #include "isis_dynhn.h"
 #include "isis_route.h"
 #include "isis_csm.h"
 #include "isis_mt.h"
+#include "isis_tlvs2.h"
 
 DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
 
+/*
+ *  supports the given af ?
+ */
+static bool speaks(uint8_t *protocols, uint8_t count, int family)
+{
+       for (uint8_t i = 0; i < count; i++) {
+               if (family == AF_INET && protocols[i] == NLPID_IP)
+                       return true;
+               if (family == AF_INET6 && protocols[i] == NLPID_IPV6)
+                       return true;
+       }
+       return false;
+}
+
 struct isis_spf_run {
        struct isis_area *area;
        int level;
@@ -340,7 +354,7 @@ static struct isis_lsp *isis_root_system_lsp(struct isis_area *area, int level,
        LSP_PSEUDO_ID(lspid) = 0;
        LSP_FRAGMENT(lspid) = 0;
        lsp = lsp_search(lspid, area->lspdb[level - 1]);
-       if (lsp && lsp->lsp_header->rem_lifetime != 0)
+       if (lsp && lsp->hdr.rem_lifetime != 0)
                return lsp;
        return NULL;
 }
@@ -546,6 +560,13 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
 
        assert(spftree && parent);
 
+       struct prefix p;
+       if (vtype >= VTYPE_IPREACH_INTERNAL) {
+               prefix_copy(&p, id);
+               apply_mask(&p);
+               id = &p;
+       }
+
        /* RFC3787 section 5.1 */
        if (spftree->area->newmetric == 1) {
                if (dist > MAX_WIDE_PATH_METRIC)
@@ -632,30 +653,29 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree,
                                uint16_t depth, u_char *root_sysid,
                                struct isis_vertex *parent)
 {
-       bool pseudo_lsp = LSP_PSEUDO_ID(lsp->lsp_header->lsp_id);
-       struct listnode *node, *fragnode = NULL;
+       bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
+       struct listnode *fragnode = NULL;
        uint32_t dist;
-       struct is_neigh *is_neigh;
-       struct te_is_neigh *te_is_neigh;
-       struct ipv4_reachability *ipreach;
-       struct te_ipv4_reachability *te_ipv4_reach;
        enum vertextype vtype;
-       struct prefix prefix;
-       struct ipv6_reachability *ip6reach;
        static const u_char null_sysid[ISIS_SYS_ID_LEN];
-       struct mt_router_info *mt_router_info = NULL;
+       struct isis_mt_router_info *mt_router_info = NULL;
+
+       if (!lsp->tlvs)
+               return ISIS_OK;
 
        if (spftree->mtid != ISIS_MT_IPV4_UNICAST)
-               mt_router_info = tlvs_lookup_mt_router_info(&lsp->tlv_data,
-                                                           spftree->mtid);
+               mt_router_info = isis_tlvs_lookup_mt_router_info(lsp->tlvs,
+                                                                spftree->mtid);
 
        if (!pseudo_lsp && (spftree->mtid == ISIS_MT_IPV4_UNICAST
-                           && !speaks(lsp->tlv_data.nlpids, spftree->family))
+                           && !speaks(lsp->tlvs->protocols_supported.protocols,
+                                      lsp->tlvs->protocols_supported.count,
+                                      spftree->family))
            && !mt_router_info)
                return ISIS_OK;
 
 lspfragloop:
-       if (lsp->lsp_header->seq_num == 0) {
+       if (lsp->hdr.seqno == 0) {
                zlog_warn(
                        "isis_spf_process_lsp(): lsp with 0 seq_num - ignore");
                return ISIS_WARNING;
@@ -663,142 +683,122 @@ lspfragloop:
 
 #ifdef EXTREME_DEBUG
        zlog_debug("ISIS-Spf: process_lsp %s",
-                  print_sys_hostname(lsp->lsp_header->lsp_id));
+                  print_sys_hostname(lsp->hdr.lsp_id));
 #endif /* EXTREME_DEBUG */
 
        /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
        if (pseudo_lsp || (spftree->mtid == ISIS_MT_IPV4_UNICAST
-                          && !ISIS_MASK_LSP_OL_BIT(lsp->lsp_header->lsp_bits))
+                          && !ISIS_MASK_LSP_OL_BIT(lsp->hdr.lsp_bits))
            || (mt_router_info && !mt_router_info->overload))
 
        {
                if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) {
-                       for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.is_neighs, node,
-                                                 is_neigh)) {
+                       struct isis_oldstyle_reach *r;
+                       for (r = (struct isis_oldstyle_reach *)
+                                        lsp->tlvs->oldstyle_reach.head;
+                            r; r = r->next) {
                                /* C.2.6 a) */
                                /* Two way connectivity */
-                               if (!memcmp(is_neigh->neigh_id, root_sysid,
-                                           ISIS_SYS_ID_LEN))
+                               if (!memcmp(r->id, root_sysid, ISIS_SYS_ID_LEN))
                                        continue;
                                if (!pseudo_lsp
-                                   && !memcmp(is_neigh->neigh_id, null_sysid,
+                                   && !memcmp(r->id, null_sysid,
                                               ISIS_SYS_ID_LEN))
                                        continue;
-                               dist = cost + is_neigh->metrics.metric_default;
+                               dist = cost + r->metric;
                                process_N(spftree,
-                                         LSP_PSEUDO_ID(is_neigh->neigh_id)
+                                         LSP_PSEUDO_ID(r->id)
                                                  ? VTYPE_PSEUDO_IS
                                                  : VTYPE_NONPSEUDO_IS,
-                                         (void *)is_neigh->neigh_id, dist,
-                                         depth + 1, parent);
+                                         (void *)r->id, dist, depth + 1,
+                                         parent);
                        }
                }
 
-               struct list *te_is_neighs = NULL;
-               if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) {
-                       te_is_neighs = lsp->tlv_data.te_is_neighs;
-               } else {
-                       struct tlv_mt_neighbors *mt_neighbors;
-                       mt_neighbors = tlvs_lookup_mt_neighbors(&lsp->tlv_data,
-                                                               spftree->mtid);
-                       if (mt_neighbors)
-                               te_is_neighs = mt_neighbors->list;
-               }
-               for (ALL_LIST_ELEMENTS_RO(te_is_neighs, node, te_is_neigh)) {
-                       if (!memcmp(te_is_neigh->neigh_id, root_sysid,
-                                   ISIS_SYS_ID_LEN))
+               struct isis_item_list *te_neighs = NULL;
+               if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
+                       te_neighs = &lsp->tlvs->extended_reach;
+               else
+                       te_neighs = isis_lookup_mt_items(&lsp->tlvs->mt_reach,
+                                                        spftree->mtid);
+
+               struct isis_extended_reach *er;
+               for (er = te_neighs
+                                 ? (struct isis_extended_reach *)
+                                           te_neighs->head
+                                 : NULL;
+                    er; er = er->next) {
+                       if (!memcmp(er->id, root_sysid, ISIS_SYS_ID_LEN))
                                continue;
                        if (!pseudo_lsp
-                           && !memcmp(te_is_neigh->neigh_id, null_sysid,
-                                      ISIS_SYS_ID_LEN))
+                           && !memcmp(er->id, null_sysid, ISIS_SYS_ID_LEN))
                                continue;
-                       dist = cost + GET_TE_METRIC(te_is_neigh);
+                       dist = cost + er->metric;
                        process_N(spftree,
-                                 LSP_PSEUDO_ID(te_is_neigh->neigh_id)
-                                         ? VTYPE_PSEUDO_TE_IS
-                                         : VTYPE_NONPSEUDO_TE_IS,
-                                 (void *)te_is_neigh->neigh_id, dist,
-                                 depth + 1, parent);
+                                 LSP_PSEUDO_ID(er->id) ? VTYPE_PSEUDO_TE_IS
+                                                       : VTYPE_NONPSEUDO_TE_IS,
+                                 (void *)er->id, dist, depth + 1, parent);
                }
        }
 
        if (!pseudo_lsp && spftree->family == AF_INET
            && spftree->mtid == ISIS_MT_IPV4_UNICAST) {
-               struct list *reachs[] = {lsp->tlv_data.ipv4_int_reachs,
-                                        lsp->tlv_data.ipv4_ext_reachs};
+               struct isis_item_list *reachs[] = {
+                       &lsp->tlvs->oldstyle_ip_reach,
+                       &lsp->tlvs->oldstyle_ip_reach_ext};
 
-               prefix.family = AF_INET;
                for (unsigned int i = 0; i < array_size(reachs); i++) {
-                       vtype = (reachs[i] == lsp->tlv_data.ipv4_int_reachs)
-                                       ? VTYPE_IPREACH_INTERNAL
-                                       : VTYPE_IPREACH_EXTERNAL;
-                       for (ALL_LIST_ELEMENTS_RO(reachs[i], node, ipreach)) {
-                               dist = cost + ipreach->metrics.metric_default;
-                               prefix.u.prefix4 = ipreach->prefix;
-                               prefix.prefixlen = ip_masklen(ipreach->mask);
-                               apply_mask(&prefix);
-                               process_N(spftree, vtype, (void *)&prefix, dist,
-                                         depth + 1, parent);
+                       vtype = i ? VTYPE_IPREACH_EXTERNAL
+                                 : VTYPE_IPREACH_INTERNAL;
+
+                       struct isis_oldstyle_ip_reach *r;
+                       for (r = (struct isis_oldstyle_ip_reach *)reachs[i]
+                                        ->head;
+                            r; r = r->next) {
+                               dist = cost + r->metric;
+                               process_N(spftree, vtype, (void *)&r->prefix,
+                                         dist, depth + 1, parent);
                        }
                }
        }
 
        if (!pseudo_lsp && spftree->family == AF_INET) {
-               struct list *ipv4reachs = NULL;
-
-               if (spftree->mtid == ISIS_MT_IPV4_UNICAST) {
-                       ipv4reachs = lsp->tlv_data.te_ipv4_reachs;
-               } else {
-                       struct tlv_mt_ipv4_reachs *mt_reachs;
-                       mt_reachs = tlvs_lookup_mt_ipv4_reachs(&lsp->tlv_data,
-                                                              spftree->mtid);
-                       if (mt_reachs)
-                               ipv4reachs = mt_reachs->list;
-               }
-
-               prefix.family = AF_INET;
-               for (ALL_LIST_ELEMENTS_RO(ipv4reachs, node, te_ipv4_reach)) {
-                       assert((te_ipv4_reach->control & 0x3F)
-                              <= IPV4_MAX_BITLEN);
-
-                       dist = cost + ntohl(te_ipv4_reach->te_metric);
-                       prefix.u.prefix4 =
-                               newprefix2inaddr(&te_ipv4_reach->prefix_start,
-                                                te_ipv4_reach->control);
-                       prefix.prefixlen = (te_ipv4_reach->control & 0x3F);
-                       apply_mask(&prefix);
-                       process_N(spftree, VTYPE_IPREACH_TE, (void *)&prefix,
+               struct isis_item_list *ipv4_reachs;
+               if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
+                       ipv4_reachs = &lsp->tlvs->extended_ip_reach;
+               else
+                       ipv4_reachs = isis_lookup_mt_items(
+                               &lsp->tlvs->mt_ip_reach, spftree->mtid);
+
+               struct isis_extended_ip_reach *r;
+               for (r = ipv4_reachs
+                                ? (struct isis_extended_ip_reach *)
+                                          ipv4_reachs->head
+                                : NULL;
+                    r; r = r->next) {
+                       dist = cost + r->metric;
+                       process_N(spftree, VTYPE_IPREACH_TE, (void *)&r->prefix,
                                  dist, depth + 1, parent);
                }
        }
 
        if (!pseudo_lsp && spftree->family == AF_INET6) {
-               struct list *ipv6reachs = NULL;
-
-               if (spftree->mtid == ISIS_MT_IPV4_UNICAST) {
-                       ipv6reachs = lsp->tlv_data.ipv6_reachs;
-               } else {
-                       struct tlv_mt_ipv6_reachs *mt_reachs;
-                       mt_reachs = tlvs_lookup_mt_ipv6_reachs(&lsp->tlv_data,
-                                                              spftree->mtid);
-                       if (mt_reachs)
-                               ipv6reachs = mt_reachs->list;
-               }
-
-               prefix.family = AF_INET6;
-               for (ALL_LIST_ELEMENTS_RO(ipv6reachs, node, ip6reach)) {
-                       assert(ip6reach->prefix_len <= IPV6_MAX_BITLEN);
-
-                       dist = cost + ntohl(ip6reach->metric);
-                       vtype = (ip6reach->control_info
-                                & CTRL_INFO_DISTRIBUTION)
-                                       ? VTYPE_IP6REACH_EXTERNAL
-                                       : VTYPE_IP6REACH_INTERNAL;
-                       prefix.prefixlen = ip6reach->prefix_len;
-                       memcpy(&prefix.u.prefix6.s6_addr, ip6reach->prefix,
-                              PSIZE(ip6reach->prefix_len));
-                       apply_mask(&prefix);
-                       process_N(spftree, vtype, (void *)&prefix, dist,
+               struct isis_item_list *ipv6_reachs;
+               if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
+                       ipv6_reachs = &lsp->tlvs->ipv6_reach;
+               else
+                       ipv6_reachs = isis_lookup_mt_items(
+                               &lsp->tlvs->mt_ipv6_reach, spftree->mtid);
+
+               struct isis_ipv6_reach *r;
+               for (r = ipv6_reachs
+                                ? (struct isis_ipv6_reach *)ipv6_reachs->head
+                                : NULL;
+                    r; r = r->next) {
+                       dist = cost + r->metric;
+                       vtype = r->external ? VTYPE_IP6REACH_EXTERNAL
+                                           : VTYPE_IP6REACH_INTERNAL;
+                       process_N(spftree, vtype, (void *)&r->prefix, dist,
                                  depth + 1, parent);
                }
        }
@@ -893,7 +893,9 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                                if (!adj_has_mt(adj, spftree->mtid))
                                        continue;
                                if (spftree->mtid == ISIS_MT_IPV4_UNICAST
-                                   && !speaks(&adj->nlpids, spftree->family))
+                                   && !speaks(adj->nlpids.nlpids,
+                                              adj->nlpids.count,
+                                              spftree->family))
                                        continue;
                                switch (adj->sys_type) {
                                case ISIS_SYSTYPE_ES:
@@ -928,8 +930,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                                                        ->lspdb[spftree->level
                                                                - 1]);
                                        if (lsp == NULL
-                                           || lsp->lsp_header->rem_lifetime
-                                                      == 0)
+                                           || lsp->hdr.rem_lifetime == 0)
                                                zlog_warn(
                                                        "ISIS-Spf: No LSP %s found for IS adjacency "
                                                        "L%d on %s (ID %u)",
@@ -979,7 +980,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                        lsp = lsp_search(
                                lsp_id,
                                spftree->area->lspdb[spftree->level - 1]);
-                       if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) {
+                       if (lsp == NULL || lsp->hdr.rem_lifetime == 0) {
                                zlog_warn(
                                        "ISIS-Spf: No lsp (%p) found from root "
                                        "to L%d DR %s on %s (ID %d)",
@@ -1015,7 +1016,9 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                                LSP_PSEUDO_ID(lsp_id) = 0;
                                LSP_FRAGMENT(lsp_id) = 0;
                                if (spftree->mtid != ISIS_MT_IPV4_UNICAST
-                                   || speaks(&adj->nlpids, spftree->family))
+                                   || speaks(adj->nlpids.nlpids,
+                                             adj->nlpids.count,
+                                             spftree->family))
                                        isis_spf_add_local(
                                                spftree,
                                                spftree->area->oldmetric
@@ -1178,7 +1181,7 @@ static int isis_run_spf(struct isis_area *area, int level, int family,
                        memcpy(lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
                        LSP_FRAGMENT(lsp_id) = 0;
                        lsp = lsp_search(lsp_id, area->lspdb[level - 1]);
-                       if (lsp && lsp->lsp_header->rem_lifetime != 0) {
+                       if (lsp && lsp->hdr.rem_lifetime != 0) {
                                isis_spf_process_lsp(spftree, lsp, vertex->d_N,
                                                     vertex->depth, sysid,
                                                     vertex);
index 6b8f1fe168b4c6bd49bdfad115e8133f2de6da91..70afef1a86ee4fe81a4b8ff14f82c4444fd48669 100644 (file)
@@ -41,6 +41,7 @@
 #include "md5.h"
 #include "sockunion.h"
 #include "network.h"
+#include "sbuf.h"
 
 #include "isisd/dict.h"
 #include "isisd/isis_constants.h"
@@ -48,7 +49,6 @@
 #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isisd.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_dynhn.h"
@@ -100,9 +100,9 @@ struct mpls_te_circuit *mpls_te_circuit_new()
 /* 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 */
-u_char add_te_subtlvs(u_char *buf, struct mpls_te_circuit *mtc)
+uint8_t add_te_subtlvs(uint8_t *buf, struct mpls_te_circuit *mtc)
 {
-       u_char size, *tlvs = buf;
+       uint8_t size, *tlvs = buf;
 
        zlog_debug("ISIS MPLS-TE: Add TE Sub TLVs to buffer");
 
@@ -232,7 +232,7 @@ u_char add_te_subtlvs(u_char *buf, struct mpls_te_circuit *mtc)
 }
 
 /* Compute total Sub-TLVs size */
-u_char subtlvs_len(struct mpls_te_circuit *mtc)
+uint8_t subtlvs_len(struct mpls_te_circuit *mtc)
 {
        int length = 0;
 
@@ -306,7 +306,7 @@ u_char subtlvs_len(struct mpls_te_circuit *mtc)
                return 0;
        }
 
-       mtc->length = (u_char)length;
+       mtc->length = (uint8_t)length;
 
        return mtc->length;
 }
@@ -666,163 +666,116 @@ void isis_mpls_te_update(struct interface *ifp)
  * Followings are vty session control functions.
  *------------------------------------------------------------------------*/
 
-static u_char show_vty_subtlv_admin_grp(struct vty *vty,
-                                       struct te_subtlv_admin_grp *tlv)
+static u_char print_subtlv_admin_grp(struct sbuf *buf, int indent,
+                                    struct te_subtlv_admin_grp *tlv)
 {
-
-       if (vty != NULL)
-               vty_out(vty, "    Administrative Group: 0x%x\n",
-                       (u_int32_t)ntohl(tlv->value));
-       else
-               zlog_debug("      Administrative Group: 0x%x",
-                          (u_int32_t)ntohl(tlv->value));
-
+       sbuf_push(buf, indent, "Administrative Group: 0x%" PRIx32 "\n",
+                 ntohl(tlv->value));
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_llri(struct vty *vty, struct te_subtlv_llri *tlv)
+static u_char print_subtlv_llri(struct sbuf *buf, int indent,
+                               struct te_subtlv_llri *tlv)
 {
-       if (vty != NULL) {
-               vty_out(vty, "    Link Local  ID: %d\n",
-                       (u_int32_t)ntohl(tlv->local));
-               vty_out(vty, "    Link Remote ID: %d\n",
-                       (u_int32_t)ntohl(tlv->remote));
-       } else {
-               zlog_debug("      Link Local  ID: %d",
-                          (u_int32_t)ntohl(tlv->local));
-               zlog_debug("      Link Remote ID: %d",
-                          (u_int32_t)ntohl(tlv->remote));
-       }
+       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 u_char show_vty_subtlv_local_ipaddr(struct vty *vty,
-                                          struct te_subtlv_local_ipaddr *tlv)
+static u_char print_subtlv_local_ipaddr(struct sbuf *buf, int indent,
+                                       struct te_subtlv_local_ipaddr *tlv)
 {
-       if (vty != NULL)
-               vty_out(vty, "    Local Interface IP Address(es): %s\n",
-                       inet_ntoa(tlv->value));
-       else
-               zlog_debug("      Local Interface IP Address(es): %s",
-                          inet_ntoa(tlv->value));
+       sbuf_push(buf, indent, "Local Interface IP Address(es): %s\n",
+                 inet_ntoa(tlv->value));
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_rmt_ipaddr(struct vty *vty,
-                                        struct te_subtlv_rmt_ipaddr *tlv)
+static u_char print_subtlv_rmt_ipaddr(struct sbuf *buf, int indent,
+                                     struct te_subtlv_rmt_ipaddr *tlv)
 {
-       if (vty != NULL)
-               vty_out(vty, "    Remote Interface IP Address(es): %s\n",
-                       inet_ntoa(tlv->value));
-       else
-               zlog_debug("      Remote Interface IP Address(es): %s",
-                          inet_ntoa(tlv->value));
+       sbuf_push(buf, indent, "Remote Interface IP Address(es): %s\n",
+                 inet_ntoa(tlv->value));
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_max_bw(struct vty *vty,
-                                    struct te_subtlv_max_bw *tlv)
+static u_char print_subtlv_max_bw(struct sbuf *buf, int indent,
+                                 struct te_subtlv_max_bw *tlv)
 {
        float fval;
 
        fval = ntohf(tlv->value);
 
-       if (vty != NULL)
-               vty_out(vty, "    Maximum Bandwidth: %g (Bytes/sec)\n", fval);
-       else
-               zlog_debug("      Maximum Bandwidth: %g (Bytes/sec)", fval);
+       sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n", fval);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_max_rsv_bw(struct vty *vty,
-                                        struct te_subtlv_max_rsv_bw *tlv)
+static u_char print_subtlv_max_rsv_bw(struct sbuf *buf, int indent,
+                                     struct te_subtlv_max_rsv_bw *tlv)
 {
        float fval;
 
        fval = ntohf(tlv->value);
 
-       if (vty != NULL)
-               vty_out(vty,
-                       "    Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
-                       fval);
-       else
-               zlog_debug("      Maximum Reservable Bandwidth: %g (Bytes/sec)",
-                          fval);
+       sbuf_push(buf, indent, "Maximum Reservable Bandwidth: %g (Bytes/sec)\n", fval);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_unrsv_bw(struct vty *vty,
-                                      struct te_subtlv_unrsv_bw *tlv)
+static u_char print_subtlv_unrsv_bw(struct sbuf *buf, int indent,
+                                   struct te_subtlv_unrsv_bw *tlv)
 {
        float fval1, fval2;
        int i;
 
-       if (vty != NULL)
-               vty_out(vty, "    Unreserved Bandwidth:\n");
-       else
-               zlog_debug("      Unreserved Bandwidth:");
+       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]);
-               if (vty != NULL)
-                       vty_out(vty,
-                               "      [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
-                               i, fval1, i + 1, fval2);
-               else
-                       zlog_debug(
-                               "        [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)",
-                               i, fval1, i + 1, fval2);
+               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 u_char show_vty_subtlv_te_metric(struct vty *vty,
-                                       struct te_subtlv_te_metric *tlv)
+static u_char print_subtlv_te_metric(struct sbuf *buf, int indent,
+                                    struct te_subtlv_te_metric *tlv)
 {
        u_int32_t te_metric;
 
        te_metric = tlv->value[2] | tlv->value[1] << 8 | tlv->value[0] << 16;
-       if (vty != NULL)
-               vty_out(vty, "    Traffic Engineering Metric: %u\n", te_metric);
-       else
-               zlog_debug("      Traffic Engineering Metric: %u", te_metric);
+       sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n", te_metric);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_ras(struct vty *vty, struct te_subtlv_ras *tlv)
+static u_char print_subtlv_ras(struct sbuf *buf, int indent,
+                              struct te_subtlv_ras *tlv)
 {
-       if (vty != NULL)
-               vty_out(vty, "    Inter-AS TE Remote AS number: %u\n",
-                       ntohl(tlv->value));
-       else
-               zlog_debug("      Inter-AS TE Remote AS number: %u",
-                          ntohl(tlv->value));
+       sbuf_push(buf, indent, "Inter-AS TE Remote AS number: %" PRIu32 "\n",
+                 ntohl(tlv->value));
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_rip(struct vty *vty, struct te_subtlv_rip *tlv)
+static u_char print_subtlv_rip(struct sbuf *buf, int indent,
+                              struct te_subtlv_rip *tlv)
 {
-       if (vty != NULL)
-               vty_out(vty, "    Inter-AS TE Remote ASBR IP address: %s\n",
-                       inet_ntoa(tlv->value));
-       else
-               zlog_debug("      Inter-AS TE Remote ASBR IP address: %s",
-                          inet_ntoa(tlv->value));
+       sbuf_push(buf, indent, "Inter-AS TE Remote ASBR IP address: %s\n",
+                 inet_ntoa(tlv->value));
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_av_delay(struct vty *vty,
-                                      struct te_subtlv_av_delay *tlv)
+static u_char print_subtlv_av_delay(struct sbuf *buf, int indent,
+                                   struct te_subtlv_av_delay *tlv)
 {
        u_int32_t delay;
        u_int32_t A;
@@ -830,18 +783,14 @@ static u_char show_vty_subtlv_av_delay(struct vty *vty,
        delay = (u_int32_t)ntohl(tlv->value) & TE_EXT_MASK;
        A = (u_int32_t)ntohl(tlv->value) & TE_EXT_ANORMAL;
 
-       if (vty != NULL)
-               vty_out(vty, "    %s Average Link Delay: %d (micro-sec)\n",
-                       A ? "Anomalous" : "Normal", delay);
-       else
-               zlog_debug("      %s Average Link Delay: %d (micro-sec)",
-                          A ? "Anomalous" : "Normal", delay);
+       sbuf_push(buf, indent, "%s Average Link Delay: %" PRIu32 " (micro-sec)\n",
+                 A ? "Anomalous" : "Normal", delay);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_mm_delay(struct vty *vty,
-                                      struct te_subtlv_mm_delay *tlv)
+static u_char print_subtlv_mm_delay(struct sbuf *buf, int indent,
+                                   struct te_subtlv_mm_delay *tlv)
 {
        u_int32_t low, high;
        u_int32_t A;
@@ -850,33 +799,26 @@ static u_char show_vty_subtlv_mm_delay(struct vty *vty,
        A = (u_int32_t)ntohl(tlv->low) & TE_EXT_ANORMAL;
        high = (u_int32_t)ntohl(tlv->high) & TE_EXT_MASK;
 
-       if (vty != NULL)
-               vty_out(vty, "    %s Min/Max Link Delay: %d / %d (micro-sec)\n",
-                       A ? "Anomalous" : "Normal", low, high);
-       else
-               zlog_debug("      %s Min/Max Link Delay: %d / %d (micro-sec)",
-                          A ? "Anomalous" : "Normal", low, high);
+       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 u_char show_vty_subtlv_delay_var(struct vty *vty,
-                                       struct te_subtlv_delay_var *tlv)
+static u_char print_subtlv_delay_var(struct sbuf *buf, int indent,
+                                    struct te_subtlv_delay_var *tlv)
 {
        u_int32_t jitter;
 
        jitter = (u_int32_t)ntohl(tlv->value) & TE_EXT_MASK;
 
-       if (vty != NULL)
-               vty_out(vty, "    Delay Variation: %d (micro-sec)\n", jitter);
-       else
-               zlog_debug("      Delay Variation: %d (micro-sec)", jitter);
+       sbuf_push(buf, indent, "Delay Variation: %" PRIu32 " (micro-sec)\n", jitter);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_pkt_loss(struct vty *vty,
-                                      struct te_subtlv_pkt_loss *tlv)
+static u_char print_subtlv_pkt_loss(struct sbuf *buf, int indent,
+                                   struct te_subtlv_pkt_loss *tlv)
 {
        u_int32_t loss;
        u_int32_t A;
@@ -886,189 +828,162 @@ static u_char show_vty_subtlv_pkt_loss(struct vty *vty,
        fval = (float)(loss * LOSS_PRECISION);
        A = (u_int32_t)ntohl(tlv->value) & TE_EXT_ANORMAL;
 
-       if (vty != NULL)
-               vty_out(vty, "    %s Link Packet Loss: %g (%%)\n",
-                       A ? "Anomalous" : "Normal", fval);
-       else
-               zlog_debug("      %s Link Packet Loss: %g (%%)",
-                          A ? "Anomalous" : "Normal", fval);
+       sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n",
+                 A ? "Anomalous" : "Normal", fval);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_res_bw(struct vty *vty,
-                                    struct te_subtlv_res_bw *tlv)
+static u_char print_subtlv_res_bw(struct sbuf *buf, int indent,
+                                 struct te_subtlv_res_bw *tlv)
 {
        float fval;
 
        fval = ntohf(tlv->value);
 
-       if (vty != NULL)
-               vty_out(vty,
-                       "    Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
-                       fval);
-       else
-               zlog_debug(
-                       "      Unidirectional Residual Bandwidth: %g (Bytes/sec)",
-                       fval);
+       sbuf_push(buf, indent, "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
+                 fval);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_ava_bw(struct vty *vty,
-                                    struct te_subtlv_ava_bw *tlv)
+static u_char print_subtlv_ava_bw(struct sbuf *buf, int indent,
+                                 struct te_subtlv_ava_bw *tlv)
 {
        float fval;
 
        fval = ntohf(tlv->value);
 
-       if (vty != NULL)
-               vty_out(vty,
-                       "    Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
-                       fval);
-       else
-               zlog_debug(
-                       "      Unidirectional Available Bandwidth: %g (Bytes/sec)",
-                       fval);
+       sbuf_push(buf, indent, "Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
+                 fval);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_use_bw(struct vty *vty,
-                                    struct te_subtlv_use_bw *tlv)
+static u_char print_subtlv_use_bw(struct sbuf *buf, int indent,
+                                 struct te_subtlv_use_bw *tlv)
 {
        float fval;
 
        fval = ntohf(tlv->value);
 
-       if (vty != NULL)
-               vty_out(vty,
-                       "    Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
-                       fval);
-       else
-               zlog_debug(
-                       "      Unidirectional Utilized Bandwidth: %g (Bytes/sec)",
-                       fval);
+       sbuf_push(buf, indent, "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
+                 fval);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_unknown_tlv(struct vty *vty, struct subtlv_header *tlvh)
+static u_char print_unknown_tlv(struct sbuf *buf, int indent,
+                               struct subtlv_header *tlvh)
 {
        int i, rtn = 1;
        u_char *v = (u_char *)tlvh;
 
-       if (vty != NULL) {
-               if (tlvh->length != 0) {
-                       vty_out(vty,
-                               "    Unknown TLV: [type(%#.2x), length(%#.2x)]\n",
-                               tlvh->type, tlvh->length);
-                       vty_out(vty, "       Dump: [00]");
-                       rtn = 1; /* initialize end of line counter */
-                       for (i = 0; i < tlvh->length; i++) {
-                               vty_out(vty, " %#.2x", v[i]);
-                               if (rtn == 8) {
-                                       vty_out(vty, "\n             [%.2x]",
-                                               i + 1);
-                                       rtn = 1;
-                               } else
-                                       rtn++;
-                       }
-                       vty_out(vty, "\n");
-               } else
-                       vty_out(vty,
-                               "    Unknown TLV: [type(%#.2x), length(%#.2x)]\n",
-                               tlvh->type, tlvh->length);
+       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 {
-               zlog_debug("      Unknown TLV: [type(%#.2x), length(%#.2x)]",
-                          tlvh->type, tlvh->length);
+               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 vty *vty, struct te_is_neigh *te)
+void mpls_te_print_detail(struct sbuf *buf, int indent,
+                         uint8_t *subtlvs, uint8_t subtlv_len)
 {
-       struct subtlv_header *tlvh;
-       u_int16_t sum = 0;
-
-       zlog_debug("ISIS MPLS-TE: Show database TE detail");
+       struct subtlv_header *tlvh = (struct subtlv_header *)subtlvs;
+       uint16_t sum = 0;
 
-       tlvh = (struct subtlv_header *)te->sub_tlvs;
-
-       for (; sum < te->sub_tlvs_length; tlvh = SUBTLV_HDR_NEXT(tlvh)) {
+       for (; sum < subtlv_len; tlvh = SUBTLV_HDR_NEXT(tlvh)) {
                switch (tlvh->type) {
                case TE_SUBTLV_ADMIN_GRP:
-                       sum += show_vty_subtlv_admin_grp(
-                               vty, (struct te_subtlv_admin_grp *)tlvh);
+                       sum += print_subtlv_admin_grp(buf, indent,
+                               (struct te_subtlv_admin_grp *)tlvh);
                        break;
                case TE_SUBTLV_LLRI:
-                       sum += show_vty_subtlv_llri(
-                               vty, (struct te_subtlv_llri *)tlvh);
+                       sum += print_subtlv_llri(buf, indent,
+                               (struct te_subtlv_llri *)tlvh);
                        break;
                case TE_SUBTLV_LOCAL_IPADDR:
-                       sum += show_vty_subtlv_local_ipaddr(
-                               vty, (struct te_subtlv_local_ipaddr *)tlvh);
+                       sum += print_subtlv_local_ipaddr(buf, indent,
+                               (struct te_subtlv_local_ipaddr *)tlvh);
                        break;
                case TE_SUBTLV_RMT_IPADDR:
-                       sum += show_vty_subtlv_rmt_ipaddr(
-                               vty, (struct te_subtlv_rmt_ipaddr *)tlvh);
+                       sum += print_subtlv_rmt_ipaddr(buf, indent,
+                               (struct te_subtlv_rmt_ipaddr *)tlvh);
                        break;
                case TE_SUBTLV_MAX_BW:
-                       sum += show_vty_subtlv_max_bw(
-                               vty, (struct te_subtlv_max_bw *)tlvh);
+                       sum += print_subtlv_max_bw(buf, indent,
+                               (struct te_subtlv_max_bw *)tlvh);
                        break;
                case TE_SUBTLV_MAX_RSV_BW:
-                       sum += show_vty_subtlv_max_rsv_bw(
-                               vty, (struct te_subtlv_max_rsv_bw *)tlvh);
+                       sum += print_subtlv_max_rsv_bw(buf, indent,
+                               (struct te_subtlv_max_rsv_bw *)tlvh);
                        break;
                case TE_SUBTLV_UNRSV_BW:
-                       sum += show_vty_subtlv_unrsv_bw(
-                               vty, (struct te_subtlv_unrsv_bw *)tlvh);
+                       sum += print_subtlv_unrsv_bw(buf, indent,
+                               (struct te_subtlv_unrsv_bw *)tlvh);
                        break;
                case TE_SUBTLV_TE_METRIC:
-                       sum += show_vty_subtlv_te_metric(
-                               vty, (struct te_subtlv_te_metric *)tlvh);
+                       sum += print_subtlv_te_metric(buf, indent,
+                               (struct te_subtlv_te_metric *)tlvh);
                        break;
                case TE_SUBTLV_RAS:
-                       sum += show_vty_subtlv_ras(
-                               vty, (struct te_subtlv_ras *)tlvh);
+                       sum += print_subtlv_ras(buf, indent,
+                               (struct te_subtlv_ras *)tlvh);
                        break;
                case TE_SUBTLV_RIP:
-                       sum += show_vty_subtlv_rip(
-                               vty, (struct te_subtlv_rip *)tlvh);
+                       sum += print_subtlv_rip(buf, indent,
+                               (struct te_subtlv_rip *)tlvh);
                        break;
                case TE_SUBTLV_AV_DELAY:
-                       sum += show_vty_subtlv_av_delay(
-                               vty, (struct te_subtlv_av_delay *)tlvh);
+                       sum += print_subtlv_av_delay(buf, indent,
+                               (struct te_subtlv_av_delay *)tlvh);
                        break;
                case TE_SUBTLV_MM_DELAY:
-                       sum += show_vty_subtlv_mm_delay(
-                               vty, (struct te_subtlv_mm_delay *)tlvh);
+                       sum += print_subtlv_mm_delay(buf, indent,
+                               (struct te_subtlv_mm_delay *)tlvh);
                        break;
                case TE_SUBTLV_DELAY_VAR:
-                       sum += show_vty_subtlv_delay_var(
-                               vty, (struct te_subtlv_delay_var *)tlvh);
+                       sum += print_subtlv_delay_var(buf, indent,
+                               (struct te_subtlv_delay_var *)tlvh);
                        break;
                case TE_SUBTLV_PKT_LOSS:
-                       sum += show_vty_subtlv_pkt_loss(
-                               vty, (struct te_subtlv_pkt_loss *)tlvh);
+                       sum += print_subtlv_pkt_loss(buf, indent,
+                               (struct te_subtlv_pkt_loss *)tlvh);
                        break;
                case TE_SUBTLV_RES_BW:
-                       sum += show_vty_subtlv_res_bw(
-                               vty, (struct te_subtlv_res_bw *)tlvh);
+                       sum += print_subtlv_res_bw(buf, indent,
+                               (struct te_subtlv_res_bw *)tlvh);
                        break;
                case TE_SUBTLV_AVA_BW:
-                       sum += show_vty_subtlv_ava_bw(
-                               vty, (struct te_subtlv_ava_bw *)tlvh);
+                       sum += print_subtlv_ava_bw(buf, indent,
+                               (struct te_subtlv_ava_bw *)tlvh);
                        break;
                case TE_SUBTLV_USE_BW:
-                       sum += show_vty_subtlv_use_bw(
-                               vty, (struct te_subtlv_use_bw *)tlvh);
+                       sum += print_subtlv_use_bw(buf, indent,
+                               (struct te_subtlv_use_bw *)tlvh);
                        break;
                default:
-                       sum += show_vty_unknown_tlv(vty, tlvh);
+                       sum += print_unknown_tlv(buf, indent, tlvh);
                        break;
                }
        }
@@ -1252,6 +1167,9 @@ DEFUN (show_isis_mpls_te_router,
 static void show_mpls_te_sub(struct vty *vty, struct interface *ifp)
 {
        struct mpls_te_circuit *mtc;
+       struct sbuf buf;
+
+       sbuf_init(&buf, NULL, 0);
 
        if ((IS_MPLS_TE(isisMplsTE))
            && ((mtc = lookup_mpls_params_by_ifp(ifp)) != NULL)) {
@@ -1276,38 +1194,42 @@ static void show_mpls_te_sub(struct vty *vty, struct interface *ifp)
                                ifp->name);
                }
 
-               show_vty_subtlv_admin_grp(vty, &mtc->admin_grp);
+               sbuf_reset(&buf);
+               print_subtlv_admin_grp(&buf, 4, &mtc->admin_grp);
 
                if (SUBTLV_TYPE(mtc->local_ipaddr) != 0)
-                       show_vty_subtlv_local_ipaddr(vty, &mtc->local_ipaddr);
+                       print_subtlv_local_ipaddr(&buf, 4, &mtc->local_ipaddr);
                if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0)
-                       show_vty_subtlv_rmt_ipaddr(vty, &mtc->rmt_ipaddr);
+                       print_subtlv_rmt_ipaddr(&buf, 4, &mtc->rmt_ipaddr);
 
-               show_vty_subtlv_max_bw(vty, &mtc->max_bw);
-               show_vty_subtlv_max_rsv_bw(vty, &mtc->max_rsv_bw);
-               show_vty_subtlv_unrsv_bw(vty, &mtc->unrsv_bw);
-               show_vty_subtlv_te_metric(vty, &mtc->te_metric);
+               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)
-                               show_vty_subtlv_ras(vty, &mtc->ras);
+                               print_subtlv_ras(&buf, 4, &mtc->ras);
                        if (SUBTLV_TYPE(mtc->rip) != 0)
-                               show_vty_subtlv_rip(vty, &mtc->rip);
+                               print_subtlv_rip(&buf, 4, &mtc->rip);
                }
 
-               show_vty_subtlv_av_delay(vty, &mtc->av_delay);
-               show_vty_subtlv_mm_delay(vty, &mtc->mm_delay);
-               show_vty_subtlv_delay_var(vty, &mtc->delay_var);
-               show_vty_subtlv_pkt_loss(vty, &mtc->pkt_loss);
-               show_vty_subtlv_res_bw(vty, &mtc->res_bw);
-               show_vty_subtlv_ava_bw(vty, &mtc->ava_bw);
-               show_vty_subtlv_use_bw(vty, &mtc->use_bw);
+               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);
+
+               vty_multiline(vty, "", "%s", sbuf_buf(&buf));
                vty_out(vty, "---------------\n\n");
        } else {
                vty_out(vty, "  %s: MPLS-TE is disabled on this interface\n",
                        ifp->name);
        }
 
+       sbuf_free(&buf);
        return;
 }
 
index 0bd076af1926faa5acef9487204098886e1b838d..9b29792e2b29119a76d7ddaed2d1aaedefa81259 100644 (file)
@@ -81,6 +81,8 @@ struct subtlv_header {
        u_char 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)
@@ -306,12 +308,13 @@ struct mpls_te_circuit {
 /* Prototypes. */
 void isis_mpls_te_init(void);
 struct mpls_te_circuit *mpls_te_circuit_new(void);
-void mpls_te_print_detail(struct vty *, struct te_is_neigh *);
+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);
-u_char subtlvs_len(struct mpls_te_circuit *);
-u_char add_te_subtlvs(u_char *, struct mpls_te_circuit *);
-u_char build_te_subtlvs(u_char *, struct isis_circuit *);
+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 *);
 void isis_mpls_te_config_write_router(struct vty *);
diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c
deleted file mode 100644 (file)
index a295f4d..0000000
+++ /dev/null
@@ -1,1453 +0,0 @@
-/*
- * IS-IS Rout(e)ing protocol - isis_tlv.c
- *                             IS-IS TLV related routines
- *
- * Copyright (C) 2001,2002   Sampo Saaristo
- *                           Tampere University of Technology
- *                           Institute of Communications Engineering
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public Licenseas published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <zebra.h>
-
-#include "log.h"
-#include "linklist.h"
-#include "stream.h"
-#include "memory.h"
-#include "prefix.h"
-#include "vty.h"
-#include "if.h"
-
-#include "isisd/dict.h"
-#include "isisd/isis_constants.h"
-#include "isisd/isis_common.h"
-#include "isisd/isis_flags.h"
-#include "isisd/isis_circuit.h"
-#include "isisd/isis_tlv.h"
-#include "isisd/isisd.h"
-#include "isisd/isis_dynhn.h"
-#include "isisd/isis_misc.h"
-#include "isisd/isis_pdu.h"
-#include "isisd/isis_lsp.h"
-#include "isisd/isis_te.h"
-#include "isisd/isis_mt.h"
-
-void free_tlv(void *val)
-{
-       XFREE(MTYPE_ISIS_TLV, val);
-
-       return;
-}
-
-/*
- * Called after parsing of a PDU. There shouldn't be any tlv's left, so this
- * is only a caution to avoid memory leaks
- */
-void free_tlvs(struct tlvs *tlvs)
-{
-       if (tlvs->area_addrs)
-               list_delete(tlvs->area_addrs);
-       if (tlvs->mt_router_info)
-               list_delete(tlvs->mt_router_info);
-       if (tlvs->is_neighs)
-               list_delete(tlvs->is_neighs);
-       if (tlvs->te_is_neighs)
-               list_delete(tlvs->te_is_neighs);
-       if (tlvs->mt_is_neighs)
-               list_delete(tlvs->mt_is_neighs);
-       if (tlvs->es_neighs)
-               list_delete(tlvs->es_neighs);
-       if (tlvs->lsp_entries)
-               list_delete(tlvs->lsp_entries);
-       if (tlvs->prefix_neighs)
-               list_delete(tlvs->prefix_neighs);
-       if (tlvs->lan_neighs)
-               list_delete(tlvs->lan_neighs);
-       if (tlvs->ipv4_addrs)
-               list_delete(tlvs->ipv4_addrs);
-       if (tlvs->ipv4_int_reachs)
-               list_delete(tlvs->ipv4_int_reachs);
-       if (tlvs->ipv4_ext_reachs)
-               list_delete(tlvs->ipv4_ext_reachs);
-       if (tlvs->te_ipv4_reachs)
-               list_delete(tlvs->te_ipv4_reachs);
-       if (tlvs->mt_ipv4_reachs)
-               list_delete(tlvs->mt_ipv4_reachs);
-       if (tlvs->ipv6_addrs)
-               list_delete(tlvs->ipv6_addrs);
-       if (tlvs->ipv6_reachs)
-               list_delete(tlvs->ipv6_reachs);
-       if (tlvs->mt_ipv6_reachs)
-               list_delete(tlvs->mt_ipv6_reachs);
-
-       memset(tlvs, 0, sizeof(struct tlvs));
-
-       return;
-}
-
-static int parse_mtid(uint16_t *mtid, bool read_mtid, unsigned int *length,
-                     u_char **pnt)
-{
-       if (!read_mtid) {
-               *mtid = ISIS_MT_IPV4_UNICAST;
-               return ISIS_OK;
-       }
-
-       uint16_t mtid_buf;
-
-       if (*length < sizeof(mtid_buf)) {
-               zlog_warn("ISIS-TLV: mt tlv too short to contain MT id");
-               return ISIS_WARNING;
-       }
-
-       memcpy(&mtid_buf, *pnt, sizeof(mtid_buf));
-       *pnt += sizeof(mtid_buf);
-       *length -= sizeof(mtid_buf);
-
-       *mtid = ntohs(mtid_buf) & ISIS_MT_MASK;
-       return ISIS_OK;
-}
-
-static int parse_mt_is_neighs(struct tlvs *tlvs, bool read_mtid,
-                             unsigned int length, u_char *pnt)
-{
-       struct list *neigh_list;
-       uint16_t mtid;
-       int rv;
-
-       rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
-       if (rv != ISIS_OK)
-               return rv;
-
-       if (mtid == ISIS_MT_IPV4_UNICAST) {
-               if (!tlvs->te_is_neighs) {
-                       tlvs->te_is_neighs = list_new();
-                       tlvs->te_is_neighs->del = free_tlv;
-               }
-               neigh_list = tlvs->te_is_neighs;
-       } else {
-               struct tlv_mt_neighbors *neighbors;
-
-               neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
-               neighbors->list->del = free_tlv;
-               neigh_list = neighbors->list;
-       }
-
-       while (length >= IS_NEIGHBOURS_LEN) {
-               struct te_is_neigh *neigh =
-                       XCALLOC(MTYPE_ISIS_TLV, sizeof(*neigh));
-
-               memcpy(neigh, pnt, IS_NEIGHBOURS_LEN);
-               pnt += IS_NEIGHBOURS_LEN;
-               length -= IS_NEIGHBOURS_LEN;
-
-               if (neigh->sub_tlvs_length > length) {
-                       zlog_warn(
-                               "ISIS-TLV: neighbor subtlv length exceeds TLV size");
-                       XFREE(MTYPE_ISIS_TLV, neigh);
-                       return ISIS_WARNING;
-               }
-
-               memcpy(neigh->sub_tlvs, pnt, neigh->sub_tlvs_length);
-               pnt += neigh->sub_tlvs_length;
-               length -= neigh->sub_tlvs_length;
-
-               listnode_add(neigh_list, neigh);
-       }
-
-       if (length) {
-               zlog_warn("ISIS-TLV: TE/MT neighor TLV has trailing data");
-               return ISIS_WARNING;
-       }
-
-       return ISIS_OK;
-}
-
-static int parse_mt_ipv4_reachs(struct tlvs *tlvs, bool read_mtid,
-                               unsigned int length, u_char *pnt)
-{
-       struct list *reach_list;
-       uint16_t mtid;
-       int rv;
-
-       rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
-       if (rv != ISIS_OK)
-               return rv;
-
-       if (mtid == ISIS_MT_IPV4_UNICAST) {
-               if (!tlvs->te_ipv4_reachs) {
-                       tlvs->te_ipv4_reachs = list_new();
-                       tlvs->te_ipv4_reachs->del = free_tlv;
-               }
-               reach_list = tlvs->te_ipv4_reachs;
-       } else {
-               struct tlv_mt_ipv4_reachs *reachs;
-
-               reachs = tlvs_get_mt_ipv4_reachs(tlvs, mtid);
-               reachs->list->del = free_tlv;
-               reach_list = reachs->list;
-       }
-
-       while (length >= 5) /* Metric + Control */
-       {
-               struct te_ipv4_reachability *reach =
-                       XCALLOC(MTYPE_ISIS_TLV, TE_IPV4_REACH_LEN);
-
-               memcpy(reach, pnt, 5); /* Metric + Control */
-               pnt += 5;
-               length -= 5;
-
-               unsigned char prefixlen = reach->control & 0x3F;
-
-               if (prefixlen > IPV4_MAX_BITLEN) {
-                       zlog_warn(
-                               "ISIS-TLV: invalid IPv4 extended reachability prefix length %d",
-                               prefixlen);
-                       XFREE(MTYPE_ISIS_TLV, reach);
-                       return ISIS_WARNING;
-               }
-
-               if (length < (unsigned int)PSIZE(prefixlen)) {
-                       zlog_warn(
-                               "ISIS-TLV: invalid IPv4 extended reachability prefix too long for tlv");
-                       XFREE(MTYPE_ISIS_TLV, reach);
-                       return ISIS_WARNING;
-               }
-
-               memcpy(&reach->prefix_start, pnt, PSIZE(prefixlen));
-               pnt += PSIZE(prefixlen);
-               length -= PSIZE(prefixlen);
-
-               if (reach->control & TE_IPV4_HAS_SUBTLV) {
-                       if (length < 1) {
-                               zlog_warn(
-                                       "ISIS-TLV: invalid IPv4 extended reachability SubTLV missing");
-                               XFREE(MTYPE_ISIS_TLV, reach);
-                               return ISIS_WARNING;
-                       }
-
-                       u_char subtlv_len = *pnt;
-                       pnt++;
-                       length--;
-
-                       if (length < subtlv_len) {
-                               zlog_warn(
-                                       "ISIS-TLV: invalid IPv4 extended reachability SubTLVs have oversize");
-                               XFREE(MTYPE_ISIS_TLV, reach);
-                               return ISIS_WARNING;
-                       }
-
-                       /* Skip Sub-TLVs for now */
-                       pnt += subtlv_len;
-                       length -= subtlv_len;
-               }
-               listnode_add(reach_list, reach);
-       }
-
-       if (length) {
-               zlog_warn(
-                       "ISIS-TLV: TE/MT ipv4 reachability TLV has trailing data");
-               return ISIS_WARNING;
-       }
-
-       return ISIS_OK;
-}
-
-static int parse_mt_ipv6_reachs(struct tlvs *tlvs, bool read_mtid,
-                               unsigned int length, u_char *pnt)
-{
-       struct list *reach_list;
-       uint16_t mtid;
-       int rv;
-
-       rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
-       if (rv != ISIS_OK)
-               return rv;
-
-       if (mtid == ISIS_MT_IPV4_UNICAST) {
-               if (!tlvs->ipv6_reachs) {
-                       tlvs->ipv6_reachs = list_new();
-                       tlvs->ipv6_reachs->del = free_tlv;
-               }
-               reach_list = tlvs->ipv6_reachs;
-       } else {
-               struct tlv_mt_ipv6_reachs *reachs;
-
-               reachs = tlvs_get_mt_ipv6_reachs(tlvs, mtid);
-               reachs->list->del = free_tlv;
-               reach_list = reachs->list;
-       }
-
-       while (length >= 6) /* Metric + Control + Prefixlen */
-       {
-               struct ipv6_reachability *reach =
-                       XCALLOC(MTYPE_ISIS_TLV, sizeof(*reach));
-
-               memcpy(reach, pnt, 6); /* Metric + Control + Prefixlen */
-               pnt += 6;
-               length -= 6;
-
-               if (reach->prefix_len > IPV6_MAX_BITLEN) {
-                       zlog_warn(
-                               "ISIS-TLV: invalid IPv6 reachability prefix length %d",
-                               reach->prefix_len);
-                       XFREE(MTYPE_ISIS_TLV, reach);
-                       return ISIS_WARNING;
-               }
-
-               if (length < (unsigned int)PSIZE(reach->prefix_len)) {
-                       zlog_warn(
-                               "ISIS-TLV: invalid IPv6 reachability prefix too long for tlv");
-                       XFREE(MTYPE_ISIS_TLV, reach);
-                       return ISIS_WARNING;
-               }
-
-               memcpy(&reach->prefix, pnt, PSIZE(reach->prefix_len));
-               pnt += PSIZE(reach->prefix_len);
-               length -= PSIZE(reach->prefix_len);
-
-               if (reach->control_info & CTRL_INFO_SUBTLVS) {
-                       if (length < 1) {
-                               zlog_warn(
-                                       "ISIS-TLV: invalid IPv6 reachability SubTLV missing");
-                               XFREE(MTYPE_ISIS_TLV, reach);
-                               return ISIS_WARNING;
-                       }
-
-                       u_char subtlv_len = *pnt;
-                       pnt++;
-                       length--;
-
-                       if (length < subtlv_len) {
-                               zlog_warn(
-                                       "ISIS-TLV: invalid IPv6 reachability SubTLVs have oversize");
-                               XFREE(MTYPE_ISIS_TLV, reach);
-                               return ISIS_WARNING;
-                       }
-
-                       /* Skip Sub-TLVs for now */
-                       pnt += subtlv_len;
-                       length -= subtlv_len;
-               }
-               listnode_add(reach_list, reach);
-       }
-
-       if (length) {
-               zlog_warn(
-                       "ISIS-TLV: (MT) IPv6 reachability TLV has trailing data");
-               return ISIS_WARNING;
-       }
-
-       return ISIS_OK;
-}
-
-/*
- * Parses the tlvs found in the variant length part of the PDU.
- * Caller tells with flags in "expected" which TLV's it is interested in.
- */
-int parse_tlvs(char *areatag, u_char *stream, int size, u_int32_t *expected,
-              u_int32_t *found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset)
-{
-       u_char type, length;
-       struct lan_neigh *lan_nei;
-       struct area_addr *area_addr;
-       struct is_neigh *is_nei;
-       struct es_neigh *es_nei;
-       struct lsp_entry *lsp_entry;
-       struct in_addr *ipv4_addr;
-       struct ipv4_reachability *ipv4_reach;
-       struct in6_addr *ipv6_addr;
-       int value_len, retval = ISIS_OK;
-       u_char *start = stream, *pnt = stream;
-
-       *found = 0;
-       memset(tlvs, 0, sizeof(struct tlvs));
-
-       while (pnt < stream + size - 2) {
-               type = *pnt;
-               length = *(pnt + 1);
-               pnt += 2;
-               value_len = 0;
-               if (pnt + length > stream + size) {
-                       zlog_warn(
-                               "ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
-                               "boundaries",
-                               areatag, type, length);
-                       retval = ISIS_WARNING;
-                       break;
-               }
-               switch (type) {
-               case AREA_ADDRESSES:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                        Address Length |
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                         Area Address |
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_AREA_ADDRS;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("TLV Area Adresses len %d", length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_AREA_ADDRS) {
-                               while (length > value_len) {
-                                       area_addr = (struct area_addr *)pnt;
-                                       value_len += area_addr->addr_len + 1;
-                                       pnt += area_addr->addr_len + 1;
-                                       if (!tlvs->area_addrs)
-                                               tlvs->area_addrs = list_new();
-                                       listnode_add(tlvs->area_addrs,
-                                                    area_addr);
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case IS_NEIGHBOURS:
-                       *found |= TLVFLAG_IS_NEIGHS;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): IS Neighbours length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (TLVFLAG_IS_NEIGHS & *expected) {
-                               /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                                * |                        Virtual Flag |
-                                * +-------+-------+-------+-------+-------+-------+-------+-------+
-                                */
-                               pnt++;
-                               value_len++;
-                               /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                                * |   0   |  I/E  |               Default
-                                * Metric                  |
-                                * +-------+-------+-------+-------+-------+-------+-------+-------+
-                                * |   S   |  I/E  |               Delay Metric
-                                * |
-                                * +-------+-------+-------+-------+-------+-------+-------+-------+
-                                * |   S   |  I/E  |               Expense
-                                * Metric                  |
-                                * +-------+-------+-------+-------+-------+-------+-------+-------+
-                                * |   S   |  I/E  |               Error Metric
-                                * |
-                                * +-------+-------+-------+-------+-------+-------+-------+-------+
-                                * |                        Neighbour ID |
-                                * +---------------------------------------------------------------+
-                                * : :
-                                */
-                               while (length > value_len) {
-                                       is_nei = (struct is_neigh *)pnt;
-                                       value_len += 4 + ISIS_SYS_ID_LEN + 1;
-                                       pnt += 4 + ISIS_SYS_ID_LEN + 1;
-                                       if (!tlvs->is_neighs)
-                                               tlvs->is_neighs = list_new();
-                                       listnode_add(tlvs->is_neighs, is_nei);
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case TE_IS_NEIGHBOURS:
-                       *found |= TLVFLAG_TE_IS_NEIGHS;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug(
-                               "ISIS-TLV (%s): Extended IS Neighbours length %d",
-                               areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (TLVFLAG_TE_IS_NEIGHS & *expected)
-                               retval = parse_mt_is_neighs(tlvs, false, length,
-                                                           pnt);
-                       pnt += length;
-                       break;
-
-               case MT_IS_NEIGHBOURS:
-                       *found |= TLVFLAG_TE_IS_NEIGHS;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): MT IS Neighbours length %d",
-                                  areatag, length);
-#endif
-                       if (TLVFLAG_TE_IS_NEIGHS & *expected)
-                               retval = parse_mt_is_neighs(tlvs, true, length,
-                                                           pnt);
-                       pnt += length;
-                       break;
-
-               case ES_NEIGHBOURS:
-/* +-------+-------+-------+-------+-------+-------+-------+-------+
- * |   0   |  I/E  |               Default Metric                  |
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |   S   |  I/E  |               Delay Metric                    |
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |   S   |  I/E  |               Expense Metric                  |
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |   S   |  I/E  |               Error Metric                    |
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |                        Neighbour ID                           |
- * +---------------------------------------------------------------+
- * |                        Neighbour ID                           |
- * +---------------------------------------------------------------+
- * :                                                               :
- */
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): ES Neighbours length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       *found |= TLVFLAG_ES_NEIGHS;
-                       if (*expected & TLVFLAG_ES_NEIGHS) {
-                               es_nei = (struct es_neigh *)pnt;
-                               value_len += 4;
-                               pnt += 4;
-                               while (length > value_len) {
-                                       /* FIXME FIXME FIXME - add to the list
-                                        */
-                                       /*          sys_id->id = pnt; */
-                                       value_len += ISIS_SYS_ID_LEN;
-                                       pnt += ISIS_SYS_ID_LEN;
-                                       /*  if (!es_nei->neigh_ids)
-                                        * es_nei->neigh_ids = sysid; */
-                               }
-                               if (!tlvs->es_neighs)
-                                       tlvs->es_neighs = list_new();
-                               listnode_add(tlvs->es_neighs, es_nei);
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case LAN_NEIGHBOURS:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                        LAN Address |
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_LAN_NEIGHS;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): LAN Neigbours length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (TLVFLAG_LAN_NEIGHS & *expected) {
-                               while (length > value_len) {
-                                       lan_nei = (struct lan_neigh *)pnt;
-                                       if (!tlvs->lan_neighs)
-                                               tlvs->lan_neighs = list_new();
-                                       listnode_add(tlvs->lan_neighs, lan_nei);
-                                       value_len += ETH_ALEN;
-                                       pnt += ETH_ALEN;
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case PADDING:
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("TLV padding %d", length);
-#endif /* EXTREME_TLV_DEBUG */
-                       pnt += length;
-                       break;
-
-               case LSP_ENTRIES:
-/* +-------+-------+-------+-------+-------+-------+-------+-------+
- * |                     Remaining Lifetime                        | 2
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |                         LSP ID                                | id+2
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |                   LSP Sequence Number                         | 4
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |                        Checksum                               | 2
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- */
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): LSP Entries length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       *found |= TLVFLAG_LSP_ENTRIES;
-                       if (TLVFLAG_LSP_ENTRIES & *expected) {
-                               while (length > value_len) {
-                                       lsp_entry = (struct lsp_entry *)pnt;
-                                       value_len += 10 + ISIS_SYS_ID_LEN;
-                                       pnt += 10 + ISIS_SYS_ID_LEN;
-                                       if (!tlvs->lsp_entries)
-                                               tlvs->lsp_entries = list_new();
-                                       listnode_add(tlvs->lsp_entries,
-                                                    lsp_entry);
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case CHECKSUM:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                   16 bit fletcher CHECKSUM |
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_CHECKSUM;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): Checksum length %d", areatag,
-                                  length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_CHECKSUM) {
-                               tlvs->checksum = (struct checksum *)pnt;
-                       }
-                       pnt += length;
-                       break;
-
-               case PROTOCOLS_SUPPORTED:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                       NLPID |
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_NLPID;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug(
-                               "ISIS-TLV (%s): Protocols Supported length %d",
-                               areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_NLPID) {
-                               tlvs->nlpids = (struct nlpids *)(pnt - 1);
-                       }
-                       pnt += length;
-                       break;
-
-               case IPV4_ADDR:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * +                 IP version 4 address + 4
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_IPV4_ADDR;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): IPv4 Address length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_IPV4_ADDR) {
-                               while (length > value_len) {
-                                       ipv4_addr = (struct in_addr *)pnt;
-#ifdef EXTREME_TLV_DEBUG
-                                       zlog_debug(
-                                               "ISIS-TLV (%s) : IP ADDR %s, pnt %p",
-                                               areatag, inet_ntoa(*ipv4_addr),
-                                               pnt);
-#endif /* EXTREME_TLV_DEBUG */
-                                       if (!tlvs->ipv4_addrs)
-                                               tlvs->ipv4_addrs = list_new();
-                                       listnode_add(tlvs->ipv4_addrs,
-                                                    ipv4_addr);
-                                       value_len += 4;
-                                       pnt += 4;
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case AUTH_INFO:
-                       *found |= TLVFLAG_AUTH_INFO;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug(
-                               "ISIS-TLV (%s): IS-IS Authentication Information",
-                               areatag);
-#endif
-                       if (*expected & TLVFLAG_AUTH_INFO) {
-                               tlvs->auth_info.type = *pnt;
-                               if (length == 0) {
-                                       zlog_warn(
-                                               "ISIS-TLV (%s): TLV (type %d, length %d) "
-                                               "incorrect.",
-                                               areatag, type, length);
-                                       return ISIS_WARNING;
-                               }
-                               --length;
-                               tlvs->auth_info.len = length;
-                               pnt++;
-                               memcpy(tlvs->auth_info.passwd, pnt, length);
-                               /* Return the authentication tlv pos for later
-                                * computation
-                                * of MD5 (RFC 5304, 2)
-                                */
-                               if (auth_tlv_offset)
-                                       *auth_tlv_offset += (pnt - start - 3);
-                               pnt += length;
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case DYNAMIC_HOSTNAME:
-                       *found |= TLVFLAG_DYN_HOSTNAME;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): Dynamic Hostname length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_DYN_HOSTNAME) {
-                               /* the length is also included in the pointed
-                                * struct */
-                               tlvs->hostname = (struct hostname *)(pnt - 1);
-                       }
-                       pnt += length;
-                       break;
-
-               case TE_ROUTER_ID:
-                       /* +---------------------------------------------------------------+
-                        * +                         Router ID + 4
-                        * +---------------------------------------------------------------+
-                        */
-                       *found |= TLVFLAG_TE_ROUTER_ID;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): TE Router ID %d", areatag,
-                                  length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_TE_ROUTER_ID)
-                               tlvs->router_id = (struct te_router_id *)(pnt);
-                       pnt += length;
-                       break;
-
-               case IPV4_INT_REACHABILITY:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   0   |  I/E  |               Default Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   S   |  I/E  |               Delay Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   S   |  I/E  |               Expense Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   S   |  I/E  |               Error Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                        ip address | 4
-                        * +---------------------------------------------------------------+
-                        * |                        address mask | 4
-                        * +---------------------------------------------------------------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_IPV4_INT_REACHABILITY;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug(
-                               "ISIS-TLV (%s): IPv4 internal Reachability length %d",
-                               areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_IPV4_INT_REACHABILITY) {
-                               while (length > value_len) {
-                                       ipv4_reach =
-                                               (struct ipv4_reachability *)pnt;
-                                       if (!tlvs->ipv4_int_reachs)
-                                               tlvs->ipv4_int_reachs =
-                                                       list_new();
-                                       listnode_add(tlvs->ipv4_int_reachs,
-                                                    ipv4_reach);
-                                       value_len += 12;
-                                       pnt += 12;
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case IPV4_EXT_REACHABILITY:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   0   |  I/E  |               Default Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   S   |  I/E  |               Delay Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   S   |  I/E  |               Expense Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   S   |  I/E  |               Error Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                        ip address | 4
-                        * +---------------------------------------------------------------+
-                        * |                        address mask | 4
-                        * +---------------------------------------------------------------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_IPV4_EXT_REACHABILITY;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug(
-                               "ISIS-TLV (%s): IPv4 external Reachability length %d",
-                               areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_IPV4_EXT_REACHABILITY) {
-                               while (length > value_len) {
-                                       ipv4_reach =
-                                               (struct ipv4_reachability *)pnt;
-                                       if (!tlvs->ipv4_ext_reachs)
-                                               tlvs->ipv4_ext_reachs =
-                                                       list_new();
-                                       listnode_add(tlvs->ipv4_ext_reachs,
-                                                    ipv4_reach);
-                                       value_len += 12;
-                                       pnt += 12;
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case TE_IPV4_REACHABILITY:
-                       *found |= TLVFLAG_TE_IPV4_REACHABILITY;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug(
-                               "ISIS-TLV (%s): IPv4 extended Reachability length %d",
-                               areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
-                               retval = parse_mt_ipv4_reachs(tlvs, false,
-                                                             length, pnt);
-                       pnt += length;
-                       break;
-               case MT_IPV4_REACHABILITY:
-                       *found |= TLVFLAG_TE_IPV4_REACHABILITY;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug(
-                               "ISIS-TLV (%s): IPv4 MT Reachability length %d",
-                               areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
-                               retval = parse_mt_ipv4_reachs(tlvs, true,
-                                                             length, pnt);
-                       pnt += length;
-                       break;
-               case IPV6_ADDR:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * +                 IP version 6 address + 16
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_IPV6_ADDR;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): IPv6 Address length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_IPV6_ADDR) {
-                               while (length > value_len) {
-                                       ipv6_addr = (struct in6_addr *)pnt;
-                                       if (!tlvs->ipv6_addrs)
-                                               tlvs->ipv6_addrs = list_new();
-                                       listnode_add(tlvs->ipv6_addrs,
-                                                    ipv6_addr);
-                                       value_len += 16;
-                                       pnt += 16;
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case IPV6_REACHABILITY:
-                       *found |= TLVFLAG_IPV6_REACHABILITY;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): IPv6 Reachability length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_IPV6_REACHABILITY)
-                               retval = parse_mt_ipv6_reachs(tlvs, false,
-                                                             length, pnt);
-                       pnt += length;
-                       break;
-               case MT_IPV6_REACHABILITY:
-                       *found |= TLVFLAG_IPV6_REACHABILITY;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): IPv6 Reachability length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_IPV6_REACHABILITY)
-                               retval = parse_mt_ipv6_reachs(tlvs, true,
-                                                             length, pnt);
-                       pnt += length;
-                       break;
-               case WAY3_HELLO:
-                       /* +---------------------------------------------------------------+
-                        * |                  Adjacency state | 1
-                        * +---------------------------------------------------------------+
-                        * |                  Extended Local Circuit ID | 4
-                        * +---------------------------------------------------------------+
-                        * |                  Neighbor System ID (If known)
-                        * | 0-8
-                        *                                      (probably 6)
-                        * +---------------------------------------------------------------+
-                        * |                  Neighbor Local Circuit ID (If
-                        * known)         | 4
-                        * +---------------------------------------------------------------+
-                        */
-                       *found |= TLVFLAG_3WAY_HELLO;
-                       if (*expected & TLVFLAG_3WAY_HELLO) {
-                               while (length > value_len) {
-                                       /* FIXME: make this work */
-                                       /*           Adjacency State (one
-                                          octet):
-                                                     0 = Up
-                                                     1 = Initializing
-                                                     2 = Down
-                                                   Extended Local Circuit ID
-                                          (four octets)
-                                                   Neighbor System ID if known
-                                          (zero to eight octets)
-                                                   Neighbor Extended Local
-                                          Circuit ID (four octets, if Neighbor
-                                                     System ID is present) */
-                                       pnt += length;
-                                       value_len += length;
-                               }
-                       } else {
-                               pnt += length;
-                       }
-
-                       break;
-               case GRACEFUL_RESTART:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |         Reserved                      |  SA   |  RA
-                        * |  RR   | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                          Remaining Time | 2
-                        * +---------------------------------------------------------------+
-                        * |                Restarting Neighbor ID (If known)
-                        * | 0-8
-                        * +---------------------------------------------------------------+
-                        */
-                       *found |= TLVFLAG_GRACEFUL_RESTART;
-                       if (*expected & TLVFLAG_GRACEFUL_RESTART) {
-                               /* FIXME: make this work */
-                       }
-                       pnt += length;
-                       break;
-
-               case MT_ROUTER_INFORMATION:
-                       *found |= TLVFLAG_MT_ROUTER_INFORMATION;
-                       if (*expected & TLVFLAG_MT_ROUTER_INFORMATION) {
-                               if (!tlvs->mt_router_info) {
-                                       tlvs->mt_router_info = list_new();
-                                       tlvs->mt_router_info->del = free_tlv;
-                               }
-                               while (length > value_len) {
-                                       uint16_t mt_info;
-                                       struct mt_router_info *info;
-
-                                       if (value_len + sizeof(mt_info)
-                                           > length) {
-                                               zlog_warn(
-                                                       "ISIS-TLV (%s): TLV 229 is truncated.",
-                                                       areatag);
-                                               pnt += length - value_len;
-                                               break;
-                                       }
-
-                                       memcpy(&mt_info, pnt, sizeof(mt_info));
-                                       pnt += sizeof(mt_info);
-                                       value_len += sizeof(mt_info);
-
-                                       mt_info = ntohs(mt_info);
-                                       info = XCALLOC(MTYPE_ISIS_TLV,
-                                                      sizeof(*info));
-                                       info->mtid = mt_info & ISIS_MT_MASK;
-                                       info->overload =
-                                               mt_info & ISIS_MT_OL_MASK;
-                                       listnode_add(tlvs->mt_router_info,
-                                                    info);
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-               default:
-                       zlog_warn(
-                               "ISIS-TLV (%s): unsupported TLV type %d, length %d",
-                               areatag, type, length);
-
-                       pnt += length;
-                       break;
-               }
-               /* Abort Parsing if error occured */
-               if (retval != ISIS_OK)
-                       return retval;
-       }
-
-       return retval;
-}
-
-int add_tlv(u_char tag, u_char len, u_char *value, struct stream *stream)
-{
-       if ((stream_get_size(stream) - stream_get_endp(stream))
-           < (((unsigned)len) + 2)) {
-               zlog_warn(
-                       "No room for TLV of type %d "
-                       "(total size %d available %d required %d)",
-                       tag, (int)stream_get_size(stream),
-                       (int)(stream_get_size(stream)
-                             - stream_get_endp(stream)),
-                       len + 2);
-               return ISIS_WARNING;
-       }
-
-       stream_putc(stream, tag);           /* TAG */
-       stream_putc(stream, len);           /* LENGTH */
-       stream_put(stream, value, (int)len); /* VALUE */
-
-#ifdef EXTREME_DEBUG
-       zlog_debug("Added TLV %d len %d", tag, len);
-#endif /* EXTREME DEBUG */
-       return ISIS_OK;
-}
-
-int tlv_add_mt_router_info(struct list *mt_router_info, struct stream *stream)
-{
-       struct listnode *node;
-       struct mt_router_info *info;
-
-       uint16_t value[127];
-       uint16_t *pos = value;
-
-       for (ALL_LIST_ELEMENTS_RO(mt_router_info, node, info)) {
-               uint16_t mt_info;
-
-               mt_info = info->mtid;
-               if (info->overload)
-                       mt_info |= ISIS_MT_OL_MASK;
-
-               *pos = htons(mt_info);
-               pos++;
-       }
-
-       return add_tlv(MT_ROUTER_INFORMATION, (pos - value) * sizeof(*pos),
-                      (u_char *)value, stream);
-}
-
-int tlv_add_area_addrs(struct list *area_addrs, struct stream *stream)
-{
-       struct listnode *node;
-       struct area_addr *area_addr;
-
-       u_char value[255];
-       u_char *pos = value;
-
-       for (ALL_LIST_ELEMENTS_RO(area_addrs, node, area_addr)) {
-               if (pos - value + area_addr->addr_len > 255)
-                       goto err;
-               *pos = area_addr->addr_len;
-               pos++;
-               memcpy(pos, area_addr->area_addr, (int)area_addr->addr_len);
-               pos += area_addr->addr_len;
-       }
-
-       return add_tlv(AREA_ADDRESSES, pos - value, value, stream);
-
-err:
-       zlog_warn("tlv_add_area_addrs(): TLV longer than 255");
-       return ISIS_WARNING;
-}
-
-int tlv_add_is_neighs(struct list *is_neighs, struct stream *stream)
-{
-       struct listnode *node;
-       struct is_neigh *is_neigh;
-       u_char value[255];
-       u_char *pos = value;
-       int retval;
-
-       *pos = 0; /*is_neigh->virtual; */
-       pos++;
-
-       for (ALL_LIST_ELEMENTS_RO(is_neighs, node, is_neigh)) {
-               if (pos - value + IS_NEIGHBOURS_LEN > 255) {
-                       retval = add_tlv(IS_NEIGHBOURS, pos - value, value,
-                                        stream);
-                       if (retval != ISIS_OK)
-                               return retval;
-                       pos = value;
-               }
-               *pos = is_neigh->metrics.metric_default;
-               pos++;
-               *pos = is_neigh->metrics.metric_delay;
-               pos++;
-               *pos = is_neigh->metrics.metric_expense;
-               pos++;
-               *pos = is_neigh->metrics.metric_error;
-               pos++;
-               memcpy(pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
-               pos += ISIS_SYS_ID_LEN + 1;
-       }
-
-       return add_tlv(IS_NEIGHBOURS, pos - value, value, stream);
-}
-
-static size_t max_tlv_size(struct stream *stream)
-{
-       size_t avail = stream_get_size(stream) - stream_get_endp(stream);
-
-       if (avail < 2)
-               return 0;
-
-       if (avail < 257)
-               return avail - 2;
-
-       return 255;
-}
-
-unsigned int tlv_add_te_is_neighs(struct list *te_is_neighs,
-                                 struct stream *stream, void *arg)
-{
-       struct listnode *node;
-       struct te_is_neigh *te_is_neigh;
-       u_char value[255];
-       u_char *pos = value;
-       uint16_t mtid = arg ? *(uint16_t *)arg : ISIS_MT_IPV4_UNICAST;
-       unsigned int consumed = 0;
-       size_t max_size = max_tlv_size(stream);
-
-       if (mtid != ISIS_MT_IPV4_UNICAST) {
-               uint16_t mtid_conversion = ntohs(mtid);
-               memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
-               pos += sizeof(mtid_conversion);
-       }
-
-       for (ALL_LIST_ELEMENTS_RO(te_is_neighs, node, te_is_neigh)) {
-               /* FIXME: Check if Total SubTLVs size doesn't exceed 255 */
-               if ((size_t)(pos - value) + IS_NEIGHBOURS_LEN
-                           + te_is_neigh->sub_tlvs_length
-                   > max_size)
-                       break;
-
-               memcpy(pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
-               pos += ISIS_SYS_ID_LEN + 1;
-               memcpy(pos, te_is_neigh->te_metric, 3);
-               pos += 3;
-               /* Set the total size of Sub TLVs */
-               *pos = te_is_neigh->sub_tlvs_length;
-               pos++;
-               /* Copy Sub TLVs if any */
-               if (te_is_neigh->sub_tlvs_length > 0) {
-                       memcpy(pos, te_is_neigh->sub_tlvs,
-                              te_is_neigh->sub_tlvs_length);
-                       pos += te_is_neigh->sub_tlvs_length;
-               }
-               consumed++;
-       }
-
-       if (consumed) {
-               int rv = add_tlv((mtid != ISIS_MT_IPV4_UNICAST)
-                                        ? MT_IS_NEIGHBOURS
-                                        : TE_IS_NEIGHBOURS,
-                                pos - value, value, stream);
-               assert(rv == ISIS_OK);
-       }
-       return consumed;
-}
-
-int tlv_add_lan_neighs(struct list *lan_neighs, struct stream *stream)
-{
-       struct listnode *node;
-       u_char *snpa;
-       u_char value[255];
-       u_char *pos = value;
-       int retval;
-
-       for (ALL_LIST_ELEMENTS_RO(lan_neighs, node, snpa)) {
-               if (pos - value + ETH_ALEN > 255) {
-                       retval = add_tlv(LAN_NEIGHBOURS, pos - value, value,
-                                        stream);
-                       if (retval != ISIS_OK)
-                               return retval;
-                       pos = value;
-               }
-               memcpy(pos, snpa, ETH_ALEN);
-               pos += ETH_ALEN;
-       }
-
-       return add_tlv(LAN_NEIGHBOURS, pos - value, value, stream);
-}
-
-int tlv_add_nlpid(struct nlpids *nlpids, struct stream *stream)
-{
-       return add_tlv(PROTOCOLS_SUPPORTED, nlpids->count, nlpids->nlpids,
-                      stream);
-}
-
-int tlv_add_authinfo(u_char auth_type, u_char auth_len, u_char *auth_value,
-                    struct stream *stream)
-{
-       u_char value[255];
-       u_char *pos = value;
-       *pos++ = auth_type;
-       memcpy(pos, auth_value, auth_len);
-
-       return add_tlv(AUTH_INFO, auth_len + 1, value, stream);
-}
-
-int tlv_add_checksum(struct checksum *checksum, struct stream *stream)
-{
-       u_char value[255];
-       u_char *pos = value;
-       return add_tlv(CHECKSUM, pos - value, value, stream);
-}
-
-int tlv_add_ip_addrs(struct list *ip_addrs, struct stream *stream)
-{
-       struct listnode *node;
-       struct prefix_ipv4 *ipv4;
-       u_char value[255];
-       u_char *pos = value;
-
-       for (ALL_LIST_ELEMENTS_RO(ip_addrs, node, ipv4)) {
-               if (pos - value + IPV4_MAX_BYTELEN > 255) {
-                       /* RFC 1195 s4.2: only one tuple of 63 allowed. */
-                       zlog_warn(
-                               "tlv_add_ip_addrs(): cutting off at 63 IP addresses");
-                       break;
-               }
-               *(u_int32_t *)pos = ipv4->prefix.s_addr;
-               pos += IPV4_MAX_BYTELEN;
-       }
-
-       return add_tlv(IPV4_ADDR, pos - value, value, stream);
-}
-
-/* Used to add TLV containing just one IPv4 address - either IPv4 address TLV
- * (in case of LSP) or TE router ID TLV. */
-int tlv_add_in_addr(struct in_addr *addr, struct stream *stream, u_char tag)
-{
-       u_char value[255];
-       u_char *pos = value;
-
-       memcpy(pos, addr, IPV4_MAX_BYTELEN);
-       pos += IPV4_MAX_BYTELEN;
-
-       return add_tlv(tag, pos - value, value, stream);
-}
-
-int tlv_add_dynamic_hostname(struct hostname *hostname, struct stream *stream)
-{
-       return add_tlv(DYNAMIC_HOSTNAME, hostname->namelen, hostname->name,
-                      stream);
-}
-
-int tlv_add_lsp_entries(struct list *lsps, struct stream *stream)
-{
-       struct listnode *node;
-       struct isis_lsp *lsp;
-       u_char value[255];
-       u_char *pos = value;
-       int retval;
-
-       for (ALL_LIST_ELEMENTS_RO(lsps, node, lsp)) {
-               if (pos - value + LSP_ENTRIES_LEN > 255) {
-                       retval = add_tlv(LSP_ENTRIES, pos - value, value,
-                                        stream);
-                       if (retval != ISIS_OK)
-                               return retval;
-                       pos = value;
-               }
-               *((u_int16_t *)pos) = lsp->lsp_header->rem_lifetime;
-               pos += 2;
-               memcpy(pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
-               pos += ISIS_SYS_ID_LEN + 2;
-               *((u_int32_t *)pos) = lsp->lsp_header->seq_num;
-               pos += 4;
-               *((u_int16_t *)pos) = lsp->lsp_header->checksum;
-               pos += 2;
-       }
-
-       return add_tlv(LSP_ENTRIES, pos - value, value, stream);
-}
-
-static int tlv_add_ipv4_reachs(u_char tag, struct list *ipv4_reachs,
-                              struct stream *stream)
-{
-       struct listnode *node;
-       struct ipv4_reachability *reach;
-       u_char value[255];
-       u_char *pos = value;
-       int retval;
-
-       for (ALL_LIST_ELEMENTS_RO(ipv4_reachs, node, reach)) {
-               if (pos - value + IPV4_REACH_LEN > 255) {
-                       retval = add_tlv(tag, pos - value, value, stream);
-                       if (retval != ISIS_OK)
-                               return retval;
-                       pos = value;
-               }
-               *pos = reach->metrics.metric_default;
-               pos++;
-               *pos = reach->metrics.metric_delay;
-               pos++;
-               *pos = reach->metrics.metric_expense;
-               pos++;
-               *pos = reach->metrics.metric_error;
-               pos++;
-               *(u_int32_t *)pos = reach->prefix.s_addr;
-               pos += IPV4_MAX_BYTELEN;
-               *(u_int32_t *)pos = reach->mask.s_addr;
-               pos += IPV4_MAX_BYTELEN;
-       }
-
-       return add_tlv(tag, pos - value, value, stream);
-}
-
-int tlv_add_ipv4_int_reachs(struct list *ipv4_reachs, struct stream *stream)
-{
-       return tlv_add_ipv4_reachs(IPV4_INT_REACHABILITY, ipv4_reachs, stream);
-}
-
-int tlv_add_ipv4_ext_reachs(struct list *ipv4_reachs, struct stream *stream)
-{
-       return tlv_add_ipv4_reachs(IPV4_EXT_REACHABILITY, ipv4_reachs, stream);
-}
-
-
-unsigned int tlv_add_te_ipv4_reachs(struct list *te_ipv4_reachs,
-                                   struct stream *stream, void *arg)
-{
-       struct listnode *node;
-       struct te_ipv4_reachability *te_reach;
-       u_char value[255];
-       u_char *pos = value;
-       uint16_t mtid = arg ? *(uint16_t *)arg : ISIS_MT_IPV4_UNICAST;
-       unsigned int consumed = 0;
-       size_t max_size = max_tlv_size(stream);
-
-       if (mtid != ISIS_MT_IPV4_UNICAST) {
-               uint16_t mtid_conversion = ntohs(mtid);
-               memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
-               pos += sizeof(mtid_conversion);
-       }
-
-       for (ALL_LIST_ELEMENTS_RO(te_ipv4_reachs, node, te_reach)) {
-               unsigned char prefixlen = te_reach->control & 0x3F;
-
-               if ((size_t)(pos - value) + 5 + PSIZE(prefixlen) > max_size)
-                       break;
-
-               *(u_int32_t *)pos = te_reach->te_metric;
-               pos += 4;
-               *pos = te_reach->control;
-               pos++;
-               memcpy(pos, &te_reach->prefix_start, PSIZE(prefixlen));
-               pos += PSIZE(prefixlen);
-               consumed++;
-       }
-
-       if (consumed) {
-               int rv = add_tlv((mtid != ISIS_MT_IPV4_UNICAST)
-                                        ? MT_IPV4_REACHABILITY
-                                        : TE_IPV4_REACHABILITY,
-                                pos - value, value, stream);
-               assert(rv == ISIS_OK);
-       }
-
-       return consumed;
-}
-
-int tlv_add_ipv6_addrs(struct list *ipv6_addrs, struct stream *stream)
-{
-       struct listnode *node;
-       struct prefix_ipv6 *ipv6;
-       u_char value[255];
-       u_char *pos = value;
-       int retval;
-
-       for (ALL_LIST_ELEMENTS_RO(ipv6_addrs, node, ipv6)) {
-               if (pos - value + IPV6_MAX_BYTELEN > 255) {
-                       retval = add_tlv(IPV6_ADDR, pos - value, value, stream);
-                       if (retval != ISIS_OK)
-                               return retval;
-                       pos = value;
-               }
-               memcpy(pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN);
-               pos += IPV6_MAX_BYTELEN;
-       }
-
-       return add_tlv(IPV6_ADDR, pos - value, value, stream);
-}
-
-unsigned int tlv_add_ipv6_reachs(struct list *ipv6_reachs,
-                                struct stream *stream, void *arg)
-{
-       struct listnode *node;
-       struct ipv6_reachability *ip6reach;
-       u_char value[255];
-       u_char *pos = value;
-       uint16_t mtid = arg ? *(uint16_t *)arg : ISIS_MT_IPV4_UNICAST;
-       unsigned int consumed = 0;
-       size_t max_size = max_tlv_size(stream);
-
-       if (mtid != ISIS_MT_IPV4_UNICAST) {
-               uint16_t mtid_conversion = ntohs(mtid);
-               memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
-               pos += sizeof(mtid_conversion);
-       }
-
-       for (ALL_LIST_ELEMENTS_RO(ipv6_reachs, node, ip6reach)) {
-               if ((size_t)(pos - value) + 6 + PSIZE(ip6reach->prefix_len)
-                   > max_size)
-                       break;
-
-               *(uint32_t *)pos = ip6reach->metric;
-               pos += 4;
-               *pos = ip6reach->control_info;
-               pos++;
-               *pos = ip6reach->prefix_len;
-               pos++;
-               memcpy(pos, ip6reach->prefix, PSIZE(ip6reach->prefix_len));
-               pos += PSIZE(ip6reach->prefix_len);
-               consumed++;
-       }
-
-       if (consumed) {
-               int rv = add_tlv((mtid != ISIS_MT_IPV4_UNICAST)
-                                        ? MT_IPV6_REACHABILITY
-                                        : IPV6_REACHABILITY,
-                                pos - value, value, stream);
-               assert(rv == ISIS_OK);
-       }
-
-       return consumed;
-}
-
-int tlv_add_padding(struct stream *stream)
-{
-       int fullpads, i, left;
-
-       /*
-        * How many times can we add full padding ?
-        */
-       fullpads = (stream_get_size(stream) - stream_get_endp(stream)) / 257;
-       for (i = 0; i < fullpads; i++) {
-               if (!stream_putc(stream, (u_char)PADDING)) /* TAG */
-                       goto err;
-               if (!stream_putc(stream, (u_char)255)) /* LENGHT */
-                       goto err;
-               stream_put(stream, NULL, 255); /* zero padding */
-       }
-
-       left = stream_get_size(stream) - stream_get_endp(stream);
-
-       if (left < 2)
-               return ISIS_OK;
-
-       if (left == 2) {
-               stream_putc(stream, PADDING);
-               stream_putc(stream, 0);
-               return ISIS_OK;
-       }
-
-       stream_putc(stream, PADDING);
-       stream_putc(stream, left - 2);
-       stream_put(stream, NULL, left - 2);
-
-       return ISIS_OK;
-
-err:
-       zlog_warn("tlv_add_padding(): no room for tlv");
-       return ISIS_WARNING;
-}
diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h
deleted file mode 100644 (file)
index d065485..0000000
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * IS-IS Rout(e)ing protocol - isis_tlv.h
- *                             IS-IS TLV related routines
- *
- * Copyright (C) 2001,2002   Sampo Saaristo
- *                           Tampere University of Technology
- *                           Institute of Communications Engineering
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public Licenseas published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _ZEBRA_ISIS_TLV_H
-#define _ZEBRA_ISIS_TLV_H
-
-#include "isisd/isis_mt.h"
-
-/*
- * The list of TLVs we (should) support.
- * ____________________________________________________________________________
- * Name                   Value  IIH LSP SNP Status
- *                               LAN
- * ____________________________________________________________________________
- *
- * Area Addresses             1   y   y   n  ISO10589
- * IIS Neighbors              2   n   y   n  ISO10589
- * ES Neighbors               3   n   y   n  ISO10589
- * IIS Neighbors              6   y   n   n  ISO10589
- * Padding                    8   y   n   n  ISO10589
- * LSP Entries                9   n   n   y  ISO10589
- * Authentication            10   y   y   y  ISO10589, RFC3567
- * Checksum                  12   y   n   y  RFC3358
- * Extended IS Reachability  22   n   y   n  RFC5305
- * IS Alias                  24   n   y   n  RFC3786
- * IP Int. Reachability     128   n   y   n  RFC1195
- * Protocols Supported      129   y   y   n  RFC1195
- * IP Ext. Reachability     130   n   y   n  RFC1195
- * IDRPI                    131   n   y   y  RFC1195
- * IP Interface Address     132   y   y   n  RFC1195
- * TE Router ID             134   n   y   n  RFC5305
- * Extended IP Reachability 135   n   y   n  RFC5305
- * Dynamic Hostname         137   n   y   n  RFC2763
- * Shared Risk Link Group   138   n   y   y  RFC5307
- * Inter-AS Reachability    141   n   y   n  RFC5316
- * Restart TLV              211   y   n   n  RFC3847
- * MT IS Reachability       222   n   y   n  RFC5120
- * MT Supported             229   y   y   n  RFC5120
- * IPv6 Interface Address   232   y   y   n  RFC5308
- * MT IP Reachability       235   n   y   n  RFC5120
- * IPv6 IP Reachability     236   n   y   n  RFC5308
- * MT IPv6 IP Reachability  237   n   y   n  RFC5120
- * P2P Adjacency State      240   y   n   n  RFC3373
- * IIH Sequence Number      241   y   n   n  draft-shen-isis-iih-sequence
- * Router Capability        242   n   y   n  RFC4971
- *
- *
- * IS Reachability sub-TLVs we support (See isis_te.[c,h])
- * ____________________________________________________________________________
- * Name                           Value   Status
- * ____________________________________________________________________________
- * Administartive group (color)       3   RFC5305
- * Link Local/Remote Identifiers      4   RFC5307
- * IPv4 interface address             6   RFC5305
- * IPv4 neighbor address              8   RFC5305
- * Maximum link bandwidth             9   RFC5305
- * Reservable link bandwidth         10   RFC5305
- * Unreserved bandwidth              11   RFC5305
- * TE Default metric                 18   RFC5305
- * Link Protection Type              20   RFC5307
- * Interface Switching Capability    21   RFC5307
- * Remote AS number                  24   RFC5316
- * IPv4 Remote ASBR identifier       25   RFC5316
- *
- *
- * IP Reachability sub-TLVs we (should) support.
- * ____________________________________________________________________________
- * Name                           Value   Status
- * ____________________________________________________________________________
- * 32bit administrative tag           1   RFC5130
- * 64bit administrative tag           2   RFC5130
- * Management prefix color          117   RFC5120
- */
-
-#define AREA_ADDRESSES            1
-#define IS_NEIGHBOURS             2
-#define ES_NEIGHBOURS             3
-#define LAN_NEIGHBOURS            6
-#define PADDING                   8
-#define LSP_ENTRIES               9
-#define AUTH_INFO                 10
-#define CHECKSUM                  12
-#define TE_IS_NEIGHBOURS          22
-#define IS_ALIAS                  24
-#define IPV4_INT_REACHABILITY     128
-#define PROTOCOLS_SUPPORTED       129
-#define IPV4_EXT_REACHABILITY     130
-#define IDRP_INFO                 131
-#define IPV4_ADDR                 132
-#define TE_ROUTER_ID              134
-#define TE_IPV4_REACHABILITY      135
-#define DYNAMIC_HOSTNAME          137
-#define GRACEFUL_RESTART          211
-#define MT_IS_NEIGHBOURS          222
-#define MT_ROUTER_INFORMATION     229
-#define IPV6_ADDR                 232
-#define MT_IPV4_REACHABILITY      235
-#define IPV6_REACHABILITY         236
-#define MT_IPV6_REACHABILITY      237
-#define WAY3_HELLO                240
-#define ROUTER_INFORMATION        242
-
-#define AUTH_INFO_HDRLEN          3
-
-#define MAX_TLV_LEN 255
-
-#define IS_NEIGHBOURS_LEN (ISIS_SYS_ID_LEN + 5)
-#define LAN_NEIGHBOURS_LEN 6
-#define LSP_ENTRIES_LEN (10 + ISIS_SYS_ID_LEN) /* FIXME: should be entry */
-#define IPV4_REACH_LEN 12
-#define IPV6_REACH_LEN 22
-#define TE_IPV4_REACH_LEN 9
-
-#define MAX_SUBTLV_SIZE         256
-
-/* struct for neighbor */
-struct is_neigh {
-       struct metric metrics;
-       u_char neigh_id[ISIS_SYS_ID_LEN + 1];
-};
-
-/* struct for te metric */
-struct te_is_neigh {
-       u_char neigh_id[ISIS_SYS_ID_LEN + 1];
-       u_char te_metric[3];
-       u_char sub_tlvs_length;
-       /* Theorical Maximum SubTLVs is 256 because the sub_tlvs_length is 8
-        * bits */
-       /* Practically, 118 bytes are necessary to store all supported TE
-        * parameters */
-       /* FIXME: A pointer will use less memory, but need to be free */
-       /* which is hard to fix, especially within free_tlvs() function */
-       /* and malloc() / free() as a CPU cost compared to the memory usage */
-       u_char sub_tlvs[MAX_SUBTLV_SIZE]; /* SUB TLVs storage */
-};
-
-/* Decode and encode three-octet metric into host byte order integer */
-#define GET_TE_METRIC(t)                                                       \
-       (((unsigned)(t)->te_metric[0] << 16) | ((t)->te_metric[1] << 8)        \
-        | (t)->te_metric[2])
-#define SET_TE_METRIC(t, m)                                                    \
-       (((t)->te_metric[0] = (m) >> 16), ((t)->te_metric[1] = (m) >> 8),      \
-        ((t)->te_metric[2] = (m)))
-
-/* struct for es neighbors */
-struct es_neigh {
-       struct metric metrics;
-       /* approximate position of first, we use the
-        * length ((uchar*)metric-1) to know all     */
-       u_char first_es_neigh[ISIS_SYS_ID_LEN];
-};
-
-struct partition_desig_level2_is {
-       struct list *isis_system_ids;
-};
-
-/* struct for lan neighbors */
-struct lan_neigh {
-       u_char LAN_addr[6];
-};
-
-#ifdef __SUNPRO_C
-#pragma pack(1)
-#endif
-
-/* struct for LSP entry */
-struct lsp_entry {
-       u_int16_t rem_lifetime;
-       u_char lsp_id[ISIS_SYS_ID_LEN + 2];
-       u_int32_t seq_num;
-       u_int16_t checksum;
-} __attribute__((packed));
-
-#ifdef __SUNPRO_C
-#pragma pack()
-#endif
-
-/* struct for checksum */
-struct checksum {
-       u_int16_t checksum;
-};
-
-/* ipv4 reachability */
-struct ipv4_reachability {
-       struct metric metrics;
-       struct in_addr prefix;
-       struct in_addr mask;
-};
-
-/* te router id */
-struct te_router_id {
-       struct in_addr id;
-};
-
-/* te ipv4 reachability */
-struct te_ipv4_reachability {
-       u_int32_t te_metric;
-       u_char control;
-       u_char prefix_start; /* since this is variable length by nature it only
-                               */
-};                          /* points to an approximate location */
-
-#define TE_IPV4_HAS_SUBTLV (0x40)
-
-struct idrp_info {
-       u_char len;
-       u_char *value;
-};
-
-struct ipv6_reachability {
-       u_int32_t metric;
-       u_char control_info;
-       u_char prefix_len;
-       u_char prefix[16];
-};
-
-/* bits in control_info */
-#define CTRL_INFO_DIRECTION    0x80
-#define DIRECTION_UP           0x00
-#define DIRECTION_DOWN         0x80
-
-#define CTRL_INFO_DISTRIBUTION 0x40
-#define DISTRIBUTION_INTERNAL  0x00
-#define DISTRIBUTION_EXTERNAL  0x40
-
-#define CTRL_INFO_SUBTLVS      0x20
-
-struct mt_router_info {
-       ISIS_MT_INFO_FIELDS
-       bool overload;
-};
-
-/*
- * Pointer to each tlv type, filled by parse_tlvs()
- */
-struct tlvs {
-       struct checksum *checksum;
-       struct hostname *hostname;
-       struct nlpids *nlpids;
-       struct te_router_id *router_id;
-       struct list *area_addrs;
-       struct list *mt_router_info;
-       struct list *is_neighs;
-       struct list *te_is_neighs;
-       struct list *mt_is_neighs;
-       struct list *es_neighs;
-       struct list *lsp_entries;
-       struct list *prefix_neighs;
-       struct list *lan_neighs;
-       struct list *ipv4_addrs;
-       struct list *ipv4_int_reachs;
-       struct list *ipv4_ext_reachs;
-       struct list *te_ipv4_reachs;
-       struct list *mt_ipv4_reachs;
-       struct list *ipv6_addrs;
-       struct list *ipv6_reachs;
-       struct list *mt_ipv6_reachs;
-       struct isis_passwd auth_info;
-};
-
-/*
- * Own definitions - used to bitmask found and expected
- */
-
-#define TLVFLAG_AREA_ADDRS                (1<<0)
-#define TLVFLAG_IS_NEIGHS                 (1<<1)
-#define TLVFLAG_ES_NEIGHS                 (1<<2)
-#define TLVFLAG_PARTITION_DESIG_LEVEL2_IS (1<<3)
-#define TLVFLAG_PREFIX_NEIGHS             (1<<4)
-#define TLVFLAG_LAN_NEIGHS                (1<<5)
-#define TLVFLAG_LSP_ENTRIES               (1<<6)
-#define TLVFLAG_PADDING                   (1<<7)
-#define TLVFLAG_AUTH_INFO                 (1<<8)
-#define TLVFLAG_IPV4_INT_REACHABILITY     (1<<9)
-#define TLVFLAG_NLPID                     (1<<10)
-#define TLVFLAG_IPV4_EXT_REACHABILITY     (1<<11)
-#define TLVFLAG_IPV4_ADDR                 (1<<12)
-#define TLVFLAG_DYN_HOSTNAME              (1<<13)
-#define TLVFLAG_IPV6_ADDR                 (1<<14)
-#define TLVFLAG_IPV6_REACHABILITY         (1<<15)
-#define TLVFLAG_TE_IS_NEIGHS              (1<<16)
-#define TLVFLAG_TE_IPV4_REACHABILITY      (1<<17)
-#define TLVFLAG_3WAY_HELLO                (1<<18)
-#define TLVFLAG_TE_ROUTER_ID              (1<<19)
-#define TLVFLAG_CHECKSUM                  (1<<20)
-#define TLVFLAG_GRACEFUL_RESTART          (1<<21)
-#define TLVFLAG_MT_ROUTER_INFORMATION     (1<<22)
-
-void init_tlvs(struct tlvs *tlvs, uint32_t expected);
-void free_tlvs(struct tlvs *tlvs);
-int parse_tlvs(char *areatag, u_char *stream, int size, u_int32_t *expected,
-              u_int32_t *found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset);
-int add_tlv(u_char, u_char, u_char *, struct stream *);
-void free_tlv(void *val);
-
-int tlv_add_mt_router_info(struct list *mt_router_info, struct stream *stream);
-int tlv_add_area_addrs(struct list *area_addrs, struct stream *stream);
-int tlv_add_is_neighs(struct list *is_neighs, struct stream *stream);
-unsigned int tlv_add_te_is_neighs(struct list *te_is_neighs,
-                                 struct stream *stream, void *arg);
-int tlv_add_lan_neighs(struct list *lan_neighs, struct stream *stream);
-int tlv_add_nlpid(struct nlpids *nlpids, struct stream *stream);
-int tlv_add_checksum(struct checksum *checksum, struct stream *stream);
-int tlv_add_authinfo(u_char auth_type, u_char authlen, u_char *auth_value,
-                    struct stream *stream);
-int tlv_add_ip_addrs(struct list *ip_addrs, struct stream *stream);
-int tlv_add_in_addr(struct in_addr *, struct stream *stream, u_char tag);
-int tlv_add_dynamic_hostname(struct hostname *hostname, struct stream *stream);
-int tlv_add_lsp_entries(struct list *lsps, struct stream *stream);
-int tlv_add_ipv4_int_reachs(struct list *ipv4_reachs, struct stream *stream);
-int tlv_add_ipv4_ext_reachs(struct list *ipv4_reachs, struct stream *stream);
-unsigned int tlv_add_te_ipv4_reachs(struct list *te_ipv4_reachs,
-                                   struct stream *stream, void *arg);
-int tlv_add_ipv6_addrs(struct list *ipv6_addrs, struct stream *stream);
-unsigned int tlv_add_ipv6_reachs(struct list *ipv6_reachs,
-                                struct stream *stream, void *arg);
-
-int tlv_add_padding(struct stream *stream);
-
-#endif /* _ZEBRA_ISIS_TLV_H */
index 18a59d1fc5ac2f244bbc14dee726574b8bc653a8..8c6968f8ececb27686c963de912b9c8776dd171d 100644 (file)
@@ -42,7 +42,6 @@
 #include "isisd/isis_flags.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_circuit.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_csm.h"
index 8bbb5cf94909e54b01b9947fd5ba0fb3d47df3b5..05797fb73add6ee63f49e6e904940b01676f0e69 100644 (file)
@@ -49,7 +49,6 @@
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_constants.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_spf.h"
 #include "isisd/isis_route.h"
index e0a4ba3700530a0cdd7c25c2282aa960bf04daa1..25a870991a9a22c4abaf781ddbc428483c7d3e5a 100644 (file)
@@ -67,7 +67,7 @@ int iso_csum_verify(u_char *buffer, int len, uint16_t csum, int offset)
                return 1;
 
        checksum = fletcher_checksum(buffer, len, offset);
-       if (checksum == csum)
+       if (checksum == htons(csum))
                return 0;
        return 1;
 }