#include "isisd/isis_lsp.h"
#include "isisd/isis_spf.h"
#include "isisd/isis_events.h"
+#include "isisd/isis_mt.h"
extern struct isis *isis;
lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
}
+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 : %-8d IS-Extended : %s%s",
+ GET_TE_METRIC(neigh), lspid, VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out(vty, " Metric : %-8d MT-Reach : %s %s%s",
+ GET_TE_METRIC(neigh), lspid,
+ isis_mtid2str(mtid), VTY_NEWLINE);
+ }
+ if (IS_MPLS_TE(isisMplsTE))
+ mpls_te_print_detail(vty, neigh);
+ }
+}
+
void
lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
{
int i;
struct listnode *lnode;
struct is_neigh *is_neigh;
- struct te_is_neigh *te_is_neigh;
struct ipv4_reachability *ipv4_reach;
struct in_addr *ipv4_addr;
struct te_ipv4_reachability *te_ipv4_reach;
struct ipv6_reachability *ipv6_reach;
struct mt_router_info *mt_router_info;
+ struct tlv_mt_neighbors *mt_is_neigh;
struct in6_addr in6;
u_char buff[BUFSIZ];
u_char LSPid[255];
}
/* TE IS neighbor tlv */
- if (lsp->tlv_data.te_is_neighs)
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
- {
- lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
- vty_out (vty, " Metric : %-8d IS-Extended : %s%s",
- GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
- if (IS_MPLS_TE(isisMplsTE))
- mpls_te_print_detail(vty, te_is_neigh);
- }
+ 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 */
if (lsp->tlv_data.te_ipv4_reachs)
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)
/* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
te_is_neigh->sub_tlvs_length = 0;
- listnode_add (tlv_data.te_is_neighs, te_is_neigh);
- lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor",
- area->area_tag, sysid_print(te_is_neigh->neigh_id),
- LSP_PSEUDO_ID(te_is_neigh->neigh_id));
+ tlvs_add_mt_bcast(&tlv_data, circuit, level, te_is_neigh);
+ XFREE(MTYPE_ISIS_TLV, te_is_neigh);
}
}
}
else
/* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
te_is_neigh->sub_tlvs_length = 0;
- listnode_add (tlv_data.te_is_neighs, te_is_neigh);
- lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag,
- sysid_print(te_is_neigh->neigh_id));
+
+ tlvs_add_mt_p2p(&tlv_data, circuit, te_is_neigh);
+ XFREE(MTYPE_ISIS_TLV, te_is_neigh);
}
}
else
{
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,
- IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
- tlv_add_te_is_neighs);
+ _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 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);
+ }
+ }
+
+
lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
free_tlvs (&tlv_data);
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);
+ 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);
#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")
/* MT naming api */
const char *isis_mtid2str(uint16_t mtid)
return rv;
}
+/* ADJ specific MT API */
static void adj_mt_set(struct isis_adjacency *adj, unsigned int index,
uint16_t mtid)
{
XFREE(MTYPE_MT_ADJ_INFO, adj->mt_set);
adj->mt_count = 0;
}
+
+/* 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;
+}
+
+static void
+mt_set_add(uint16_t **mt_set, unsigned int *size,
+ unsigned int *index, uint16_t mtid)
+{
+ for (unsigned int i = 0; i < *index; i++)
+ {
+ if ((*mt_set)[i] == mtid)
+ return;
+ }
+
+ if (*index >= *size)
+ {
+ *mt_set = XREALLOC(MTYPE_TMP, *mt_set, sizeof(**mt_set) * ((*index) + 1));
+ *size = (*index) + 1;
+ }
+
+ (*mt_set)[*index] = mtid;
+ *index = (*index) + 1;
+}
+
+static uint16_t *
+circuit_bcast_mt_set(struct isis_circuit *circuit, int level,
+ unsigned int *mt_count)
+{
+ static uint16_t *rv;
+ static unsigned int size;
+ struct listnode *node;
+ struct isis_adjacency *adj;
+
+ unsigned int count = 0;
+
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST)
+ {
+ *mt_count = 0;
+ return NULL;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(circuit->u.bc.adjdb[level - 1], node, adj))
+ {
+ if (adj->adj_state != ISIS_ADJ_UP)
+ continue;
+ for (unsigned int i = 0; i < adj->mt_count; i++)
+ mt_set_add(&rv, &size, &count, adj->mt_set[i]);
+ }
+
+ *mt_count = count;
+ return rv;
+}
+
+static void
+tlvs_add_mt_set(struct isis_area *area,
+ struct tlvs *tlvs, unsigned int mt_count,
+ uint16_t *mt_set, struct te_is_neigh *neigh)
+{
+ 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));
+ }
+ 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));
+ }
+ }
+}
+
+void
+tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
+ int level, struct te_is_neigh *neigh)
+{
+ 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);
+}
+
+void
+tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
+ struct te_is_neigh *neigh)
+{
+ struct isis_adjacency *adj = circuit->u.p2p.neighbor;
+
+ tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, neigh);
+}
#define ISIS_MT_INFO_FIELDS \
uint16_t mtid;
+struct list;
+
struct isis_area_mt_setting {
ISIS_MT_INFO_FIELDS
bool enabled;
bool enabled;
};
+struct tlv_mt_neighbors {
+ ISIS_MT_INFO_FIELDS
+ struct list *list;
+};
+
const char *isis_mtid2str(uint16_t mtid);
uint16_t isis_str2mtid(const char *name);
struct isis_area;
struct isis_circuit;
struct tlvs;
+struct te_is_neigh;
+
+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 isis_area_mt_setting* area_lookup_mt_setting(struct isis_area *area,
uint16_t mtid);
bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
struct isis_adjacency *adj);
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);
#endif
#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)
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)
return;
}
+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;
+
+ if (read_mtid)
+ {
+ 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;
+ }
+ else
+ {
+ mtid = ISIS_MT_IPV4_UNICAST;
+ }
+
+ 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;
+}
+
/*
* 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.
struct lan_neigh *lan_nei;
struct area_addr *area_addr;
struct is_neigh *is_nei;
- struct te_is_neigh *te_is_nei;
struct es_neigh *es_nei;
struct lsp_entry *lsp_entry;
struct in_addr *ipv4_addr;
break;
case TE_IS_NEIGHBOURS:
- /* +-------+-------+-------+-------+-------+-------+-------+-------+
- * | Neighbour ID | 7
- * +---------------------------------------------------------------+
- * | TE Metric | 3
- * +---------------------------------------------------------------+
- * | SubTLVs Length | 1
- * +---------------------------------------------------------------+
- * : :
- */
*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)
- {
- while (length > value_len)
- {
- te_is_nei = (struct te_is_neigh *) pnt;
- value_len += IS_NEIGHBOURS_LEN;
- pnt += IS_NEIGHBOURS_LEN;
- /* FIXME - subtlvs are handled here, for now we skip */
- /* FIXME: All TE SubTLVs are not necessary present in LSP PDU. */
- /* So, it must be copied in a new te_is_neigh structure */
- /* rather than just initialize pointer to the original LSP PDU */
- /* to avoid consider the rest of lspdu as subTLVs or buffer overflow */
- if (IS_MPLS_TE(isisMplsTE))
- {
- struct te_is_neigh *new = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh));
- memcpy(new->neigh_id, te_is_nei->neigh_id, ISIS_SYS_ID_LEN + 1);
- memcpy(new->te_metric, te_is_nei->te_metric, 3);
- new->sub_tlvs_length = te_is_nei->sub_tlvs_length;
- memcpy(new->sub_tlvs, pnt, te_is_nei->sub_tlvs_length);
- te_is_nei = new;
- }
- /* Skip SUB TLVs payload */
- value_len += te_is_nei->sub_tlvs_length;
- pnt += te_is_nei->sub_tlvs_length;
-
- if (!tlvs->te_is_neighs)
- tlvs->te_is_neighs = list_new ();
- listnode_add (tlvs->te_is_neighs, te_is_nei);
- }
- }
- else
- {
- pnt += length;
- }
+ 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:
return add_tlv (IS_NEIGHBOURS, pos - value, value, stream);
}
-int
-tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *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;
- int retval;
+ 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 (pos - value + IS_NEIGHBOURS_LEN + te_is_neigh->sub_tlvs_length > 255)
- {
- retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
- if (retval != ISIS_OK)
- return retval;
- pos = value;
- }
-
+ 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);
memcpy (pos, te_is_neigh->sub_tlvs, te_is_neigh->sub_tlvs_length);
pos += te_is_neigh->sub_tlvs_length;
}
+ consumed++;
}
- return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream);
+ 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
#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 IPV6_REACHABILITY 236
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;
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);
-int tlv_add_te_is_neighs (struct list *te_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);