1/*
2 * Copyright (C) 1999 Yasuhiro Ohara
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING.  If not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22#include "ospf6d.h"
23
24#include <zebra.h>
25
26#include "log.h"
27#include "thread.h"
28#include "linklist.h"
29#include "vty.h"
30#include "command.h"
31
32#include "ospf6_lsa.h"
33#include "ospf6_message.h"
34#include "ospf6_neighbor.h"
35#include "ospf6_nsm.h"
36#include "ospf6_lsa.h"
37#include "ospf6_lsdb.h"
38
39char *ospf6_neighbor_state_string[] =
40{
41  "None", "Down", "Attempt", "Init", "Twoway",
42  "ExStart", "ExChange", "Loading", "Full", NULL
43};
44
45int
46ospf6_neighbor_last_dbdesc_release (struct thread *thread)
47{
48  struct ospf6_neighbor *o6n;
49
50  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
51  assert (o6n);
52  memset (&o6n->last_dd, 0, sizeof (struct ospf6_dbdesc));
53  return 0;
54}
55
56
57
58void
59ospf6_neighbor_thread_cancel_all (struct ospf6_neighbor *o6n)
60{
61  if (o6n->inactivity_timer)
62    thread_cancel (o6n->inactivity_timer);
63  o6n->inactivity_timer = (struct thread *) NULL;
64
65  if (o6n->send_update)
66    thread_cancel (o6n->send_update);
67  o6n->send_update = (struct thread *) NULL;
68
69  if (o6n->thread_send_dbdesc)
70    thread_cancel (o6n->thread_send_dbdesc);
71  o6n->thread_send_dbdesc = (struct thread *) NULL;
72  if (o6n->thread_rxmt_dbdesc)
73    thread_cancel (o6n->thread_rxmt_dbdesc);
74  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
75
76  if (o6n->thread_rxmt_lsreq)
77    thread_cancel (o6n->thread_rxmt_lsreq);
78  o6n->thread_rxmt_lsreq = (struct thread *) NULL;
79}
80
81void
82ospf6_neighbor_lslist_clear (struct ospf6_neighbor *nei)
83{
84  ospf6_lsdb_remove_all (nei->summary_list);
85  ospf6_lsdb_remove_all (nei->request_list);
86  ospf6_lsdb_remove_all (nei->retrans_list);
87  ospf6_lsdb_remove_all (nei->dbdesc_list);
88}
89
90void
91ospf6_neighbor_summary_add (struct ospf6_lsa *lsa,
92                            struct ospf6_neighbor *nei)
93{
94  struct ospf6_lsa *summary;
95
96  if (IS_OSPF6_DUMP_NEIGHBOR)
97    {
98      zlog_info ("Neighbor %s summary-list:", nei->str);
99      zlog_info ("    Add %s", lsa->str);
100    }
101
102  ospf6_lsa_age_current (lsa);
103  summary = ospf6_lsa_summary_create (lsa->header);
104  ospf6_lsdb_add (summary, nei->summary_list);
105}
106
107void
108ospf6_neighbor_summary_remove (struct ospf6_lsa *lsa,
109                               struct ospf6_neighbor *nei)
110{
111  struct ospf6_lsa *summary;
112
113  if (IS_OSPF6_DUMP_NEIGHBOR)
114    {
115      zlog_info ("Neighbor %s summary-list:", nei->str);
116      zlog_info ("    Remove %s", lsa->str);
117    }
118
119  summary = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
120                                    lsa->header->adv_router, nei->summary_list);
121  ospf6_lsdb_remove (summary, nei->summary_list);
122}
123
124void
125ospf6_neighbor_request_add (struct ospf6_lsa *lsa,
126                            struct ospf6_neighbor *nei)
127{
128  struct ospf6_lsa *summary;
129
130  if (IS_OSPF6_DUMP_NEIGHBOR)
131    {
132      zlog_info ("Neighbor %s request-list:", nei->str);
133      zlog_info ("    Add %s", lsa->str);
134    }
135
136  ospf6_lsa_age_current (lsa);
137  summary = ospf6_lsa_summary_create (lsa->header);
138  ospf6_lsdb_add (summary, nei->request_list);
139}
140
141void
142ospf6_neighbor_request_remove (struct ospf6_lsa *lsa,
143                               struct ospf6_neighbor *nei)
144{
145  struct ospf6_lsa *summary;
146
147  if (IS_OSPF6_DUMP_NEIGHBOR)
148    {
149      zlog_info ("Neighbor %s request-list:", nei->str);
150      zlog_info ("    Remove %s", lsa->str);
151    }
152
153  summary = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
154                                    lsa->header->adv_router, nei->request_list);
155  ospf6_lsdb_remove (summary, nei->request_list);
156}
157
158void
159ospf6_neighbor_retrans_add (struct ospf6_lsa *lsa,
160                            struct ospf6_neighbor *nei)
161{
162  if (IS_OSPF6_DUMP_NEIGHBOR)
163    {
164      zlog_info ("Neighbor %s retrans-list:", nei->str);
165      zlog_info ("    Add %s", lsa->str);
166    }
167
168  ospf6_lsdb_add (lsa, nei->retrans_list);
169}
170
171void
172ospf6_neighbor_retrans_remove (struct ospf6_lsa *lsa,
173                               struct ospf6_neighbor *nei)
174{
175  if (IS_OSPF6_DUMP_NEIGHBOR)
176    {
177      zlog_info ("Neighbor %s retrans-list:", nei->str);
178      zlog_info ("    Remove %s", lsa->str);
179    }
180
181  ospf6_lsdb_remove (lsa, nei->retrans_list);
182}
183
184void
185ospf6_neighbor_dbdesc_add (struct ospf6_lsa *lsa,
186                           struct ospf6_neighbor *nei)
187{
188  if (IS_OSPF6_DUMP_NEIGHBOR)
189    {
190      zlog_info ("Neighbor %s dbdesc-list:", nei->str);
191      zlog_info ("    Add %s", lsa->str);
192    }
193
194  ospf6_lsdb_add (lsa, nei->dbdesc_list);
195}
196
197void
198ospf6_neighbor_dbdesc_remove (struct ospf6_lsa *lsa,
199                              struct ospf6_neighbor *nei)
200{
201  if (IS_OSPF6_DUMP_NEIGHBOR)
202    {
203      zlog_info ("Neighbor %s dbdesc-list:", nei->str);
204      zlog_info ("    Remove %s", lsa->str);
205    }
206
207  ospf6_lsdb_remove (lsa, nei->dbdesc_list);
208}
209
210
211/* prepare summary-list of his neighbor structure */
212void
213ospf6_neighbor_dbex_init (struct ospf6_neighbor *nei)
214{
215  struct ospf6_lsdb_node node;
216
217  /* clear ls-list */
218  ospf6_neighbor_lslist_clear (nei);
219
220  /* AS scope LSAs */
221  for (ospf6_lsdb_head (&node, nei->ospf6_interface->area->ospf6->lsdb);
222       ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
223    {
224      if (IS_LSA_MAXAGE (node.lsa))
225        ospf6_neighbor_retrans_add (node.lsa, nei);
226      else
227        ospf6_neighbor_summary_add (node.lsa, nei);
228    }
229
230  /* AREA scope LSAs */
231  for (ospf6_lsdb_head (&node, nei->ospf6_interface->area->lsdb);
232       ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
233    {
234      if (IS_LSA_MAXAGE (node.lsa))
235        ospf6_neighbor_retrans_add (node.lsa, nei);
236      else
237        ospf6_neighbor_summary_add (node.lsa, nei);
238    }
239
240  /* INTERFACE scope LSAs */
241  for (ospf6_lsdb_head (&node, nei->ospf6_interface->lsdb);
242       ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
243    {
244      if (IS_LSA_MAXAGE (node.lsa))
245        ospf6_neighbor_retrans_add (node.lsa, nei);
246      else
247        ospf6_neighbor_summary_add (node.lsa, nei);
248    }
249}
250
251/* create ospf6_neighbor */
252struct ospf6_neighbor *
253ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *o6i)
254{
255  struct ospf6_neighbor *new;
256  char buf[32];
257
258  new = (struct ospf6_neighbor *)
259    XMALLOC (MTYPE_OSPF6_NEIGHBOR, sizeof (struct ospf6_neighbor));
260  if (new == NULL)
261    {
262      zlog_warn ("neighbor: malloc failed");
263      return NULL;
264    }
265
266  memset (new, 0, sizeof (struct ospf6_neighbor));
267
268  new->state = OSPF6_NEIGHBOR_STATE_DOWN;
269
270  new->router_id = router_id;
271  inet_ntop (AF_INET, &router_id, buf, sizeof (buf));
272  snprintf (new->str, sizeof (new->str), "%s%%%s", buf, o6i->interface->name);
273  new->inactivity_timer = (struct thread *) NULL;
274
275  new->summary_list = ospf6_lsdb_create ();
276  new->request_list = ospf6_lsdb_create ();
277  new->retrans_list = ospf6_lsdb_create ();
278  new->dbdesc_list = ospf6_lsdb_create ();
279
280  listnode_add (o6i->neighbor_list, new);
281  new->ospf6_interface = o6i;
282
283  CALL_ADD_HOOK (&neighbor_hook, new);
284
285  return new;
286}
287
288void
289ospf6_neighbor_delete (struct ospf6_neighbor *o6n)
290{
291  CALL_REMOVE_HOOK (&neighbor_hook, o6n);
292
293  ospf6_neighbor_thread_cancel_all (o6n);
294  ospf6_neighbor_lslist_clear (o6n);
295
296  list_free (o6n->dbdesc_lsa);
297
298  ospf6_lsdb_delete (o6n->summary_list);
299  ospf6_lsdb_delete (o6n->request_list);
300  ospf6_lsdb_delete (o6n->retrans_list);
301  ospf6_lsdb_delete (o6n->dbdesc_list);
302
303  XFREE (MTYPE_OSPF6_NEIGHBOR, o6n);
304}
305
306struct ospf6_neighbor *
307ospf6_neighbor_lookup (u_int32_t router_id,
308                       struct ospf6_interface *o6i)
309{
310  listnode n;
311  struct ospf6_neighbor *o6n;
312
313  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
314    {
315      o6n = (struct ospf6_neighbor *) getdata (n);
316      if (o6n->router_id == router_id)
317        return o6n;
318    }
319  return (struct ospf6_neighbor *) NULL;
320}
321
322
323/* vty functions */
324/* show neighbor structure */
325void
326ospf6_neighbor_show_summary (struct vty *vty, struct ospf6_neighbor *o6n)
327{
328  char router_id[16];
329  char dr[16], bdr[16];
330  char duration[16];
331  struct timeval now, res;
332
333/*
334    vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
335             "RouterID", "State", "Duration", "DR", "BDR", "I/F",
336             "State", VTY_NEWLINE);
337*/
338
339  inet_ntop (AF_INET, &o6n->router_id, router_id, sizeof (router_id));
340  inet_ntop (AF_INET, &o6n->dr, dr, sizeof (dr));
341  inet_ntop (AF_INET, &o6n->bdr, bdr, sizeof (bdr));
342
343  gettimeofday (&now, NULL);
344  ospf6_timeval_sub (&now, &o6n->last_changed, &res);
345  ospf6_timeval_string_summary (&res, duration, sizeof (duration));
346
347  vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
348           router_id, ospf6_neighbor_state_string[o6n->state],
349           duration, dr, bdr, o6n->ospf6_interface->interface->name,
350           ospf6_interface_state_string[o6n->ospf6_interface->state],
351           VTY_NEWLINE);
352}
353
354void
355ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *o6n)
356{
357  char hisaddr[64], timestring[32];
358  struct timeval now, res;
359
360  inet_ntop (AF_INET6, &o6n->hisaddr, hisaddr, sizeof (hisaddr));
361  vty_out (vty, " Neighbor %s, interface address %s%s",
362           o6n->str, hisaddr, VTY_NEWLINE);
363  vty_out (vty, "    Area %s via interface %s (ifindex %d)%s",
364           o6n->ospf6_interface->area->str,
365           o6n->ospf6_interface->interface->name,
366           o6n->ospf6_interface->interface->ifindex,
367           VTY_NEWLINE);
368  vty_out (vty, "    Priority: %d, State: %s, %d state changes%s",
369           o6n->priority, ospf6_neighbor_state_string[o6n->state],
370           o6n->ospf6_stat_state_changed, VTY_NEWLINE);
371
372  gettimeofday (&now, NULL);
373  ospf6_timeval_sub (&now, &o6n->last_changed, &res);
374  ospf6_timeval_string_summary (&res, timestring, sizeof (timestring));
375  vty_out (vty, "    Last state changed: %s ago%s", timestring, VTY_NEWLINE);
376}
377
378void
379ospf6_neighbor_show_detail (struct vty *vty, struct ospf6_neighbor *o6n)
380{
381  char hisdr[16], hisbdr[16];
382
383  ospf6_neighbor_show (vty, o6n);
384
385  inet_ntop (AF_INET, &o6n->dr, hisdr, sizeof (hisdr));
386  inet_ntop (AF_INET, &o6n->bdr, hisbdr, sizeof (hisbdr));
387
388  vty_out (vty, "    His Ifindex of myside: %d%s",
389                o6n->ifid, VTY_NEWLINE);
390  vty_out (vty, "    His DR Election: DR %s, BDR %s%s",
391                hisdr, hisbdr, VTY_NEWLINE);
392
393  vty_out (vty, "    Last received DbDesc: opt:%s"
394                " ifmtu:%hu bit:%s%s%s seqnum:%ld%s",
395                "xxx", ntohs (o6n->last_dd.ifmtu),
396                (DD_IS_IBIT_SET (o6n->last_dd.bits) ? "I" : "-"),
397                (DD_IS_MBIT_SET (o6n->last_dd.bits) ? "M" : "-"),
398                (DD_IS_MSBIT_SET (o6n->last_dd.bits) ? "m" : "s"),
399                (u_long)ntohl (o6n->last_dd.seqnum), VTY_NEWLINE);
400  vty_out (vty, "    My DbDesc bit for this neighbor: %s%s%s%s",
401           (DD_IS_IBIT_SET (o6n->dbdesc_bits) ? "I" : "-"),
402           (DD_IS_MBIT_SET (o6n->dbdesc_bits) ? "M" : "-"),
403           (DD_IS_MSBIT_SET (o6n->dbdesc_bits) ? "m" : "s"),
404           VTY_NEWLINE);
405
406  vty_out (vty, "    %-16s %5d times, %-16s %5d times%s",
407                "SeqnumMismatch", o6n->ospf6_stat_seqnum_mismatch,
408                "BadLSReq", o6n->ospf6_stat_bad_lsreq, VTY_NEWLINE);
409  vty_out (vty, "    %-16s %5d times, %-16s %5d times%s",
410                "OnewayReceived", o6n->ospf6_stat_oneway_received,
411                "InactivityTimer", o6n->ospf6_stat_inactivity_timer,
412                VTY_NEWLINE);
413  vty_out (vty, "    %-16s %5d times, %-16s %5d times%s",
414                "DbDescRetrans", o6n->ospf6_stat_retrans_dbdesc,
415                "LSReqRetrans", o6n->ospf6_stat_retrans_lsreq,
416                VTY_NEWLINE);
417  vty_out (vty, "    %-16s %5d times%s",
418                "LSUpdateRetrans", o6n->ospf6_stat_retrans_lsupdate,
419                VTY_NEWLINE);
420  vty_out (vty, "    %-16s %5d times, %-16s %5d times%s",
421                "LSAReceived", o6n->ospf6_stat_received_lsa,
422                "LSUpdateReceived", o6n->ospf6_stat_received_lsupdate,
423                VTY_NEWLINE);
424
425  vty_out (vty, "    %-12s %-12s %-12s%s",
426           "Message", "DbDesc", "LSReq", VTY_NEWLINE);
427  vty_out (vty, "    %-12s %12d %12d%s", "LSA Send",
428           o6n->lsa_send[OSPF6_MESSAGE_TYPE_DBDESC],
429           o6n->lsa_send[OSPF6_MESSAGE_TYPE_LSREQ], VTY_NEWLINE);
430  vty_out (vty, "    %-12s %12d %12d%s", "LSA Receive",
431           o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC],
432           o6n->lsa_receive[OSPF6_MESSAGE_TYPE_LSREQ], VTY_NEWLINE);
433  vty_out (vty, "%s", VTY_NEWLINE);
434}
435
436void
437ospf6_neighbor_timestamp_hello (struct ospf6_neighbor *o6n)
438{
439  struct timeval now, interval;
440  gettimeofday (&now, (struct timezone *) NULL);
441  if (o6n->tv_last_hello_received.tv_sec)
442    {
443      ospf6_timeval_sub (&now, &o6n->tv_last_hello_received, &interval);
444      zlog_info ("Hello Interval %s : %ld msec",
445                  o6n->str, interval.tv_sec * 1000 + interval.tv_usec % 1000);
446    }
447  o6n->tv_last_hello_received.tv_sec = now.tv_sec;
448  o6n->tv_last_hello_received.tv_usec = now.tv_usec;
449}
450
451DEFUN (show_ipv6_ospf6_neighbor_routerid,
452       show_ipv6_ospf6_neighbor_routerid_cmd,
453       "show ipv6 ospf6 neighbor A.B.C.D",
454       SHOW_STR
455       IP6_STR
456       OSPF6_STR
457       "Neighbor list\n"
458       "OSPF6 neighbor Router ID in IP address format\n"
459       )
460{
461  u_int32_t router_id;
462  struct ospf6_neighbor *o6n;
463  struct ospf6_interface *o6i;
464  struct ospf6_area *o6a;
465  listnode nodei, nodej, nodek;
466
467  OSPF6_CMD_CHECK_RUNNING ();
468
469  if (argc == 0)
470    vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
471             "RouterID", "State", "Duration", "DR", "BDR", "I/F",
472             "State", VTY_NEWLINE);
473  else if (inet_pton (AF_INET, argv[0], &router_id) != 1)
474    {
475      vty_out (vty, "Malformed Router-ID: %s%s", argv[0], VTY_NEWLINE);
476      return CMD_SUCCESS;
477    }
478
479  for (nodei = listhead (ospf6->area_list); nodei; nextnode (nodei))
480    {
481      o6a = getdata (nodei);
482      for (nodej = listhead (o6a->if_list); nodej; nextnode (nodej))
483        {
484          o6i = getdata (nodej);
485          for (nodek = listhead (o6i->neighbor_list); nodek; nextnode (nodek))
486            {
487              o6n = getdata (nodek);
488              if (argc == 0)
489                ospf6_neighbor_show_summary (vty, o6n);
490              else if (o6n->router_id == router_id)
491                ospf6_neighbor_show_detail (vty, o6n);
492            }
493        }
494    }
495  return CMD_SUCCESS;
496}
497
498ALIAS (show_ipv6_ospf6_neighbor_routerid,
499       show_ipv6_ospf6_neighbor_cmd,
500       "show ipv6 ospf6 neighbor",
501       SHOW_STR
502       IP6_STR
503       OSPF6_STR
504       "Neighbor list\n"
505       )
506
507DEFUN (show_ipv6_ospf6_neighborlist,
508       show_ipv6_ospf6_neighborlist_cmd,
509       "show ipv6 ospf6 (summary-list|request-list|retrans-list|dbdesc-list)",
510       SHOW_STR
511       IP6_STR
512       OSPF6_STR
513       "Link State summary list\n"
514       "Link State request list\n"
515       "Link State retransmission list\n"
516       "Link State Description list (Used to retrans DbDesc)\n"
517       )
518{
519  struct ospf6_area *o6a;
520  struct ospf6_interface *o6i;
521  struct ospf6_neighbor *o6n;
522  listnode i, j, k, l;
523  struct ospf6_lsa *lsa;
524  struct ospf6_lsdb *lsdb = NULL;
525  char type[16], id[16], adv_router[16];
526  struct ospf6_lsdb_node node;
527  u_int16_t age, cksum, len;
528  u_int32_t seqnum;
529
530  OSPF6_CMD_CHECK_RUNNING ();
531  i = j = k = l = NULL;
532
533  for (i = listhead (ospf6->area_list); i; nextnode (i))
534    {
535      o6a = (struct ospf6_area *) getdata (i);
536      for (j = listhead (o6a->if_list); j; nextnode (j))
537        {
538          o6i = (struct ospf6_interface *) getdata (j);
539          for (k = listhead (o6i->neighbor_list); k; nextnode (k))
540            {
541              o6n = (struct ospf6_neighbor *) getdata (k);
542
543              if (strncmp (argv[0], "sum", 3) == 0)
544                lsdb = o6n->summary_list;
545              else if (strncmp (argv[0], "req", 3) == 0)
546                lsdb = o6n->request_list;
547              else if (strncmp (argv[0], "ret", 3) == 0)
548                lsdb = o6n->retrans_list;
549              else if (strncmp (argv[0], "dbd", 3) == 0)
550                lsdb = o6n->dbdesc_list;
551
552              vty_out (vty, "neighbor %s on interface %s: %d%s", o6n->str,
553                       o6i->interface->name, lsdb->count,
554                       VTY_NEWLINE);
555              for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
556                   ospf6_lsdb_next (&node))
557                {
558                  lsa = node.lsa;
559                  ospf6_lsa_age_current (lsa);
560
561                  ospf6_lsa_type_string (lsa->header->type, type,
562                                         sizeof (type));
563                  inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id));
564                  inet_ntop (AF_INET, &lsa->header->adv_router, adv_router,
565                             sizeof (adv_router));
566                  age = ntohs (lsa->header->age);
567                  seqnum = ntohl (lsa->header->seqnum);
568                  cksum = ntohs (lsa->header->checksum);
569                  len = ntohs (lsa->header->length);
570
571                  vty_out (vty, "  %s-LSA ID=%s Adv=%s%s",
572                           type, id, adv_router, VTY_NEWLINE);
573                  vty_out (vty, "  Age: %hu SeqNum: %#x Cksum: %hx Len: %hu%s",
574                           age, seqnum, cksum, len, VTY_NEWLINE);
575                }
576            }
577        }
578    }
579
580  return CMD_SUCCESS;
581}
582
583void
584ospf6_neighbor_init ()
585{
586  install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd);
587  install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_routerid_cmd);
588  install_element (VIEW_NODE, &show_ipv6_ospf6_neighborlist_cmd);
589
590  install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_cmd);
591  install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_routerid_cmd);
592  install_element (ENABLE_NODE, &show_ipv6_ospf6_neighborlist_cmd);
593}
594
595
596