summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--isisd/isis_adjacency.c79
-rw-r--r--isisd/isis_adjacency.h15
-rw-r--r--isisd/isis_memory.c1
-rw-r--r--isisd/isis_memory.h1
-rw-r--r--isisd/isis_mt.c15
-rw-r--r--isisd/isis_mt.h3
-rw-r--r--isisd/isis_pdu.c1113
-rw-r--r--isisd/isis_route.c14
-rw-r--r--isisd/isis_te.c10
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]);
}
}