| /* |
| * 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; |
| } |
| |
| void |
| ospf_area_range_free (struct ospf_area_range *range) |
| { |
| XFREE (MTYPE_OSPF_AREA_RANGE, range); |
| } |
| |
| void |
| ospf_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; |
| } |
| |
| void |
| ospf_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; |
| } |
| |
| int |
| ospf_area_range_active (struct ospf_area_range *range) |
| { |
| return range->specifics; |
| } |
| |
| int |
| ospf_area_actively_attached (struct ospf_area *area) |
| { |
| return area->act_ints; |
| } |
| |
| int |
| ospf_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_DECIMAL; |
| |
| area = ospf_area_get (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 (); |
| } |
| else |
| { |
| range = ospf_area_range_new (p); |
| ospf_area_range_add (area, range); |
| ospf_schedule_abr_task (); |
| } |
| |
| 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; |
| } |
| |
| int |
| ospf_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_DECIMAL; |
| |
| area = ospf_area_get (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 (); |
| } |
| |
| return 1; |
| } |
| |
| int |
| ospf_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 (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_area_range_delete (area, range); |
| |
| return 1; |
| } |
| |
| int |
| ospf_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_DECIMAL; |
| |
| area = ospf_area_get (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 (); |
| } |
| else |
| { |
| range = ospf_area_range_new (p); |
| ospf_area_range_add (area, range); |
| ospf_schedule_abr_task (); |
| } |
| |
| 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; |
| } |
| |
| int |
| ospf_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 (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 (); |
| |
| UNSET_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE); |
| range->subst_addr.s_addr = 0; |
| range->subst_masklen = 0; |
| |
| return 1; |
| } |
| |
| int |
| ospf_act_bb_connection () |
| { |
| if (ospf_top->backbone == NULL) |
| return 0; |
| |
| return ospf_top->backbone->full_nbrs; |
| } |
| |
| /* Check area border router status. */ |
| void |
| ospf_check_abr_status () |
| { |
| 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_top->flags; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_check_abr_status(): Start"); |
| |
| for (node = listhead (ospf_top->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_top->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_top->flags) |
| { |
| ospf_spf_calculate_schedule (); |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_check_abr_status(): new router flags: %x",new_flags); |
| ospf_top->flags = new_flags; |
| OSPF_TIMER_ON (ospf_top->t_router_lsa_update, |
| ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY); |
| } |
| } |
| |
| void |
| ospf_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 void |
| set_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_NSSA |
| int |
| ospf_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 */ |
| int |
| ospf_abr_translate_nssa (struct ospf_lsa *lsa, void *p_arg, int int_arg) |
| { |
| /* 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 (NULL, dup); /* Install this Type-5 into LSDB, Lock = 2. */ |
| |
| ospf_flood_through_as (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; |
| } |
| |
| void |
| ospf_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 */ |
| |
| void |
| ospf_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_SUMMARY_LSA_SELF_FIND_BY_PREFIX (area, p); |
| |
| 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)) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_network_to_area(): " |
| "old summary approved"); |
| SET_FLAG (old->flags, OSPF_LSA_APPROVED); |
| } |
| else |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_network_to_area(): " |
| "creating new summary"); |
| if (old) |
| { |
| |
| set_metric (old, cost); |
| lsa = ospf_summary_lsa_refresh (old); |
| /* This will flood through area. */ |
| } |
| else |
| { |
| lsa = ospf_summary_lsa_originate (p, cost, area); |
| /* This will flood through area. */ |
| } |
| |
| |
| SET_FLAG (lsa->flags, OSPF_LSA_APPROVED); |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_network_to_area(): " |
| "flooding new version of summary"); |
| |
| #ifndef HAVE_NSSA |
| ospf_flood_through_area (area, NULL, lsa); |
| #endif /* ! HAVE_NSSA */ |
| } |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_network_to_area(): Stop"); |
| } |
| |
| int |
| ospf_abr_nexthops_belong_to_area (struct ospf_route *or, |
| struct ospf_area *area) |
| { |
| listnode node; |
| |
| for (node = listhead (or->path); node; nextnode (node)) |
| { |
| struct ospf_path *path = node->data; |
| struct ospf_interface *oi = path->oi; |
| |
| if (oi != NULL) |
| if (oi->area == area) |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| int |
| ospf_abr_should_accept (struct prefix *p, struct ospf_area *area) |
| { |
| if (IMPORT_NAME (area)) |
| { |
| if (IMPORT_LIST (area) == NULL) |
| IMPORT_LIST (area) = access_list_lookup (AFI_IP, IMPORT_NAME (area)); |
| |
| if (IMPORT_LIST (area)) |
| if (access_list_apply (IMPORT_LIST (area), p) == FILTER_DENY) |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| int |
| ospf_abr_plist_in_check (struct ospf_area *area, struct ospf_route *or, |
| struct prefix *p) |
| { |
| if (PREFIX_NAME_IN (area)) |
| { |
| if (PREFIX_LIST_IN (area) == NULL) |
| PREFIX_LIST_IN (area) = prefix_list_lookup (AFI_IP, |
| PREFIX_NAME_IN (area)); |
| if (PREFIX_LIST_IN (area)) |
| if (prefix_list_apply (PREFIX_LIST_IN (area), p) != PREFIX_PERMIT) |
| return 0; |
| } |
| return 1; |
| } |
| |
| int |
| ospf_abr_plist_out_check (struct ospf_area *area, struct ospf_route *or, |
| struct prefix *p) |
| { |
| if (PREFIX_NAME_OUT (area)) |
| { |
| if (PREFIX_LIST_OUT (area) == NULL) |
| PREFIX_LIST_OUT (area) = prefix_list_lookup (AFI_IP, |
| PREFIX_NAME_OUT (area)); |
| if (PREFIX_LIST_OUT (area)) |
| if (prefix_list_apply (PREFIX_LIST_OUT (area), p) != PREFIX_PERMIT) |
| return 0; |
| } |
| return 1; |
| } |
| |
| void |
| ospf_abr_announce_network (struct route_node *n, struct ospf_route *or) |
| { |
| listnode node; |
| struct ospf_area_range *range; |
| struct prefix_ipv4 *p; |
| struct ospf_area *area, *or_area; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_network(): Start"); |
| p = (struct prefix_ipv4 *) &n->p; |
| |
| or_area = ospf_area_lookup_by_area_id (or->u.std.area_id); |
| assert (or_area); |
| |
| for (node = listhead (ospf_top->areas); node; nextnode (node)) |
| { |
| area = getdata (node); |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_network(): looking at area %s", |
| inet_ntoa (area->area_id)); |
| |
| if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id)) |
| continue; |
| |
| if (ospf_abr_nexthops_belong_to_area (or, area)) |
| continue; |
| |
| if (!ospf_abr_should_accept (&n->p, area)) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_network(): " |
| "prefix %s/%d was denied by import-list", |
| inet_ntoa (p->prefix), p->prefixlen); |
| continue; |
| } |
| |
| if (!ospf_abr_plist_in_check (area, or, &n->p)) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_network(): " |
| "prefix %s/%d was denied by prefix-list", |
| inet_ntoa (p->prefix), p->prefixlen); |
| continue; |
| } |
| |
| if (area->external_routing != OSPF_AREA_DEFAULT && area->no_summary) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_network(): " |
| "area %s is stub and no_summary", |
| inet_ntoa (area->area_id)); |
| continue; |
| } |
| |
| if (or->path_type == OSPF_PATH_INTER_AREA) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_network(): this is " |
| "inter-area route to %s/%d", |
| inet_ntoa (p->prefix), p->prefixlen); |
| |
| if (!OSPF_IS_AREA_BACKBONE (area)) |
| ospf_abr_announce_network_to_area (p, or->cost, area); |
| } |
| |
| if (or->path_type == OSPF_PATH_INTRA_AREA) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_network(): " |
| "this is intra-area route to %s/%d", |
| inet_ntoa (p->prefix), p->prefixlen); |
| if ((range = ospf_area_range_match (or_area, p)) && |
| !ospf_area_is_transit (area)) |
| ospf_abr_update_aggregate (range, or); |
| else |
| ospf_abr_announce_network_to_area (p, or->cost, area); |
| } |
| } |
| } |
| |
| int |
| ospf_abr_should_announce (struct prefix *p, struct ospf_route *or) |
| { |
| struct ospf_area *area = ospf_area_lookup_by_area_id (or->u.std.area_id); |
| |
| assert (area); |
| |
| if (EXPORT_NAME (area)) |
| { |
| if (EXPORT_LIST (area) == NULL) |
| EXPORT_LIST (area) = access_list_lookup (AFI_IP, EXPORT_NAME (area)); |
| |
| if (EXPORT_LIST (area)) |
| if (access_list_apply (EXPORT_LIST (area), p) == FILTER_DENY) |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| #ifdef HAVE_NSSA |
| void |
| ospf_abr_process_nssa_translates () |
| { |
| /* Scan through all NSSA_LSDB records for all areas; |
| |
| If P-bit is on, translate all Type-7's to 5's and aggregate or |
| flood install as approved in Type-5 LSDB with XLATE Flag on |
| later, do same for all aggregates... At end, DISCARD all |
| remaining UNAPPROVED Type-5's (Aggregate is for future ) */ |
| listnode node; |
| struct ospf_area *area; |
| |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_process_nssa_translates(): Start"); |
| |
| for (node = listhead (ospf_top->areas); node; nextnode (node)) |
| { |
| area = getdata (node); |
| |
| if (! area->NSSATranslator) |
| continue; /* skip if not translator */ |
| |
| if (area->external_routing != OSPF_AREA_NSSA) |
| continue; /* skip if not Nssa Area */ |
| |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_process_nssa_translates(): " |
| "looking at area %s", inet_ntoa (area->area_id)); |
| |
| foreach_lsa (NSSA_LSDB (area), area, 0, ospf_abr_translate_nssa); |
| } |
| |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_process_nssa_translates(): Stop"); |
| |
| } |
| #endif /* HAVE_NSSA */ |
| |
| void |
| ospf_abr_process_network_rt (struct route_table *rt) |
| { |
| struct route_node *rn; |
| struct ospf_route *or; |
| struct ospf_area *area; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_network_rt(): Start"); |
| |
| for (rn = route_top (rt); rn; rn = route_next (rn)) |
| { |
| if ((or = rn->info) == NULL) |
| continue; |
| |
| if (!(area = ospf_area_lookup_by_area_id (or->u.std.area_id))) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_network_rt(): area %s no longer exists", |
| inet_ntoa (or->u.std.area_id)); |
| continue; |
| } |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_network_rt(): this is a route to %s/%d", |
| inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); |
| if (or->path_type >= OSPF_PATH_TYPE1_EXTERNAL) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_network_rt(): " |
| "this is an External router, skipping"); |
| continue; |
| } |
| |
| if (or->cost >= OSPF_LS_INFINITY) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_network_rt():" |
| " this route's cost is infinity, skipping"); |
| continue; |
| } |
| |
| if (or->type == OSPF_DESTINATION_DISCARD) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_network_rt():" |
| " this is a discard entry, skipping"); |
| continue; |
| } |
| |
| if (or->path_type == OSPF_PATH_INTRA_AREA && |
| !ospf_abr_should_announce (&rn->p, or)) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info("ospf_abr_process_network_rt(): denied by export-list"); |
| continue; |
| } |
| |
| if (or->path_type == OSPF_PATH_INTRA_AREA && |
| !ospf_abr_plist_out_check (area, or, &rn->p)) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info("ospf_abr_process_network_rt(): denied by prefix-list"); |
| continue; |
| } |
| |
| if ((or->path_type == OSPF_PATH_INTER_AREA) && |
| !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_network_rt():" |
| " this is route is not backbone one, skipping"); |
| continue; |
| } |
| |
| |
| if ((ospf_top->abr_type == OSPF_ABR_CISCO) || |
| (ospf_top->abr_type == OSPF_ABR_IBM)) |
| |
| if (!ospf_act_bb_connection () && |
| or->path_type != OSPF_PATH_INTRA_AREA) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_network_rt(): ALT ABR: " |
| "No BB connection, skip not intra-area routes"); |
| continue; |
| } |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_network_rt(): announcing"); |
| ospf_abr_announce_network (rn, or); |
| } |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_network_rt(): Stop"); |
| } |
| |
| void |
| ospf_abr_announce_rtr_to_area (struct prefix_ipv4 *p, u_int32_t cost, |
| struct ospf_area *area) |
| { |
| struct ospf_lsa *lsa, *old = NULL; |
| struct summary_lsa *slsa = NULL; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_rtr_to_area(): Start"); |
| |
| old = OSPF_SUMMARY_ASBR_LSA_SELF_FIND_BY_PREFIX (area, p); |
| /* old = ospf_find_self_summary_asbr_lsa_by_prefix (area, p); */ |
| |
| if (old) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_rtr_to_area(): old summary found"); |
| slsa = (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 (slsa->metric), cost); |
| } |
| |
| if (old && (GET_METRIC (slsa->metric) == cost)) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_rtr_to_area(): old summary approved"); |
| SET_FLAG (old->flags, OSPF_LSA_APPROVED); |
| } |
| else |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_rtr_to_area(): 2.2"); |
| |
| if (old) |
| { |
| set_metric (old, cost); |
| lsa = ospf_summary_asbr_lsa_refresh (old); |
| } |
| else |
| lsa = ospf_summary_asbr_lsa_originate (p, cost, area); |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_rtr_to_area(): " |
| "flooding new version of summary"); |
| /* |
| zlog_info ("ospf_abr_announce_rtr_to_area(): creating new summary"); |
| lsa = ospf_summary_asbr_lsa (p, cost, area, old); */ |
| |
| SET_FLAG (lsa->flags, OSPF_LSA_APPROVED); |
| /* ospf_flood_through_area (area, NULL, lsa);*/ |
| } |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_rtr_to_area(): Stop"); |
| } |
| |
| |
| void |
| ospf_abr_announce_rtr (struct prefix_ipv4 *p, struct ospf_route *or) |
| { |
| listnode node; |
| struct ospf_area *area; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_rtr(): Start"); |
| |
| for (node = listhead (ospf_top->areas); node; nextnode (node)) |
| { |
| area = getdata (node); |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_rtr(): looking at area %s", |
| inet_ntoa (area->area_id)); |
| |
| if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id)) |
| continue; |
| |
| if (ospf_abr_nexthops_belong_to_area (or, area)) |
| continue; |
| |
| if (area->external_routing != OSPF_AREA_DEFAULT) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_network(): " |
| "area %s doesn't support external routing", |
| inet_ntoa(area->area_id)); |
| continue; |
| } |
| |
| if (or->path_type == OSPF_PATH_INTER_AREA) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_rtr(): " |
| "this is inter-area route to %s", inet_ntoa (p->prefix)); |
| if (!OSPF_IS_AREA_BACKBONE (area)) |
| ospf_abr_announce_rtr_to_area (p, or->cost, area); |
| } |
| |
| if (or->path_type == OSPF_PATH_INTRA_AREA) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_rtr(): " |
| "this is intra-area route to %s", inet_ntoa (p->prefix)); |
| ospf_abr_announce_rtr_to_area (p, or->cost, area); |
| } |
| } |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_rtr(): Stop"); |
| } |
| |
| void |
| ospf_abr_process_router_rt (struct route_table *rt) |
| { |
| struct route_node *rn; |
| struct ospf_route *or; |
| struct list *l; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_router_rt(): Start"); |
| |
| for (rn = route_top (rt); rn; rn = route_next (rn)) |
| { |
| listnode node; |
| char flag = 0; |
| struct ospf_route *best = NULL; |
| |
| if (rn->info == NULL) |
| continue; |
| |
| l = rn->info; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_router_rt(): this is a route to %s", |
| inet_ntoa (rn->p.u.prefix4)); |
| |
| for (node = listhead (l); node; nextnode (node)) |
| { |
| or = getdata (node); |
| if (or == NULL) |
| continue; |
| |
| if (!ospf_area_lookup_by_area_id (or->u.std.area_id)) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_router_rt(): area %s no longer exists", |
| inet_ntoa (or->u.std.area_id)); |
| continue; |
| } |
| |
| |
| if (!CHECK_FLAG (or->u.std.flags, ROUTER_LSA_EXTERNAL)) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_router_rt(): " |
| "This is not an ASBR, skipping"); |
| continue; |
| } |
| |
| if (!flag) |
| { |
| best = ospf_find_asbr_route (rt, (struct prefix_ipv4 *) &rn->p); |
| flag = 1; |
| } |
| |
| if (best == NULL) |
| continue; |
| |
| if (or != best) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_router_rt(): " |
| "This route is not the best among possible, skipping"); |
| continue; |
| } |
| |
| if (or->path_type == OSPF_PATH_INTER_AREA && |
| !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_router_rt(): " |
| "This route is not a backbone one, skipping"); |
| continue; |
| } |
| |
| if (or->cost >= OSPF_LS_INFINITY) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_router_rt(): " |
| "This route has LS_INFINITY metric, skipping"); |
| continue; |
| } |
| |
| if (ospf_top->abr_type == OSPF_ABR_CISCO || |
| ospf_top->abr_type == OSPF_ABR_IBM) |
| if (!ospf_act_bb_connection () && |
| or->path_type != OSPF_PATH_INTRA_AREA) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info("ospf_abr_process_network_rt(): ALT ABR: " |
| "No BB connection, skip not intra-area routes"); |
| continue; |
| } |
| |
| ospf_abr_announce_rtr ((struct prefix_ipv4 *) &rn->p, or); |
| |
| } |
| |
| } |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_process_router_rt(): Stop"); |
| } |
| |
| #ifdef HAVE_NSSA |
| int |
| ospf_abr_unapprove_translates_apply (struct ospf_lsa *lsa, void *p_arg, |
| int int_arg) |
| { |
| /* Could be a mix of Normal Type-5's, self-originated, or Type-7s |
| that are Locally ABR Translated */ |
| |
| if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) |
| UNSET_FLAG (lsa->flags, OSPF_LSA_APPROVED); |
| |
| return 0; |
| } |
| |
| void |
| ospf_abr_unapprove_translates () /* For NSSA Translations */ |
| { |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_unapprove_translates(): Start"); |
| |
| /* NSSA Translator is not checked, because it may have gone away, |
| and we would want to flush any residuals anyway */ |
| |
| foreach_lsa (EXTERNAL_LSDB (ospf_top), NULL, 0, |
| ospf_abr_unapprove_translates_apply); |
| |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_unapprove_translates(): Stop"); |
| } |
| #endif /* HAVE_NSSA */ |
| |
| int |
| ospf_abr_unapprove_summaries_apply (struct ospf_lsa *lsa, void *p_arg, |
| int int_arg) |
| { |
| if (ospf_lsa_is_self_originated (lsa)) |
| UNSET_FLAG (lsa->flags, OSPF_LSA_APPROVED); |
| |
| return 0; |
| } |
| |
| void |
| ospf_abr_unapprove_summaries () |
| { |
| listnode node; |
| struct ospf_area *area; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_unapprove_summaries(): Start"); |
| |
| for (node = listhead (ospf_top->areas); node; nextnode (node)) |
| { |
| area = getdata (node); |
| foreach_lsa (SUMMARY_LSDB (area), NULL, 0, |
| ospf_abr_unapprove_summaries_apply); |
| foreach_lsa (ASBR_SUMMARY_LSDB (area), NULL, 0, |
| ospf_abr_unapprove_summaries_apply); |
| } |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_unapprove_summaries(): Stop"); |
| } |
| |
| void |
| ospf_abr_prepare_aggregates () |
| { |
| listnode node; |
| struct route_node *rn; |
| struct ospf_area_range *range; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_prepare_aggregates(): Start"); |
| |
| for (node = listhead (ospf_top->areas); node; nextnode (node)) |
| { |
| struct ospf_area *area = getdata (node); |
| |
| for (rn = route_top (area->ranges); rn; rn = route_next (rn)) |
| if ((range = rn->info) != NULL) |
| { |
| range->cost = 0; |
| range->specifics = 0; |
| } |
| } |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_prepare_aggregates(): Stop"); |
| } |
| |
| void |
| ospf_abr_announce_aggregates () |
| { |
| struct ospf_area *area, *ar; |
| struct ospf_area_range *range; |
| struct route_node *rn; |
| struct prefix_ipv4 p; |
| listnode node, n; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_aggregates(): Start"); |
| |
| for (node = listhead (ospf_top->areas); node; nextnode (node)) |
| { |
| area = getdata (node); |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_aggregates(): looking at area %s", |
| inet_ntoa (area->area_id)); |
| |
| for (rn = route_top (area->ranges); rn; rn = route_next (rn)) |
| if ((range = rn->info)) |
| { |
| if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_aggregates():" |
| " discarding suppress-ranges"); |
| continue; |
| } |
| |
| p.family = AF_INET; |
| p.prefix = range->addr; |
| p.prefixlen = range->masklen; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_aggregates():" |
| " this is range: %s/%d", |
| inet_ntoa (p.prefix), p.prefixlen); |
| |
| if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) |
| { |
| p.family = AF_INET; |
| p.prefix = range->subst_addr; |
| p.prefixlen = range->subst_masklen; |
| } |
| |
| if (range->specifics) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_aggregates(): active range"); |
| |
| for (n = listhead (ospf_top->areas); n; nextnode (n)) |
| { |
| ar = getdata (n); |
| if (ar == area) |
| continue; |
| |
| /* We do not check nexthops here, because |
| intra-area routes can be associated with |
| one area only */ |
| |
| /* backbone routes are not summarized |
| when announced into transit areas */ |
| |
| if (ospf_area_is_transit (ar) && |
| OSPF_IS_AREA_BACKBONE (area)) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_aggregates(): Skipping " |
| "announcement of BB aggregate into" |
| " a transit area"); |
| continue; |
| } |
| ospf_abr_announce_network_to_area (&p, range->cost, ar); |
| } |
| } |
| } |
| } |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_aggregates(): Stop"); |
| } |
| |
| #ifdef HAVE_NSSA |
| void |
| ospf_abr_send_nssa_aggregates () /* temporarily turned off */ |
| { |
| listnode node; /*, n; */ |
| struct ospf_area *area; /*, *ar; */ |
| struct route_node *rn; |
| struct ospf_area_range *range; |
| struct prefix_ipv4 p; |
| |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_send_nssa_aggregates(): Start"); |
| |
| for (node = listhead (ospf_top->areas); node; nextnode (node)) |
| { |
| area = getdata (node); |
| |
| if (! area->NSSATranslator) |
| continue; |
| |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_send_nssa_aggregates(): looking at area %s", |
| inet_ntoa (area->area_id)); |
| |
| for (rn = route_top (area->ranges); rn; rn = route_next (rn)) |
| { |
| if (rn->info == NULL) |
| continue; |
| |
| range = rn->info; |
| |
| if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) |
| { |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_send_nssa_aggregates():" |
| " discarding suppress-ranges"); |
| continue; |
| } |
| |
| p.family = AF_INET; |
| p.prefix = range->addr; |
| p.prefixlen = range->masklen; |
| |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_send_nssa_aggregates():" |
| " this is range: %s/%d", |
| inet_ntoa (p.prefix), p.prefixlen); |
| |
| if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) |
| { |
| p.family = AF_INET; |
| p.prefix = range->subst_addr; |
| p.prefixlen = range->subst_masklen; |
| } |
| |
| if (range->specifics) |
| { |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_send_nssa_aggregates(): active range"); |
| |
| /* Fetch LSA-Type-7 from aggregate prefix, and then |
| translate, Install (as Type-5), Approve, and Flood */ |
| ospf_abr_translate_nssa_range (&p, range->cost); |
| } /* if (range->specifics)*/ |
| } /* all area ranges*/ |
| } /* all areas */ |
| |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_send_nssa_aggregates(): Stop"); |
| } |
| |
| void |
| ospf_abr_announce_nssa_defaults () /* By ABR-Translator */ |
| { |
| listnode node; |
| struct ospf_area *area; |
| struct prefix_ipv4 p; |
| |
| if (! OSPF_IS_ABR) |
| return; |
| |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_announce_stub_defaults(): Start"); |
| |
| p.family = AF_INET; |
| p.prefix.s_addr = OSPF_DEFAULT_DESTINATION; |
| p.prefixlen = 0; |
| |
| for (node = listhead (ospf_top->areas); node; nextnode (node)) |
| { |
| area = getdata (node); |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_announce_nssa_defaults(): looking at area %s", |
| inet_ntoa (area->area_id)); |
| |
| if (area->external_routing != OSPF_AREA_NSSA) |
| continue; |
| |
| if (OSPF_IS_AREA_BACKBONE (area)) |
| continue; /* Sanity Check */ |
| |
| /* if (!TranslatorRole continue V 1.0 look for "always" conf */ |
| if (area->NSSATranslator) |
| { |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_announce_nssa_defaults(): " |
| "announcing 0.0.0.0/0 to this nssa"); |
| /* ospf_abr_announce_nssa_asbr_to_as (&p, area->default_cost, area); */ |
| } |
| } |
| } |
| #endif /* HAVE_NSSA */ |
| |
| void |
| ospf_abr_announce_stub_defaults () |
| { |
| listnode node; |
| struct ospf_area *area; |
| struct prefix_ipv4 p; |
| |
| if (! OSPF_IS_ABR) |
| return; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_stub_defaults(): Start"); |
| |
| p.family = AF_INET; |
| p.prefix.s_addr = OSPF_DEFAULT_DESTINATION; |
| p.prefixlen = 0; |
| |
| for (node = listhead (ospf_top->areas); node; nextnode (node)) |
| { |
| area = getdata (node); |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_stub_defaults(): looking at area %s", |
| inet_ntoa (area->area_id)); |
| |
| #ifdef HAVE_NSSA |
| if (area->external_routing != OSPF_AREA_STUB) |
| #else /* ! HAVE_NSSA */ |
| if (area->external_routing == OSPF_AREA_DEFAULT) |
| #endif /* HAVE_NSSA */ |
| continue; |
| |
| if (OSPF_IS_AREA_BACKBONE (area)) |
| continue; /* Sanity Check */ |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_stub_defaults(): " |
| "announcing 0.0.0.0/0 to this area"); |
| ospf_abr_announce_network_to_area (&p, area->default_cost, area); |
| } |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_announce_stub_defaults(): Stop"); |
| } |
| |
| #ifdef HAVE_NSSA |
| int |
| ospf_abr_remove_unapproved_translates_apply (struct ospf_lsa *lsa, void *p_arg, |
| int int_arg) |
| { |
| if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT) |
| && ! CHECK_FLAG (lsa->flags, OSPF_LSA_APPROVED)) |
| { |
| zlog_info ("ospf_abr_remove_unapproved_translates(): " |
| "removing unapproved translates, ID: %s", |
| inet_ntoa (lsa->data->id)); |
| |
| /* FLUSH THROUGHOUT AS */ |
| ospf_lsa_flush_as (lsa); |
| |
| /* DISCARD from LSDB */ |
| } |
| return 0; |
| } |
| |
| void |
| ospf_abr_remove_unapproved_translates () /* For NSSA Translations */ |
| { |
| /* All AREA PROCESS should have APPROVED necessary LSAs */ |
| /* Remove any left over and not APPROVED */ |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_remove_unapproved_translates(): Start"); |
| |
| foreach_lsa (EXTERNAL_LSDB (ospf_top), NULL, 0, |
| ospf_abr_remove_unapproved_translates_apply); |
| |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_remove_unapproved_translates(): Stop"); |
| } |
| #endif /* HAVE_NSSA */ |
| |
| int |
| ospf_abr_remove_unapproved_summaries_apply (struct ospf_lsa *lsa, void *p_arg, |
| int int_arg) |
| { |
| struct ospf_area *area; |
| |
| area = (struct ospf_area *) p_arg; |
| |
| if (ospf_lsa_is_self_originated (lsa) && |
| !CHECK_FLAG (lsa->flags, OSPF_LSA_APPROVED)) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_remove_unapproved_summaries(): " |
| "removing unapproved summary, ID: %s", |
| inet_ntoa (lsa->data->id)); |
| ospf_lsa_flush_area (lsa, area); |
| } |
| return 0; |
| } |
| |
| void |
| ospf_abr_remove_unapproved_summaries () |
| { |
| listnode node; |
| struct ospf_area *area; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_remove_unapproved_summaries(): Start"); |
| |
| for (node = listhead (ospf_top->areas); node; nextnode (node)) |
| { |
| area = getdata (node); |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_remove_unapproved_summaries(): " |
| "looking at area %s", inet_ntoa (area->area_id)); |
| |
| foreach_lsa (SUMMARY_LSDB (area), area, 0, |
| ospf_abr_remove_unapproved_summaries_apply); |
| foreach_lsa (ASBR_SUMMARY_LSDB (area), area, 0, |
| ospf_abr_remove_unapproved_summaries_apply); |
| } |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_remove_unapproved_summaries(): Stop"); |
| } |
| |
| void |
| ospf_abr_manage_discard_routes () |
| { |
| listnode node; |
| struct route_node *rn; |
| struct ospf_area *area; |
| struct ospf_area_range *range; |
| |
| for (node = listhead (ospf_top->areas); node; nextnode (node)) |
| if ((area = node->data) != NULL) |
| for (rn = route_top (area->ranges); rn; rn = route_next (rn)) |
| if ((range = rn->info) != NULL) |
| if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) |
| { |
| if (range->specifics) |
| ospf_add_discard_route (ospf_top->new_table, area, |
| (struct prefix_ipv4 *) &rn->p); |
| else |
| ospf_delete_discard_route ((struct prefix_ipv4 *) &rn->p); |
| } |
| } |
| |
| #ifdef HAVE_NSSA |
| /* This is the function taking care about ABR NSSA, i.e. NSSA |
| Translator, -LSA aggregation and flooding. For all NSSAs |
| |
| Any SELF-AS-LSA is in the Type-5 LSDB and Type-7 LSDB. These LSA's |
| are refreshed from the Type-5 LSDB, installed into the Type-7 LSDB |
| with the P-bit set. |
| |
| Any received Type-5s are legal for an ABR, else illegal for IR. |
| Received Type-7s are installed, by area, with incoming P-bit. They |
| are flooded; if the Elected NSSA Translator, then P-bit off. |
| |
| Additionally, this ABR will place "translated type-7's" into the |
| Type-5 LSDB in order to keep track of APPROVAL or not. |
| |
| It will scan through every area, looking for Type-7 LSAs with P-Bit |
| SET. The Type-7's are either AS-FLOODED & 5-INSTALLED or |
| AGGREGATED. Later, the AGGREGATED LSAs are AS-FLOODED & |
| 5-INSTALLED. |
| |
| 5-INSTALLED is into the Type-5 LSDB; Any UNAPPROVED Type-5 LSAs |
| left over are FLUSHED and DISCARDED. |
| |
| For External Calculations, any NSSA areas use the Type-7 AREA-LSDB, |
| any ABR-non-NSSA areas use the Type-5 GLOBAL-LSDB. */ |
| |
| void |
| ospf_abr_nssa_task () /* called only if any_nssa */ |
| { |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("Check for NSSA-ABR Tasks():"); |
| |
| if (! OSPF_IS_ABR) |
| return; |
| |
| if (! ospf_top->anyNSSA) |
| return; |
| |
| /* Each area must confirm TranslatorRole */ |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_nssa_task(): Start"); |
| |
| /* For all Global Entries flagged "local-translate", unset APPROVED */ |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_nssa_task(): unapprove translates"); |
| |
| ospf_abr_unapprove_translates (); |
| |
| /* RESET all Ranges in every Area, same as summaries */ |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_nssa_task(): NSSA initialize aggregates"); |
| |
| /* ospf_abr_prepare_aggregates (); TURNED OFF just for now */ |
| |
| /* For all NSSAs, Type-7s, translate to 5's, INSTALL/FLOOD, or |
| Aggregate as Type-7 */ |
| /* Install or Approve in Type-5 Global LSDB */ |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_nssa_task(): process translates"); |
| |
| ospf_abr_process_nssa_translates (ospf_top->new_table); |
| |
| /* Translate/Send any "ranged" aggregates, and also 5-Install and |
| Approve */ |
| /* Scan Type-7's for aggregates, translate to Type-5's, |
| Install/Flood/Approve */ |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info("ospf_abr_nssa_task(): send NSSA aggregates"); |
| /* ospf_abr_send_nssa_aggregates (); TURNED OFF FOR NOW */ |
| |
| /* Send any NSSA defaults as Type-5 */ |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_nssa_task(): announce nssa defaults"); |
| ospf_abr_announce_nssa_defaults (); |
| |
| /* Flush any unapproved previous translates from Global Data Base */ |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_nssa_task(): remove unapproved translates"); |
| ospf_abr_remove_unapproved_translates (); |
| |
| ospf_abr_manage_discard_routes (); /* same as normal...discard */ |
| |
| if (IS_DEBUG_OSPF_NSSA) |
| zlog_info ("ospf_abr_nssa_task(): Stop"); |
| } |
| #endif /* HAVE_NSSA */ |
| |
| /* This is the function taking care about ABR stuff, i.e. |
| summary-LSA origination and flooding. */ |
| void |
| ospf_abr_task () |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_task(): Start"); |
| |
| if (ospf_top->new_table == NULL || ospf_top->new_rtrs == NULL) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_task(): Routing tables are not yet ready"); |
| return; |
| } |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_task(): unapprove summaries"); |
| ospf_abr_unapprove_summaries (); |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_task(): prepare aggregates"); |
| ospf_abr_prepare_aggregates (); |
| |
| if (OSPF_IS_ABR) |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_task(): process network RT"); |
| ospf_abr_process_network_rt (ospf_top->new_table); |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_task(): process router RT"); |
| ospf_abr_process_router_rt (ospf_top->new_rtrs); |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_task(): announce aggregates"); |
| ospf_abr_announce_aggregates (); |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_task(): announce stub defaults"); |
| ospf_abr_announce_stub_defaults (); |
| } |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_task(): remove unapproved summaries"); |
| ospf_abr_remove_unapproved_summaries (); |
| |
| ospf_abr_manage_discard_routes (); |
| |
| #ifdef HAVE_NSSA |
| ospf_abr_nssa_task(); /* if nssa-abr, then scan Type-7 LSDB */ |
| #endif /* HAVE_NSSA */ |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("ospf_abr_task(): Stop"); |
| } |
| |
| |
| int |
| ospf_abr_task_timer (struct thread *t) |
| { |
| ospf_top->t_abr_task = 0; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("Running ABR task on timer"); |
| |
| ospf_check_abr_status (); |
| |
| ospf_abr_task (); |
| |
| return 0; |
| } |
| |
| void |
| ospf_schedule_abr_task () |
| { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_info ("Scheduling ABR task"); |
| if (! ospf_top->t_abr_task) |
| ospf_top->t_abr_task = thread_add_timer (master, ospf_abr_task_timer, |
| 0, OSPF_ABR_TASK_DELAY); |
| } |