| /* |
| * OSPF AS Boundary Router functions. |
| * Copyright (C) 1999, 2000 Kunihiro Ishiguro, 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 "log.h" |
| |
| #include "ospfd/ospfd.h" |
| #include "ospfd/ospf_interface.h" |
| #include "ospfd/ospf_asbr.h" |
| #include "ospfd/ospf_lsa.h" |
| #include "ospfd/ospf_lsdb.h" |
| #include "ospfd/ospf_neighbor.h" |
| #include "ospfd/ospf_spf.h" |
| #include "ospfd/ospf_flood.h" |
| #include "ospfd/ospf_route.h" |
| #include "ospfd/ospf_zebra.h" |
| #include "ospfd/ospf_dump.h" |
| |
| |
| /* Remove external route. */ |
| void |
| ospf_external_route_remove (struct ospf *ospf, struct prefix_ipv4 *p) |
| { |
| struct route_node *rn; |
| struct ospf_route *or; |
| |
| rn = route_node_lookup (ospf->old_external_route, (struct prefix *) p); |
| if (rn) |
| if ((or = rn->info)) |
| { |
| zlog_info ("Route[%s/%d]: external path deleted", |
| inet_ntoa (p->prefix), p->prefixlen); |
| |
| /* Remove route from zebra. */ |
| if (or->type == OSPF_DESTINATION_NETWORK) |
| ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); |
| |
| ospf_route_free (or); |
| rn->info = NULL; |
| |
| route_unlock_node (rn); |
| route_unlock_node (rn); |
| return; |
| } |
| |
| zlog_info ("Route[%s/%d]: no such external path", |
| inet_ntoa (p->prefix), p->prefixlen); |
| } |
| |
| /* Lookup external route. */ |
| struct ospf_route * |
| ospf_external_route_lookup (struct ospf *ospf, |
| struct prefix_ipv4 *p) |
| { |
| struct route_node *rn; |
| |
| rn = route_node_lookup (ospf->old_external_route, (struct prefix *) p); |
| if (rn) |
| { |
| route_unlock_node (rn); |
| if (rn->info) |
| return rn->info; |
| } |
| |
| zlog_warn ("Route[%s/%d]: lookup, no such prefix", |
| inet_ntoa (p->prefix), p->prefixlen); |
| |
| return NULL; |
| } |
| |
| |
| /* Add an External info for AS-external-LSA. */ |
| struct external_info * |
| ospf_external_info_new (u_char type) |
| { |
| struct external_info *new; |
| |
| new = (struct external_info *) |
| XCALLOC (MTYPE_OSPF_EXTERNAL_INFO, sizeof (struct external_info)); |
| new->type = type; |
| |
| ospf_reset_route_map_set_values (&new->route_map_set); |
| return new; |
| } |
| |
| static void |
| ospf_external_info_free (struct external_info *ei) |
| { |
| XFREE (MTYPE_OSPF_EXTERNAL_INFO, ei); |
| } |
| |
| void |
| ospf_reset_route_map_set_values (struct route_map_set_values *values) |
| { |
| values->metric = -1; |
| values->metric_type = -1; |
| } |
| |
| int |
| ospf_route_map_set_compare (struct route_map_set_values *values1, |
| struct route_map_set_values *values2) |
| { |
| return values1->metric == values2->metric && |
| values1->metric_type == values2->metric_type; |
| } |
| |
| /* Add an External info for AS-external-LSA. */ |
| struct external_info * |
| ospf_external_info_add (u_char type, struct prefix_ipv4 p, |
| unsigned int ifindex, struct in_addr nexthop) |
| { |
| struct external_info *new; |
| struct route_node *rn; |
| |
| /* Initialize route table. */ |
| if (EXTERNAL_INFO (type) == NULL) |
| EXTERNAL_INFO (type) = route_table_init (); |
| |
| rn = route_node_get (EXTERNAL_INFO (type), (struct prefix *) &p); |
| /* If old info exists, -- discard new one or overwrite with new one? */ |
| if (rn) |
| if (rn->info) |
| { |
| route_unlock_node (rn); |
| zlog_warn ("Redistribute[%s]: %s/%d already exists, discard.", |
| ospf_redist_string(type), |
| inet_ntoa (p.prefix), p.prefixlen); |
| /* XFREE (MTYPE_OSPF_TMP, rn->info); */ |
| return rn->info; |
| } |
| |
| /* Create new External info instance. */ |
| new = ospf_external_info_new (type); |
| new->p = p; |
| new->ifindex = ifindex; |
| new->nexthop = nexthop; |
| new->tag = 0; |
| |
| if (rn) |
| rn->info = new; |
| |
| if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) |
| zlog_debug ("Redistribute[%s]: %s/%d external info created.", |
| ospf_redist_string(type), |
| inet_ntoa (p.prefix), p.prefixlen); |
| return new; |
| } |
| |
| void |
| ospf_external_info_delete (u_char type, struct prefix_ipv4 p) |
| { |
| struct route_node *rn; |
| |
| rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) &p); |
| if (rn) |
| { |
| ospf_external_info_free (rn->info); |
| rn->info = NULL; |
| route_unlock_node (rn); |
| route_unlock_node (rn); |
| } |
| } |
| |
| struct external_info * |
| ospf_external_info_lookup (u_char type, struct prefix_ipv4 *p) |
| { |
| struct route_node *rn; |
| rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) p); |
| if (rn) |
| { |
| route_unlock_node (rn); |
| if (rn->info) |
| return rn->info; |
| } |
| |
| return NULL; |
| } |
| |
| struct ospf_lsa * |
| ospf_external_info_find_lsa (struct ospf *ospf, |
| struct prefix_ipv4 *p) |
| { |
| struct ospf_lsa *lsa; |
| struct as_external_lsa *al; |
| struct in_addr mask, id; |
| |
| lsa = ospf_lsdb_lookup_by_id (ospf->lsdb, OSPF_AS_EXTERNAL_LSA, |
| p->prefix, ospf->router_id); |
| |
| if (!lsa) |
| return NULL; |
| |
| al = (struct as_external_lsa *) lsa->data; |
| |
| masklen2ip (p->prefixlen, &mask); |
| |
| if (mask.s_addr != al->mask.s_addr) |
| { |
| id.s_addr = p->prefix.s_addr | (~mask.s_addr); |
| lsa = ospf_lsdb_lookup_by_id (ospf->lsdb, OSPF_AS_EXTERNAL_LSA, |
| id, ospf->router_id); |
| if (!lsa) |
| return NULL; |
| } |
| |
| return lsa; |
| } |
| |
| |
| /* Update ASBR status. */ |
| void |
| ospf_asbr_status_update (struct ospf *ospf, u_char status) |
| { |
| zlog_info ("ASBR[Status:%d]: Update", status); |
| |
| /* ASBR on. */ |
| if (status) |
| { |
| /* Already ASBR. */ |
| if (IS_OSPF_ASBR (ospf)) |
| { |
| zlog_info ("ASBR[Status:%d]: Already ASBR", status); |
| return; |
| } |
| SET_FLAG (ospf->flags, OSPF_FLAG_ASBR); |
| } |
| else |
| { |
| /* Already non ASBR. */ |
| if (! IS_OSPF_ASBR (ospf)) |
| { |
| zlog_info ("ASBR[Status:%d]: Already non ASBR", status); |
| return; |
| } |
| UNSET_FLAG (ospf->flags, OSPF_FLAG_ASBR); |
| } |
| |
| /* Transition from/to status ASBR, schedule timer. */ |
| ospf_flag_spf_reason (SPF_FLAG_ASBR_STATUS_CHANGE); |
| ospf_spf_calculate_schedule (ospf); |
| ospf_router_lsa_update (ospf); |
| } |
| |
| void |
| ospf_redistribute_withdraw (struct ospf *ospf, u_char type) |
| { |
| struct route_node *rn; |
| struct external_info *ei; |
| |
| /* Delete external info for specified type. */ |
| if (EXTERNAL_INFO (type)) |
| for (rn = route_top (EXTERNAL_INFO (type)); rn; rn = route_next (rn)) |
| if ((ei = rn->info)) |
| if (ospf_external_info_find_lsa (ospf, &ei->p)) |
| { |
| if (is_prefix_default (&ei->p) && |
| ospf->default_originate != DEFAULT_ORIGINATE_NONE) |
| continue; |
| ospf_external_lsa_flush (ospf, type, &ei->p, |
| ei->ifindex /*, ei->nexthop */); |
| |
| ospf_external_info_free (ei); |
| route_unlock_node (rn); |
| rn->info = NULL; |
| } |
| } |