From: Christian Franke Date: Thu, 27 Apr 2017 11:56:43 +0000 (+0200) Subject: isisd: announce and parse MT IS reachabilities X-Git-Tag: reindent-master-before~209^2~2 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=206f4aae58385290ca6d0bb376cf20b6b1e194da;p=matthieu%2Ffrr.git isisd: announce and parse MT IS reachabilities Signed-off-by: Christian Franke --- diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index c6fc6b008d..fea99ec907 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -47,6 +47,7 @@ #include "isisd/isis_lsp.h" #include "isisd/isis_spf.h" #include "isisd/isis_events.h" +#include "isisd/isis_mt.h" extern struct isis *isis; diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index d7d76942a6..5009c34b02 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -828,6 +828,34 @@ lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost) 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) { @@ -835,12 +863,12 @@ 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]; @@ -978,15 +1006,12 @@ lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) } /* 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) @@ -1039,6 +1064,42 @@ 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) @@ -1637,10 +1698,8 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) /* 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); } } } @@ -1697,9 +1756,9 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) 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 @@ -1791,13 +1850,31 @@ lsp_build (struct isis_lsp *lsp, struct isis_area *area) { 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); @@ -2234,7 +2311,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, 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); diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index 4e36b91433..e66c9d7d9c 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -26,11 +26,14 @@ #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) @@ -362,6 +365,7 @@ circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count) return rv; } +/* ADJ specific MT API */ static void adj_mt_set(struct isis_adjacency *adj, unsigned int index, uint16_t mtid) { @@ -437,3 +441,156 @@ adj_mt_finish(struct isis_adjacency *adj) 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); +} diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index 3ad8c05e47..313e992b4a 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -53,6 +53,8 @@ #define ISIS_MT_INFO_FIELDS \ uint16_t mtid; +struct list; + struct isis_area_mt_setting { ISIS_MT_INFO_FIELDS bool enabled; @@ -64,6 +66,11 @@ struct isis_circuit_mt_setting { 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); @@ -71,6 +78,10 @@ struct isis_adjacency; 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); @@ -107,4 +118,8 @@ struct isis_circuit_mt_setting** circuit_mt_settings(struct isis_circuit *circui 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 diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index 14ebed94d3..41c861bf58 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -43,6 +43,7 @@ #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) @@ -67,6 +68,8 @@ free_tlvs (struct tlvs *tlvs) 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) @@ -93,6 +96,83 @@ free_tlvs (struct tlvs *tlvs) 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. @@ -105,7 +185,6 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, 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; @@ -209,54 +288,25 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, 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: @@ -950,26 +1000,44 @@ tlv_add_is_neighs (struct list *is_neighs, struct stream *stream) 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); @@ -983,9 +1051,17 @@ tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream) 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 diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h index 12025ff73a..f3c04baf54 100644 --- a/isisd/isis_tlv.h +++ b/isisd/isis_tlv.h @@ -111,6 +111,7 @@ #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 @@ -272,6 +273,7 @@ struct tlvs 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; @@ -324,7 +326,7 @@ 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); -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);