📄 ospf_abr.c
字号:
/* * OSPF ABR functions. * Copyright (C) 1999, 2000 Alex Zinin, 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 "memory.h"#include "linklist.h"#include "prefix.h"#include "if.h"#include "table.h"#include "vty.h"#include "filter.h"#include "plist.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_spf.h"#include "ospfd/ospf_route.h"#include "ospfd/ospf_ia.h"#include "ospfd/ospf_flood.h"#include "ospfd/ospf_abr.h"#include "ospfd/ospf_ase.h"#include "ospfd/ospf_zebra.h"#include "ospfd/ospf_dump.h"struct ospf_area_range *ospf_area_range_new (struct prefix_ipv4 *p){ struct ospf_area_range *range; range = XCALLOC (MTYPE_OSPF_AREA_RANGE, sizeof (struct ospf_area_range)); range->addr = p->prefix; range->masklen = p->prefixlen; range->cost_config = OSPF_AREA_RANGE_COST_UNSPEC; return range;}voidospf_area_range_free (struct ospf_area_range *range){ XFREE (MTYPE_OSPF_AREA_RANGE, range);}voidospf_area_range_add (struct ospf_area *area, struct ospf_area_range *range){ struct route_node *rn; struct prefix_ipv4 p; p.family = AF_INET; p.prefixlen = range->masklen; p.prefix = range->addr; rn = route_node_get (area->ranges, (struct prefix *)&p); if (rn->info) route_unlock_node (rn); else rn->info = range;}voidospf_area_range_delete (struct ospf_area *area, struct ospf_area_range *range){ struct route_node *rn; struct prefix_ipv4 p; p.family = AF_INET; p.prefixlen = range->masklen; p.prefix = range->addr; rn = route_node_lookup (area->ranges, (struct prefix *)&p); if (rn) { ospf_area_range_free (rn->info); rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); }}struct ospf_area_range *ospf_area_range_lookup (struct ospf_area *area, struct prefix_ipv4 *p){ struct route_node *rn; rn = route_node_lookup (area->ranges, (struct prefix *)p); if (rn) { route_unlock_node (rn); return rn->info; } return NULL;}struct ospf_area_range *ospf_area_range_lookup_next (struct ospf_area *area, struct in_addr *range_net, int first){ struct route_node *rn; struct prefix_ipv4 p; struct ospf_area_range *find; p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.prefix = *range_net; if (first) rn = route_top (area->ranges); else { rn = route_node_get (area->ranges, (struct prefix *) &p); rn = route_next (rn); } for (; rn; rn = route_next (rn)) if (rn->info) break; if (rn && rn->info) { find = rn->info; *range_net = rn->p.u.prefix4; route_unlock_node (rn); return find; } return NULL;}struct ospf_area_range *ospf_area_range_match (struct ospf_area *area, struct prefix_ipv4 *p){ struct route_node *node; node = route_node_match (area->ranges, (struct prefix *) p); if (node) { route_unlock_node (node); return node->info; } return NULL;}struct ospf_area_range *ospf_area_range_match_any (struct ospf *ospf, struct prefix_ipv4 *p){ struct ospf_area_range *range; listnode node; for (node = listhead (ospf->areas); node; nextnode (node)) if ((range = ospf_area_range_match (node->data, p))) return range; return NULL;}intospf_area_range_active (struct ospf_area_range *range){ return range->specifics;}intospf_area_actively_attached (struct ospf_area *area){ return area->act_ints;}intospf_area_range_set (struct ospf *ospf, struct in_addr area_id, struct prefix_ipv4 *p, int advertise){ struct ospf_area *area; struct ospf_area_range *range; int ret = OSPF_AREA_ID_FORMAT_ADDRESS; area = ospf_area_get (ospf, area_id, ret); if (area == NULL) return 0; range = ospf_area_range_lookup (area, p); if (range != NULL) { if ((CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE) && !CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE)) || (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE) && CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE))) ospf_schedule_abr_task (ospf); } else { range = ospf_area_range_new (p); ospf_area_range_add (area, range); ospf_schedule_abr_task (ospf); } if (CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE)) SET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE); else UNSET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE); return 1;}intospf_area_range_cost_set (struct ospf *ospf, struct in_addr area_id, struct prefix_ipv4 *p, u_int32_t cost){ struct ospf_area *area; struct ospf_area_range *range; int ret = OSPF_AREA_ID_FORMAT_ADDRESS; area = ospf_area_get (ospf, area_id, ret); if (area == NULL) return 0; range = ospf_area_range_new (p); if (range == NULL) return 0; if (range->cost_config != cost) { range->cost_config = cost; if (ospf_area_range_active (range)) ospf_schedule_abr_task (ospf); } return 1;}intospf_area_range_unset (struct ospf *ospf, struct in_addr area_id, struct prefix_ipv4 *p){ struct ospf_area *area; struct ospf_area_range *range; area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return 0; range = ospf_area_range_lookup (area, p); if (range == NULL) return 0; if (ospf_area_range_active (range)) ospf_schedule_abr_task (ospf); ospf_area_range_delete (area, range); return 1;}intospf_area_range_substitute_set (struct ospf *ospf, struct in_addr area_id, struct prefix_ipv4 *p, struct prefix_ipv4 *s){ struct ospf_area *area; struct ospf_area_range *range; int ret = OSPF_AREA_ID_FORMAT_ADDRESS; area = ospf_area_get (ospf, area_id, ret); range = ospf_area_range_lookup (area, p); if (range != NULL) { if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE) || !CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) ospf_schedule_abr_task (ospf); } else { range = ospf_area_range_new (p); ospf_area_range_add (area, range); ospf_schedule_abr_task (ospf); } SET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE); SET_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE); range->subst_addr = s->prefix; range->subst_masklen = s->prefixlen; return 1;}intospf_area_range_substitute_unset (struct ospf *ospf, struct in_addr area_id, struct prefix_ipv4 *p){ struct ospf_area *area; struct ospf_area_range *range; area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return 0; range = ospf_area_range_lookup (area, p); if (range == NULL) return 0; if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) if (ospf_area_range_active (range)) ospf_schedule_abr_task (ospf); UNSET_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE); range->subst_addr.s_addr = 0; range->subst_masklen = 0; return 1;}intospf_act_bb_connection (struct ospf *ospf){ if (ospf->backbone == NULL) return 0; return ospf->backbone->full_nbrs;}/* Check area border router status. */voidospf_check_abr_status (struct ospf *ospf){ struct ospf_area *area; listnode node; int bb_configured = 0; int bb_act_attached = 0; int areas_configured = 0; int areas_act_attached = 0; u_char new_flags = ospf->flags; if (IS_DEBUG_OSPF_EVENT) zlog_info ("ospf_check_abr_status(): Start"); for (node = listhead (ospf->areas); node; nextnode (node)) { area = getdata (node); if (listcount (area->oiflist)) { areas_configured++; if (OSPF_IS_AREA_BACKBONE (area)) bb_configured = 1; } if (ospf_area_actively_attached (area)) { areas_act_attached++; if (OSPF_IS_AREA_BACKBONE (area)) bb_act_attached = 1; } } if (IS_DEBUG_OSPF_EVENT) { zlog_info ("ospf_check_abr_status(): looked through areas"); zlog_info ("ospf_check_abr_status(): bb_configured: %d", bb_configured); zlog_info ("ospf_check_abr_status(): bb_act_attached: %d", bb_act_attached); zlog_info ("ospf_check_abr_status(): areas_configured: %d", areas_configured); zlog_info ("ospf_check_abr_status(): areas_act_attached: %d", areas_act_attached); } switch (ospf->abr_type) { case OSPF_ABR_SHORTCUT: case OSPF_ABR_STAND: if (areas_act_attached > 1) SET_FLAG (new_flags, OSPF_FLAG_ABR); else UNSET_FLAG (new_flags, OSPF_FLAG_ABR); break; case OSPF_ABR_IBM: if ((areas_act_attached > 1) && bb_configured) SET_FLAG (new_flags, OSPF_FLAG_ABR); else UNSET_FLAG (new_flags, OSPF_FLAG_ABR); break; case OSPF_ABR_CISCO: if ((areas_configured > 1) && bb_act_attached) SET_FLAG (new_flags, OSPF_FLAG_ABR); else UNSET_FLAG (new_flags, OSPF_FLAG_ABR); break; default: break; } if (new_flags != ospf->flags) { ospf_spf_calculate_schedule (ospf); if (IS_DEBUG_OSPF_EVENT) zlog_info ("ospf_check_abr_status(): new router flags: %x",new_flags); ospf->flags = new_flags; OSPF_TIMER_ON (ospf->t_router_lsa_update, ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY); }}voidospf_abr_update_aggregate (struct ospf_area_range *range, struct ospf_route *or){ if (IS_DEBUG_OSPF_EVENT) zlog_info ("ospf_abr_update_aggregate(): Start"); if (range->cost_config != -1) { if (IS_DEBUG_OSPF_EVENT) zlog_info ("ospf_abr_update_aggregate(): use configured cost %d", range->cost_config); range->cost = range->cost_config; } else { if (range->specifics == 0) range->cost = or->cost; /* 1st time get 1st cost */ if (or->cost < range->cost) { if (IS_DEBUG_OSPF_EVENT) zlog_info ("ospf_abr_update_aggregate(): lowest cost, update"); range->cost = or->cost; } } range->specifics++;}static voidset_metric (struct ospf_lsa *lsa, u_int32_t metric){ struct summary_lsa *header; u_char *mp; metric = htonl (metric); mp = (char *) &metric; mp++; header = (struct summary_lsa *) lsa->data; memcpy(header->metric, mp, 3);}#ifdef HAVE_NSSAintospf_abr_check_nssa_range (struct prefix_ipv4 *p, u_int32_t cost, struct ospf_area *area){ /* The Type-7 is tested against the aggregated prefix and forwarded for lsa installation and flooding */ return 0;}/* ospf_abr_translate_nssa */intospf_abr_translate_nssa (struct ospf_area *area, struct ospf_lsa *lsa){ /* Incoming Type-7 or later aggregated Type-7 LSA is skipped if P-bit is off. LSA is aggregated if within range. The Type-7 is translated, Installed/Approved as a Type-5 into global LSDB, then Flooded through AS Later, any Unapproved Translated Type-5's are flushed/discarded */ struct ospf_lsa *dup; if (! CHECK_FLAG (lsa->data->options, OSPF_OPTION_NP)) { if (IS_DEBUG_OSPF_NSSA) zlog_info ("ospf_abr_nssa(): P-bit off, NO Translation"); return 0; } if (IS_DEBUG_OSPF_NSSA) zlog_info ("ospf_abr_nssa(): TRANSLATING 7 to 5"); /* No more P-bit. */ /* UNSET_FLAG (lsa->data->options, OSPF_OPTION_NP); */ /* Area where Aggregate testing will be inserted, just like summary advertisements */ /* ospf_abr_check_nssa_range (p_arg, lsa-> cost, lsa -> area); */ /* Follow thru here means no aggregation */ dup = ospf_lsa_dup (lsa); /* keep LSDB intact, lock = 1 */ SET_FLAG (dup->flags, OSPF_LSA_LOCAL_XLT); /* Translated from 7 */ SET_FLAG (dup->flags, OSPF_LSA_APPROVED); /* So, do not remove it */ dup->data->type = OSPF_AS_EXTERNAL_LSA; /* make Type-5 */ ospf_lsa_checksum (dup->data); ospf_lsa_install (area->ospf, NULL, dup); /* Install this Type-5 into LSDB, Lock = 2. */ ospf_flood_through_as (area->ospf, NULL, dup); /* flood non-NSSA/STUB areas */ /* This translated Type-5 will go to all non-NSSA areas connected to this ABR; The Type-5 could come from any of the NSSA's connected to this ABR. */ return 0;}voidospf_abr_translate_nssa_range (struct prefix_ipv4 *p, u_int32_t cost){ /* The Type-7 is created from the aggregated prefix and forwarded for lsa installation and flooding... to be added... */}#endif /* HAVE_NSSA */voidospf_abr_announce_network_to_area (struct prefix_ipv4 *p, u_int32_t cost, struct ospf_area *area){ struct ospf_lsa *lsa, *old = NULL; struct summary_lsa *sl = NULL; if (IS_DEBUG_OSPF_EVENT) zlog_info ("ospf_abr_announce_network_to_area(): Start"); old = ospf_lsa_lookup_by_prefix (area->lsdb, OSPF_SUMMARY_LSA, p, area->ospf->router_id); if (old) { if (IS_DEBUG_OSPF_EVENT) zlog_info ("ospf_abr_announce_network_to_area(): old summary found"); sl = (struct summary_lsa *) old->data; if (IS_DEBUG_OSPF_EVENT) zlog_info ("ospf_abr_announce_network_to_area(): " "old metric: %d, new metric: %d", GET_METRIC (sl->metric), cost); } if (old && (GET_METRIC (sl->metric) == cost)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -