diff options
-rw-r--r-- | isisd/isis_adjacency.c | 79 | ||||
-rw-r--r-- | isisd/isis_adjacency.h | 15 | ||||
-rw-r--r-- | isisd/isis_memory.c | 1 | ||||
-rw-r--r-- | isisd/isis_memory.h | 1 | ||||
-rw-r--r-- | isisd/isis_mt.c | 15 | ||||
-rw-r--r-- | isisd/isis_mt.h | 3 | ||||
-rw-r--r-- | isisd/isis_pdu.c | 1113 | ||||
-rw-r--r-- | isisd/isis_route.c | 14 | ||||
-rw-r--r-- | isisd/isis_te.c | 10 |
9 files changed, 382 insertions, 869 deletions
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index d8cb32375..e13b3769e 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -69,11 +69,6 @@ struct isis_adjacency *isis_new_adj(const u_char *id, const u_char *snpa, adj = adj_alloc(id); /* P2P kludge */ - if (adj == NULL) { - zlog_err("Out of memory!"); - return NULL; - } - if (snpa) { memcpy(adj->snpa, snpa, ETH_ALEN); } else { @@ -137,12 +132,12 @@ void isis_delete_adj(void *arg) /* remove from SPF trees */ spftree_area_adj_del(adj->circuit->area, adj); - if (adj->area_addrs) - list_delete(adj->area_addrs); - if (adj->ipv4_addrs) - list_delete(adj->ipv4_addrs); - if (adj->ipv6_addrs) - list_delete(adj->ipv6_addrs); + if (adj->area_addresses) + XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses); + if (adj->ipv4_addresses) + XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses); + if (adj->ipv6_addresses) + XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses); adj_mt_finish(adj); @@ -301,10 +296,6 @@ void isis_adj_state_change(struct isis_adjacency *adj, void isis_adj_print(struct isis_adjacency *adj) { struct isis_dynhn *dyn; - struct listnode *node; - struct in_addr *ipv4_addr; - struct in6_addr *ipv6_addr; - u_char ip6[INET6_ADDRSTRLEN]; if (!adj) return; @@ -315,19 +306,19 @@ void isis_adj_print(struct isis_adjacency *adj) zlog_debug("SystemId %20s SNPA %s, level %d\nHolding Time %d", sysid_print(adj->sysid), snpa_print(adj->snpa), adj->level, adj->hold_time); - if (adj->ipv4_addrs && listcount(adj->ipv4_addrs) > 0) { + if (adj->ipv4_address_count) { zlog_debug("IPv4 Address(es):"); - - for (ALL_LIST_ELEMENTS_RO(adj->ipv4_addrs, node, ipv4_addr)) - zlog_debug("%s", inet_ntoa(*ipv4_addr)); + for (unsigned int i = 0; i < adj->ipv4_address_count; i++) + zlog_debug("%s", inet_ntoa(adj->ipv4_addresses[i])); } - if (adj->ipv6_addrs && listcount(adj->ipv6_addrs) > 0) { + if (adj->ipv6_address_count) { zlog_debug("IPv6 Address(es):"); - for (ALL_LIST_ELEMENTS_RO(adj->ipv6_addrs, node, ipv6_addr)) { - inet_ntop(AF_INET6, ipv6_addr, (char *)ip6, - INET6_ADDRSTRLEN); - zlog_debug("%s", ip6); + for (unsigned int i = 0; i < adj->ipv6_address_count; i++) { + char buf[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &adj->ipv6_addresses[i], buf, + sizeof(buf)); + zlog_debug("%s", buf); } } zlog_debug("Speaks: %s", nlpid2string(&adj->nlpids)); @@ -358,13 +349,9 @@ int isis_adj_expire(struct thread *thread) void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, char detail) { - struct in6_addr *ipv6_addr; - u_char ip6[INET6_ADDRSTRLEN]; - struct in_addr *ip_addr; time_t now; struct isis_dynhn *dyn; int level; - struct listnode *node; dyn = dynhn_find_by_id(adj->sysid); if (dyn) @@ -452,28 +439,32 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, } vty_out(vty, "\n"); - if (adj->area_addrs && listcount(adj->area_addrs) > 0) { - struct area_addr *area_addr; + if (adj->area_address_count) { vty_out(vty, " Area Address(es):\n"); - for (ALL_LIST_ELEMENTS_RO(adj->area_addrs, node, - area_addr)) + for (unsigned int i = 0; i < adj->area_address_count; + i++) { vty_out(vty, " %s\n", - isonet_print(area_addr->area_addr, - area_addr->addr_len)); + isonet_print(adj->area_addresses[i] + .area_addr, + adj->area_addresses[i] + .addr_len)); + } } - if (adj->ipv4_addrs && listcount(adj->ipv4_addrs) > 0) { + if (adj->ipv4_address_count) { vty_out(vty, " IPv4 Address(es):\n"); - for (ALL_LIST_ELEMENTS_RO(adj->ipv4_addrs, node, - ip_addr)) - vty_out(vty, " %s\n", inet_ntoa(*ip_addr)); + for (unsigned int i = 0; i < adj->ipv4_address_count; + i++) + vty_out(vty, " %s\n", + inet_ntoa(adj->ipv4_addresses[i])); } - if (adj->ipv6_addrs && listcount(adj->ipv6_addrs) > 0) { + if (adj->ipv6_address_count) { vty_out(vty, " IPv6 Address(es):\n"); - for (ALL_LIST_ELEMENTS_RO(adj->ipv6_addrs, node, - ipv6_addr)) { - inet_ntop(AF_INET6, ipv6_addr, (char *)ip6, - INET6_ADDRSTRLEN); - vty_out(vty, " %s\n", ip6); + for (unsigned int i = 0; i < adj->ipv6_address_count; + i++) { + char buf[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &adj->ipv6_addresses[i], + buf, sizeof(buf)); + vty_out(vty, " %s\n", buf); } } vty_out(vty, "\n"); diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index 9f4af1b45..98bb9838f 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -73,13 +73,16 @@ struct isis_adjacency { int dischanges[ISIS_LEVELS]; /* how many DIS changes ? */ /* an array of N levels for M records */ struct isis_dis_record dis_record[DIS_RECORDS * ISIS_LEVELS]; - enum isis_adj_state adj_state; /* adjacencyState */ - enum isis_adj_usage adj_usage; /* adjacencyUsage */ - struct list *area_addrs; /* areaAdressesOfNeighbour */ - struct nlpids nlpids; /* protocols spoken ... */ - struct list *ipv4_addrs; + enum isis_adj_state adj_state; /* adjacencyState */ + enum isis_adj_usage adj_usage; /* adjacencyUsage */ + struct area_addr *area_addresses; /* areaAdressesOfNeighbour */ + unsigned int area_address_count; + struct nlpids nlpids; /* protocols spoken ... */ + struct in_addr *ipv4_addresses; + unsigned int ipv4_address_count; struct in_addr router_address; - struct list *ipv6_addrs; + struct in6_addr *ipv6_addresses; + unsigned int ipv6_address_count; struct in6_addr router_address6; u_char prio[ISIS_LEVELS]; /* priorityOfNeighbour for DIS */ int circuit_t; /* from hello PDU hdr */ diff --git a/isisd/isis_memory.c b/isisd/isis_memory.c index 4ad26cf91..f88442949 100644 --- a/isisd/isis_memory.c +++ b/isisd/isis_memory.c @@ -31,6 +31,7 @@ DEFINE_MTYPE(ISISD, ISIS_TMP, "ISIS TMP") DEFINE_MTYPE(ISISD, ISIS_CIRCUIT, "ISIS circuit") DEFINE_MTYPE(ISISD, ISIS_LSP, "ISIS LSP") DEFINE_MTYPE(ISISD, ISIS_ADJACENCY, "ISIS adjacency") +DEFINE_MTYPE(ISISD, ISIS_ADJACENCY_INFO, "ISIS adjacency info") DEFINE_MTYPE(ISISD, ISIS_AREA, "ISIS area") DEFINE_MTYPE(ISISD, ISIS_AREA_ADDR, "ISIS area address") DEFINE_MTYPE(ISISD, ISIS_TLV, "ISIS TLV") diff --git a/isisd/isis_memory.h b/isisd/isis_memory.h index 7729ebac3..e204704c8 100644 --- a/isisd/isis_memory.h +++ b/isisd/isis_memory.h @@ -30,6 +30,7 @@ DECLARE_MTYPE(ISIS_TMP) DECLARE_MTYPE(ISIS_CIRCUIT) DECLARE_MTYPE(ISIS_LSP) DECLARE_MTYPE(ISIS_ADJACENCY) +DECLARE_MTYPE(ISIS_ADJACENCY_INFO) DECLARE_MTYPE(ISIS_AREA) DECLARE_MTYPE(ISIS_AREA_ADDR) DECLARE_MTYPE(ISIS_TLV) diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index 46b57510a..ff0b95487 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -28,6 +28,7 @@ #include "isisd/isis_misc.h" #include "isisd/isis_lsp.h" #include "isisd/isis_mt.h" +#include "isisd/isis_tlvs2.h" DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting") DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting") @@ -367,7 +368,7 @@ static void adj_mt_set(struct isis_adjacency *adj, unsigned int index, adj->mt_set[index] = mtid; } -bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable, +bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable, struct isis_adjacency *adj) { struct isis_circuit_mt_setting **mt_settings; @@ -388,17 +389,19 @@ bool tlvs_to_adj_mt_set(struct 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) { + 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) adj_mt_set(adj, intersect_count++, ISIS_MT_IPV4_UNICAST); } else { - struct listnode *node; - struct mt_router_info *info; - for (ALL_LIST_ELEMENTS_RO(tlvs->mt_router_info, node, - info)) { + struct isis_mt_router_info *info_head; + + info_head = (struct isis_mt_router_info *) + tlvs->mt_router_info.head; + for (struct isis_mt_router_info *info = info_head; info; + info = info->next) { if (mt_settings[i]->mtid == info->mtid) { bool usable; switch (info->mtid) { diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index 57a747990..496da8558 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -88,6 +88,7 @@ struct isis_area; struct isis_circuit; struct tlvs; struct te_is_neigh; +struct isis_tlvs; uint16_t isis_area_ipv6_topology(struct isis_area *area); @@ -138,7 +139,7 @@ circuit_get_mt_setting(struct isis_circuit *circuit, uint16_t mtid); int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty); struct isis_circuit_mt_setting ** circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count); -bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable, +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); diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 937bd3bbe..047a3f08d 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -54,6 +54,7 @@ #include "isisd/isis_events.h" #include "isisd/isis_te.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 */ @@ -67,26 +68,6 @@ */ /* - * Compares two sets of area addresses - */ -static int area_match(struct list *left, struct list *right) -{ - struct area_addr *addr1, *addr2; - struct listnode *node1, *node2; - - for (ALL_LIST_ELEMENTS_RO(left, node1, addr1)) { - for (ALL_LIST_ELEMENTS_RO(right, node2, addr2)) { - if (addr1->addr_len == addr2->addr_len - && !memcmp(addr1->area_addr, addr2->area_addr, - (int)addr1->addr_len)) - return 1; /* match */ - } - } - - return 0; /* mismatch */ -} - -/* * Checks whether we should accept a PDU of given level */ static int accept_level(int level, int circuit_t) @@ -209,342 +190,81 @@ static int lsp_authentication_check(struct stream *stream, } /* - * Processing helper functions - */ -static void del_addr(void *val) -{ - XFREE(MTYPE_ISIS_TMP, val); -} - -static void tlvs_to_adj_area_addrs(struct tlvs *tlvs, - struct isis_adjacency *adj) -{ - struct listnode *node; - struct area_addr *area_addr, *malloced; - - if (adj->area_addrs) { - adj->area_addrs->del = del_addr; - list_delete(adj->area_addrs); - } - adj->area_addrs = list_new(); - if (tlvs->area_addrs) { - for (ALL_LIST_ELEMENTS_RO(tlvs->area_addrs, node, area_addr)) { - malloced = XMALLOC(MTYPE_ISIS_TMP, - sizeof(struct area_addr)); - memcpy(malloced, area_addr, sizeof(struct area_addr)); - listnode_add(adj->area_addrs, malloced); - } - } -} - -static int tlvs_to_adj_nlpids(struct tlvs *tlvs, struct isis_adjacency *adj) -{ - int i; - struct nlpids *tlv_nlpids; - - if (tlvs->nlpids) { - - tlv_nlpids = tlvs->nlpids; - if (tlv_nlpids->count > array_size(adj->nlpids.nlpids)) - return 1; - - adj->nlpids.count = tlv_nlpids->count; - - for (i = 0; i < tlv_nlpids->count; i++) { - adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i]; - } - } - return 0; -} - -static void tlvs_to_adj_ipv4_addrs(struct tlvs *tlvs, - struct isis_adjacency *adj) -{ - struct listnode *node; - struct in_addr *ipv4_addr, *malloced; - - if (adj->ipv4_addrs) { - adj->ipv4_addrs->del = del_addr; - list_delete(adj->ipv4_addrs); - } - adj->ipv4_addrs = list_new(); - if (tlvs->ipv4_addrs) { - for (ALL_LIST_ELEMENTS_RO(tlvs->ipv4_addrs, node, ipv4_addr)) { - malloced = - XMALLOC(MTYPE_ISIS_TMP, sizeof(struct in_addr)); - memcpy(malloced, ipv4_addr, sizeof(struct in_addr)); - listnode_add(adj->ipv4_addrs, malloced); - } - } -} - -static void tlvs_to_adj_ipv6_addrs(struct tlvs *tlvs, - struct isis_adjacency *adj) -{ - struct listnode *node; - struct in6_addr *ipv6_addr, *malloced; - - if (adj->ipv6_addrs) { - adj->ipv6_addrs->del = del_addr; - list_delete(adj->ipv6_addrs); - } - adj->ipv6_addrs = list_new(); - if (tlvs->ipv6_addrs) { - for (ALL_LIST_ELEMENTS_RO(tlvs->ipv6_addrs, node, ipv6_addr)) { - malloced = XMALLOC(MTYPE_ISIS_TMP, - sizeof(struct in6_addr)); - memcpy(malloced, ipv6_addr, sizeof(struct in6_addr)); - listnode_add(adj->ipv6_addrs, malloced); - } - } -} - -/* * RECEIVE SIDE */ -/* - * Process P2P IIH - * ISO - 10589 - * Section 8.2.5 - Receiving point-to-point IIH PDUs - * - */ -static int process_p2p_hello(struct isis_circuit *circuit) -{ - int retval = ISIS_OK; - struct isis_p2p_hello_hdr *hdr; - struct isis_adjacency *adj; - u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; - uint16_t pdu_len; - struct tlvs tlvs; - int v4_usable = 0, v6_usable = 0; - - if (isis->debugs & DEBUG_ADJ_PACKETS) { - zlog_debug( - "ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u", - circuit->area->area_tag, circuit->interface->name, - circuit_t2string(circuit->is_type), - circuit->circuit_id); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data(STREAM_DATA(circuit->rcv_stream), - stream_get_endp(circuit->rcv_stream)); - } - - if (circuit->circ_type != CIRCUIT_T_P2P) { - zlog_warn("p2p hello on non p2p circuit"); - return ISIS_WARNING; - } - - if ((stream_get_endp(circuit->rcv_stream) - - stream_get_getp(circuit->rcv_stream)) - < ISIS_P2PHELLO_HDRLEN) { - zlog_warn("Packet too short"); - return ISIS_WARNING; - } - - /* 8.2.5.1 PDU acceptance tests */ - - /* 8.2.5.1 a) external domain untrue */ - /* FIXME: not useful at all? */ - - /* 8.2.5.1 b) ID Length mismatch */ - /* checked at the handle_pdu */ - - /* 8.2.5.2 IIH PDU Processing */ - - /* 8.2.5.2 a) 1) Maximum Area Addresses */ - /* Already checked, and can also be ommited */ - - /* - * Get the header - */ - hdr = (struct isis_p2p_hello_hdr *)STREAM_PNT(circuit->rcv_stream); - pdu_len = ntohs(hdr->pdu_len); - - if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_P2PHELLO_HDRLEN) - || pdu_len > ISO_MTU(circuit) - || pdu_len > stream_get_endp(circuit->rcv_stream)) { - zlog_warn( - "ISIS-Adj (%s): Rcvd P2P IIH from (%s) with " - "invalid pdu length %d", - circuit->area->area_tag, circuit->interface->name, - 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); - - stream_forward_getp(circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN); - - /* - * Lets get the TLVS now - */ - expected |= TLVFLAG_AREA_ADDRS; - expected |= TLVFLAG_AUTH_INFO; - expected |= TLVFLAG_NLPID; - expected |= TLVFLAG_IPV4_ADDR; - expected |= TLVFLAG_IPV6_ADDR; - expected |= TLVFLAG_MT_ROUTER_INFORMATION; - - auth_tlv_offset = stream_get_getp(circuit->rcv_stream); - retval = parse_tlvs(circuit->area->area_tag, - STREAM_PNT(circuit->rcv_stream), - pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, - &expected, &found, &tlvs, &auth_tlv_offset); - - if (retval > ISIS_WARNING) { - zlog_warn("parse_tlvs() failed"); - free_tlvs(&tlvs); - return retval; - }; - - if (!(found & TLVFLAG_AREA_ADDRS)) { - zlog_warn("No Area addresses TLV in P2P IS to IS hello"); - free_tlvs(&tlvs); - return ISIS_WARNING; - } - - if (!(found & TLVFLAG_NLPID)) { - zlog_warn("No supported protocols TLV in P2P IS to IS hello"); - free_tlvs(&tlvs); - return ISIS_WARNING; - } - - /* 8.2.5.1 c) Authentication */ - if (circuit->passwd.type) { - if (!(found & TLVFLAG_AUTH_INFO) - || authentication_check(&tlvs.auth_info, &circuit->passwd, - circuit->rcv_stream, - auth_tlv_offset)) { - isis_event_auth_failure( - circuit->area->area_tag, - "P2P hello authentication failure", - hdr->source_id); - free_tlvs(&tlvs); - return ISIS_OK; - } - } +struct iih_info { + struct isis_circuit *circuit; + u_char *ssnpa; + int level; - /* - * check if both ends have an IPv4 address - */ - if (circuit->ip_addrs && listcount(circuit->ip_addrs) && tlvs.ipv4_addrs - && listcount(tlvs.ipv4_addrs)) { - v4_usable = 1; - } - - if (found & TLVFLAG_IPV6_ADDR) { - /* TBA: check that we have a linklocal ourselves? */ - struct listnode *node; - struct in6_addr *ip; - for (ALL_LIST_ELEMENTS_RO(tlvs.ipv6_addrs, node, ip)) - if (IN6_IS_ADDR_LINKLOCAL(ip)) { - v6_usable = 1; - break; - } + uint8_t circ_type; + uint8_t sys_id[ISIS_SYS_ID_LEN]; + uint16_t holdtime; + uint16_t pdu_len; - if (!v6_usable) - zlog_warn( - "ISIS-Adj: IPv6 addresses present but no link-local " - "in P2P IIH from %s\n", - circuit->interface->name); - } + uint8_t circuit_id; - if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR))) - zlog_warn( - "ISIS-Adj: neither IPv4 nor IPv6 addr in P2P IIH from %s\n", - circuit->interface->name); + uint8_t priority; + uint8_t dis[ISIS_SYS_ID_LEN + 1]; - if (!v6_usable && !v4_usable) { - free_tlvs(&tlvs); - return ISIS_WARNING; - } + bool v4_usable; + bool v6_usable; - /* - * it's own p2p IIH PDU - discard - */ - if (!memcmp(hdr->source_id, isis->sysid, ISIS_SYS_ID_LEN)) { - zlog_warn("ISIS-Adj (%s): it's own IIH PDU - discarded", - circuit->area->area_tag); - free_tlvs(&tlvs); - return ISIS_WARNING; - } + struct isis_tlvs *tlvs; +}; +static int process_p2p_hello(struct iih_info *iih) +{ /* * My interpertation of the ISO, if no adj exists we will create one for * the circuit */ - adj = circuit->u.p2p.neighbor; + struct isis_adjacency *adj = iih->circuit->u.p2p.neighbor; /* If an adjacency exists, check it is with the source of the hello * packets */ if (adj) { - if (memcmp(hdr->source_id, adj->sysid, ISIS_SYS_ID_LEN)) { + if (memcmp(iih->sys_id, adj->sysid, ISIS_SYS_ID_LEN)) { zlog_debug( "hello source and adjacency do not match, set adj down\n"); isis_adj_state_change(adj, ISIS_ADJ_DOWN, "adj do not exist"); - return 0; + return ISIS_OK; } } - if (!adj || adj->level != hdr->circuit_t) { + if (!adj || adj->level != iih->circ_type) { if (!adj) { - adj = isis_new_adj(hdr->source_id, NULL, hdr->circuit_t, - circuit); - if (adj == NULL) - return ISIS_ERROR; + adj = isis_new_adj(iih->sys_id, NULL, iih->circ_type, + iih->circuit); } else { - adj->level = hdr->circuit_t; + adj->level = iih->circ_type; } - circuit->u.p2p.neighbor = adj; + iih->circuit->u.p2p.neighbor = adj; /* Build lsp with the new neighbor entry when a new * adjacency is formed. Set adjacency circuit type to * IIH PDU header circuit type before lsp is regenerated * when an adjacency is up. This will result in the new * adjacency entry getting added to the lsp tlv neighbor list. */ - adj->circuit_t = hdr->circuit_t; + adj->circuit_t = iih->circ_type; isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL); adj->sys_type = ISIS_SYSTYPE_UNKNOWN; } /* 8.2.6 Monitoring point-to-point adjacencies */ - adj->hold_time = ntohs(hdr->hold_time); + adj->hold_time = iih->holdtime; adj->last_upd = time(NULL); - /* we do this now because the adj may not survive till the end... */ - tlvs_to_adj_area_addrs(&tlvs, adj); - - /* which protocol are spoken ??? */ - if (tlvs_to_adj_nlpids(&tlvs, adj)) { - free_tlvs(&tlvs); - return ISIS_WARNING; - } - - /* we need to copy addresses to the adj */ - if (found & TLVFLAG_IPV4_ADDR) - tlvs_to_adj_ipv4_addrs(&tlvs, adj); + bool changed; + isis_tlvs_to_adj(iih->tlvs, adj, &changed); + changed |= tlvs_to_adj_mt_set(iih->tlvs, iih->v4_usable, iih->v6_usable, + adj); /* Update MPLS TE Remote IP address parameter if possible */ - if (IS_MPLS_TE(isisMplsTE) && circuit->mtc - && IS_CIRCUIT_TE(circuit->mtc)) - if (adj->ipv4_addrs != NULL - && listcount(adj->ipv4_addrs) != 0) { - struct in_addr *ip_addr; - ip_addr = (struct in_addr *)listgetdata( - (struct listnode *)listhead(adj->ipv4_addrs)); - set_circuitparams_rmt_ipaddr(circuit->mtc, *ip_addr); - } - - if (found & TLVFLAG_IPV6_ADDR) - tlvs_to_adj_ipv6_addrs(&tlvs, adj); - - bool mt_set_changed = - tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj); + if (IS_MPLS_TE(isisMplsTE) && iih->circuit->mtc + && IS_CIRCUIT_TE(iih->circuit->mtc) && adj->ipv4_address_count) + set_circuitparams_rmt_ipaddr(iih->circuit->mtc, + adj->ipv4_addresses[0]); /* lets take care of the expiry */ THREAD_TIMER_OFF(adj->t_expire); @@ -552,10 +272,11 @@ static int process_p2p_hello(struct isis_circuit *circuit) &adj->t_expire); /* 8.2.5.2 a) a match was detected */ - if (area_match(circuit->area->area_addrs, tlvs.area_addrs)) { + if (isis_tlvs_area_addresses_match(iih->tlvs, + iih->circuit->area->area_addrs)) { /* 8.2.5.2 a) 2) If the system is L1 - table 5 */ - if (circuit->area->is_type == IS_LEVEL_1) { - switch (hdr->circuit_t) { + if (iih->circuit->area->is_type == IS_LEVEL_1) { + switch (iih->circ_type) { case IS_LEVEL_1: case IS_LEVEL_1_AND_2: if (adj->adj_state != ISIS_ADJ_UP) { @@ -573,8 +294,7 @@ static int process_p2p_hello(struct isis_circuit *circuit) /* (7) reject - wrong system type event */ zlog_warn("wrongSystemType"); - free_tlvs(&tlvs); - return ISIS_WARNING; /* Reject */ + return ISIS_WARNING; } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { /* (6) down - wrong system */ isis_adj_state_change(adj, @@ -586,8 +306,8 @@ static int process_p2p_hello(struct isis_circuit *circuit) } /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */ - if (circuit->area->is_type == IS_LEVEL_1_AND_2) { - switch (hdr->circuit_t) { + if (iih->circuit->area->is_type == IS_LEVEL_1_AND_2) { + switch (iih->circ_type) { case IS_LEVEL_1: if (adj->adj_state != ISIS_ADJ_UP) { /* (6) adj state up */ @@ -648,15 +368,14 @@ static int process_p2p_hello(struct isis_circuit *circuit) } /* 8.2.5.2 a) 4) If the system is L2 - table 7 */ - if (circuit->area->is_type == IS_LEVEL_2) { - switch (hdr->circuit_t) { + if (iih->circuit->area->is_type == IS_LEVEL_2) { + switch (iih->circ_type) { case IS_LEVEL_1: if (adj->adj_state != ISIS_ADJ_UP) { /* (5) reject - wrong system type event */ zlog_warn("wrongSystemType"); - free_tlvs(&tlvs); - return ISIS_WARNING; /* Reject */ + return ISIS_WARNING; } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || (adj->adj_usage @@ -689,8 +408,8 @@ static int process_p2p_hello(struct isis_circuit *circuit) } } /* 8.2.5.2 b) if no match was detected */ - else if (listcount(circuit->area->area_addrs) > 0) { - if (circuit->area->is_type == IS_LEVEL_1) { + else if (listcount(iih->circuit->area->area_addrs) > 0) { + if (iih->circuit->area->is_type == IS_LEVEL_1) { /* 8.2.5.2 b) 1) is_type L1 and adj is not up */ if (adj->adj_state != ISIS_ADJ_UP) { isis_adj_state_change(adj, ISIS_ADJ_DOWN, @@ -703,13 +422,12 @@ static int process_p2p_hello(struct isis_circuit *circuit) } /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */ else { - switch (hdr->circuit_t) { + switch (iih->circ_type) { case IS_LEVEL_1: if (adj->adj_state != ISIS_ADJ_UP) { /* (6) reject - Area Mismatch event */ zlog_warn("AreaMismatch"); - free_tlvs(&tlvs); - return ISIS_WARNING; /* Reject */ + return ISIS_WARNING; } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { /* (7) down - area mismatch */ isis_adj_state_change(adj, @@ -741,7 +459,7 @@ static int process_p2p_hello(struct isis_circuit *circuit) "Wrong System"); } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { - if (hdr->circuit_t == IS_LEVEL_2) { + if (iih->circ_type == IS_LEVEL_2) { /* (7) down - wrong system */ isis_adj_state_change( adj, ISIS_ADJ_DOWN, @@ -763,7 +481,7 @@ static int process_p2p_hello(struct isis_circuit *circuit) isis_adj_state_change(adj, ISIS_ADJ_DOWN, "Area Mismatch"); } - if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed) { + if (adj->adj_state == ISIS_ADJ_UP && changed) { lsp_regenerate_schedule(adj->circuit->area, isis_adj_usage2levels(adj->adj_usage), 0); @@ -790,109 +508,190 @@ static int process_p2p_hello(struct isis_circuit *circuit) break; } - if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug( "ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s," " cir id %02d, length %d", - circuit->area->area_tag, circuit->interface->name, - circuit_t2string(circuit->is_type), circuit->circuit_id, - pdu_len); + iih->circuit->area->area_tag, + iih->circuit->interface->name, + circuit_t2string(iih->circuit->is_type), + iih->circuit->circuit_id, iih->pdu_len); } - free_tlvs(&tlvs); - - return retval; + return ISIS_OK; } -/* - * Process IS-IS LAN Level 1/2 Hello PDU - */ -static int process_lan_hello(int level, struct isis_circuit *circuit, - const u_char *ssnpa) +static int process_lan_hello(struct iih_info *iih) { - int retval = ISIS_OK; - struct isis_lan_hello_hdr hdr; struct isis_adjacency *adj; - u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; - struct tlvs tlvs; - u_char *snpa; - struct listnode *node; - int v4_usable = 0, v6_usable = 0; + adj = isis_adj_lookup(iih->sys_id, + iih->circuit->u.bc.adjdb[iih->level - 1]); + if ((adj == NULL) || (memcmp(adj->snpa, iih->ssnpa, ETH_ALEN)) + || (adj->level != iih->level)) { + if (!adj) { + /* Do as in 8.4.2.5 */ + adj = isis_new_adj(iih->sys_id, iih->ssnpa, iih->level, + iih->circuit); + } else { + if (iih->ssnpa) { + memcpy(adj->snpa, iih->ssnpa, 6); + } else { + memset(adj->snpa, ' ', 6); + } + adj->level = iih->level; + } + isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL); - if (isis->debugs & DEBUG_ADJ_PACKETS) { - zlog_debug( - "ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, " - "cirID %u", - circuit->area->area_tag, level, - circuit->interface->name, - circuit_t2string(circuit->is_type), - circuit->circuit_id); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data(STREAM_DATA(circuit->rcv_stream), - stream_get_endp(circuit->rcv_stream)); + if (iih->level == IS_LEVEL_1) + adj->sys_type = ISIS_SYSTYPE_L1_IS; + else + adj->sys_type = ISIS_SYSTYPE_L2_IS; + list_delete_all_node( + iih->circuit->u.bc.lan_neighs[iih->level - 1]); + isis_adj_build_neigh_list( + iih->circuit->u.bc.adjdb[iih->level - 1], + iih->circuit->u.bc.lan_neighs[iih->level - 1]); + } + + if (adj->dis_record[iih->level - 1].dis == ISIS_IS_DIS) { + u_char *dis = (iih->level == 1) + ? iih->circuit->u.bc.l1_desig_is + : iih->circuit->u.bc.l2_desig_is; + + if (memcmp(dis, iih->dis, ISIS_SYS_ID_LEN + 1)) { + thread_add_event(master, isis_event_dis_status_change, + iih->circuit, 0, NULL); + memcpy(dis, iih->dis, ISIS_SYS_ID_LEN + 1); + } } - if (circuit->circ_type != CIRCUIT_T_BROADCAST) { - zlog_warn("lan hello on non broadcast circuit"); - return ISIS_WARNING; - } + adj->circuit_t = iih->circ_type; + adj->hold_time = iih->holdtime; + adj->last_upd = time(NULL); + adj->prio[iih->level - 1] = iih->priority; + memcpy(adj->lanid, iih->dis, ISIS_SYS_ID_LEN + 1); - if ((stream_get_endp(circuit->rcv_stream) - - stream_get_getp(circuit->rcv_stream)) - < ISIS_LANHELLO_HDRLEN) { - zlog_warn("Packet too short"); - return ISIS_WARNING; + bool changed; + isis_tlvs_to_adj(iih->tlvs, adj, &changed); + changed |= tlvs_to_adj_mt_set(iih->tlvs, iih->v4_usable, iih->v6_usable, + adj); + + /* lets take care of the expiry */ + THREAD_TIMER_OFF(adj->t_expire); + thread_add_timer(master, isis_adj_expire, adj, (long)adj->hold_time, + &adj->t_expire); + + /* + * If the snpa for this circuit is found from LAN Neighbours TLV + * we have two-way communication -> adjacency can be put to state "up" + */ + bool own_snpa_found = + isis_tlvs_own_snpa_found(iih->tlvs, iih->circuit->u.bc.snpa); + + if (adj->adj_state != ISIS_ADJ_UP) { + if (own_snpa_found) { + isis_adj_state_change( + adj, ISIS_ADJ_UP, + "own SNPA found in LAN Neighbours TLV"); + } + } else { + if (!own_snpa_found) { + isis_adj_state_change( + adj, ISIS_ADJ_INITIALIZING, + "own SNPA not found in LAN Neighbours TLV"); + } } - if (circuit->ext_domain) { + if (adj->adj_state == ISIS_ADJ_UP && changed) + lsp_regenerate_schedule(adj->circuit->area, iih->level, 0); + + if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug( - "level %d LAN Hello received over circuit with " - "externalDomain = true", - level); - return ISIS_WARNING; + "ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, cirID %u, length %zd", + iih->circuit->area->area_tag, iih->level, + snpa_print(iih->ssnpa), iih->circuit->interface->name, + circuit_t2string(iih->circuit->is_type), + iih->circuit->circuit_id, + stream_get_endp(iih->circuit->rcv_stream)); } + return ISIS_OK; +} - if (!accept_level(level, circuit->is_type)) { - if (isis->debugs & DEBUG_ADJ_PACKETS) { +static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, + u_char *ssnpa) +{ + bool p2p_hello = (pdu_type == P2P_HELLO); + int level = p2p_hello ? 0 + : (pdu_type == L1_LAN_HELLO) ? ISIS_LEVEL1 + : ISIS_LEVEL2; + const char *pdu_name = + p2p_hello + ? "P2P IIH" + : (level == ISIS_LEVEL1) ? "L1 LAN IIH" : "L2 LAN IIH"; + + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_debug("ISIS-Adj (%s): Rcvd %s on %s, cirType %s, cirID %u", + circuit->area->area_tag, pdu_name, + circuit->interface->name, + circuit_t2string(circuit->is_type), + circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data(STREAM_DATA(circuit->rcv_stream), + stream_get_endp(circuit->rcv_stream)); + } + + if (p2p_hello) { + if (circuit->circ_type != CIRCUIT_T_P2P) { + zlog_warn("p2p hello on non p2p circuit"); + return ISIS_WARNING; + } + } else { + if (circuit->circ_type != CIRCUIT_T_BROADCAST) { + zlog_warn("lan hello on non broadcast circuit"); + return ISIS_WARNING; + } + + if (circuit->ext_domain) { zlog_debug( - "ISIS-Adj (%s): Interface level mismatch, %s", - circuit->area->area_tag, - circuit->interface->name); + "level %d LAN Hello received over circuit with externalDomain = true", + level); + return ISIS_WARNING; + } + + if (!accept_level(level, circuit->is_type)) { + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_debug( + "ISIS-Adj (%s): Interface level mismatch, %s", + circuit->area->area_tag, + circuit->interface->name); + } + return ISIS_WARNING; } - return ISIS_WARNING; } -#if 0 - /* Cisco's debug message compatability */ - if (!accept_level (level, circuit->area->is_type)) - { - if (isis->debugs & DEBUG_ADJ_PACKETS) - { - zlog_debug ("ISIS-Adj (%s): is type mismatch", - circuit->area->area_tag); + struct iih_info iih = { + .circuit = circuit, .ssnpa = ssnpa, .level = level}; + + /* Generic IIH Header */ + iih.circ_type = stream_getc(circuit->rcv_stream) & 0x03; + stream_get(iih.sys_id, circuit->rcv_stream, ISIS_SYS_ID_LEN); + iih.holdtime = stream_getw(circuit->rcv_stream); + iih.pdu_len = stream_getw(circuit->rcv_stream); + + if (p2p_hello) { + iih.circuit_id = stream_getc(circuit->rcv_stream); + } else { + iih.priority = stream_getc(circuit->rcv_stream); + stream_get(iih.dis, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1); } - return ISIS_WARNING; - } -#endif - /* - * Fill the header - */ - hdr.circuit_t = stream_getc(circuit->rcv_stream); - stream_get(hdr.source_id, circuit->rcv_stream, ISIS_SYS_ID_LEN); - hdr.hold_time = stream_getw(circuit->rcv_stream); - hdr.pdu_len = stream_getw(circuit->rcv_stream); - hdr.prio = stream_getc(circuit->rcv_stream); - stream_get(hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1); - - if (hdr.pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LANHELLO_HDRLEN) - || hdr.pdu_len > ISO_MTU(circuit) - || hdr.pdu_len > stream_get_endp(circuit->rcv_stream)) { + + if (iih.pdu_len < stream_get_getp(circuit->rcv_stream) + || iih.pdu_len > ISO_MTU(circuit) + || iih.pdu_len > stream_get_endp(circuit->rcv_stream)) { zlog_warn( - "ISIS-Adj (%s): Rcvd LAN IIH from (%s) with " - "invalid pdu length %d", - circuit->area->area_tag, circuit->interface->name, - hdr.pdu_len); + "ISIS-Adj (%s): Rcvd %s from (%s) with invalid pdu length %" PRIu16, + circuit->area->area_tag, pdu_name, + circuit->interface->name, iih.pdu_len); return ISIS_WARNING; } @@ -900,277 +699,75 @@ static int process_lan_hello(int level, struct isis_circuit *circuit, * Set the stream endp to PDU length, ignoring additional padding * introduced by transport chips. */ - if (hdr.pdu_len < stream_get_endp(circuit->rcv_stream)) - stream_set_endp(circuit->rcv_stream, hdr.pdu_len); + if (iih.pdu_len < stream_get_endp(circuit->rcv_stream)) + stream_set_endp(circuit->rcv_stream, iih.pdu_len); - if (hdr.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2 - && hdr.circuit_t != IS_LEVEL_1_AND_2 - && (level & hdr.circuit_t) == 0) { + if (!p2p_hello && !(level & iih.circ_type)) { zlog_err("Level %d LAN Hello with Circuit Type %d", level, - hdr.circuit_t); + iih.circ_type); return ISIS_ERROR; } - /* - * Then get the tlvs - */ - expected |= TLVFLAG_AUTH_INFO; - expected |= TLVFLAG_AREA_ADDRS; - expected |= TLVFLAG_LAN_NEIGHS; - expected |= TLVFLAG_NLPID; - expected |= TLVFLAG_IPV4_ADDR; - expected |= TLVFLAG_IPV6_ADDR; - expected |= TLVFLAG_MT_ROUTER_INFORMATION; - - auth_tlv_offset = stream_get_getp(circuit->rcv_stream); - retval = parse_tlvs( - circuit->area->area_tag, STREAM_PNT(circuit->rcv_stream), - hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, - &expected, &found, &tlvs, &auth_tlv_offset); + const char *error_log; + int retval = ISIS_WARNING; - if (retval > ISIS_WARNING) { - zlog_warn("parse_tlvs() failed"); + if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream), + circuit->rcv_stream, &iih.tlvs, &error_log)) { + zlog_warn("isis_unpack_tlvs() failed: %s", error_log); goto out; } - if (!(found & TLVFLAG_AREA_ADDRS)) { - zlog_warn( - "No Area addresses TLV in Level %d LAN IS to IS hello", - level); - retval = ISIS_WARNING; + if (!iih.tlvs->area_addresses.count) { + zlog_warn("No Area addresses TLV in %s", pdu_name); goto out; } - if (!(found & TLVFLAG_NLPID)) { - zlog_warn( - "No supported protocols TLV in Level %d LAN IS to IS hello", - level); - retval = ISIS_WARNING; + if (!iih.tlvs->protocols_supported.count) { + zlog_warn("No supported protocols TLV in %s", pdu_name); goto out; } - /* Verify authentication, either cleartext of HMAC MD5 */ - if (circuit->passwd.type) { - if (!(found & TLVFLAG_AUTH_INFO) - || authentication_check(&tlvs.auth_info, &circuit->passwd, - circuit->rcv_stream, - auth_tlv_offset)) { - isis_event_auth_failure( - circuit->area->area_tag, - "LAN hello authentication failure", - hdr.source_id); - retval = ISIS_WARNING; - goto out; - } + if (!isis_tlvs_auth_is_valid(iih.tlvs, &circuit->passwd, + circuit->rcv_stream)) { + isis_event_auth_failure(circuit->area->area_tag, + "IIH authentication failure", + iih.sys_id); + goto out; } - if (!memcmp(hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN)) { - zlog_warn("ISIS-Adj (%s): duplicate system ID on interface %s", - circuit->area->area_tag, circuit->interface->name); - return ISIS_WARNING; + if (!memcmp(iih.sys_id, isis->sysid, ISIS_SYS_ID_LEN)) { + zlog_warn( + "ISIS-Adj (%s): Received IIH with own sysid - discard", + circuit->area->area_tag); + goto out; } - /* - * Accept the level 1 adjacency only if a match between local and - * remote area addresses is found - */ - if (listcount(circuit->area->area_addrs) == 0 - || (level == IS_LEVEL_1 - && area_match(circuit->area->area_addrs, tlvs.area_addrs) - == 0)) { + if (!p2p_hello + && (listcount(circuit->area->area_addrs) == 0 + || (level == ISIS_LEVEL1 + && !isis_tlvs_area_addresses_match( + iih.tlvs, circuit->area->area_addrs)))) { if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug( "ISIS-Adj (%s): Area mismatch, level %d IIH on %s", circuit->area->area_tag, level, circuit->interface->name); } - retval = ISIS_OK; goto out; } - /* - * it's own IIH PDU - discard silently - */ - if (!memcmp(circuit->u.bc.snpa, ssnpa, ETH_ALEN)) { - zlog_debug("ISIS-Adj (%s): it's own IIH PDU - discarded", - circuit->area->area_tag); - - retval = ISIS_OK; - goto out; - } - - /* - * check if both ends have an IPv4 address - */ - if (circuit->ip_addrs && listcount(circuit->ip_addrs) && tlvs.ipv4_addrs - && listcount(tlvs.ipv4_addrs)) { - v4_usable = 1; - } - - if (found & TLVFLAG_IPV6_ADDR) { - /* TBA: check that we have a linklocal ourselves? */ - struct listnode *node; - struct in6_addr *ip; - for (ALL_LIST_ELEMENTS_RO(tlvs.ipv6_addrs, node, ip)) - if (IN6_IS_ADDR_LINKLOCAL(ip)) { - v6_usable = 1; - break; - } - - if (!v6_usable) - zlog_warn( - "ISIS-Adj: IPv6 addresses present but no link-local " - "in LAN IIH from %s\n", - circuit->interface->name); - } - - if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR))) - zlog_warn( - "ISIS-Adj: neither IPv4 nor IPv6 addr in LAN IIH from %s\n", - circuit->interface->name); - - if (!v6_usable && !v4_usable) { - free_tlvs(&tlvs); - return ISIS_WARNING; - } - + iih.v4_usable = (circuit->ip_addrs && listcount(circuit->ip_addrs) + && iih.tlvs->ipv4_address.count); - adj = isis_adj_lookup(hdr.source_id, circuit->u.bc.adjdb[level - 1]); - if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN)) - || (adj->level != level)) { - if (!adj) { - /* - * Do as in 8.4.2.5 - */ - adj = isis_new_adj(hdr.source_id, ssnpa, level, - circuit); - if (adj == NULL) { - retval = ISIS_ERROR; - goto out; - } - } else { - if (ssnpa) { - memcpy(adj->snpa, ssnpa, 6); - } else { - memset(adj->snpa, ' ', 6); - } - adj->level = level; - } - isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL); + iih.v6_usable = (circuit->ipv6_link && listcount(circuit->ipv6_link) + && iih.tlvs->ipv6_address.count); - if (level == IS_LEVEL_1) - adj->sys_type = ISIS_SYSTYPE_L1_IS; - else - adj->sys_type = ISIS_SYSTYPE_L2_IS; - list_delete_all_node(circuit->u.bc.lan_neighs[level - 1]); - isis_adj_build_neigh_list(circuit->u.bc.adjdb[level - 1], - circuit->u.bc.lan_neighs[level - 1]); - } - - if (adj->dis_record[level - 1].dis == ISIS_IS_DIS) - switch (level) { - case 1: - if (memcmp(circuit->u.bc.l1_desig_is, hdr.lan_id, - ISIS_SYS_ID_LEN + 1)) { - thread_add_event(master, - isis_event_dis_status_change, - circuit, 0, NULL); - memcpy(&circuit->u.bc.l1_desig_is, hdr.lan_id, - ISIS_SYS_ID_LEN + 1); - } - break; - case 2: - if (memcmp(circuit->u.bc.l2_desig_is, hdr.lan_id, - ISIS_SYS_ID_LEN + 1)) { - thread_add_event(master, - isis_event_dis_status_change, - circuit, 0, NULL); - memcpy(&circuit->u.bc.l2_desig_is, hdr.lan_id, - ISIS_SYS_ID_LEN + 1); - } - break; - } - - adj->hold_time = hdr.hold_time; - adj->last_upd = time(NULL); - adj->prio[level - 1] = hdr.prio; - - memcpy(adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1); - - tlvs_to_adj_area_addrs(&tlvs, adj); - - /* which protocol are spoken ??? */ - if (tlvs_to_adj_nlpids(&tlvs, adj)) { - retval = ISIS_WARNING; + if (!iih.v4_usable && !iih.v6_usable) goto out; - } - - /* we need to copy addresses to the adj */ - if (found & TLVFLAG_IPV4_ADDR) - tlvs_to_adj_ipv4_addrs(&tlvs, adj); - - if (found & TLVFLAG_IPV6_ADDR) - tlvs_to_adj_ipv6_addrs(&tlvs, adj); - - adj->circuit_t = hdr.circuit_t; - - bool mt_set_changed = - tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj); - - /* lets take care of the expiry */ - THREAD_TIMER_OFF(adj->t_expire); - thread_add_timer(master, isis_adj_expire, adj, (long)adj->hold_time, - &adj->t_expire); - - /* - * If the snpa for this circuit is found from LAN Neighbours TLV - * we have two-way communication -> adjacency can be put to state "up" - */ - - if (found & TLVFLAG_LAN_NEIGHS) { - if (adj->adj_state != ISIS_ADJ_UP) { - for (ALL_LIST_ELEMENTS_RO(tlvs.lan_neighs, node, - snpa)) { - if (!memcmp(snpa, circuit->u.bc.snpa, - ETH_ALEN)) { - isis_adj_state_change( - adj, ISIS_ADJ_UP, - "own SNPA found in LAN Neighbours TLV"); - } - } - } else { - int found = 0; - for (ALL_LIST_ELEMENTS_RO(tlvs.lan_neighs, node, snpa)) - if (!memcmp(snpa, circuit->u.bc.snpa, - ETH_ALEN)) { - found = 1; - break; - } - if (found == 0) - isis_adj_state_change( - adj, ISIS_ADJ_INITIALIZING, - "own SNPA not found in LAN Neighbours TLV"); - } - } else if (adj->adj_state == ISIS_ADJ_UP) { - isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, - "no LAN Neighbours TLV found"); - } - - if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed) - lsp_regenerate_schedule(adj->circuit->area, level, 0); + retval = p2p_hello ? process_p2p_hello(&iih) : process_lan_hello(&iih); out: - if (isis->debugs & DEBUG_ADJ_PACKETS) { - zlog_debug( - "ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, " - "cirID %u, length %zd", - circuit->area->area_tag, level, snpa_print(ssnpa), - circuit->interface->name, - circuit_t2string(circuit->is_type), circuit->circuit_id, - stream_get_endp(circuit->rcv_stream)); - } - - free_tlvs(&tlvs); + isis_free_tlvs(iih.tlvs); return retval; } @@ -2005,13 +1602,9 @@ static int isis_handle_pdu(struct isis_circuit *circuit, u_char *ssnpa) switch (pdu_type) { case L1_LAN_HELLO: - retval = process_lan_hello(ISIS_LEVEL1, circuit, ssnpa); - break; case L2_LAN_HELLO: - retval = process_lan_hello(ISIS_LEVEL2, circuit, ssnpa); - break; case P2P_HELLO: - retval = process_p2p_hello(circuit); + retval = process_hello(pdu_type, circuit, ssnpa); break; case L1_LINK_STATE: retval = process_lsp(ISIS_LEVEL1, circuit, ssnpa); @@ -2088,25 +1681,9 @@ void fill_fixed_hdr(uint8_t pdu_type, struct stream *stream) stream_putc(stream, 0); /* Max Area Addresses 0 => 3 */ } -int send_hello(struct isis_circuit *circuit, int level) +static void put_hello_hdr(struct isis_circuit *circuit, int level, + size_t *len_pointer) { - struct isis_lan_hello_hdr hello_hdr; - struct isis_p2p_hello_hdr p2p_hello_hdr; - unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; - size_t len_pointer, length, auth_tlv_offset = 0; - u_int32_t interval; - int retval; - - if (circuit->is_passive) - return ISIS_OK; - - if (circuit->interface->mtu == 0) { - zlog_warn("circuit has zero MTU"); - return ISIS_WARNING; - } - - isis_circuit_stream(circuit, &circuit->snd_stream); - uint8_t pdu_type; if (circuit->circ_type == CIRCUIT_T_BROADCAST) @@ -2114,102 +1691,62 @@ int send_hello(struct isis_circuit *circuit, int level) else pdu_type = P2P_HELLO; + isis_circuit_stream(circuit, &circuit->snd_stream); fill_fixed_hdr(pdu_type, circuit->snd_stream); - /* - * Fill LAN Level 1 or 2 Hello PDU header - */ - memset(&hello_hdr, 0, sizeof(struct isis_lan_hello_hdr)); - interval = circuit->hello_multiplier[level - 1] - * circuit->hello_interval[level - 1]; - if (interval > USHRT_MAX) - interval = USHRT_MAX; - hello_hdr.circuit_t = circuit->is_type; - memcpy(hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN); - hello_hdr.hold_time = htons((u_int16_t)interval); - - hello_hdr.pdu_len = 0; /* Update the PDU Length later */ - len_pointer = - stream_get_endp(circuit->snd_stream) + 3 + ISIS_SYS_ID_LEN; - - /* copy the shared part of the hello to the p2p hello if needed */ - if (circuit->circ_type == CIRCUIT_T_P2P) { - memcpy(&p2p_hello_hdr, &hello_hdr, 5 + ISIS_SYS_ID_LEN); - p2p_hello_hdr.local_id = circuit->circuit_id; - /* FIXME: need better understanding */ - stream_put(circuit->snd_stream, &p2p_hello_hdr, - ISIS_P2PHELLO_HDRLEN); - } else { - hello_hdr.prio = circuit->priority[level - 1]; - if (level == IS_LEVEL_1) { - memcpy(hello_hdr.lan_id, circuit->u.bc.l1_desig_is, - ISIS_SYS_ID_LEN + 1); - } else if (level == IS_LEVEL_2) { - memcpy(hello_hdr.lan_id, circuit->u.bc.l2_desig_is, - ISIS_SYS_ID_LEN + 1); - } - stream_put(circuit->snd_stream, &hello_hdr, - ISIS_LANHELLO_HDRLEN); - } + stream_putc(circuit->snd_stream, circuit->is_type); + stream_put(circuit->snd_stream, circuit->area->isis->sysid, + ISIS_SYS_ID_LEN); - /* - * Then the variable length part. - */ + uint32_t holdtime = circuit->hello_multiplier[level - 1] + * circuit->hello_interval[level - 1]; - /* add circuit password */ - switch (circuit->passwd.type) { - /* Cleartext */ - case ISIS_PASSWD_TYPE_CLEARTXT: - if (tlv_add_authinfo(circuit->passwd.type, circuit->passwd.len, - circuit->passwd.passwd, - circuit->snd_stream)) - return ISIS_WARNING; - break; + if (holdtime > 0xffff) + holdtime = 0xffff; - /* HMAC MD5 */ - case ISIS_PASSWD_TYPE_HMAC_MD5: - /* Remember where TLV is written so we can later overwrite the - * MD5 hash */ - auth_tlv_offset = stream_get_endp(circuit->snd_stream); - memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); - if (tlv_add_authinfo(circuit->passwd.type, ISIS_AUTH_MD5_SIZE, - hmac_md5_hash, circuit->snd_stream)) - return ISIS_WARNING; - break; + stream_putw(circuit->snd_stream, holdtime); + *len_pointer = stream_get_endp(circuit->snd_stream); + stream_putw(circuit->snd_stream, 0); /* length is filled in later */ - default: - break; + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + u_char *desig_is = (level == IS_LEVEL_1) + ? circuit->u.bc.l1_desig_is + : circuit->u.bc.l2_desig_is; + stream_putc(circuit->snd_stream, circuit->priority[level - 1]); + stream_put(circuit->snd_stream, desig_is, ISIS_SYS_ID_LEN + 1); + } else { + stream_putc(circuit->snd_stream, circuit->circuit_id); } +} - /* Area Addresses TLV */ - if (listcount(circuit->area->area_addrs) == 0) +int send_hello(struct isis_circuit *circuit, int level) +{ + size_t len_pointer; + int retval; + + if (circuit->is_passive) + return ISIS_OK; + + if (circuit->interface->mtu == 0) { + zlog_warn("circuit has zero MTU"); return ISIS_WARNING; - if (tlv_add_area_addrs(circuit->area->area_addrs, circuit->snd_stream)) + } + + put_hello_hdr(circuit, level, &len_pointer); + + struct isis_tlvs *tlvs = isis_alloc_tlvs(); + + isis_tlvs_add_auth(tlvs, &circuit->passwd); + + if (!listcount(circuit->area->area_addrs)) return ISIS_WARNING; + isis_tlvs_add_area_addresses(tlvs, circuit->area->area_addrs); - /* LAN Neighbors TLV */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) { - if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0] - && listcount(circuit->u.bc.lan_neighs[0]) > 0) - if (tlv_add_lan_neighs(circuit->u.bc.lan_neighs[0], - circuit->snd_stream)) - return ISIS_WARNING; - if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1] - && listcount(circuit->u.bc.lan_neighs[1]) > 0) - if (tlv_add_lan_neighs(circuit->u.bc.lan_neighs[1], - circuit->snd_stream)) - return ISIS_WARNING; - } + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + isis_tlvs_add_lan_neighbors( + tlvs, circuit->u.bc.lan_neighs[level - 1]); - /* Protocols Supported TLV */ - if (circuit->nlpids.count > 0) - if (tlv_add_nlpid(&circuit->nlpids, circuit->snd_stream)) - return ISIS_WARNING; - /* IP interface Address TLV */ - if (circuit->ip_router && circuit->ip_addrs - && listcount(circuit->ip_addrs) > 0) - if (tlv_add_ip_addrs(circuit->ip_addrs, circuit->snd_stream)) - return ISIS_WARNING; + isis_tlvs_set_protocols_supported(tlvs, &circuit->nlpids); /* * MT Supported TLV @@ -2222,48 +1759,26 @@ int send_hello(struct isis_circuit *circuit, int level) unsigned int mt_count; mt_settings = circuit_mt_settings(circuit, &mt_count); - if ((mt_count == 0 && area_is_mt(circuit->area)) - || (mt_count == 1 && mt_settings[0]->mtid != ISIS_MT_IPV4_UNICAST) - || (mt_count > 1)) { - struct list *mt_info = list_new(); - mt_info->del = free_tlv; - - 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; - /* overload info is not valid in IIH, so it's not - * included here */ - listnode_add(mt_info, info); - } - tlv_add_mt_router_info(mt_info, circuit->snd_stream); - list_free(mt_info); + if (mt_count == 0 && area_is_mt(circuit->area)) { + tlvs->mt_router_info_empty = true; + } else if ((mt_count == 1 + && mt_settings[0]->mtid != ISIS_MT_IPV4_UNICAST) + || (mt_count > 1)) { + for (unsigned int i = 0; i < mt_count; i++) + isis_tlvs_add_mt_router_info(tlvs, mt_settings[i]->mtid, + false, false); } - /* IPv6 Interface Address TLV */ - if (circuit->ipv6_router && circuit->ipv6_link - && listcount(circuit->ipv6_link) > 0) - if (tlv_add_ipv6_addrs(circuit->ipv6_link, circuit->snd_stream)) - return ISIS_WARNING; + if (circuit->ip_router && circuit->ip_addrs) + isis_tlvs_add_ipv4_addresses(tlvs, circuit->ip_addrs); - if (circuit->pad_hellos) - if (tlv_add_padding(circuit->snd_stream)) - return ISIS_WARNING; + if (circuit->ipv6_router && circuit->ipv6_link) + isis_tlvs_add_ipv6_addresses(tlvs, circuit->ipv6_link); - length = stream_get_endp(circuit->snd_stream); - /* Update PDU length */ - stream_putw_at(circuit->snd_stream, len_pointer, (u_int16_t)length); - - /* For HMAC MD5 we need to compute the md5 hash and store it */ - if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { - hmac_md5(STREAM_DATA(circuit->snd_stream), - stream_get_endp(circuit->snd_stream), - (unsigned char *)&circuit->passwd.passwd, - circuit->passwd.len, (unsigned char *)&hmac_md5_hash); - /* Copy the hash into the stream */ - memcpy(STREAM_DATA(circuit->snd_stream) + auth_tlv_offset + 3, - hmac_md5_hash, ISIS_AUTH_MD5_SIZE); + if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer, + circuit->pad_hellos)) { + isis_free_tlvs(tlvs); + return ISIS_WARNING; /* XXX: Maybe Log TLV structure? */ } if (isis->debugs & DEBUG_ADJ_PACKETS) { @@ -2271,18 +1786,22 @@ int send_hello(struct isis_circuit *circuit, int level) zlog_debug( "ISIS-Adj (%s): Sending L%d LAN IIH on %s, length %zd", circuit->area->area_tag, level, - circuit->interface->name, length); + circuit->interface->name, + stream_get_endp(circuit->snd_stream)); } else { zlog_debug( "ISIS-Adj (%s): Sending P2P IIH on %s, length %zd", circuit->area->area_tag, - circuit->interface->name, length); + circuit->interface->name, + stream_get_endp(circuit->snd_stream)); } if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data(STREAM_DATA(circuit->snd_stream), stream_get_endp(circuit->snd_stream)); } + isis_free_tlvs(tlvs); + retval = circuit->tx(circuit, level); if (retval != ISIS_OK) zlog_err("ISIS-Adj (%s): Send L%d IIH on %s failed", diff --git a/isisd/isis_route.c b/isisd/isis_route.c index afc4f6512..8cb5aa9ed 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -208,13 +208,12 @@ static void nexthops6_print(struct list *nhs6) static void adjinfo2nexthop(struct list *nexthops, struct isis_adjacency *adj) { struct isis_nexthop *nh; - struct listnode *node; - struct in_addr *ipv4_addr; - if (adj->ipv4_addrs == NULL) + if (!adj->ipv4_address_count) return; - for (ALL_LIST_ELEMENTS_RO(adj->ipv4_addrs, node, ipv4_addr)) { + for (unsigned int i = 0; i < adj->ipv4_address_count; i++) { + struct in_addr *ipv4_addr = &adj->ipv4_addresses[i]; if (!nexthoplookup(nexthops, ipv4_addr, adj->circuit->interface->ifindex)) { nh = isis_nexthop_create( @@ -227,14 +226,13 @@ static void adjinfo2nexthop(struct list *nexthops, struct isis_adjacency *adj) static void adjinfo2nexthop6(struct list *nexthops6, struct isis_adjacency *adj) { - struct listnode *node; - struct in6_addr *ipv6_addr; struct isis_nexthop6 *nh6; - if (!adj->ipv6_addrs) + if (!adj->ipv6_address_count) return; - for (ALL_LIST_ELEMENTS_RO(adj->ipv6_addrs, node, ipv6_addr)) { + for (unsigned int i = 0; i < adj->ipv6_address_count; i++) { + struct in6_addr *ipv6_addr = &adj->ipv6_addresses[i]; if (!nexthop6lookup(nexthops6, ipv6_addr, adj->circuit->interface->ifindex)) { nh6 = isis_nexthop6_create( diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 5296d9948..6b8f1fe16 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -546,13 +546,9 @@ void isis_link_params_update(struct isis_circuit *circuit, if ((SUBTLV_TYPE(mtc->rmt_ipaddr) == 0) && (circuit->circ_type == CIRCUIT_T_P2P)) { struct isis_adjacency *adj = circuit->u.p2p.neighbor; - if (adj->ipv4_addrs != NULL - && listcount(adj->ipv4_addrs) != 0) { - struct in_addr *ip_addr; - ip_addr = (struct in_addr *)listgetdata( - (struct listnode *)listhead( - adj->ipv4_addrs)); - set_circuitparams_rmt_ipaddr(mtc, *ip_addr); + if (adj->ipv4_address_count) { + set_circuitparams_rmt_ipaddr( + mtc, adj->ipv4_addresses[0]); } } |