isis_adjacency.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /*
  2. * IS-IS Rout(e)ing protocol - isis_adjacency.c
  3. * handling of IS-IS adjacencies
  4. *
  5. * Copyright (C) 2001,2002 Sampo Saaristo
  6. * Tampere University of Technology
  7. * Institute of Communications Engineering
  8. *
  9. * This program is free software; you can redistribute it and/or modify it
  10. * under the terms of the GNU General Public Licenseas published by the Free
  11. * Software Foundation; either version 2 of the License, or (at your option)
  12. * any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,but WITHOUT
  15. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  17. * more details.
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. #include <zebra.h>
  23. #include "log.h"
  24. #include "memory.h"
  25. #include "hash.h"
  26. #include "vty.h"
  27. #include "linklist.h"
  28. #include "thread.h"
  29. #include "if.h"
  30. #include "stream.h"
  31. #include "isisd/dict.h"
  32. #include "isisd/include-netbsd/iso.h"
  33. #include "isisd/isis_constants.h"
  34. #include "isisd/isis_common.h"
  35. #include "isisd/isis_flags.h"
  36. #include "isisd/isisd.h"
  37. #include "isisd/isis_circuit.h"
  38. #include "isisd/isis_adjacency.h"
  39. #include "isisd/isis_misc.h"
  40. #include "isisd/isis_dr.h"
  41. #include "isisd/isis_dynhn.h"
  42. #include "isisd/isis_pdu.h"
  43. #include "isisd/isis_tlv.h"
  44. #include "isisd/isis_lsp.h"
  45. #include "isisd/isis_spf.h"
  46. #include "isisd/isis_events.h"
  47. extern struct isis *isis;
  48. static struct isis_adjacency *
  49. adj_alloc (u_char * id)
  50. {
  51. struct isis_adjacency *adj;
  52. adj = XCALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency));
  53. memcpy (adj->sysid, id, ISIS_SYS_ID_LEN);
  54. return adj;
  55. }
  56. struct isis_adjacency *
  57. isis_new_adj (u_char * id, u_char * snpa, int level,
  58. struct isis_circuit *circuit)
  59. {
  60. struct isis_adjacency *adj;
  61. int i;
  62. adj = adj_alloc (id); /* P2P kludge */
  63. if (adj == NULL)
  64. {
  65. zlog_err ("Out of memory!");
  66. return NULL;
  67. }
  68. if (snpa) {
  69. memcpy (adj->snpa, snpa, ETH_ALEN);
  70. } else {
  71. memset (adj->snpa, ' ', ETH_ALEN);
  72. }
  73. adj->circuit = circuit;
  74. adj->level = level;
  75. adj->flaps = 0;
  76. adj->last_flap = time (NULL);
  77. if (circuit->circ_type == CIRCUIT_T_BROADCAST)
  78. {
  79. listnode_add (circuit->u.bc.adjdb[level - 1], adj);
  80. adj->dischanges[level - 1] = 0;
  81. for (i = 0; i < DIS_RECORDS; i++) /* clear N DIS state change records */
  82. {
  83. adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis
  84. = ISIS_UNKNOWN_DIS;
  85. adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change
  86. = time (NULL);
  87. }
  88. }
  89. return adj;
  90. }
  91. struct isis_adjacency *
  92. isis_adj_lookup (u_char * sysid, struct list *adjdb)
  93. {
  94. struct isis_adjacency *adj;
  95. struct listnode *node;
  96. for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
  97. if (memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0)
  98. return adj;
  99. return NULL;
  100. }
  101. struct isis_adjacency *
  102. isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb)
  103. {
  104. struct listnode *node;
  105. struct isis_adjacency *adj;
  106. for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
  107. if (memcmp (adj->snpa, ssnpa, ETH_ALEN) == 0)
  108. return adj;
  109. return NULL;
  110. }
  111. void
  112. isis_delete_adj (void *arg)
  113. {
  114. struct isis_adjacency *adj = arg;
  115. if (!adj)
  116. return;
  117. THREAD_TIMER_OFF (adj->t_expire);
  118. /* remove from SPF trees */
  119. spftree_area_adj_del (adj->circuit->area, adj);
  120. if (adj->area_addrs)
  121. list_delete (adj->area_addrs);
  122. if (adj->ipv4_addrs)
  123. list_delete (adj->ipv4_addrs);
  124. #ifdef HAVE_IPV6
  125. if (adj->ipv6_addrs)
  126. list_delete (adj->ipv6_addrs);
  127. #endif
  128. XFREE (MTYPE_ISIS_ADJACENCY, adj);
  129. return;
  130. }
  131. static const char *
  132. adj_state2string (int state)
  133. {
  134. switch (state)
  135. {
  136. case ISIS_ADJ_INITIALIZING:
  137. return "Initializing";
  138. case ISIS_ADJ_UP:
  139. return "Up";
  140. case ISIS_ADJ_DOWN:
  141. return "Down";
  142. default:
  143. return "Unknown";
  144. }
  145. return NULL; /* not reached */
  146. }
  147. void
  148. isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state,
  149. const char *reason)
  150. {
  151. int old_state;
  152. int level;
  153. struct isis_circuit *circuit;
  154. old_state = adj->adj_state;
  155. adj->adj_state = new_state;
  156. circuit = adj->circuit;
  157. if (isis->debugs & DEBUG_ADJ_PACKETS)
  158. {
  159. zlog_debug ("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
  160. circuit->area->area_tag,
  161. old_state, new_state, reason ? reason : "unspecified");
  162. }
  163. if (circuit->area->log_adj_changes)
  164. {
  165. const char *adj_name;
  166. struct isis_dynhn *dyn;
  167. dyn = dynhn_find_by_id (adj->sysid);
  168. if (dyn)
  169. adj_name = (const char *)dyn->name.name;
  170. else
  171. adj_name = adj->sysid ? sysid_print (adj->sysid) : "unknown";
  172. zlog_info ("%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s",
  173. adj_name,
  174. adj->circuit ? adj->circuit->interface->name : "no circuit",
  175. adj_state2string (old_state),
  176. adj_state2string (new_state),
  177. reason ? reason : "unspecified");
  178. }
  179. if (circuit->circ_type == CIRCUIT_T_BROADCAST)
  180. {
  181. for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++)
  182. {
  183. if ((adj->level & level) == 0)
  184. continue;
  185. if (new_state == ISIS_ADJ_UP)
  186. {
  187. circuit->upadjcount[level - 1]++;
  188. isis_event_adjacency_state_change (adj, new_state);
  189. /* update counter & timers for debugging purposes */
  190. adj->last_flap = time (NULL);
  191. adj->flaps++;
  192. }
  193. else if (new_state == ISIS_ADJ_DOWN)
  194. {
  195. listnode_delete (circuit->u.bc.adjdb[level - 1], adj);
  196. circuit->upadjcount[level - 1]--;
  197. if (circuit->upadjcount[level - 1] == 0)
  198. {
  199. /* Clean lsp_queue when no adj is up. */
  200. if (circuit->lsp_queue)
  201. list_delete_all_node (circuit->lsp_queue);
  202. }
  203. isis_event_adjacency_state_change (adj, new_state);
  204. isis_delete_adj (adj);
  205. }
  206. if (circuit->u.bc.lan_neighs[level - 1])
  207. {
  208. list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
  209. isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
  210. circuit->u.bc.lan_neighs[level - 1]);
  211. }
  212. /* On adjacency state change send new pseudo LSP if we are the DR */
  213. if (circuit->u.bc.is_dr[level - 1])
  214. lsp_regenerate_schedule_pseudo (circuit, level);
  215. }
  216. }
  217. else if (circuit->circ_type == CIRCUIT_T_P2P)
  218. {
  219. for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++)
  220. {
  221. if ((adj->level & level) == 0)
  222. continue;
  223. if (new_state == ISIS_ADJ_UP)
  224. {
  225. circuit->upadjcount[level - 1]++;
  226. isis_event_adjacency_state_change (adj, new_state);
  227. if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
  228. send_hello (circuit, level);
  229. /* update counter & timers for debugging purposes */
  230. adj->last_flap = time (NULL);
  231. adj->flaps++;
  232. /* 7.3.17 - going up on P2P -> send CSNP */
  233. /* FIXME: yup, I know its wrong... but i will do it! (for now) */
  234. send_csnp (circuit, level);
  235. }
  236. else if (new_state == ISIS_ADJ_DOWN)
  237. {
  238. if (adj->circuit->u.p2p.neighbor == adj)
  239. adj->circuit->u.p2p.neighbor = NULL;
  240. circuit->upadjcount[level - 1]--;
  241. if (circuit->upadjcount[level - 1] == 0)
  242. {
  243. /* Clean lsp_queue when no adj is up. */
  244. if (circuit->lsp_queue)
  245. list_delete_all_node (circuit->lsp_queue);
  246. }
  247. isis_event_adjacency_state_change (adj, new_state);
  248. isis_delete_adj (adj);
  249. }
  250. }
  251. }
  252. return;
  253. }
  254. void
  255. isis_adj_print (struct isis_adjacency *adj)
  256. {
  257. struct isis_dynhn *dyn;
  258. struct listnode *node;
  259. struct in_addr *ipv4_addr;
  260. #ifdef HAVE_IPV6
  261. struct in6_addr *ipv6_addr;
  262. u_char ip6[INET6_ADDRSTRLEN];
  263. #endif /* HAVE_IPV6 */
  264. if (!adj)
  265. return;
  266. dyn = dynhn_find_by_id (adj->sysid);
  267. if (dyn)
  268. zlog_debug ("%s", dyn->name.name);
  269. zlog_debug ("SystemId %20s SNPA %s, level %d\nHolding Time %d",
  270. adj->sysid ? sysid_print (adj->sysid) : "unknown",
  271. snpa_print (adj->snpa), adj->level, adj->hold_time);
  272. if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
  273. {
  274. zlog_debug ("IPv4 Address(es):");
  275. for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
  276. zlog_debug ("%s", inet_ntoa (*ipv4_addr));
  277. }
  278. #ifdef HAVE_IPV6
  279. if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
  280. {
  281. zlog_debug ("IPv6 Address(es):");
  282. for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
  283. {
  284. inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
  285. zlog_debug ("%s", ip6);
  286. }
  287. }
  288. #endif /* HAVE_IPV6 */
  289. zlog_debug ("Speaks: %s", nlpid2string (&adj->nlpids));
  290. return;
  291. }
  292. int
  293. isis_adj_expire (struct thread *thread)
  294. {
  295. struct isis_adjacency *adj;
  296. /*
  297. * Get the adjacency
  298. */
  299. adj = THREAD_ARG (thread);
  300. assert (adj);
  301. adj->t_expire = NULL;
  302. /* trigger the adj expire event */
  303. isis_adj_state_change (adj, ISIS_ADJ_DOWN, "holding time expired");
  304. return 0;
  305. }
  306. /*
  307. * show isis neighbor [detail]
  308. */
  309. void
  310. isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail)
  311. {
  312. #ifdef HAVE_IPV6
  313. struct in6_addr *ipv6_addr;
  314. u_char ip6[INET6_ADDRSTRLEN];
  315. #endif /* HAVE_IPV6 */
  316. struct in_addr *ip_addr;
  317. time_t now;
  318. struct isis_dynhn *dyn;
  319. int level;
  320. struct listnode *node;
  321. dyn = dynhn_find_by_id (adj->sysid);
  322. if (dyn)
  323. vty_out (vty, " %-20s", dyn->name.name);
  324. else if (adj->sysid)
  325. {
  326. vty_out (vty, " %-20s", sysid_print (adj->sysid));
  327. }
  328. else
  329. {
  330. vty_out (vty, " unknown ");
  331. }
  332. if (detail == ISIS_UI_LEVEL_BRIEF)
  333. {
  334. if (adj->circuit)
  335. vty_out (vty, "%-12s", adj->circuit->interface->name);
  336. else
  337. vty_out (vty, "NULL circuit!");
  338. vty_out (vty, "%-3u", adj->level); /* level */
  339. vty_out (vty, "%-13s", adj_state2string (adj->adj_state));
  340. now = time (NULL);
  341. if (adj->last_upd)
  342. vty_out (vty, "%-9lu", adj->last_upd + adj->hold_time - now);
  343. else
  344. vty_out (vty, "- ");
  345. vty_out (vty, "%-10s", snpa_print (adj->snpa));
  346. vty_out (vty, "%s", VTY_NEWLINE);
  347. }
  348. if (detail == ISIS_UI_LEVEL_DETAIL)
  349. {
  350. level = adj->level;
  351. vty_out (vty, "%s", VTY_NEWLINE);
  352. if (adj->circuit)
  353. vty_out (vty, " Interface: %s", adj->circuit->interface->name);
  354. else
  355. vty_out (vty, " Interface: NULL circuit");
  356. vty_out (vty, ", Level: %u", adj->level); /* level */
  357. vty_out (vty, ", State: %s", adj_state2string (adj->adj_state));
  358. now = time (NULL);
  359. if (adj->last_upd)
  360. vty_out (vty, ", Expires in %s",
  361. time2string (adj->last_upd + adj->hold_time - now));
  362. else
  363. vty_out (vty, ", Expires in %s", time2string (adj->hold_time));
  364. vty_out (vty, "%s", VTY_NEWLINE);
  365. vty_out (vty, " Adjacency flaps: %u", adj->flaps);
  366. vty_out (vty, ", Last: %s ago", time2string (now - adj->last_flap));
  367. vty_out (vty, "%s", VTY_NEWLINE);
  368. vty_out (vty, " Circuit type: %s", circuit_t2string (adj->circuit_t));
  369. vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids));
  370. vty_out (vty, "%s", VTY_NEWLINE);
  371. vty_out (vty, " SNPA: %s", snpa_print (adj->snpa));
  372. if (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)
  373. {
  374. dyn = dynhn_find_by_id (adj->lanid);
  375. if (dyn)
  376. vty_out (vty, ", LAN id: %s.%02x",
  377. dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]);
  378. else
  379. vty_out (vty, ", LAN id: %s.%02x",
  380. sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]);
  381. vty_out (vty, "%s", VTY_NEWLINE);
  382. vty_out (vty, " LAN Priority: %u", adj->prio[adj->level - 1]);
  383. vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago",
  384. isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1].
  385. dis), adj->dischanges[level - 1],
  386. time2string (now -
  387. (adj->dis_record[ISIS_LEVELS + level - 1].
  388. last_dis_change)));
  389. }
  390. vty_out (vty, "%s", VTY_NEWLINE);
  391. if (adj->area_addrs && listcount (adj->area_addrs) > 0)
  392. {
  393. struct area_addr *area_addr;
  394. vty_out (vty, " Area Address(es):%s", VTY_NEWLINE);
  395. for (ALL_LIST_ELEMENTS_RO (adj->area_addrs, node, area_addr))
  396. vty_out (vty, " %s%s", isonet_print (area_addr->area_addr,
  397. area_addr->addr_len), VTY_NEWLINE);
  398. }
  399. if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
  400. {
  401. vty_out (vty, " IPv4 Address(es):%s", VTY_NEWLINE);
  402. for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ip_addr))
  403. vty_out (vty, " %s%s", inet_ntoa (*ip_addr), VTY_NEWLINE);
  404. }
  405. #ifdef HAVE_IPV6
  406. if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
  407. {
  408. vty_out (vty, " IPv6 Address(es):%s", VTY_NEWLINE);
  409. for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
  410. {
  411. inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
  412. vty_out (vty, " %s%s", ip6, VTY_NEWLINE);
  413. }
  414. }
  415. #endif /* HAVE_IPV6 */
  416. vty_out (vty, "%s", VTY_NEWLINE);
  417. }
  418. return;
  419. }
  420. void
  421. isis_adj_build_neigh_list (struct list *adjdb, struct list *list)
  422. {
  423. struct isis_adjacency *adj;
  424. struct listnode *node;
  425. if (!list)
  426. {
  427. zlog_warn ("isis_adj_build_neigh_list(): NULL list");
  428. return;
  429. }
  430. for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
  431. {
  432. if (!adj)
  433. {
  434. zlog_warn ("isis_adj_build_neigh_list(): NULL adj");
  435. return;
  436. }
  437. if ((adj->adj_state == ISIS_ADJ_UP ||
  438. adj->adj_state == ISIS_ADJ_INITIALIZING))
  439. listnode_add (list, adj->snpa);
  440. }
  441. return;
  442. }
  443. void
  444. isis_adj_build_up_list (struct list *adjdb, struct list *list)
  445. {
  446. struct isis_adjacency *adj;
  447. struct listnode *node;
  448. if (!list)
  449. {
  450. zlog_warn ("isis_adj_build_up_list(): NULL list");
  451. return;
  452. }
  453. for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
  454. {
  455. if (!adj)
  456. {
  457. zlog_warn ("isis_adj_build_up_list(): NULL adj");
  458. return;
  459. }
  460. if (adj->adj_state == ISIS_ADJ_UP)
  461. listnode_add (list, adj);
  462. }
  463. return;
  464. }