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/* Interface State Machine */
23
24#include "ospf6d.h"
25
26int
27ifs_change (state_t ifs_next, char *reason, struct ospf6_interface *o6i)
28{
29  state_t ifs_prev;
30
31  ifs_prev = o6i->state;
32
33  if (ifs_prev == ifs_next)
34    return 0;
35
36  if (IS_OSPF6_DUMP_INTERFACE)
37    zlog_info ("I/F: %s: %s -> %s (%s)",
38               o6i->interface->name,
39               ospf6_interface_state_string[ifs_prev],
40               ospf6_interface_state_string[ifs_next], reason);
41
42  if ((ifs_prev == IFS_DR || ifs_prev == IFS_BDR) &&
43      (ifs_next != IFS_DR && ifs_next != IFS_BDR))
44    ospf6_leave_alldrouters (o6i->interface->ifindex);
45  else if ((ifs_prev != IFS_DR && ifs_prev != IFS_BDR) &&
46           (ifs_next == IFS_DR || ifs_next == IFS_BDR))
47    ospf6_join_alldrouters (o6i->interface->ifindex);
48
49  o6i->state = ifs_next;
50
51  if (o6i->prevdr != o6i->dr || o6i->prevbdr != o6i->bdr)
52    {
53      if (IS_OSPF6_DUMP_INTERFACE)
54        {
55          char dr[16], bdr[16], prevdr[16], prevbdr[16];
56          inet_ntop (AF_INET, &o6i->prevdr, prevdr, sizeof (prevdr));
57          inet_ntop (AF_INET, &o6i->prevbdr, prevbdr, sizeof (prevbdr));
58          inet_ntop (AF_INET, &o6i->dr, dr, sizeof (dr));
59          inet_ntop (AF_INET, &o6i->bdr, bdr, sizeof (bdr));
60          zlog_info ("I/F: %s: DR: %s -> %s", o6i->interface->name,
61                     prevdr, dr);
62          zlog_info ("I/F: %s: BDR: %s -> %s", o6i->interface->name,
63                     prevbdr, bdr);
64        }
65    }
66
67  CALL_CHANGE_HOOK (&interface_hook, o6i);
68  return 0;
69}
70
71
72/* Interface State Machine */
73int
74interface_up (struct thread *thread)
75{
76  struct ospf6_interface *ospf6_interface;
77
78  ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread);
79
80  assert (ospf6_interface);
81  assert (ospf6_interface->interface);
82
83  if (IS_OSPF6_DUMP_INTERFACE)
84    zlog_info ("I/F: %s: InterfaceUp",
85               ospf6_interface->interface->name);
86
87  /* check physical interface is up */
88  if (!if_is_up (ospf6_interface->interface))
89    {
90      if (IS_OSPF6_DUMP_INTERFACE)
91        zlog_warn ("  interface %s down, can't execute InterfaceUp",
92                   ospf6_interface->interface->name);
93      return -1;
94    }
95
96  /* if already enabled, do nothing */
97  if (ospf6_interface->state > IFS_DOWN)
98    {
99      zlog_warn ("Interface %s already up",
100                 ospf6_interface->interface->name);
101      return 0;
102    }
103
104  /* ifid of this interface */
105  ospf6_interface->if_id = ospf6_interface->interface->ifindex;
106
107  /* Join AllSPFRouters */
108  ospf6_join_allspfrouters (ospf6_interface->interface->ifindex);
109
110  /* set socket options */
111  ospf6_set_reuseaddr ();
112  ospf6_reset_mcastloop ();
113  ospf6_set_pktinfo ();
114  ospf6_set_checksum ();
115
116  /* Schedule Hello */
117  if (! CHECK_FLAG (ospf6_interface->flag, OSPF6_INTERFACE_FLAG_PASSIVE))
118    thread_add_event (master, ospf6_send_hello, ospf6_interface, 0);
119
120  /* decide next interface state */
121  if (if_is_pointopoint (ospf6_interface->interface))
122    ifs_change (IFS_PTOP, "IF Type PointToPoint", ospf6_interface);
123  else if (ospf6_interface->priority == 0)
124    ifs_change (IFS_DROTHER, "Router Priority = 0", ospf6_interface);
125  else
126    {
127      ifs_change (IFS_WAITING, "Priority > 0", ospf6_interface);
128      thread_add_timer (master, wait_timer, ospf6_interface,
129                        ospf6_interface->dead_interval);
130    }
131
132  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, ospf6_interface);
133
134  return 0;
135}
136
137int
138wait_timer (struct thread *thread)
139{
140  struct ospf6_interface *ospf6_interface;
141
142  ospf6_interface = (struct ospf6_interface *)THREAD_ARG  (thread);
143  assert (ospf6_interface);
144
145  if (ospf6_interface->state != IFS_WAITING)
146    return 0;
147
148  if (IS_OSPF6_DUMP_INTERFACE)
149    zlog_info ("I/F: %s: WaitTimer", ospf6_interface->interface->name);
150
151  ifs_change (dr_election (ospf6_interface),
152              "WaitTimer:DR Election", ospf6_interface);
153  return 0;
154}
155
156int backup_seen (struct thread *thread)
157{
158  struct ospf6_interface *ospf6_interface;
159
160  ospf6_interface = (struct ospf6_interface *)THREAD_ARG  (thread);
161  assert (ospf6_interface);
162
163  if (IS_OSPF6_DUMP_INTERFACE)
164    zlog_info ("I/F: %s: BackupSeen", ospf6_interface->interface->name);
165
166  if (ospf6_interface->state == IFS_WAITING)
167    ifs_change (dr_election (ospf6_interface),
168                "BackupSeen:DR Election", ospf6_interface);
169
170  return 0;
171}
172
173int neighbor_change (struct thread *thread)
174{
175  struct ospf6_interface *ospf6_interface;
176
177  ospf6_interface = (struct ospf6_interface *)THREAD_ARG  (thread);
178  assert (ospf6_interface);
179
180  if (ospf6_interface->state != IFS_DROTHER &&
181      ospf6_interface->state != IFS_BDR &&
182      ospf6_interface->state != IFS_DR)
183    return 0;
184
185  if (IS_OSPF6_DUMP_INTERFACE)
186    zlog_info ("I/F: %s: NeighborChange", ospf6_interface->interface->name);
187
188  ifs_change (dr_election (ospf6_interface),
189              "NeighborChange:DR Election", ospf6_interface);
190
191  return 0;
192}
193
194int
195loopind (struct thread *thread)
196{
197  struct ospf6_interface *ospf6_interface;
198
199  ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread);
200  assert (ospf6_interface);
201
202  if (IS_OSPF6_DUMP_INTERFACE)
203    zlog_info ("I/F: %s: LoopInd", ospf6_interface->interface->name);
204
205  /* XXX not yet */
206
207  return 0;
208}
209
210int
211interface_down (struct thread *thread)
212{
213  struct ospf6_interface *ospf6_interface;
214
215  ospf6_interface = (struct ospf6_interface *) THREAD_ARG (thread);
216  assert (ospf6_interface);
217
218  if (IS_OSPF6_DUMP_INTERFACE)
219    zlog_info ("I/F: %s: InterfaceDown", ospf6_interface->interface->name);
220
221  if (ospf6_interface->state == IFS_NONE)
222    return 1;
223
224  /* Leave AllSPFRouters */
225  if (ospf6_interface_is_enabled (ospf6_interface->interface->ifindex))
226    ospf6_leave_allspfrouters (ospf6_interface->interface->ifindex);
227
228  ifs_change (IFS_DOWN, "Configured", ospf6_interface);
229
230  return 0;
231}
232
233
234/* 9.4 of RFC2328 */
235int
236dr_election (struct ospf6_interface *ospf6_interface)
237{
238  list candidate_list = list_new ();
239  listnode i, j, n;
240  ifid_t prevdr, prevbdr, dr = 0, bdr;
241  struct ospf6_neighbor *nbpi, *nbpj, myself, *nbr;
242  int declare = 0;
243  int gofive = 0;
244
245  /* statistics */
246  ospf6_interface->ospf6_stat_dr_election++;
247
248  /* pseudo neighbor "myself" */
249  memset (&myself, 0, sizeof (myself));
250  myself.state = NBS_TWOWAY;
251  myself.dr = ospf6_interface->dr;
252  myself.bdr = ospf6_interface->bdr;
253  myself.priority = ospf6_interface->priority;
254  myself.ifid = ospf6_interface->if_id;
255  myself.router_id = ospf6_interface->area->ospf6->router_id;
256
257/* step_one: */
258
259  ospf6_interface->prevdr = prevdr = ospf6_interface->dr;
260  ospf6_interface->prevbdr = prevbdr = ospf6_interface->bdr;
261
262step_two:
263
264  /* Calculate Backup Designated Router. */
265  /* Make Candidate list */
266  if (!list_isempty (candidate_list))
267    list_delete_all_node (candidate_list);
268  declare = 0;
269  for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i))
270    {
271      nbpi = (struct ospf6_neighbor *)getdata (i);
272      if (nbpi->priority == 0)
273        continue;
274      if (nbpi->state < NBS_TWOWAY)
275        continue;
276      if (nbpi->dr == nbpi->router_id)
277        continue;
278      if (nbpi->bdr == nbpi->router_id)
279        declare++;
280      listnode_add (candidate_list, nbpi);
281    }
282
283  if (myself.priority)
284    {
285      if (myself.dr != myself.router_id)
286        {
287          if (myself.bdr == myself.router_id)
288            declare++;
289          listnode_add (candidate_list, &myself);
290        }
291    }
292
293  /* Elect BDR */
294  for (i = listhead (candidate_list);
295       candidate_list->count > 1;
296       i = listhead (candidate_list))
297    {
298      j = i;
299      nextnode(j);
300      assert (j);
301      nbpi = (struct ospf6_neighbor *)getdata (i);
302      nbpj = (struct ospf6_neighbor *)getdata (j);
303      if (declare)
304        {
305          int deleted = 0;
306          if (nbpi->bdr != nbpi->router_id)
307            {
308              listnode_delete (candidate_list, nbpi);
309              deleted++;
310            }
311          if (nbpj->bdr != nbpj->router_id)
312            {
313              listnode_delete (candidate_list, nbpj);
314              deleted++;
315            }
316          if (deleted)
317            continue;
318        }
319      if (nbpi->priority > nbpj->priority)
320        {
321          listnode_delete (candidate_list, nbpj);
322          continue;
323        }
324      else if (nbpi->priority < nbpj->priority)
325        {
326          listnode_delete (candidate_list, nbpi);
327          continue;
328        }
329      else /* equal, case of tie */
330        {
331          if (ntohl (nbpi->router_id) > ntohl (nbpj->router_id))
332            {
333              listnode_delete (candidate_list, nbpj);
334              continue;
335            }
336          else if (ntohl (nbpi->router_id) < ntohl (nbpj->router_id))
337            {
338              listnode_delete (candidate_list, nbpi);
339              continue;
340            }
341          else
342            assert (0);
343        }
344    }
345
346  if (!list_isempty (candidate_list))
347    {
348      assert (candidate_list->count == 1);
349      n = listhead (candidate_list);
350      nbr = (struct ospf6_neighbor *)getdata (n);
351      bdr = nbr->router_id;
352    }
353  else
354    bdr = 0;
355
356/* step_three: */
357
358  /* Calculate Designated Router. */
359  /* Make Candidate list */
360  if (!list_isempty (candidate_list))
361    list_delete_all_node (candidate_list);
362  declare = 0;
363  for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i))
364    {
365      nbpi = (struct ospf6_neighbor *)getdata (i);
366      if (nbpi->priority == 0)
367        continue;
368      if (nbpi->state < NBS_TWOWAY)
369        continue;
370      if (nbpi->dr == nbpi->router_id)
371        {
372          declare++;
373          listnode_add (candidate_list, nbpi);
374        }
375    }
376  if (myself.priority)
377    {
378      if (myself.dr == myself.router_id)
379        {
380          declare++;
381          listnode_add (candidate_list, &myself);
382        }
383    }
384
385  /* Elect DR */
386  if (declare == 0)
387    {
388      assert (list_isempty (candidate_list));
389      /* No one declare but candidate_list not empty */
390      dr = bdr;
391    }
392  else
393    {
394      assert (!list_isempty (candidate_list));
395      for (i = listhead (candidate_list);
396           candidate_list->count > 1;
397           i = listhead (candidate_list))
398        {
399          j = i;
400          nextnode (j);
401          assert (j);
402          nbpi = (struct ospf6_neighbor *)getdata (i);
403          nbpj = (struct ospf6_neighbor *)getdata (j);
404
405          if (nbpi->dr != nbpi->router_id)
406            {
407              list_delete_node (candidate_list, i);
408              continue;
409            }
410          if (nbpj->dr != nbpj->router_id)
411            {
412              list_delete_node (candidate_list, j);
413              continue;
414            }
415
416          if (nbpi->priority > nbpj->priority)
417            {
418              list_delete_node (candidate_list, j);
419              continue;
420            }
421          else if (nbpi->priority < nbpj->priority)
422            {
423              list_delete_node (candidate_list, i);
424              continue;
425            }
426          else /* equal, case of tie */
427            {
428              if (nbpi->router_id > nbpj->router_id)
429                {
430                  list_delete_node (candidate_list, j);
431                  continue;
432                }
433              else if (nbpi->router_id < nbpj->router_id)
434                {
435                  list_delete_node (candidate_list, i);
436                  continue;
437                }
438              else
439                {
440                  zlog_warn ("!!!THE SAME ROUTER ID FOR DIFFERENT NEIGHBOR");
441                  zlog_warn ("!!!MISCONFIGURATION?");
442                  list_delete_node (candidate_list, i);
443                  continue;
444                }
445            }
446        }
447      if (!list_isempty (candidate_list))
448        {
449          assert (candidate_list->count == 1);
450          n = listhead (candidate_list);
451          nbr = (struct ospf6_neighbor *)getdata (n);
452          dr = nbr->router_id;
453        }
454      else
455        assert (0);
456    }
457
458/* step_four: */
459
460  if (gofive)
461    goto step_five;
462
463  if (dr != prevdr)
464    {
465      if ((dr == myself.router_id || prevdr == myself.router_id)
466          && !(dr == myself.router_id && prevdr == myself.router_id))
467        {
468          myself.dr = dr;
469          myself.bdr = bdr;
470          gofive++;
471          goto step_two;
472        }
473    }
474  if (bdr != prevbdr)
475    {
476      if ((bdr == myself.router_id || prevbdr == myself.router_id)
477          && !(bdr == myself.router_id && prevbdr == myself.router_id))
478        {
479          myself.dr = dr;
480          myself.bdr = bdr;
481          gofive++;
482          goto step_two;
483        }
484    }
485
486step_five:
487
488  ospf6_interface->dr = dr;
489  ospf6_interface->bdr = bdr;
490
491  if (prevdr != dr || prevbdr != bdr)
492    {
493      for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i))
494        {
495          nbpi = getdata (i);
496          if (nbpi->state < NBS_TWOWAY)
497            continue;
498          /* Schedule or Execute AdjOK. which does "invoke" mean? */
499          thread_add_event (master, adj_ok, nbpi, 0);
500        }
501    }
502
503  list_delete (candidate_list);
504
505  if (dr == myself.router_id)
506    {
507      assert (bdr != myself.router_id);
508      return IFS_DR;
509    }
510  else if (bdr == myself.router_id)
511    {
512      assert (dr != myself.router_id);
513      return IFS_BDR;
514    }
515  else
516    return IFS_DROTHER;
517}
518
519
520