diff options
author | paul <paul> | 2002-12-13 20:15:29 +0000 |
---|---|---|
committer | paul <paul> | 2002-12-13 20:15:29 +0000 |
commit | 718e3744195351130f4ce7dbe0613f4b3e23df93 (patch) | |
tree | bac2ad39971cd43f31241ef123bd4e470f695ac9 /ospf6d/ospf6_ism.c |
Initial revision
Diffstat (limited to 'ospf6d/ospf6_ism.c')
-rw-r--r-- | ospf6d/ospf6_ism.c | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/ospf6d/ospf6_ism.c b/ospf6d/ospf6_ism.c new file mode 100644 index 00000000..d13be127 --- /dev/null +++ b/ospf6d/ospf6_ism.c @@ -0,0 +1,519 @@ +/* + * Copyright (C) 1999 Yasuhiro Ohara + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* Interface State Machine */ + +#include "ospf6d.h" + +int +ifs_change (state_t ifs_next, char *reason, struct ospf6_interface *o6i) +{ + state_t ifs_prev; + + ifs_prev = o6i->state; + + if (ifs_prev == ifs_next) + return 0; + + if (IS_OSPF6_DUMP_INTERFACE) + zlog_info ("I/F: %s: %s -> %s (%s)", + o6i->interface->name, + ospf6_interface_state_string[ifs_prev], + ospf6_interface_state_string[ifs_next], reason); + + if ((ifs_prev == IFS_DR || ifs_prev == IFS_BDR) && + (ifs_next != IFS_DR && ifs_next != IFS_BDR)) + ospf6_leave_alldrouters (o6i->interface->ifindex); + else if ((ifs_prev != IFS_DR && ifs_prev != IFS_BDR) && + (ifs_next == IFS_DR || ifs_next == IFS_BDR)) + ospf6_join_alldrouters (o6i->interface->ifindex); + + o6i->state = ifs_next; + + if (o6i->prevdr != o6i->dr || o6i->prevbdr != o6i->bdr) + { + if (IS_OSPF6_DUMP_INTERFACE) + { + char dr[16], bdr[16], prevdr[16], prevbdr[16]; + inet_ntop (AF_INET, &o6i->prevdr, prevdr, sizeof (prevdr)); + inet_ntop (AF_INET, &o6i->prevbdr, prevbdr, sizeof (prevbdr)); + inet_ntop (AF_INET, &o6i->dr, dr, sizeof (dr)); + inet_ntop (AF_INET, &o6i->bdr, bdr, sizeof (bdr)); + zlog_info ("I/F: %s: DR: %s -> %s", o6i->interface->name, + prevdr, dr); + zlog_info ("I/F: %s: BDR: %s -> %s", o6i->interface->name, + prevbdr, bdr); + } + } + + CALL_CHANGE_HOOK (&interface_hook, o6i); + return 0; +} + + +/* Interface State Machine */ +int +interface_up (struct thread *thread) +{ + struct ospf6_interface *ospf6_interface; + + ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread); + + assert (ospf6_interface); + assert (ospf6_interface->interface); + + if (IS_OSPF6_DUMP_INTERFACE) + zlog_info ("I/F: %s: InterfaceUp", + ospf6_interface->interface->name); + + /* check physical interface is up */ + if (!if_is_up (ospf6_interface->interface)) + { + if (IS_OSPF6_DUMP_INTERFACE) + zlog_warn (" interface %s down, can't execute InterfaceUp", + ospf6_interface->interface->name); + return -1; + } + + /* if already enabled, do nothing */ + if (ospf6_interface->state > IFS_DOWN) + { + zlog_warn ("Interface %s already up", + ospf6_interface->interface->name); + return 0; + } + + /* ifid of this interface */ + ospf6_interface->if_id = ospf6_interface->interface->ifindex; + + /* Join AllSPFRouters */ + ospf6_join_allspfrouters (ospf6_interface->interface->ifindex); + + /* set socket options */ + ospf6_set_reuseaddr (); + ospf6_reset_mcastloop (); + ospf6_set_pktinfo (); + ospf6_set_checksum (); + + /* Schedule Hello */ + if (! CHECK_FLAG (ospf6_interface->flag, OSPF6_INTERFACE_FLAG_PASSIVE)) + thread_add_event (master, ospf6_send_hello, ospf6_interface, 0); + + /* decide next interface state */ + if (if_is_pointopoint (ospf6_interface->interface)) + ifs_change (IFS_PTOP, "IF Type PointToPoint", ospf6_interface); + else if (ospf6_interface->priority == 0) + ifs_change (IFS_DROTHER, "Router Priority = 0", ospf6_interface); + else + { + ifs_change (IFS_WAITING, "Priority > 0", ospf6_interface); + thread_add_timer (master, wait_timer, ospf6_interface, + ospf6_interface->dead_interval); + } + + CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, ospf6_interface); + + return 0; +} + +int +wait_timer (struct thread *thread) +{ + struct ospf6_interface *ospf6_interface; + + ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread); + assert (ospf6_interface); + + if (ospf6_interface->state != IFS_WAITING) + return 0; + + if (IS_OSPF6_DUMP_INTERFACE) + zlog_info ("I/F: %s: WaitTimer", ospf6_interface->interface->name); + + ifs_change (dr_election (ospf6_interface), + "WaitTimer:DR Election", ospf6_interface); + return 0; +} + +int backup_seen (struct thread *thread) +{ + struct ospf6_interface *ospf6_interface; + + ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread); + assert (ospf6_interface); + + if (IS_OSPF6_DUMP_INTERFACE) + zlog_info ("I/F: %s: BackupSeen", ospf6_interface->interface->name); + + if (ospf6_interface->state == IFS_WAITING) + ifs_change (dr_election (ospf6_interface), + "BackupSeen:DR Election", ospf6_interface); + + return 0; +} + +int neighbor_change (struct thread *thread) +{ + struct ospf6_interface *ospf6_interface; + + ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread); + assert (ospf6_interface); + + if (ospf6_interface->state != IFS_DROTHER && + ospf6_interface->state != IFS_BDR && + ospf6_interface->state != IFS_DR) + return 0; + + if (IS_OSPF6_DUMP_INTERFACE) + zlog_info ("I/F: %s: NeighborChange", ospf6_interface->interface->name); + + ifs_change (dr_election (ospf6_interface), + "NeighborChange:DR Election", ospf6_interface); + + return 0; +} + +int +loopind (struct thread *thread) +{ + struct ospf6_interface *ospf6_interface; + + ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread); + assert (ospf6_interface); + + if (IS_OSPF6_DUMP_INTERFACE) + zlog_info ("I/F: %s: LoopInd", ospf6_interface->interface->name); + + /* XXX not yet */ + + return 0; +} + +int +interface_down (struct thread *thread) +{ + struct ospf6_interface *ospf6_interface; + + ospf6_interface = (struct ospf6_interface *) THREAD_ARG (thread); + assert (ospf6_interface); + + if (IS_OSPF6_DUMP_INTERFACE) + zlog_info ("I/F: %s: InterfaceDown", ospf6_interface->interface->name); + + if (ospf6_interface->state == IFS_NONE) + return 1; + + /* Leave AllSPFRouters */ + if (ospf6_interface_is_enabled (ospf6_interface->interface->ifindex)) + ospf6_leave_allspfrouters (ospf6_interface->interface->ifindex); + + ifs_change (IFS_DOWN, "Configured", ospf6_interface); + + return 0; +} + + +/* 9.4 of RFC2328 */ +int +dr_election (struct ospf6_interface *ospf6_interface) +{ + list candidate_list = list_new (); + listnode i, j, n; + ifid_t prevdr, prevbdr, dr = 0, bdr; + struct ospf6_neighbor *nbpi, *nbpj, myself, *nbr; + int declare = 0; + int gofive = 0; + + /* statistics */ + ospf6_interface->ospf6_stat_dr_election++; + + /* pseudo neighbor "myself" */ + memset (&myself, 0, sizeof (myself)); + myself.state = NBS_TWOWAY; + myself.dr = ospf6_interface->dr; + myself.bdr = ospf6_interface->bdr; + myself.priority = ospf6_interface->priority; + myself.ifid = ospf6_interface->if_id; + myself.router_id = ospf6_interface->area->ospf6->router_id; + +/* step_one: */ + + ospf6_interface->prevdr = prevdr = ospf6_interface->dr; + ospf6_interface->prevbdr = prevbdr = ospf6_interface->bdr; + +step_two: + + /* Calculate Backup Designated Router. */ + /* Make Candidate list */ + if (!list_isempty (candidate_list)) + list_delete_all_node (candidate_list); + declare = 0; + for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i)) + { + nbpi = (struct ospf6_neighbor *)getdata (i); + if (nbpi->priority == 0) + continue; + if (nbpi->state < NBS_TWOWAY) + continue; + if (nbpi->dr == nbpi->router_id) + continue; + if (nbpi->bdr == nbpi->router_id) + declare++; + listnode_add (candidate_list, nbpi); + } + + if (myself.priority) + { + if (myself.dr != myself.router_id) + { + if (myself.bdr == myself.router_id) + declare++; + listnode_add (candidate_list, &myself); + } + } + + /* Elect BDR */ + for (i = listhead (candidate_list); + candidate_list->count > 1; + i = listhead (candidate_list)) + { + j = i; + nextnode(j); + assert (j); + nbpi = (struct ospf6_neighbor *)getdata (i); + nbpj = (struct ospf6_neighbor *)getdata (j); + if (declare) + { + int deleted = 0; + if (nbpi->bdr != nbpi->router_id) + { + listnode_delete (candidate_list, nbpi); + deleted++; + } + if (nbpj->bdr != nbpj->router_id) + { + listnode_delete (candidate_list, nbpj); + deleted++; + } + if (deleted) + continue; + } + if (nbpi->priority > nbpj->priority) + { + listnode_delete (candidate_list, nbpj); + continue; + } + else if (nbpi->priority < nbpj->priority) + { + listnode_delete (candidate_list, nbpi); + continue; + } + else /* equal, case of tie */ + { + if (ntohl (nbpi->router_id) > ntohl (nbpj->router_id)) + { + listnode_delete (candidate_list, nbpj); + continue; + } + else if (ntohl (nbpi->router_id) < ntohl (nbpj->router_id)) + { + listnode_delete (candidate_list, nbpi); + continue; + } + else + assert (0); + } + } + + if (!list_isempty (candidate_list)) + { + assert (candidate_list->count == 1); + n = listhead (candidate_list); + nbr = (struct ospf6_neighbor *)getdata (n); + bdr = nbr->router_id; + } + else + bdr = 0; + +/* step_three: */ + + /* Calculate Designated Router. */ + /* Make Candidate list */ + if (!list_isempty (candidate_list)) + list_delete_all_node (candidate_list); + declare = 0; + for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i)) + { + nbpi = (struct ospf6_neighbor *)getdata (i); + if (nbpi->priority == 0) + continue; + if (nbpi->state < NBS_TWOWAY) + continue; + if (nbpi->dr == nbpi->router_id) + { + declare++; + listnode_add (candidate_list, nbpi); + } + } + if (myself.priority) + { + if (myself.dr == myself.router_id) + { + declare++; + listnode_add (candidate_list, &myself); + } + } + + /* Elect DR */ + if (declare == 0) + { + assert (list_isempty (candidate_list)); + /* No one declare but candidate_list not empty */ + dr = bdr; + } + else + { + assert (!list_isempty (candidate_list)); + for (i = listhead (candidate_list); + candidate_list->count > 1; + i = listhead (candidate_list)) + { + j = i; + nextnode (j); + assert (j); + nbpi = (struct ospf6_neighbor *)getdata (i); + nbpj = (struct ospf6_neighbor *)getdata (j); + + if (nbpi->dr != nbpi->router_id) + { + list_delete_node (candidate_list, i); + continue; + } + if (nbpj->dr != nbpj->router_id) + { + list_delete_node (candidate_list, j); + continue; + } + + if (nbpi->priority > nbpj->priority) + { + list_delete_node (candidate_list, j); + continue; + } + else if (nbpi->priority < nbpj->priority) + { + list_delete_node (candidate_list, i); + continue; + } + else /* equal, case of tie */ + { + if (nbpi->router_id > nbpj->router_id) + { + list_delete_node (candidate_list, j); + continue; + } + else if (nbpi->router_id < nbpj->router_id) + { + list_delete_node (candidate_list, i); + continue; + } + else + { + zlog_warn ("!!!THE SAME ROUTER ID FOR DIFFERENT NEIGHBOR"); + zlog_warn ("!!!MISCONFIGURATION?"); + list_delete_node (candidate_list, i); + continue; + } + } + } + if (!list_isempty (candidate_list)) + { + assert (candidate_list->count == 1); + n = listhead (candidate_list); + nbr = (struct ospf6_neighbor *)getdata (n); + dr = nbr->router_id; + } + else + assert (0); + } + +/* step_four: */ + + if (gofive) + goto step_five; + + if (dr != prevdr) + { + if ((dr == myself.router_id || prevdr == myself.router_id) + && !(dr == myself.router_id && prevdr == myself.router_id)) + { + myself.dr = dr; + myself.bdr = bdr; + gofive++; + goto step_two; + } + } + if (bdr != prevbdr) + { + if ((bdr == myself.router_id || prevbdr == myself.router_id) + && !(bdr == myself.router_id && prevbdr == myself.router_id)) + { + myself.dr = dr; + myself.bdr = bdr; + gofive++; + goto step_two; + } + } + +step_five: + + ospf6_interface->dr = dr; + ospf6_interface->bdr = bdr; + + if (prevdr != dr || prevbdr != bdr) + { + for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i)) + { + nbpi = getdata (i); + if (nbpi->state < NBS_TWOWAY) + continue; + /* Schedule or Execute AdjOK. which does "invoke" mean? */ + thread_add_event (master, adj_ok, nbpi, 0); + } + } + + list_delete (candidate_list); + + if (dr == myself.router_id) + { + assert (bdr != myself.router_id); + return IFS_DR; + } + else if (bdr == myself.router_id) + { + assert (dr != myself.router_id); + return IFS_BDR; + } + else + return IFS_DROTHER; +} + + |