/* * 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 #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; 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_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; } }