/* * 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 this program; see the file COPYING; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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( ospf, (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); } /* Add an External info for AS-external-LSA. */ struct external_info *ospf_external_info_new(uint8_t type, unsigned short instance) { struct external_info *new; new = XCALLOC(MTYPE_OSPF_EXTERNAL_INFO, sizeof(struct external_info)); new->type = type; new->instance = instance; 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(struct ospf *ospf, uint8_t type, unsigned short instance, struct prefix_ipv4 p, ifindex_t ifindex, struct in_addr nexthop, route_tag_t tag) { struct external_info *new; struct route_node *rn; struct ospf_external *ext; char inetbuf[INET6_BUFSIZ]; ext = ospf_external_lookup(ospf, type, instance); if (!ext) ext = ospf_external_add(ospf, type, instance); rn = route_node_get(EXTERNAL_INFO(ext), (struct prefix *)&p); /* If old info exists, -- discard new one or overwrite with new one? */ if (rn) if (rn->info) { new = rn->info; if ((new->ifindex == ifindex) && (new->nexthop.s_addr == nexthop.s_addr) && (new->tag == tag)) { route_unlock_node(rn); return NULL; /* NULL => no LSA to refresh */ } inet_ntop(AF_INET, (void *)&nexthop.s_addr, inetbuf, INET6_BUFSIZ); if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) zlog_debug( "Redistribute[%s][%d][%u]: %s/%d discarding old info with NH %s.", ospf_redist_string(type), instance, ospf->vrf_id, inet_ntoa(p.prefix), p.prefixlen, inetbuf); XFREE(MTYPE_OSPF_EXTERNAL_INFO, rn->info); } /* Create new External info instance. */ new = ospf_external_info_new(type, instance); new->p = p; new->ifindex = ifindex; new->nexthop = nexthop; new->tag = tag; new->orig_tag = tag; /* we don't unlock rn from the get() because we're attaching the info */ if (rn) rn->info = new; if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { inet_ntop(AF_INET, (void *)&nexthop.s_addr, inetbuf, INET6_BUFSIZ); zlog_debug( "Redistribute[%s][%u]: %s/%d external info created, with NH %s", ospf_redist_string(type), ospf->vrf_id, inet_ntoa(p.prefix), p.prefixlen, inetbuf); } return new; } void ospf_external_info_delete(struct ospf *ospf, uint8_t type, unsigned short instance, struct prefix_ipv4 p) { struct route_node *rn; struct ospf_external *ext; ext = ospf_external_lookup(ospf, type, instance); if (!ext) return; rn = route_node_lookup(EXTERNAL_INFO(ext), (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(struct ospf *ospf, uint8_t type, unsigned short instance, struct prefix_ipv4 *p) { struct route_node *rn; struct ospf_external *ext; ext = ospf_external_lookup(ospf, type, instance); if (!ext) return NULL; rn = route_node_lookup(EXTERNAL_INFO(ext), (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; /* Fisrt search the lsdb with address specifc LSID * where all the host bits are set, if there a matched * LSA, return. * Ex: For route 10.0.0.0/16, LSID is 10.0.255.255 * If no lsa with above LSID, use received address as * LSID and check if any LSA in LSDB. * If LSA found, check if the mask is same b/w the matched * LSA and received prefix, if same then it is the LSA for * this prefix. * Ex: For route 10.0.0.0/16, LSID is 10.0.0.0 */ masklen2ip(p->prefixlen, &mask); 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 lsa; lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, OSPF_AS_EXTERNAL_LSA, p->prefix, ospf->router_id); if (lsa) { al = (struct as_external_lsa *)lsa->data; if (mask.s_addr == al->mask.s_addr) return lsa; } return NULL; } /* Update ASBR status. */ void ospf_asbr_status_update(struct ospf *ospf, uint8_t status) { zlog_info("ASBR[%s:Status:%d]: Update", ospf_get_name(ospf), status); /* ASBR on. */ if (status) { /* Already ASBR. */ if (IS_OSPF_ASBR(ospf)) { zlog_info("ASBR[%s:Status:%d]: Already ASBR", ospf_get_name(ospf), status); return; } SET_FLAG(ospf->flags, OSPF_FLAG_ASBR); } else { /* Already non ASBR. */ if (!IS_OSPF_ASBR(ospf)) { zlog_info("ASBR[%s:Status:%d]: Already non ASBR", ospf_get_name(ospf), status); return; } UNSET_FLAG(ospf->flags, OSPF_FLAG_ASBR); } /* Transition from/to status ASBR, schedule timer. */ ospf_spf_calculate_schedule(ospf, SPF_FLAG_ASBR_STATUS_CHANGE); ospf_router_lsa_update(ospf); } /* If there's redistribution configured, we need to refresh external * LSAs in order to install Type-7 and flood to all NSSA Areas */ void ospf_asbr_nssa_redist_task(struct ospf *ospf) { int type; for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { struct list *red_list; struct listnode *node; struct ospf_redist *red; red_list = ospf->redist[type]; if (!red_list) continue; for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) ospf_external_lsa_refresh_type( ospf, type, red->instance, LSA_REFRESH_FORCE); } ospf_external_lsa_refresh_default(ospf); } void ospf_redistribute_withdraw(struct ospf *ospf, uint8_t type, unsigned short instance) { struct route_node *rn; struct external_info *ei; struct ospf_external *ext; ext = ospf_external_lookup(ospf, type, instance); if (!ext) return; /* Delete external info for specified type. */ if (EXTERNAL_INFO(ext)) for (rn = route_top(EXTERNAL_INFO(ext)); 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; } }