From eb5d44eb8dcf25a1b328e57d1eabb1f89e3bc59b Mon Sep 17 00:00:00 2001 From: jardin Date: Tue, 23 Dec 2003 08:09:43 +0000 Subject: Initial revision --- isisd/isis_adjacency.c | 508 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 508 insertions(+) create mode 100644 isisd/isis_adjacency.c (limited to 'isisd/isis_adjacency.c') diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c new file mode 100644 index 00000000..8079bd17 --- /dev/null +++ b/isisd/isis_adjacency.c @@ -0,0 +1,508 @@ +/* + * IS-IS Rout(e)ing protocol - isis_adjacency.c + * handling of IS-IS adjacencies + * + * Copyright (C) 2001,2002 Sampo Saaristo + * Tampere University of Technology + * Institute of Communications Engineering + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public Licenseas published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful,but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + + +#include "log.h" +#include "memory.h" +#include "hash.h" +#include "vty.h" +#include "linklist.h" +#include "thread.h" +#include "if.h" +#include "stream.h" + +#include "isisd/dict.h" +#include "isisd/include-netbsd/iso.h" +#include "isisd/isis_constants.h" +#include "isisd/isis_common.h" +#include "isisd/isisd.h" +#include "isisd/isis_circuit.h" +#include "isisd/isis_adjacency.h" +#include "isisd/isis_misc.h" +#include "isisd/isis_dr.h" +#include "isisd/isis_dynhn.h" +#include "isisd/isis_pdu.h" + + +extern struct isis *isis; + + +struct isis_adjacency * +adj_alloc (u_char *id) +{ + struct isis_adjacency *adj; + + adj = XMALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency)); + memset (adj, 0, sizeof (struct isis_adjacency)); + memcpy (adj->sysid, id, ISIS_SYS_ID_LEN); + + return adj; +} + +struct isis_adjacency * +isis_new_adj (u_char *id, u_char *snpa, int level, + struct isis_circuit *circuit) +{ + + struct isis_adjacency *adj; + int i; + + adj = adj_alloc (id); /* P2P kludge */ + + if (adj == NULL){ + zlog_err ("Out of memory!"); + return NULL; + } + + memcpy (adj->snpa, snpa, 6); + adj->circuit = circuit; + adj->level = level; + adj->flaps = 0; + adj->last_flap = time (NULL); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + listnode_add (circuit->u.bc.adjdb[level-1], adj); + adj->dischanges[level - 1] = 0; + for (i = 0; i < DIS_RECORDS; i++) /* clear N DIS state change records */ + { + adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis + = ISIS_UNKNOWN_DIS; + adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change + = time (NULL); + } + } + + return adj; +} + +struct isis_adjacency * +isis_adj_lookup (u_char *sysid, struct list *adjdb) +{ + struct isis_adjacency *adj; + struct listnode *node; + + for (node = listhead (adjdb); node; nextnode (node)) { + adj = getdata (node); + if (memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0) + return adj; + } + + return NULL; +} + + +struct isis_adjacency * +isis_adj_lookup_snpa (u_char *ssnpa, struct list *adjdb) +{ + struct listnode *node; + struct isis_adjacency *adj; + + for (node = listhead (adjdb); node; nextnode (node)) { + adj = getdata (node); + if (memcmp (adj->snpa, ssnpa, ETH_ALEN) == 0) + return adj; + } + + return NULL; +} + +/* + * When we recieve a NULL list, we will know its p2p + */ +void +isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb) +{ + struct isis_adjacency *adj2; + struct listnode *node; + + if (adjdb) { + for (node = listhead (adjdb); node; nextnode (node)) { + adj2 = getdata (node); + if (adj2 == adj) + break; + } + listnode_delete (adjdb, node); + } + + if (adj->ipv4_addrs) + list_delete (adj->ipv4_addrs); +#ifdef HAVE_IPV6 + if (adj->ipv6_addrs) + list_delete (adj->ipv6_addrs); +#endif + if (adj) { + XFREE (MTYPE_ISIS_ADJACENCY,adj); + } else { + zlog_info ("tried to delete a non-existent adjacency"); + } + + + + return; +} + +void +isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state, + char *reason) + +{ + int old_state; + int level = adj->level; + struct isis_circuit *circuit; + + old_state = adj->adj_state; + adj->adj_state = state; + + circuit = adj->circuit; + + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_info ("ISIS-Adj (%s): Adjacency state change %d->%d: %s", + circuit->area->area_tag, + old_state, + state, + reason ? reason : "unspecified"); + } + + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + if (state == ISIS_ADJ_UP) + circuit->upadjcount[level-1]++; + if (state == ISIS_ADJ_DOWN) { + isis_delete_adj (adj, adj->circuit->u.bc.adjdb[level - 1]); + circuit->upadjcount[level-1]--; + } + + 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]); + } else if (state == ISIS_ADJ_UP) { /* p2p interface */ + if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN) + send_hello (circuit, 1); + + /* update counter & timers for debugging purposes */ + adj->last_flap = time(NULL); + adj->flaps++; + + /* 7.3.17 - going up on P2P -> send CSNP */ + /* FIXME: yup, I know its wrong... but i will do it! (for now) */ + send_csnp (circuit,1); + send_csnp (circuit,2); + } else if (state == ISIS_ADJ_DOWN) { /* p2p interface */ + adj->circuit->u.p2p.neighbor = NULL; + isis_delete_adj (adj, NULL); + } + return; +} + + +void +isis_adj_print (struct isis_adjacency *adj) +{ + struct isis_dynhn *dyn; + struct listnode *node; + struct in_addr *ipv4_addr; +#ifdef HAVE_IPV6 + struct in6_addr *ipv6_addr; + u_char ip6 [INET6_ADDRSTRLEN]; +#endif /* HAVE_IPV6 */ + + if(!adj) + return; + dyn = dynhn_find_by_id (adj->sysid); + if (dyn) + zlog_info ("%s", dyn->name.name); + + zlog_info ("SystemId %20s SNPA %s, level %d\nHolding Time %d", + adj->sysid ? sysid_print (adj->sysid) : "unknown" , + snpa_print (adj->snpa), + adj->level, adj->hold_time); + if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0) { + zlog_info ("IPv4 Addresses:"); + + for (node = listhead (adj->ipv4_addrs); node; nextnode (node)) { + ipv4_addr = getdata (node); + zlog_info ("%s", inet_ntoa(*ipv4_addr)); + } + } + +#ifdef HAVE_IPV6 + if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0) { + zlog_info ("IPv6 Addresses:"); + for (node = listhead (adj->ipv6_addrs); node; nextnode (node)) { + ipv6_addr = getdata (node); + inet_ntop (AF_INET6, ipv6_addr, ip6, INET6_ADDRSTRLEN); + zlog_info ("%s", ip6); + } + } +#endif /* HAVE_IPV6 */ + zlog_info ("Speaks: %s", nlpid2string(&adj->nlpids)); + + + return; +} + +int +isis_adj_expire (struct thread *thread) +{ + struct isis_adjacency *adj; + int level; + + /* + * Get the adjacency + */ + adj = THREAD_ARG (thread); + assert (adj); + level = adj->level; + + /* trigger the adj expire event */ + isis_adj_state_change (adj, ISIS_ADJ_DOWN, "holding time expired"); + + return 0; +} + +const char * +adj_state2string (int state) +{ + + switch (state) { + case ISIS_ADJ_INITIALIZING: + return "Initializing"; + case ISIS_ADJ_UP: + return "Up"; + case ISIS_ADJ_DOWN: + return "Down"; + default: + return "Unknown"; + } + + return NULL; /* not reached */ +} + +/* + * show clns/isis neighbor (detail) + */ +void +isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail) +{ + +#ifdef HAVE_IPV6 + struct in6_addr *ipv6_addr; + u_char ip6 [INET6_ADDRSTRLEN]; +#endif /* HAVE_IPV6 */ + 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) + vty_out (vty, " %-20s", dyn->name.name); + else if (adj->sysid){ + vty_out (vty, " %-20s", sysid_print (adj->sysid)); + } else { + vty_out (vty, " unknown "); + } + + if (detail == ISIS_UI_LEVEL_BRIEF) { + if (adj->circuit) + vty_out (vty, "%-12s",adj->circuit->interface->name); + else + vty_out (vty, "NULL circuit!"); + vty_out (vty, "%-3u", adj->level); /* level */ + vty_out (vty, "%-13s", adj_state2string (adj->adj_state)); + now = time (NULL); + vty_out (vty, "%-9lu", adj->last_upd + adj->hold_time - now); + vty_out (vty, "%-10s", snpa_print (adj->snpa)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + if (detail == ISIS_UI_LEVEL_DETAIL) { + level = adj->level; + if (adj->circuit) + vty_out (vty, "%s Interface: %s", + VTY_NEWLINE, + adj->circuit->interface->name); /* interface name */ + else + vty_out (vty, "NULL circuit!%s", VTY_NEWLINE); + vty_out (vty, ", Level: %u", adj->level); /* level */ + vty_out (vty, ", State: %s", adj_state2string (adj->adj_state)); + now = time (NULL); + vty_out (vty, ", Expires in %s", + time2string (adj->last_upd + adj->hold_time - now)); + vty_out (vty, "%s Adjacency flaps: %u", + VTY_NEWLINE, + adj->flaps); + vty_out (vty, ", Last: %s ago", time2string(now - adj->last_flap)); + vty_out (vty, "%s Circuit type: %s", + VTY_NEWLINE, + circuit_t2string(adj->circuit_t)); + vty_out (vty, ", Speaks: %s", nlpid2string(&adj->nlpids)); + vty_out (vty, "%s SNPA: %s", + VTY_NEWLINE, + snpa_print (adj->snpa)); + dyn = dynhn_find_by_id (adj->lanid); + if (dyn) + vty_out (vty, ", LAN id: %s.%02x", + dyn->name.name, + adj->lanid[ISIS_SYS_ID_LEN]); + else + vty_out (vty, ", LAN id: %s.%02x", + sysid_print (adj->lanid), + adj->lanid[ISIS_SYS_ID_LEN]); + + vty_out (vty, "%s Priority: %u", + VTY_NEWLINE, + adj->prio[adj->level-1]); + + vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago%s", + isis_disflag2string(adj->dis_record[ISIS_LEVELS+level-1].dis), + adj->dischanges[level-1], + time2string (now - + (adj->dis_record[ISIS_LEVELS + level - 1].last_dis_change)), + VTY_NEWLINE); + + if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0) { + vty_out (vty, " IPv4 Addresses:%s", VTY_NEWLINE); + for (node = listhead (adj->ipv4_addrs);node; nextnode (node)) { + ip_addr = getdata (node); + vty_out (vty, " %s%s", inet_ntoa(*ip_addr), VTY_NEWLINE); + } + } +#ifdef HAVE_IPV6 + if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0) { + vty_out (vty, " IPv6 Addresses:%s", VTY_NEWLINE); + for (node = listhead (adj->ipv6_addrs); node; nextnode (node)) { + ipv6_addr = getdata (node); + inet_ntop (AF_INET6, ipv6_addr, ip6, INET6_ADDRSTRLEN); + vty_out (vty, " %s%s", ip6, VTY_NEWLINE); + } + } +#endif /* HAVE_IPV6 */ + vty_out (vty, "%s", VTY_NEWLINE); + } + return; +} + +void +isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty) { + isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF); +} + +void +isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty) { + isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL); +} + +void +isis_adj_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty) { + isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE); +} + +void +isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty) +{ + isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF); +} + +void +isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj, struct vty *vty) +{ + isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL); +} + +void +isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty) +{ + isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE); +} + +void +isis_adjdb_iterate (struct list *adjdb, void (*func)(struct isis_adjacency*, + void *), void *arg) +{ + struct listnode *node; + struct isis_adjacency *adj; + for (node = listhead (adjdb); node; nextnode (node)) { + adj = getdata (node); + (*func)(adj, arg); + } +} + +void +isis_adj_build_neigh_list (struct list *adjdb, struct list *list) + +{ + struct isis_adjacency *adj; + struct listnode *node; + + + if (!list) { + zlog_warn ("isis_adj_build_neigh_list(): NULL list"); + return; + } + + for (node = listhead (adjdb); node; nextnode (node)) { + adj = getdata (node); + if (!adj) { + zlog_warn ("isis_adj_build_neigh_list(): NULL adj"); + return; + } + + if ((adj->adj_state == ISIS_ADJ_UP || + adj->adj_state == ISIS_ADJ_INITIALIZING)) + listnode_add (list, adj->snpa); + } + return; +} + +void +isis_adj_build_up_list (struct list *adjdb, struct list *list) +{ + struct isis_adjacency *adj; + struct listnode *node; + + if (!list) { + zlog_warn ("isis_adj_build_up_list(): NULL list"); + return; + } + + for (node = listhead (adjdb); node; nextnode (node)) { + adj = getdata (node); + + if (!adj) { + zlog_warn ("isis_adj_build_up_list(): NULL adj"); + return; + } + + if (adj->adj_state == ISIS_ADJ_UP) + listnode_add (list, adj); + } + + return; +} + -- cgit v1.2.1