📄 ospf6_interface.c
字号:
/* * Copyright (C) 2003 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. */#include <zebra.h>#include "memory.h"#include "if.h"#include "log.h"#include "command.h"#include "thread.h"#include "prefix.h"#include "plist.h"#include "ospf6_lsa.h"#include "ospf6_lsdb.h"#include "ospf6_network.h"#include "ospf6_message.h"#include "ospf6_route.h"#include "ospf6_top.h"#include "ospf6_area.h"#include "ospf6_interface.h"#include "ospf6_neighbor.h"#include "ospf6_intra.h"#include "ospf6_spf.h"#include "ospf6d.h"unsigned char conf_debug_ospf6_interface = 0;char *ospf6_interface_state_str[] ={ "None", "Down", "Loopback", "Waiting", "PointToPoint", "DROther", "BDR", "DR", NULL};struct ospf6_interface *ospf6_interface_lookup_by_ifindex (int ifindex){ struct ospf6_interface *oi; struct interface *ifp; ifp = if_lookup_by_index (ifindex); if (ifp == NULL) return (struct ospf6_interface *) NULL; oi = (struct ospf6_interface *) ifp->info; return oi;}struct ospf6_interface *ospf6_interface_lookup_by_name (char *ifname){ struct ospf6_interface *oi; struct interface *ifp; ifp = if_lookup_by_name (ifname); if (ifp == NULL) return (struct ospf6_interface *) NULL; oi = (struct ospf6_interface *) ifp->info; return oi;}/* schedule routing table recalculation */voidospf6_interface_lsdb_hook (struct ospf6_lsa *lsa){ switch (ntohs (lsa->header->type)) { case OSPF6_LSTYPE_LINK: if (OSPF6_INTERFACE (lsa->lsdb->data)->state == OSPF6_INTERFACE_DR) OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (OSPF6_INTERFACE (lsa->lsdb->data)); ospf6_spf_schedule (OSPF6_INTERFACE (lsa->lsdb->data)->area); break; default: break; }}/* Create new ospf6 interface structure */struct ospf6_interface *ospf6_interface_create (struct interface *ifp){ struct ospf6_interface *oi; int iobuflen; oi = (struct ospf6_interface *) XMALLOC (MTYPE_OSPF6_IF, sizeof (struct ospf6_interface)); if (oi) memset (oi, 0, sizeof (struct ospf6_interface)); else { zlog_err ("Can't malloc ospf6_interface for ifindex %d", ifp->ifindex); return (struct ospf6_interface *) NULL; } oi->area = (struct ospf6_area *) NULL; oi->neighbor_list = list_new (); oi->neighbor_list->cmp = ospf6_neighbor_cmp; oi->linklocal_addr = (struct in6_addr *) NULL; oi->instance_id = 0; oi->transdelay = 1; oi->priority = 1; oi->hello_interval = 10; oi->dead_interval = 40; oi->rxmt_interval = 5; oi->cost = 1; oi->state = OSPF6_INTERFACE_DOWN; oi->flag = 0; /* Try to adjust I/O buffer size with IfMtu */ oi->ifmtu = ifp->mtu; iobuflen = ospf6_iobuf_size (ifp->mtu); if (oi->ifmtu > iobuflen) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_info ("Interface %s: IfMtu is adjusted to I/O buffer size: %d.", ifp->name, iobuflen); oi->ifmtu = iobuflen; } oi->lsupdate_list = ospf6_lsdb_create (oi); oi->lsack_list = ospf6_lsdb_create (oi); oi->lsdb = ospf6_lsdb_create (oi); oi->lsdb->hook_add = ospf6_interface_lsdb_hook; oi->lsdb->hook_remove = ospf6_interface_lsdb_hook; oi->lsdb_self = ospf6_lsdb_create (oi); oi->route_connected = ospf6_route_table_create (); /* link both */ oi->interface = ifp; ifp->info = oi; return oi;}voidospf6_interface_delete (struct ospf6_interface *oi){ listnode n; struct ospf6_neighbor *on; for (n = listhead (oi->neighbor_list); n; nextnode (n)) { on = (struct ospf6_neighbor *) getdata (n); ospf6_neighbor_delete (on); } list_delete (oi->neighbor_list); THREAD_OFF (oi->thread_send_hello); THREAD_OFF (oi->thread_send_lsupdate); THREAD_OFF (oi->thread_send_lsack); ospf6_lsdb_remove_all (oi->lsdb); ospf6_lsdb_remove_all (oi->lsupdate_list); ospf6_lsdb_remove_all (oi->lsack_list); ospf6_lsdb_delete (oi->lsdb); ospf6_lsdb_delete (oi->lsdb_self); ospf6_lsdb_delete (oi->lsupdate_list); ospf6_lsdb_delete (oi->lsack_list); ospf6_route_table_delete (oi->route_connected); /* cut link */ oi->interface->info = NULL; /* plist_name */ if (oi->plist_name) XFREE (MTYPE_PREFIX_LIST_STR, oi->plist_name); XFREE (MTYPE_OSPF6_IF, oi);}voidospf6_interface_enable (struct ospf6_interface *oi){ UNSET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE); oi->thread_send_hello = thread_add_event (master, ospf6_hello_send, oi, 0);}voidospf6_interface_disable (struct ospf6_interface *oi){ listnode i; struct ospf6_neighbor *on; SET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE); for (i = listhead (oi->neighbor_list); i; nextnode (i)) { on = (struct ospf6_neighbor *) getdata (i); ospf6_neighbor_delete (on); } list_delete_all_node (oi->neighbor_list); ospf6_lsdb_remove_all (oi->lsdb); ospf6_lsdb_remove_all (oi->lsupdate_list); ospf6_lsdb_remove_all (oi->lsack_list); THREAD_OFF (oi->thread_send_hello); THREAD_OFF (oi->thread_send_lsupdate); THREAD_OFF (oi->thread_send_lsack);}static struct in6_addr *ospf6_interface_get_linklocal_address (struct interface *ifp){ listnode n; struct connected *c; struct in6_addr *l = (struct in6_addr *) NULL; /* for each connected address */ for (n = listhead (ifp->connected); n; nextnode (n)) { c = (struct connected *) getdata (n); /* if family not AF_INET6, ignore */ if (c->address->family != AF_INET6) continue; /* linklocal scope check */ if (IN6_IS_ADDR_LINKLOCAL (&c->address->u.prefix6)) l = &c->address->u.prefix6; } return l;}voidospf6_interface_if_add (struct interface *ifp){ struct ospf6_interface *oi; int iobuflen; oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) return; /* Try to adjust I/O buffer size with IfMtu */ if (oi->ifmtu == 0) oi->ifmtu = ifp->mtu; iobuflen = ospf6_iobuf_size (ifp->mtu); if (oi->ifmtu > iobuflen) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_info ("Interface %s: IfMtu is adjusted to I/O buffer size: %d.", ifp->name, iobuflen); oi->ifmtu = iobuflen; } /* interface start */ if (oi->area) thread_add_event (master, interface_up, oi, 0);}voidospf6_interface_if_del (struct interface *ifp){ struct ospf6_interface *oi; oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) return; /* interface stop */ if (oi->area) thread_execute (master, interface_down, oi, 0); listnode_delete (oi->area->if_list, oi); oi->area = (struct ospf6_area *) NULL; /* cut link */ oi->interface = NULL; ifp->info = NULL; ospf6_interface_delete (oi);}voidospf6_interface_state_update (struct interface *ifp){ struct ospf6_interface *oi; oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) return; if (oi->area == NULL) return; if (if_is_up (ifp)) thread_add_event (master, interface_up, oi, 0); else thread_add_event (master, interface_down, oi, 0); return;}voidospf6_interface_connected_route_update (struct interface *ifp){ struct ospf6_interface *oi; struct ospf6_route *route; struct connected *c; listnode i; oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) return; /* reset linklocal pointer */ oi->linklocal_addr = ospf6_interface_get_linklocal_address (ifp); /* if area is null, do not make connected-route list */ if (oi->area == NULL) return; /* update "route to advertise" interface route table */ ospf6_route_remove_all (oi->route_connected); for (i = listhead (oi->interface->connected); i; nextnode (i)) { c = (struct connected *) getdata (i); if (c->address->family != AF_INET6) continue; CONTINUE_IF_ADDRESS_LINKLOCAL (IS_OSPF6_DEBUG_INTERFACE, c->address); CONTINUE_IF_ADDRESS_UNSPECIFIED (IS_OSPF6_DEBUG_INTERFACE, c->address); CONTINUE_IF_ADDRESS_LOOPBACK (IS_OSPF6_DEBUG_INTERFACE, c->address); CONTINUE_IF_ADDRESS_V4COMPAT (IS_OSPF6_DEBUG_INTERFACE, c->address); CONTINUE_IF_ADDRESS_V4MAPPED (IS_OSPF6_DEBUG_INTERFACE, c->address); /* apply filter */ if (oi->plist_name) { struct prefix_list *plist; enum prefix_list_type ret; char buf[128]; prefix2str (c->address, buf, sizeof (buf)); plist = prefix_list_lookup (AFI_IP6, oi->plist_name); ret = prefix_list_apply (plist, (void *) c->address); if (ret == PREFIX_DENY) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_info ("%s on %s filtered by prefix-list %s ", buf, oi->interface->name, oi->plist_name); continue; } } route = ospf6_route_create (); memcpy (&route->prefix, c->address, sizeof (struct prefix)); apply_mask (&route->prefix); route->type = OSPF6_DEST_TYPE_NETWORK; route->path.area_id = oi->area->area_id; route->path.type = OSPF6_PATH_TYPE_INTRA; route->path.cost = oi->cost; route->nexthop[0].ifindex = oi->interface->ifindex; inet_pton (AF_INET6, "::1", &route->nexthop[0].address); ospf6_route_add (route, oi->route_connected); } /* create new Link-LSA */ OSPF6_LINK_LSA_SCHEDULE (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area);}static voidospf6_interface_state_change (u_char next_state, struct ospf6_interface *oi){ u_char prev_state; prev_state = oi->state; oi->state = next_state; if (prev_state == next_state) return; /* log */ if (IS_OSPF6_DEBUG_INTERFACE) { zlog_info ("Interface state change %s: %s -> %s", oi->interface->name, ospf6_interface_state_str[prev_state], ospf6_interface_state_str[next_state]); } if ((prev_state == OSPF6_INTERFACE_DR || prev_state == OSPF6_INTERFACE_BDR) && (next_state != OSPF6_INTERFACE_DR && next_state != OSPF6_INTERFACE_BDR)) ospf6_leave_alldrouters (oi->interface->ifindex); if ((prev_state != OSPF6_INTERFACE_DR && prev_state != OSPF6_INTERFACE_BDR) && (next_state == OSPF6_INTERFACE_DR || next_state == OSPF6_INTERFACE_BDR)) ospf6_join_alldrouters (oi->interface->ifindex); OSPF6_ROUTER_LSA_SCHEDULE (oi->area); if (next_state == OSPF6_INTERFACE_DOWN) { OSPF6_NETWORK_LSA_EXECUTE (oi); OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); } else if (prev_state == OSPF6_INTERFACE_DR || next_state == OSPF6_INTERFACE_DR) { OSPF6_NETWORK_LSA_SCHEDULE (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); }}/* DR Election, RFC2328 section 9.4 */#define IS_ELIGIBLE(n) \ ((n)->state >= OSPF6_NEIGHBOR_TWOWAY && (n)->priority != 0)static struct ospf6_neighbor *better_bdrouter (struct ospf6_neighbor *a, struct ospf6_neighbor *b){ if ((a == NULL || ! IS_ELIGIBLE (a) || a->drouter == a->router_id) && (b == NULL || ! IS_ELIGIBLE (b) || b->drouter == b->router_id)) return NULL; else if (a == NULL || ! IS_ELIGIBLE (a) || a->drouter == a->router_id) return b; else if (b == NULL || ! IS_ELIGIBLE (b) || b->drouter == b->router_id) return a; if (a->bdrouter == a->router_id && b->bdrouter != b->router_id) return a; if (a->bdrouter != a->router_id && b->bdrouter == b->router_id) return b; if (a->priority > b->priority) return a; if (a->priority < b->priority) return b; if (ntohl (a->router_id) > ntohl (b->router_id)) return a; if (ntohl (a->router_id) < ntohl (b->router_id)) return b; zlog_warn ("Router-ID duplicate ?"); return a;}static struct ospf6_neighbor *better_drouter (struct ospf6_neighbor *a, struct ospf6_neighbor *b){ if ((a == NULL || ! IS_ELIGIBLE (a) || a->drouter != a->router_id) && (b == NULL || ! IS_ELIGIBLE (b) || b->drouter != b->router_id)) return NULL; else if (a == NULL || ! IS_ELIGIBLE (a) || a->drouter != a->router_id) return b; else if (b == NULL || ! IS_ELIGIBLE (b) || b->drouter != b->router_id) return a; if (a->drouter == a->router_id && b->drouter != b->router_id) return a; if (a->drouter != a->router_id && b->drouter == b->router_id) return b; if (a->priority > b->priority) return a; if (a->priority < b->priority) return b; if (ntohl (a->router_id) > ntohl (b->router_id)) return a; if (ntohl (a->router_id) < ntohl (b->router_id)) return b; zlog_warn ("Router-ID duplicate ?"); return a;}static u_chardr_election (struct ospf6_interface *oi){ listnode i; struct ospf6_neighbor *on, *drouter, *bdrouter, myself; struct ospf6_neighbor *best_drouter, *best_bdrouter; u_char next_state = 0; drouter = bdrouter = NULL; best_drouter = best_bdrouter = NULL; /* pseudo neighbor myself, including noting current DR/BDR (1) */ memset (&myself, 0, sizeof (myself)); inet_ntop (AF_INET, &oi->area->ospf6->router_id, myself.name, sizeof (myself.name)); myself.state = OSPF6_NEIGHBOR_TWOWAY; myself.drouter = oi->drouter; myself.bdrouter = oi->bdrouter; myself.priority = oi->priority; myself.router_id = oi->area->ospf6->router_id; /* Electing BDR (2) */ for (i = listhead (oi->neighbor_list); i; nextnode (i)) { on = (struct ospf6_neighbor *) getdata (i); bdrouter = better_bdrouter (bdrouter, on); } best_bdrouter = bdrouter; bdrouter = better_bdrouter (best_bdrouter, &myself); /* Electing DR (3) */ for (i = listhead (oi->neighbor_list); i; nextnode (i)) { on = (struct ospf6_neighbor *) getdata (i);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -