isis_adjacency.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  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 <stdio.h>
  23. #include <limits.h>
  24. #include <string.h>
  25. #include <zebra.h>
  26. #include "log.h"
  27. #include "memory.h"
  28. #include "hash.h"
  29. #include "vty.h"
  30. #include "linklist.h"
  31. #include "thread.h"
  32. #include "if.h"
  33. #include "stream.h"
  34. #include "isisd/dict.h"
  35. #include "isisd/include-netbsd/iso.h"
  36. #include "isisd/isis_constants.h"
  37. #include "isisd/isis_common.h"
  38. #include "isisd/isisd.h"
  39. #include "isisd/isis_circuit.h"
  40. #include "isisd/isis_adjacency.h"
  41. #include "isisd/isis_misc.h"
  42. #include "isisd/isis_dr.h"
  43. #include "isisd/isis_dynhn.h"
  44. #include "isisd/isis_pdu.h"
  45. extern struct isis *isis;
  46. struct isis_adjacency *
  47. adj_alloc (u_char * id)
  48. {
  49. struct isis_adjacency *adj;
  50. adj = XMALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency));
  51. memset (adj, 0, sizeof (struct isis_adjacency));
  52. memcpy (adj->sysid, id, ISIS_SYS_ID_LEN);
  53. return adj;
  54. }
  55. struct isis_adjacency *
  56. isis_new_adj (u_char * id, u_char * snpa, int level,
  57. struct isis_circuit *circuit)
  58. {
  59. struct isis_adjacency *adj;
  60. int i;
  61. adj = adj_alloc (id); /* P2P kludge */
  62. if (adj == NULL)
  63. {
  64. zlog_err ("Out of memory!");
  65. return NULL;
  66. }
  67. memcpy (adj->snpa, snpa, 6);
  68. adj->circuit = circuit;
  69. adj->level = level;
  70. adj->flaps = 0;
  71. adj->last_flap = time (NULL);
  72. if (circuit->circ_type == CIRCUIT_T_BROADCAST)
  73. {
  74. listnode_add (circuit->u.bc.adjdb[level - 1], adj);
  75. adj->dischanges[level - 1] = 0;
  76. for (i = 0; i < DIS_RECORDS; i++) /* clear N DIS state change records */
  77. {
  78. adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis
  79. = ISIS_UNKNOWN_DIS;
  80. adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change
  81. = time (NULL);
  82. }
  83. }
  84. return adj;
  85. }
  86. struct isis_adjacency *
  87. isis_adj_lookup (u_char * sysid, struct list *adjdb)
  88. {
  89. struct isis_adjacency *adj;
  90. struct listnode *node;
  91. for (node = listhead (adjdb); node; nextnode (node))
  92. {
  93. adj = getdata (node);
  94. if (memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0)
  95. return adj;
  96. }
  97. return NULL;
  98. }
  99. struct isis_adjacency *
  100. isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb)
  101. {
  102. struct listnode *node;
  103. struct isis_adjacency *adj;
  104. for (node = listhead (adjdb); node; nextnode (node))
  105. {
  106. adj = getdata (node);
  107. if (memcmp (adj->snpa, ssnpa, ETH_ALEN) == 0)
  108. return adj;
  109. }
  110. return NULL;
  111. }
  112. /*
  113. * When we recieve a NULL list, we will know its p2p
  114. */
  115. void
  116. isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb)
  117. {
  118. struct isis_adjacency *adj2;
  119. struct listnode *node;
  120. if (adjdb)
  121. {
  122. for (node = listhead (adjdb); node; nextnode (node))
  123. {
  124. adj2 = getdata (node);
  125. if (adj2 == adj)
  126. break;
  127. }
  128. listnode_delete (adjdb, adj);
  129. }
  130. if (adj->ipv4_addrs)
  131. list_delete (adj->ipv4_addrs);
  132. #ifdef HAVE_IPV6
  133. if (adj->ipv6_addrs)
  134. list_delete (adj->ipv6_addrs);
  135. #endif
  136. if (adj)
  137. {
  138. XFREE (MTYPE_ISIS_ADJACENCY, adj);
  139. }
  140. else
  141. {
  142. zlog_info ("tried to delete a non-existent adjacency");
  143. }
  144. return;
  145. }
  146. void
  147. isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state,
  148. char *reason)
  149. {
  150. int old_state;
  151. int level = adj->level;
  152. struct isis_circuit *circuit;
  153. old_state = adj->adj_state;
  154. adj->adj_state = state;
  155. circuit = adj->circuit;
  156. if (isis->debugs & DEBUG_ADJ_PACKETS)
  157. {
  158. zlog_info ("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
  159. circuit->area->area_tag,
  160. old_state, state, reason ? reason : "unspecified");
  161. }
  162. if (circuit->circ_type == CIRCUIT_T_BROADCAST)
  163. {
  164. if (state == ISIS_ADJ_UP)
  165. circuit->upadjcount[level - 1]++;
  166. if (state == ISIS_ADJ_DOWN)
  167. {
  168. isis_delete_adj (adj, adj->circuit->u.bc.adjdb[level - 1]);
  169. circuit->upadjcount[level - 1]--;
  170. }
  171. list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
  172. isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
  173. circuit->u.bc.lan_neighs[level - 1]);
  174. }
  175. else if (state == ISIS_ADJ_UP)
  176. { /* p2p interface */
  177. if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
  178. send_hello (circuit, 1);
  179. /* update counter & timers for debugging purposes */
  180. adj->last_flap = time (NULL);
  181. adj->flaps++;
  182. /* 7.3.17 - going up on P2P -> send CSNP */
  183. /* FIXME: yup, I know its wrong... but i will do it! (for now) */
  184. send_csnp (circuit, 1);
  185. send_csnp (circuit, 2);
  186. }
  187. else if (state == ISIS_ADJ_DOWN)
  188. { /* p2p interface */
  189. adj->circuit->u.p2p.neighbor = NULL;
  190. isis_delete_adj (adj, NULL);
  191. }
  192. return;
  193. }
  194. void
  195. isis_adj_print (struct isis_adjacency *adj)
  196. {
  197. struct isis_dynhn *dyn;
  198. struct listnode *node;
  199. struct in_addr *ipv4_addr;
  200. #ifdef HAVE_IPV6
  201. struct in6_addr *ipv6_addr;
  202. u_char ip6[INET6_ADDRSTRLEN];
  203. #endif /* HAVE_IPV6 */
  204. if (!adj)
  205. return;
  206. dyn = dynhn_find_by_id (adj->sysid);
  207. if (dyn)
  208. zlog_info ("%s", dyn->name.name);
  209. zlog_info ("SystemId %20s SNPA %s, level %d\nHolding Time %d",
  210. adj->sysid ? sysid_print (adj->sysid) : "unknown",
  211. snpa_print (adj->snpa), adj->level, adj->hold_time);
  212. if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
  213. {
  214. zlog_info ("IPv4 Addresses:");
  215. for (node = listhead (adj->ipv4_addrs); node; nextnode (node))
  216. {
  217. ipv4_addr = getdata (node);
  218. zlog_info ("%s", inet_ntoa (*ipv4_addr));
  219. }
  220. }
  221. #ifdef HAVE_IPV6
  222. if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
  223. {
  224. zlog_info ("IPv6 Addresses:");
  225. for (node = listhead (adj->ipv6_addrs); node; nextnode (node))
  226. {
  227. ipv6_addr = getdata (node);
  228. inet_ntop (AF_INET6, ipv6_addr, ip6, INET6_ADDRSTRLEN);
  229. zlog_info ("%s", ip6);
  230. }
  231. }
  232. #endif /* HAVE_IPV6 */
  233. zlog_info ("Speaks: %s", nlpid2string (&adj->nlpids));
  234. return;
  235. }
  236. int
  237. isis_adj_expire (struct thread *thread)
  238. {
  239. struct isis_adjacency *adj;
  240. int level;
  241. /*
  242. * Get the adjacency
  243. */
  244. adj = THREAD_ARG (thread);
  245. assert (adj);
  246. level = adj->level;
  247. adj->t_expire = NULL;
  248. /* trigger the adj expire event */
  249. isis_adj_state_change (adj, ISIS_ADJ_DOWN, "holding time expired");
  250. return 0;
  251. }
  252. const char *
  253. adj_state2string (int state)
  254. {
  255. switch (state)
  256. {
  257. case ISIS_ADJ_INITIALIZING:
  258. return "Initializing";
  259. case ISIS_ADJ_UP:
  260. return "Up";
  261. case ISIS_ADJ_DOWN:
  262. return "Down";
  263. default:
  264. return "Unknown";
  265. }
  266. return NULL; /* not reached */
  267. }
  268. /*
  269. * show clns/isis neighbor (detail)
  270. */
  271. void
  272. isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
  273. {
  274. #ifdef HAVE_IPV6
  275. struct in6_addr *ipv6_addr;
  276. u_char ip6[INET6_ADDRSTRLEN];
  277. #endif /* HAVE_IPV6 */
  278. struct in_addr *ip_addr;
  279. time_t now;
  280. struct isis_dynhn *dyn;
  281. int level;
  282. struct listnode *node;
  283. dyn = dynhn_find_by_id (adj->sysid);
  284. if (dyn)
  285. vty_out (vty, " %-20s", dyn->name.name);
  286. else if (adj->sysid)
  287. {
  288. vty_out (vty, " %-20s", sysid_print (adj->sysid));
  289. }
  290. else
  291. {
  292. vty_out (vty, " unknown ");
  293. }
  294. if (detail == ISIS_UI_LEVEL_BRIEF)
  295. {
  296. if (adj->circuit)
  297. vty_out (vty, "%-12s", adj->circuit->interface->name);
  298. else
  299. vty_out (vty, "NULL circuit!");
  300. vty_out (vty, "%-3u", adj->level); /* level */
  301. vty_out (vty, "%-13s", adj_state2string (adj->adj_state));
  302. now = time (NULL);
  303. if (adj->last_upd)
  304. vty_out (vty, "%-9lu", adj->last_upd + adj->hold_time - now);
  305. else
  306. vty_out (vty, "- ");
  307. vty_out (vty, "%-10s", snpa_print (adj->snpa));
  308. vty_out (vty, "%s", VTY_NEWLINE);
  309. }
  310. if (detail == ISIS_UI_LEVEL_DETAIL)
  311. {
  312. level = adj->level;
  313. if (adj->circuit)
  314. vty_out (vty, "%s Interface: %s", VTY_NEWLINE, adj->circuit->interface->name); /* interface name */
  315. else
  316. vty_out (vty, "NULL circuit!%s", VTY_NEWLINE);
  317. vty_out (vty, ", Level: %u", adj->level); /* level */
  318. vty_out (vty, ", State: %s", adj_state2string (adj->adj_state));
  319. now = time (NULL);
  320. if (adj->last_upd)
  321. vty_out (vty, ", Expires in %s",
  322. time2string (adj->last_upd + adj->hold_time - now));
  323. else
  324. vty_out (vty, ", Expires in %s", time2string (adj->hold_time));
  325. vty_out (vty, "%s Adjacency flaps: %u", VTY_NEWLINE, adj->flaps);
  326. vty_out (vty, ", Last: %s ago", time2string (now - adj->last_flap));
  327. vty_out (vty, "%s Circuit type: %s",
  328. VTY_NEWLINE, circuit_t2string (adj->circuit_t));
  329. vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids));
  330. vty_out (vty, "%s SNPA: %s", VTY_NEWLINE, snpa_print (adj->snpa));
  331. dyn = dynhn_find_by_id (adj->lanid);
  332. if (dyn)
  333. vty_out (vty, ", LAN id: %s.%02x",
  334. dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]);
  335. else
  336. vty_out (vty, ", LAN id: %s.%02x",
  337. sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]);
  338. vty_out (vty, "%s Priority: %u",
  339. VTY_NEWLINE, adj->prio[adj->level - 1]);
  340. vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago%s",
  341. isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1].
  342. dis), adj->dischanges[level - 1],
  343. time2string (now -
  344. (adj->dis_record[ISIS_LEVELS + level - 1].
  345. last_dis_change)), VTY_NEWLINE);
  346. if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
  347. {
  348. vty_out (vty, " IPv4 Addresses:%s", VTY_NEWLINE);
  349. for (node = listhead (adj->ipv4_addrs); node; nextnode (node))
  350. {
  351. ip_addr = getdata (node);
  352. vty_out (vty, " %s%s", inet_ntoa (*ip_addr), VTY_NEWLINE);
  353. }
  354. }
  355. #ifdef HAVE_IPV6
  356. if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
  357. {
  358. vty_out (vty, " IPv6 Addresses:%s", VTY_NEWLINE);
  359. for (node = listhead (adj->ipv6_addrs); node; nextnode (node))
  360. {
  361. ipv6_addr = getdata (node);
  362. inet_ntop (AF_INET6, ipv6_addr, ip6, INET6_ADDRSTRLEN);
  363. vty_out (vty, " %s%s", ip6, VTY_NEWLINE);
  364. }
  365. }
  366. #endif /* HAVE_IPV6 */
  367. vty_out (vty, "%s", VTY_NEWLINE);
  368. }
  369. return;
  370. }
  371. void
  372. isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty)
  373. {
  374. isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
  375. }
  376. void
  377. isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
  378. {
  379. isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
  380. }
  381. void
  382. isis_adj_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
  383. {
  384. isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
  385. }
  386. void
  387. isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty)
  388. {
  389. isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
  390. }
  391. void
  392. isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
  393. {
  394. isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
  395. }
  396. void
  397. isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
  398. {
  399. isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
  400. }
  401. void
  402. isis_adjdb_iterate (struct list *adjdb, void (*func) (struct isis_adjacency *,
  403. void *), void *arg)
  404. {
  405. struct listnode *node;
  406. struct isis_adjacency *adj;
  407. for (node = listhead (adjdb); node; nextnode (node))
  408. {
  409. adj = getdata (node);
  410. (*func) (adj, arg);
  411. }
  412. }
  413. void
  414. isis_adj_build_neigh_list (struct list *adjdb, struct list *list)
  415. {
  416. struct isis_adjacency *adj;
  417. struct listnode *node;
  418. if (!list)
  419. {
  420. zlog_warn ("isis_adj_build_neigh_list(): NULL list");
  421. return;
  422. }
  423. for (node = listhead (adjdb); node; nextnode (node))
  424. {
  425. adj = getdata (node);
  426. if (!adj)
  427. {
  428. zlog_warn ("isis_adj_build_neigh_list(): NULL adj");
  429. return;
  430. }
  431. if ((adj->adj_state == ISIS_ADJ_UP ||
  432. adj->adj_state == ISIS_ADJ_INITIALIZING))
  433. listnode_add (list, adj->snpa);
  434. }
  435. return;
  436. }
  437. void
  438. isis_adj_build_up_list (struct list *adjdb, struct list *list)
  439. {
  440. struct isis_adjacency *adj;
  441. struct listnode *node;
  442. if (!list)
  443. {
  444. zlog_warn ("isis_adj_build_up_list(): NULL list");
  445. return;
  446. }
  447. for (node = listhead (adjdb); node; nextnode (node))
  448. {
  449. adj = getdata (node);
  450. if (!adj)
  451. {
  452. zlog_warn ("isis_adj_build_up_list(): NULL adj");
  453. return;
  454. }
  455. if (adj->adj_state == ISIS_ADJ_UP)
  456. listnode_add (list, adj);
  457. }
  458. return;
  459. }