📄 ospf_ism.c
字号:
/* * OSPF version 2 Interface State Machine * From RFC2328 [OSPF Version 2] * Copyright (C) 1999, 2000 Toshiaki Takada * * 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. */#include <zebra.h>#include "thread.h"#include "linklist.h"#include "prefix.h"#include "if.h"#include "table.h"#include "log.h"#include "ospfd/ospfd.h"#include "ospfd/ospf_interface.h"#include "ospfd/ospf_ism.h"#include "ospfd/ospf_asbr.h"#include "ospfd/ospf_lsa.h"#include "ospfd/ospf_lsdb.h"#include "ospfd/ospf_neighbor.h"#include "ospfd/ospf_nsm.h"#include "ospfd/ospf_network.h"#include "ospfd/ospf_dump.h"#include "ospfd/ospf_packet.h"#include "ospfd/ospf_flood.h"#include "ospfd/ospf_abr.h"/* elect DR and BDR. Refer to RFC2319 section 9.4 */struct ospf_neighbor *ospf_dr_election_sub (list routers){ listnode node; struct ospf_neighbor *nbr, *max = NULL; /* Choose highest router priority. In case of tie, choose highest Router ID. */ for (node = listhead (routers); node; nextnode (node)) { nbr = getdata (node); if (max == NULL) max = nbr; else { if (max->priority < nbr->priority) max = nbr; else if (max->priority == nbr->priority) if (IPV4_ADDR_CMP (&max->router_id, &nbr->router_id) < 0) max = nbr; } } return max;}struct ospf_neighbor *ospf_elect_dr (struct ospf_interface *oi, list el_list){ list dr_list; listnode node; struct ospf_neighbor *nbr, *dr = NULL, *bdr = NULL; dr_list = list_new (); /* Add neighbors to the list. */ for (node = listhead (el_list); node; nextnode (node)) { nbr = getdata (node); /* neighbor declared to be DR. */ if (NBR_IS_DR (nbr)) listnode_add (dr_list, nbr); /* Preserve neighbor BDR. */ if (IPV4_ADDR_SAME (&BDR (oi), &nbr->address.u.prefix4)) bdr = nbr; } /* Elect Designated Router. */ if (listcount (dr_list) > 0) dr = ospf_dr_election_sub (dr_list); else dr = bdr; /* Set DR to interface. */ if (dr) { DR (oi) = dr->address.u.prefix4; dr->d_router = dr->address.u.prefix4; } else DR (oi).s_addr = 0; list_delete (dr_list); return dr;}struct ospf_neighbor *ospf_elect_bdr (struct ospf_interface *oi, list el_list){ list bdr_list, no_dr_list; listnode node; struct ospf_neighbor *nbr, *bdr = NULL; bdr_list = list_new (); no_dr_list = list_new (); /* Add neighbors to the list. */ for (node = listhead (el_list); node; nextnode (node)) { nbr = getdata (node); /* neighbor declared to be DR. */ if (NBR_IS_DR (nbr)) continue; /* neighbor declared to be BDR. */ if (NBR_IS_BDR (nbr)) listnode_add (bdr_list, nbr); listnode_add (no_dr_list, nbr); } /* Elect Backup Designated Router. */ if (listcount (bdr_list) > 0) bdr = ospf_dr_election_sub (bdr_list); else bdr = ospf_dr_election_sub (no_dr_list); /* Set BDR to interface. */ if (bdr) { BDR (oi) = bdr->address.u.prefix4; bdr->bd_router = bdr->address.u.prefix4; } else BDR (oi).s_addr = 0; list_delete (bdr_list); list_delete (no_dr_list); return bdr;}intospf_ism_state (struct ospf_interface *oi){ if (IPV4_ADDR_SAME (&DR (oi), &oi->address->u.prefix4)) return ISM_DR; else if (IPV4_ADDR_SAME (&BDR (oi), &oi->address->u.prefix4)) return ISM_Backup; else return ISM_DROther;}voidospf_dr_eligible_routers (struct route_table *nbrs, list el_list){ struct route_node *rn; struct ospf_neighbor *nbr; for (rn = route_top (nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL) /* Ignore 0.0.0.0 node*/ if (nbr->router_id.s_addr != 0) /* Is neighbor eligible? */ if (nbr->priority != 0) /* Is neighbor upper 2-Way? */ if (nbr->state >= NSM_TwoWay) listnode_add (el_list, nbr);}/* Generate AdjOK? NSM event. */voidospf_dr_change (struct ospf *ospf, struct route_table *nbrs){ struct route_node *rn; struct ospf_neighbor *nbr; for (rn = route_top (nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL) /* Ignore 0.0.0.0 node*/ if (nbr->router_id.s_addr != 0) /* Is neighbor upper 2-Way? */ if (nbr->state >= NSM_TwoWay) /* Ignore myself. */ if (!IPV4_ADDR_SAME (&nbr->router_id, &ospf->router_id)) OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_AdjOK);}intospf_dr_election (struct ospf_interface *oi){ struct in_addr old_dr, old_bdr; int old_state, new_state; list el_list; struct ospf_neighbor *dr, *bdr; /* backup current values. */ old_dr = DR (oi); old_bdr = BDR (oi); old_state = oi->state; el_list = list_new (); /* List eligible routers. */ ospf_dr_eligible_routers (oi->nbrs, el_list); /* First election of DR and BDR. */ bdr = ospf_elect_bdr (oi, el_list); dr = ospf_elect_dr (oi, el_list); new_state = ospf_ism_state (oi); zlog_info ("DR-Election[1st]: Backup %s", inet_ntoa (BDR (oi))); zlog_info ("DR-Election[1st]: DR %s", inet_ntoa (DR (oi))); if (new_state != old_state && !(new_state == ISM_DROther && old_state < ISM_DROther)) { ospf_elect_bdr (oi, el_list); ospf_elect_dr (oi, el_list); new_state = ospf_ism_state (oi); zlog_info ("DR-Election[2nd]: Backup %s", inet_ntoa (BDR (oi))); zlog_info ("DR-Election[2nd]: DR %s", inet_ntoa (DR (oi))); } list_delete (el_list); /* if DR or BDR changes, cause AdjOK? neighbor event. */ if (!IPV4_ADDR_SAME (&old_dr, &DR (oi)) || !IPV4_ADDR_SAME (&old_bdr, &BDR (oi))) ospf_dr_change (oi->ospf, oi->nbrs); if (oi->type == OSPF_IFTYPE_BROADCAST || oi->type == OSPF_IFTYPE_POINTOPOINT) { /* Multicast group change. */ if ((old_state != ISM_DR && old_state != ISM_Backup) && (new_state == ISM_DR || new_state == ISM_Backup)) ospf_if_add_alldrouters (oi->ospf, oi->address, oi->ifp->ifindex); else if ((old_state == ISM_DR || old_state == ISM_Backup) && (new_state != ISM_DR && new_state != ISM_Backup)) ospf_if_drop_alldrouters (oi->ospf, oi->address, oi->ifp->ifindex); } return new_state;}intospf_hello_timer (struct thread *thread){ struct ospf_interface *oi; oi = THREAD_ARG (thread); oi->t_hello = NULL; if (IS_DEBUG_OSPF (ism, ISM_TIMERS)) zlog (NULL, LOG_DEBUG, "ISM[%s]: Timer (Hello timer expire)", IF_NAME (oi)); /* Sending hello packet. */ ospf_hello_send (oi); /* Hello timer set. */ OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, OSPF_IF_PARAM (oi, v_hello)); return 0;}intospf_wait_timer (struct thread *thread){ struct ospf_interface *oi; oi = THREAD_ARG (thread); oi->t_wait = NULL; if (IS_DEBUG_OSPF (ism, ISM_TIMERS)) zlog (NULL, LOG_DEBUG, "ISM[%s]: Timer (Wait timer expire)", IF_NAME (oi)); OSPF_ISM_EVENT_SCHEDULE (oi, ISM_WaitTimer); return 0;}/* Hook function called after ospf ISM event is occured. And vty's network command invoke this function after making interface structure. */voidism_timer_set (struct ospf_interface *oi){ switch (oi->state) { case ISM_Down: /* First entry point of ospf interface state machine. In this state interface parameters must be set to initial values, and timers are reset also. */ OSPF_ISM_TIMER_OFF (oi->t_hello); OSPF_ISM_TIMER_OFF (oi->t_wait); OSPF_ISM_TIMER_OFF (oi->t_ls_ack); break; case ISM_Loopback: /* In this state, the interface may be looped back and will be unavailable for regular data traffic. */ OSPF_ISM_TIMER_OFF (oi->t_hello);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -