| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include <zebra.h> |
| |
| #include "thread.h" |
| #include "command.h" |
| #include "network.h" |
| #include "prefix.h" |
| #include "routemap.h" |
| #include "table.h" |
| #include "stream.h" |
| #include "memory.h" |
| #include "zclient.h" |
| #include "filter.h" |
| #include "plist.h" |
| #include "log.h" |
| #include "lib/bfd.h" |
| #include "nexthop.h" |
| |
| #include "ospfd/ospfd.h" |
| #include "ospfd/ospf_interface.h" |
| #include "ospfd/ospf_ism.h" |
| #include "ospfd/ospf_asbr.h" |
| #include "ospfd/ospf_asbr.h" |
| #include "ospfd/ospf_abr.h" |
| #include "ospfd/ospf_lsa.h" |
| #include "ospfd/ospf_dump.h" |
| #include "ospfd/ospf_route.h" |
| #include "ospfd/ospf_lsdb.h" |
| #include "ospfd/ospf_neighbor.h" |
| #include "ospfd/ospf_nsm.h" |
| #include "ospfd/ospf_zebra.h" |
| #include "ospfd/ospf_te.h" |
| #include "ospfd/ospf_sr.h" |
| |
| DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table") |
| DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute") |
| DEFINE_MTYPE_STATIC(OSPFD, OSPF_DIST_ARGS, "OSPF Distribute arguments") |
| |
| |
| |
| struct zclient *zclient = NULL; |
| |
| static struct zclient *zclient_sync; |
| |
| |
| extern struct thread_master *master; |
| |
| |
| static int ospf_router_id_update_zebra(ZAPI_CALLBACK_ARGS) |
| { |
| struct ospf *ospf = NULL; |
| struct prefix router_id; |
| zebra_router_id_update_read(zclient->ibuf, &router_id); |
| |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) { |
| char buf[PREFIX2STR_BUFFER]; |
| prefix2str(&router_id, buf, sizeof(buf)); |
| zlog_debug("Zebra rcvd: router id update %s vrf %s id %u", buf, |
| ospf_vrf_id_to_name(vrf_id), vrf_id); |
| } |
| |
| ospf = ospf_lookup_by_vrf_id(vrf_id); |
| |
| if (ospf != NULL) { |
| ospf->router_id_zebra = router_id.u.prefix4; |
| ospf_router_id_update(ospf); |
| } else { |
| if (IS_DEBUG_OSPF_EVENT) { |
| char buf[PREFIX2STR_BUFFER]; |
| |
| prefix2str(&router_id, buf, sizeof(buf)); |
| zlog_debug( |
| "%s: ospf instance not found for vrf %s id %u router_id %s", |
| __func__, ospf_vrf_id_to_name(vrf_id), vrf_id, |
| buf); |
| } |
| } |
| return 0; |
| } |
| |
| static int ospf_interface_address_add(ZAPI_CALLBACK_ARGS) |
| { |
| struct connected *c; |
| struct ospf *ospf = NULL; |
| |
| |
| c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id); |
| |
| if (c == NULL) |
| return 0; |
| |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) { |
| char buf[PREFIX2STR_BUFFER]; |
| prefix2str(c->address, buf, sizeof(buf)); |
| zlog_debug("Zebra: interface %s address add %s vrf %s id %u", |
| c->ifp->name, buf, ospf_vrf_id_to_name(vrf_id), |
| vrf_id); |
| } |
| |
| ospf = ospf_lookup_by_vrf_id(vrf_id); |
| if (!ospf) |
| return 0; |
| |
| ospf_if_update(ospf, c->ifp); |
| |
| ospf_if_interface(c->ifp); |
| |
| return 0; |
| } |
| |
| static int ospf_interface_address_delete(ZAPI_CALLBACK_ARGS) |
| { |
| struct connected *c; |
| struct interface *ifp; |
| struct ospf_interface *oi; |
| struct route_node *rn; |
| struct prefix p; |
| |
| c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id); |
| |
| if (c == NULL) |
| return 0; |
| |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) { |
| char buf[PREFIX2STR_BUFFER]; |
| prefix2str(c->address, buf, sizeof(buf)); |
| zlog_debug("Zebra: interface %s address delete %s", |
| c->ifp->name, buf); |
| } |
| |
| ifp = c->ifp; |
| p = *c->address; |
| p.prefixlen = IPV4_MAX_PREFIXLEN; |
| |
| rn = route_node_lookup(IF_OIFS(ifp), &p); |
| if (!rn) { |
| connected_free(&c); |
| return 0; |
| } |
| |
| assert(rn->info); |
| oi = rn->info; |
| route_unlock_node(rn); |
| |
| |
| ospf_if_free(oi); |
| |
| ospf_if_interface(c->ifp); |
| |
| connected_free(&c); |
| |
| return 0; |
| } |
| |
| static int ospf_interface_link_params(ZAPI_CALLBACK_ARGS) |
| { |
| struct interface *ifp; |
| |
| ifp = zebra_interface_link_params_read(zclient->ibuf, vrf_id); |
| |
| if (ifp == NULL) |
| return 0; |
| |
| |
| ospf_mpls_te_update_if(ifp); |
| |
| return 0; |
| } |
| |
| |
| static int ospf_interface_vrf_update(ZAPI_CALLBACK_ARGS) |
| { |
| struct interface *ifp = NULL; |
| vrf_id_t new_vrf_id; |
| |
| ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, |
| &new_vrf_id); |
| if (!ifp) |
| return 0; |
| |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_debug( |
| "%s: Rx Interface %s VRF change vrf_id %u New vrf %s id %u", |
| __func__, ifp->name, vrf_id, |
| ospf_vrf_id_to_name(new_vrf_id), new_vrf_id); |
| |
| |
| if_update_to_new_vrf(ifp, new_vrf_id); |
| |
| return 0; |
| } |
| |
| void ospf_zebra_add(struct ospf *ospf, struct prefix_ipv4 *p, |
| struct ospf_route * or) |
| { |
| struct zapi_route api; |
| struct zapi_nexthop *api_nh; |
| uint8_t distance; |
| struct ospf_path *path; |
| struct listnode *node; |
| int count = 0; |
| |
| memset(&api, 0, sizeof(api)); |
| api.vrf_id = ospf->vrf_id; |
| api.type = ZEBRA_ROUTE_OSPF; |
| api.instance = ospf->instance; |
| api.safi = SAFI_UNICAST; |
| |
| memcpy(&api.prefix, p, sizeof(*p)); |
| SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); |
| |
| |
| SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); |
| if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL) |
| api.metric = or->cost + or->u.ext.type2_cost; |
| else if (or->path_type == OSPF_PATH_TYPE2_EXTERNAL) |
| api.metric = or->u.ext.type2_cost; |
| else |
| api.metric = or->cost; |
| |
| |
| if (((or->path_type == OSPF_PATH_TYPE1_EXTERNAL) |
| || (or->path_type == OSPF_PATH_TYPE2_EXTERNAL)) |
| && (or->u.ext.tag > 0) && (or->u.ext.tag <= ROUTE_TAG_MAX)) { |
| SET_FLAG(api.message, ZAPI_MESSAGE_TAG); |
| api.tag = or->u.ext.tag; |
| } |
| |
| |
| distance = ospf_distance_apply(ospf, p, or); |
| if (distance) { |
| SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); |
| api.distance = distance; |
| } |
| |
| |
| for (ALL_LIST_ELEMENTS_RO(or->paths, node, path)) { |
| if (count >= MULTIPATH_NUM) |
| break; |
| api_nh = &api.nexthops[count]; |
| #ifdef HAVE_NETLINK |
| if (path->unnumbered || (path->nexthop.s_addr != INADDR_ANY |
| && path->ifindex != 0)) { |
| #else |
| if (path->nexthop.s_addr != INADDR_ANY && path->ifindex != 0) { |
| #endif |
| api_nh->gate.ipv4 = path->nexthop; |
| api_nh->ifindex = path->ifindex; |
| api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; |
| } else if (path->nexthop.s_addr != INADDR_ANY) { |
| api_nh->gate.ipv4 = path->nexthop; |
| api_nh->type = NEXTHOP_TYPE_IPV4; |
| } else { |
| api_nh->ifindex = path->ifindex; |
| api_nh->type = NEXTHOP_TYPE_IFINDEX; |
| } |
| api_nh->vrf_id = ospf->vrf_id; |
| count++; |
| |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) { |
| char buf[2][PREFIX2STR_BUFFER]; |
| struct interface *ifp; |
| |
| ifp = if_lookup_by_index(path->ifindex, ospf->vrf_id); |
| |
| zlog_debug( |
| "Zebra: Route add %s nexthop %s, ifindex=%d %s", |
| prefix2str(p, buf[0], sizeof(buf[0])), |
| inet_ntop(AF_INET, &path->nexthop, |
| buf[1], sizeof(buf[1])), |
| path->ifindex, ifp ? ifp->name : " "); |
| } |
| } |
| api.nexthop_num = count; |
| |
| zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); |
| } |
| |
| void ospf_zebra_delete(struct ospf *ospf, struct prefix_ipv4 *p, |
| struct ospf_route * or) |
| { |
| struct zapi_route api; |
| |
| memset(&api, 0, sizeof(api)); |
| api.vrf_id = ospf->vrf_id; |
| api.type = ZEBRA_ROUTE_OSPF; |
| api.instance = ospf->instance; |
| api.safi = SAFI_UNICAST; |
| memcpy(&api.prefix, p, sizeof(*p)); |
| |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) { |
| char buf[PREFIX2STR_BUFFER]; |
| zlog_debug("Zebra: Route delete %s", |
| prefix2str(p, buf, sizeof(buf))); |
| } |
| |
| zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); |
| } |
| |
| void ospf_zebra_add_discard(struct ospf *ospf, struct prefix_ipv4 *p) |
| { |
| struct zapi_route api; |
| |
| memset(&api, 0, sizeof(api)); |
| api.vrf_id = ospf->vrf_id; |
| api.type = ZEBRA_ROUTE_OSPF; |
| api.instance = ospf->instance; |
| api.safi = SAFI_UNICAST; |
| memcpy(&api.prefix, p, sizeof(*p)); |
| zapi_route_set_blackhole(&api, BLACKHOLE_NULL); |
| |
| zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); |
| |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) { |
| char buf[PREFIX2STR_BUFFER]; |
| zlog_debug("Zebra: Route add discard %s", |
| prefix2str(p, buf, sizeof(buf))); |
| } |
| } |
| |
| void ospf_zebra_delete_discard(struct ospf *ospf, struct prefix_ipv4 *p) |
| { |
| struct zapi_route api; |
| |
| memset(&api, 0, sizeof(api)); |
| api.vrf_id = ospf->vrf_id; |
| api.type = ZEBRA_ROUTE_OSPF; |
| api.instance = ospf->instance; |
| api.safi = SAFI_UNICAST; |
| memcpy(&api.prefix, p, sizeof(*p)); |
| zapi_route_set_blackhole(&api, BLACKHOLE_NULL); |
| |
| zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); |
| |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) { |
| char buf[PREFIX2STR_BUFFER]; |
| zlog_debug("Zebra: Route delete discard %s", |
| prefix2str(p, buf, sizeof(buf))); |
| } |
| } |
| |
| struct ospf_external *ospf_external_lookup(struct ospf *ospf, uint8_t type, |
| unsigned short instance) |
| { |
| struct list *ext_list; |
| struct listnode *node; |
| struct ospf_external *ext; |
| |
| ext_list = ospf->external[type]; |
| if (!ext_list) |
| return (NULL); |
| |
| for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) |
| if (ext->instance == instance) |
| return ext; |
| |
| return NULL; |
| } |
| |
| struct ospf_external *ospf_external_add(struct ospf *ospf, uint8_t type, |
| unsigned short instance) |
| { |
| struct list *ext_list; |
| struct ospf_external *ext; |
| |
| ext = ospf_external_lookup(ospf, type, instance); |
| if (ext) |
| return ext; |
| |
| if (!ospf->external[type]) |
| ospf->external[type] = list_new(); |
| |
| ext_list = ospf->external[type]; |
| ext = XCALLOC(MTYPE_OSPF_EXTERNAL, sizeof(struct ospf_external)); |
| ext->instance = instance; |
| EXTERNAL_INFO(ext) = route_table_init(); |
| |
| listnode_add(ext_list, ext); |
| |
| return ext; |
| } |
| |
| |
| |
| |
| |
| bool ospf_external_default_routemap_apply_walk(struct ospf *ospf, |
| struct list *ext_list, |
| struct external_info *default_ei) |
| { |
| struct listnode *node; |
| struct ospf_external *ext; |
| struct route_node *rn; |
| struct external_info *ei = NULL; |
| int ret = 0; |
| |
| for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { |
| if (!ext->external_info) |
| continue; |
| |
| for (rn = route_top(ext->external_info); rn; |
| rn = route_next(rn)) { |
| ei = rn->info; |
| if (!ei) |
| continue; |
| ret = ospf_external_info_apply_default_routemap( |
| ospf, ei, default_ei); |
| if (ret) |
| break; |
| } |
| } |
| |
| if (ret && ei) { |
| if (IS_DEBUG_OSPF_DEFAULT_INFO) |
| zlog_debug("Default originate routemap permit ei: %s", |
| inet_ntoa(ei->p.prefix)); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| |
| |
| |
| |
| static int ospf_external_lsa_default_routemap_timer(struct thread *thread) |
| { |
| struct list *ext_list; |
| struct ospf *ospf = THREAD_ARG(thread); |
| struct prefix_ipv4 p; |
| int type; |
| int ret = 0; |
| struct ospf_lsa *lsa; |
| struct external_info *default_ei; |
| |
| p.family = AF_INET; |
| p.prefixlen = 0; |
| p.prefix.s_addr = INADDR_ANY; |
| |
| |
| default_ei = ospf_external_info_lookup(ospf, DEFAULT_ROUTE, |
| ospf->instance, &p); |
| if (!default_ei) { |
| |
| if (IS_DEBUG_OSPF_DEFAULT_INFO) |
| zlog_debug("Default originate info not present"); |
| return 0; |
| } |
| |
| |
| for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { |
| ext_list = ospf->external[type]; |
| if (!ext_list || type == ZEBRA_ROUTE_OSPF) |
| continue; |
| |
| ret = ospf_external_default_routemap_apply_walk(ospf, ext_list, |
| default_ei); |
| if (ret) |
| break; |
| } |
| |
| |
| lsa = ospf_external_info_find_lsa(ospf, &p); |
| |
| |
| if (ret && !lsa) |
| ospf_external_lsa_originate(ospf, default_ei); |
| else if (ret && lsa && IS_LSA_MAXAGE(lsa)) |
| ospf_external_lsa_refresh(ospf, lsa, default_ei, true); |
| else if (!ret && lsa) |
| ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &default_ei->p, 0); |
| |
| return 1; |
| } |
| |
| |
| void ospf_external_del(struct ospf *ospf, uint8_t type, unsigned short instance) |
| { |
| struct ospf_external *ext; |
| |
| ext = ospf_external_lookup(ospf, type, instance); |
| |
| if (ext) { |
| if (EXTERNAL_INFO(ext)) |
| route_table_finish(EXTERNAL_INFO(ext)); |
| |
| listnode_delete(ospf->external[type], ext); |
| |
| if (!ospf->external[type]->count) |
| list_delete(&ospf->external[type]); |
| |
| XFREE(MTYPE_OSPF_EXTERNAL, ext); |
| } |
| |
| |
| |
| |
| thread_add_event(master, ospf_external_lsa_default_routemap_timer, ospf, |
| 0, &ospf->t_default_routemap_timer); |
| } |
| |
| |
| void ospf_zebra_update_prefix_sid(const struct sr_prefix *srp) |
| { |
| struct zapi_labels zl; |
| struct zapi_nexthop *znh; |
| struct listnode *node; |
| struct ospf_path *path; |
| |
| osr_debug("SR (%s): Update Labels %u for Prefix %pFX", __func__, |
| srp->label_in, (struct prefix *)&srp->prefv4); |
| |
| |
| memset(&zl, 0, sizeof(zl)); |
| zl.type = ZEBRA_LSP_OSPF_SR; |
| zl.local_label = srp->label_in; |
| |
| switch (srp->type) { |
| case LOCAL_SID: |
| |
| znh = &zl.nexthops[zl.nexthop_num++]; |
| znh->type = NEXTHOP_TYPE_IFINDEX; |
| znh->ifindex = srp->nhlfe.ifindex; |
| znh->label_num = 1; |
| znh->labels[0] = srp->nhlfe.label_out; |
| break; |
| |
| case PREF_SID: |
| |
| SET_FLAG(zl.message, ZAPI_LABELS_FTN); |
| zl.route.prefix.u.prefix4 = srp->prefv4.prefix; |
| zl.route.prefix.prefixlen = srp->prefv4.prefixlen; |
| zl.route.prefix.family = srp->prefv4.family; |
| zl.route.type = ZEBRA_ROUTE_OSPF; |
| zl.route.instance = 0; |
| |
| |
| if (srp->route == NULL) { |
| return; |
| } |
| for (ALL_LIST_ELEMENTS_RO(srp->route->paths, node, path)) { |
| if (path->srni.label_out == MPLS_INVALID_LABEL) |
| continue; |
| |
| if (zl.nexthop_num >= MULTIPATH_NUM) |
| break; |
| |
| znh = &zl.nexthops[zl.nexthop_num++]; |
| znh->type = NEXTHOP_TYPE_IPV4_IFINDEX; |
| znh->gate.ipv4 = path->nexthop; |
| znh->ifindex = path->ifindex; |
| znh->label_num = 1; |
| znh->labels[0] = path->srni.label_out; |
| } |
| break; |
| default: |
| return; |
| } |
| |
| |
| (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_REPLACE, &zl); |
| } |
| |
| |
| void ospf_zebra_delete_prefix_sid(const struct sr_prefix *srp) |
| { |
| struct zapi_labels zl; |
| |
| osr_debug("SR (%s): Delete Labels %u for Prefix %pFX", __func__, |
| srp->label_in, (struct prefix *)&srp->prefv4); |
| |
| |
| memset(&zl, 0, sizeof(zl)); |
| zl.type = ZEBRA_LSP_OSPF_SR; |
| zl.local_label = srp->label_in; |
| |
| if (srp->type == PREF_SID) { |
| |
| SET_FLAG(zl.message, ZAPI_LABELS_FTN); |
| zl.route.prefix.u.prefix4 = srp->prefv4.prefix; |
| zl.route.prefix.prefixlen = srp->prefv4.prefixlen; |
| zl.route.prefix.family = srp->prefv4.family; |
| zl.route.type = ZEBRA_ROUTE_OSPF; |
| zl.route.instance = 0; |
| } |
| |
| |
| (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_DELETE, &zl); |
| } |
| |
| |
| void ospf_zebra_send_adjacency_sid(int cmd, struct sr_nhlfe nhlfe) |
| { |
| struct zapi_labels zl; |
| struct zapi_nexthop *znh; |
| |
| osr_debug("SR (%s): %s Labels %u/%u for Adjacency via %u", __func__, |
| cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete", |
| nhlfe.label_in, nhlfe.label_out, nhlfe.ifindex); |
| |
| memset(&zl, 0, sizeof(zl)); |
| zl.type = ZEBRA_LSP_OSPF_SR; |
| zl.local_label = nhlfe.label_in; |
| zl.nexthop_num = 1; |
| znh = &zl.nexthops[0]; |
| znh->type = NEXTHOP_TYPE_IPV4_IFINDEX; |
| znh->gate.ipv4 = nhlfe.nexthop; |
| znh->ifindex = nhlfe.ifindex; |
| znh->label_num = 1; |
| znh->labels[0] = nhlfe.label_out; |
| |
| (void)zebra_send_mpls_labels(zclient, cmd, &zl); |
| } |
| |
| struct ospf_redist *ospf_redist_lookup(struct ospf *ospf, uint8_t type, |
| unsigned short instance) |
| { |
| struct list *red_list; |
| struct listnode *node; |
| struct ospf_redist *red; |
| |
| red_list = ospf->redist[type]; |
| if (!red_list) |
| return (NULL); |
| |
| for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) |
| if (red->instance == instance) |
| return red; |
| |
| return NULL; |
| } |
| |
| struct ospf_redist *ospf_redist_add(struct ospf *ospf, uint8_t type, |
| unsigned short instance) |
| { |
| struct list *red_list; |
| struct ospf_redist *red; |
| |
| red = ospf_redist_lookup(ospf, type, instance); |
| if (red) |
| return red; |
| |
| if (!ospf->redist[type]) |
| ospf->redist[type] = list_new(); |
| |
| red_list = ospf->redist[type]; |
| red = XCALLOC(MTYPE_OSPF_REDISTRIBUTE, sizeof(struct ospf_redist)); |
| red->instance = instance; |
| red->dmetric.type = -1; |
| red->dmetric.value = -1; |
| ROUTEMAP_NAME(red) = NULL; |
| ROUTEMAP(red) = NULL; |
| |
| listnode_add(red_list, red); |
| |
| return red; |
| } |
| |
| void ospf_redist_del(struct ospf *ospf, uint8_t type, unsigned short instance) |
| { |
| struct ospf_redist *red; |
| |
| red = ospf_redist_lookup(ospf, type, instance); |
| |
| if (red) { |
| listnode_delete(ospf->redist[type], red); |
| if (!ospf->redist[type]->count) { |
| list_delete(&ospf->redist[type]); |
| } |
| ospf_routemap_unset(red); |
| XFREE(MTYPE_OSPF_REDISTRIBUTE, red); |
| } |
| } |
| |
| |
| int ospf_is_type_redistributed(struct ospf *ospf, int type, |
| unsigned short instance) |
| { |
| return (DEFAULT_ROUTE_TYPE(type) |
| ? vrf_bitmap_check(zclient->default_information[AFI_IP], |
| ospf->vrf_id) |
| : ((instance |
| && redist_check_instance( |
| &zclient->mi_redist[AFI_IP][type], |
| instance)) |
| || (!instance |
| && vrf_bitmap_check( |
| zclient->redist[AFI_IP][type], |
| ospf->vrf_id)))); |
| } |
| |
| int ospf_redistribute_set(struct ospf *ospf, int type, unsigned short instance, |
| int mtype, int mvalue) |
| { |
| int force = 0; |
| struct ospf_redist *red; |
| |
| red = ospf_redist_lookup(ospf, type, instance); |
| |
| if (red == NULL) { |
| zlog_err( |
| "Redistribute[%s][%d]: Lookup failed Type[%d] , Metric[%d]", |
| ospf_redist_string(type), instance, |
| metric_type(ospf, type, instance), |
| metric_value(ospf, type, instance)); |
| return CMD_WARNING_CONFIG_FAILED; |
| } |
| |
| if (ospf_is_type_redistributed(ospf, type, instance)) { |
| if (mtype != red->dmetric.type) { |
| red->dmetric.type = mtype; |
| force = LSA_REFRESH_FORCE; |
| } |
| if (mvalue != red->dmetric.value) { |
| red->dmetric.value = mvalue; |
| force = LSA_REFRESH_FORCE; |
| } |
| |
| ospf_external_lsa_refresh_type(ospf, type, instance, force); |
| |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) |
| zlog_debug( |
| "Redistribute[%s][%d]: Refresh Type[%d], Metric[%d]", |
| ospf_redist_string(type), instance, |
| metric_type(ospf, type, instance), |
| metric_value(ospf, type, instance)); |
| |
| return CMD_SUCCESS; |
| } |
| |
| red->dmetric.type = mtype; |
| red->dmetric.value = mvalue; |
| |
| ospf_external_add(ospf, type, instance); |
| |
| zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type, |
| instance, ospf->vrf_id); |
| |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) |
| zlog_debug( |
| "Redistribute[%s][%d] vrf id %u: Start Type[%d], Metric[%d]", |
| ospf_redist_string(type), instance, ospf->vrf_id, |
| metric_type(ospf, type, instance), |
| metric_value(ospf, type, instance)); |
| |
| ospf_asbr_status_update(ospf, ++ospf->redistribute); |
| |
| return CMD_SUCCESS; |
| } |
| |
| int ospf_redistribute_unset(struct ospf *ospf, int type, |
| unsigned short instance) |
| { |
| if (type == zclient->redist_default && instance == zclient->instance) |
| return CMD_SUCCESS; |
| |
| if (!ospf_is_type_redistributed(ospf, type, instance)) |
| return CMD_SUCCESS; |
| |
| zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, AFI_IP, type, |
| instance, ospf->vrf_id); |
| |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) |
| zlog_debug("Redistribute[%s][%d] vrf id %u: Stop", |
| ospf_redist_string(type), instance, ospf->vrf_id); |
| |
| |
| ospf_redistribute_withdraw(ospf, type, instance); |
| |
| ospf_external_del(ospf, type, instance); |
| |
| ospf_asbr_status_update(ospf, --ospf->redistribute); |
| |
| return CMD_SUCCESS; |
| } |
| |
| int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype, |
| int mvalue) |
| { |
| struct prefix_ipv4 p; |
| struct in_addr nexthop; |
| int cur_originate = ospf->default_originate; |
| const char *type_str = NULL; |
| |
| nexthop.s_addr = INADDR_ANY; |
| p.family = AF_INET; |
| p.prefix.s_addr = INADDR_ANY; |
| p.prefixlen = 0; |
| |
| ospf->default_originate = originate; |
| |
| if (cur_originate == originate) { |
| |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) |
| zlog_debug( |
| "Redistribute[%s]: Refresh Type[%d], Metric[%d]", |
| ospf_redist_string(DEFAULT_ROUTE), |
| metric_type(ospf, DEFAULT_ROUTE, 0), |
| metric_value(ospf, DEFAULT_ROUTE, 0)); |
| |
| ospf_external_lsa_refresh_default(ospf); |
| return CMD_SUCCESS; |
| } |
| |
| switch (cur_originate) { |
| case DEFAULT_ORIGINATE_NONE: |
| break; |
| case DEFAULT_ORIGINATE_ZEBRA: |
| zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, |
| zclient, AFI_IP, ospf->vrf_id); |
| ospf->redistribute--; |
| break; |
| case DEFAULT_ORIGINATE_ALWAYS: |
| ospf_external_info_delete(ospf, DEFAULT_ROUTE, 0, p); |
| ospf_external_del(ospf, DEFAULT_ROUTE, 0); |
| ospf->redistribute--; |
| break; |
| } |
| |
| switch (originate) { |
| case DEFAULT_ORIGINATE_NONE: |
| type_str = "none"; |
| break; |
| case DEFAULT_ORIGINATE_ZEBRA: |
| type_str = "normal"; |
| ospf->redistribute++; |
| zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, |
| zclient, AFI_IP, ospf->vrf_id); |
| break; |
| case DEFAULT_ORIGINATE_ALWAYS: |
| type_str = "always"; |
| ospf->redistribute++; |
| ospf_external_add(ospf, DEFAULT_ROUTE, 0); |
| ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, p, 0, nexthop, |
| 0); |
| break; |
| } |
| |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) |
| zlog_debug("Redistribute[DEFAULT]: %s Type[%d], Metric[%d]", |
| type_str, |
| metric_type(ospf, DEFAULT_ROUTE, 0), |
| metric_value(ospf, DEFAULT_ROUTE, 0)); |
| |
| ospf_external_lsa_refresh_default(ospf); |
| ospf_asbr_status_update(ospf, ospf->redistribute); |
| return CMD_SUCCESS; |
| } |
| |
| static int ospf_external_lsa_originate_check(struct ospf *ospf, |
| struct external_info *ei) |
| { |
| |
| if (IN_MULTICAST(htonl(ei->p.prefix.s_addr))) { |
| zlog_info( |
| "LSA[Type5:%s]: Not originate AS-external-LSA, Prefix belongs multicast", |
| inet_ntoa(ei->p.prefix)); |
| return 0; |
| } |
| |
| |
| if (is_prefix_default(&ei->p)) |
| if (ospf->default_originate == DEFAULT_ORIGINATE_NONE) { |
| zlog_info( |
| "LSA[Type5:0.0.0.0]: Not originate AS-external-LSA for default"); |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| |
| int ospf_distribute_check_connected(struct ospf *ospf, struct external_info *ei) |
| { |
| struct listnode *node; |
| struct ospf_interface *oi; |
| |
| |
| for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) |
| if (prefix_match(oi->address, (struct prefix *)&ei->p)) |
| return 0; |
| return 1; |
| } |
| |
| |
| |
| int ospf_external_info_apply_default_routemap(struct ospf *ospf, |
| struct external_info *ei, |
| struct external_info *default_ei) |
| { |
| struct ospf_redist *red; |
| int type = default_ei->type; |
| struct prefix_ipv4 *p = &ei->p; |
| struct route_map_set_values save_values; |
| |
| |
| if (!ospf_external_lsa_originate_check(ospf, default_ei)) |
| return 0; |
| |
| save_values = default_ei->route_map_set; |
| ospf_reset_route_map_set_values(&default_ei->route_map_set); |
| |
| |
| red = ospf_redist_lookup(ospf, type, ospf->instance); |
| if (red && ROUTEMAP_NAME(red)) { |
| route_map_result_t ret; |
| |
| ret = route_map_apply(ROUTEMAP(red), (struct prefix *)p, |
| RMAP_OSPF, ei); |
| |
| if (ret == RMAP_DENYMATCH) { |
| ei->route_map_set = save_values; |
| return 0; |
| } |
| } |
| |
| return 1; |
| } |
| |
| |
| |
| |
| |
| |
| |
| static bool ospf_external_lsa_default_routemap_apply(struct ospf *ospf, |
| struct external_info *ei, |
| int cmd) |
| { |
| struct external_info *default_ei; |
| struct prefix_ipv4 p; |
| struct ospf_lsa *lsa; |
| int ret; |
| |
| p.family = AF_INET; |
| p.prefixlen = 0; |
| p.prefix.s_addr = INADDR_ANY; |
| |
| |
| |
| default_ei = ospf_external_info_lookup(ospf, DEFAULT_ROUTE, |
| ospf->instance, &p); |
| if (!default_ei) { |
| |
| return false; |
| } |
| |
| if (IS_DEBUG_OSPF_DEFAULT_INFO) |
| zlog_debug("Apply default originate routemap on ei: %s cmd: %d", |
| inet_ntoa(ei->p.prefix), cmd); |
| |
| ret = ospf_external_info_apply_default_routemap(ospf, ei, default_ei); |
| |
| |
| if (!ret) { |
| if (IS_DEBUG_OSPF_DEFAULT_INFO) |
| zlog_debug("Default originte routemap deny for ei: %s", |
| inet_ntoa(ei->p.prefix)); |
| return false; |
| } |
| |
| |
| lsa = ospf_external_info_find_lsa(ospf, &p); |
| |
| |
| if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) { |
| |
| if (lsa && !IS_LSA_MAXAGE(lsa)) { |
| if (IS_DEBUG_OSPF_DEFAULT_INFO) |
| zlog_debug("Defult lsa already originated"); |
| return true; |
| } |
| |
| if (IS_DEBUG_OSPF_DEFAULT_INFO) |
| zlog_debug("Originating/Refreshing default lsa"); |
| |
| if (lsa && IS_LSA_MAXAGE(lsa)) |
| |
| ospf_external_lsa_refresh(ospf, lsa, default_ei, true); |
| else |
| |
| |
| ospf_external_lsa_originate(ospf, default_ei); |
| |
| } else if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_DEL) { |
| |
| if (!lsa) { |
| if (IS_DEBUG_OSPF_DEFAULT_INFO) |
| zlog_debug( |
| "Default lsa not originated, not flushing"); |
| return true; |
| } |
| |
| if (IS_DEBUG_OSPF_DEFAULT_INFO) |
| zlog_debug( |
| "Running default route-map again as ei: %s deleted", |
| inet_ntoa(ei->p.prefix)); |
| |
| |
| |
| |
| |
| thread_add_event(master, |
| ospf_external_lsa_default_routemap_timer, ospf, |
| 0, &ospf->t_default_routemap_timer); |
| } |
| |
| return true; |
| } |
| |
| |
| int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei, |
| int *changed) |
| { |
| struct route_map_set_values save_values; |
| struct prefix_ipv4 *p = &ei->p; |
| struct ospf_redist *red; |
| uint8_t type = is_prefix_default(&ei->p) ? DEFAULT_ROUTE : ei->type; |
| unsigned short instance = is_prefix_default(&ei->p) ? 0 : ei->instance; |
| route_tag_t saved_tag = 0; |
| |
| |
| if (type == DEFAULT_ROUTE) |
| return 1; |
| |
| if (changed) |
| *changed = 0; |
| |
| if (!ospf_external_lsa_originate_check(ospf, ei)) |
| return 0; |
| |
| |
| if (type == ZEBRA_ROUTE_CONNECT |
| && !ospf_distribute_check_connected(ospf, ei)) |
| return 0; |
| |
| if (!DEFAULT_ROUTE_TYPE(type) && DISTRIBUTE_NAME(ospf, type)) |
| |
| if (DISTRIBUTE_LIST(ospf, type)) |
| if (access_list_apply(DISTRIBUTE_LIST(ospf, type), p) |
| == FILTER_DENY) { |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) { |
| char buf[PREFIX2STR_BUFFER]; |
| zlog_debug( |
| "Redistribute[%s]: %s filtered by distribute-list.", |
| ospf_redist_string(type), |
| prefix2str(p, buf, sizeof(buf))); |
| } |
| return 0; |
| } |
| |
| save_values = ei->route_map_set; |
| ospf_reset_route_map_set_values(&ei->route_map_set); |
| |
| saved_tag = ei->tag; |
| |
| ei->tag = ei->orig_tag; |
| |
| |
| red = ospf_redist_lookup(ospf, type, instance); |
| if (red && ROUTEMAP_NAME(red)) { |
| route_map_result_t ret; |
| |
| ret = route_map_apply(ROUTEMAP(red), (struct prefix *)p, |
| RMAP_OSPF, ei); |
| |
| if (ret == RMAP_DENYMATCH) { |
| ei->route_map_set = save_values; |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) { |
| char buf[PREFIX2STR_BUFFER]; |
| zlog_debug( |
| "Redistribute[%s]: %s filtered by route-map.", |
| ospf_redist_string(type), |
| prefix2str(p, buf, sizeof(buf))); |
| } |
| return 0; |
| } |
| |
| |
| if (changed) { |
| *changed = !ospf_route_map_set_compare( |
| &ei->route_map_set, &save_values); |
| |
| |
| *changed |= (saved_tag != ei->tag); |
| } |
| } |
| |
| return 1; |
| } |
| |
| |
| void ospf_routemap_set(struct ospf_redist *red, const char *name) |
| { |
| if (ROUTEMAP_NAME(red)) { |
| route_map_counter_decrement(ROUTEMAP(red)); |
| free(ROUTEMAP_NAME(red)); |
| } |
| |
| ROUTEMAP_NAME(red) = strdup(name); |
| ROUTEMAP(red) = route_map_lookup_by_name(name); |
| route_map_counter_increment(ROUTEMAP(red)); |
| } |
| |
| void ospf_routemap_unset(struct ospf_redist *red) |
| { |
| if (ROUTEMAP_NAME(red)) { |
| route_map_counter_decrement(ROUTEMAP(red)); |
| free(ROUTEMAP_NAME(red)); |
| } |
| |
| ROUTEMAP_NAME(red) = NULL; |
| ROUTEMAP(red) = NULL; |
| } |
| |
| |
| static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) |
| { |
| struct zapi_route api; |
| struct prefix_ipv4 p; |
| unsigned long ifindex; |
| struct in_addr nexthop; |
| struct external_info *ei; |
| struct ospf *ospf; |
| int i; |
| uint8_t rt_type; |
| |
| ospf = ospf_lookup_by_vrf_id(vrf_id); |
| if (ospf == NULL) |
| return 0; |
| |
| if (zapi_route_decode(zclient->ibuf, &api) < 0) |
| return -1; |
| |
| ifindex = api.nexthops[0].ifindex; |
| nexthop = api.nexthops[0].gate.ipv4; |
| rt_type = api.type; |
| |
| memcpy(&p, &api.prefix, sizeof(p)); |
| if (IPV4_NET127(ntohl(p.prefix.s_addr))) |
| return 0; |
| |
| |
| |
| |
| |
| |
| |
| if (is_prefix_default(&p)) |
| rt_type = DEFAULT_ROUTE; |
| |
| if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) { |
| char buf_prefix[PREFIX_STRLEN]; |
| prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix)); |
| |
| zlog_debug("%s: cmd %s from client %s: vrf_id %d, p %s", |
| __func__, zserv_command_string(cmd), |
| zebra_route_string(api.type), vrf_id, buf_prefix); |
| } |
| |
| if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) { |
| |
| |
| |
| |
| |
| |
| |
| |
| if (ospf->dtag[rt_type] > 0) |
| api.tag = ospf->dtag[rt_type]; |
| |
| |
| |
| |
| |
| |
| |
| |
| for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) |
| if (i != rt_type) |
| ospf_external_info_delete(ospf, i, api.instance, |
| p); |
| |
| ei = ospf_external_info_add(ospf, rt_type, api.instance, p, |
| ifindex, nexthop, api.tag); |
| if (ei == NULL) { |
| |
| return 0; |
| } |
| if (ospf->router_id.s_addr != INADDR_ANY) { |
| if (ei) { |
| if (is_prefix_default(&p)) |
| ospf_external_lsa_refresh_default(ospf); |
| else { |
| struct ospf_lsa *current; |
| |
| current = ospf_external_info_find_lsa( |
| ospf, &ei->p); |
| if (!current) |
| ospf_external_lsa_originate( |
| ospf, ei); |
| else { |
| if (IS_DEBUG_OSPF( |
| zebra, |
| ZEBRA_REDISTRIBUTE)) |
| zlog_debug( |
| "ospf_zebra_read_route() : %s refreshing LSA", |
| inet_ntoa( |
| p.prefix)); |
| ospf_external_lsa_refresh( |
| ospf, current, ei, |
| LSA_REFRESH_FORCE); |
| } |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| ospf_external_lsa_default_routemap_apply(ospf, ei, cmd); |
| |
| } else |
| { |
| |
| |
| |
| |
| |
| ei = ospf_external_info_lookup(ospf, rt_type, api.instance, &p); |
| if (ei) |
| ospf_external_lsa_default_routemap_apply(ospf, ei, cmd); |
| |
| ospf_external_info_delete(ospf, rt_type, api.instance, p); |
| if (is_prefix_default(&p)) |
| ospf_external_lsa_refresh_default(ospf); |
| else |
| ospf_external_lsa_flush(ospf, rt_type, &p, |
| ifindex ); |
| } |
| |
| |
| return 0; |
| } |
| |
| |
| int ospf_distribute_list_out_set(struct ospf *ospf, int type, const char *name) |
| { |
| |
| DISTRIBUTE_LIST(ospf, type) = access_list_lookup(AFI_IP, name); |
| |
| |
| if (DISTRIBUTE_NAME(ospf, type)) |
| free(DISTRIBUTE_NAME(ospf, type)); |
| |
| |
| DISTRIBUTE_NAME(ospf, type) = strdup(name); |
| |
| |
| if (DISTRIBUTE_LIST(ospf, type)) |
| ospf_distribute_list_update(ospf, type, 0); |
| |
| return CMD_SUCCESS; |
| } |
| |
| int ospf_distribute_list_out_unset(struct ospf *ospf, int type, |
| const char *name) |
| { |
| |
| if (DISTRIBUTE_LIST(ospf, type)) |
| ospf_distribute_list_update(ospf, type, 0); |
| |
| |
| DISTRIBUTE_LIST(ospf, type) = NULL; |
| |
| |
| if (DISTRIBUTE_NAME(ospf, type)) |
| free(DISTRIBUTE_NAME(ospf, type)); |
| |
| DISTRIBUTE_NAME(ospf, type) = NULL; |
| |
| return CMD_SUCCESS; |
| } |
| |
| |
| static int ospf_distribute_list_update_timer(struct thread *thread) |
| { |
| struct route_node *rn; |
| struct external_info *ei; |
| struct route_table *rt; |
| struct ospf_lsa *lsa; |
| int type, default_refresh = 0, arg_type; |
| struct ospf *ospf = NULL; |
| void **arg = THREAD_ARG(thread); |
| |
| ospf = (struct ospf *)arg[0]; |
| arg_type = (int)(intptr_t)arg[1]; |
| |
| if (ospf == NULL) |
| return 0; |
| |
| ospf->t_distribute_update = NULL; |
| |
| zlog_info("Zebra[Redistribute]: distribute-list update timer fired!"); |
| |
| if (IS_DEBUG_OSPF_EVENT) { |
| zlog_debug( |
| "%s: ospf distribute-list update arg_type %d vrf %s id %d", |
| __func__, arg_type, ospf_vrf_id_to_name(ospf->vrf_id), |
| ospf->vrf_id); |
| } |
| |
| |
| for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { |
| struct list *ext_list; |
| struct listnode *node; |
| struct ospf_external *ext; |
| |
| ext_list = ospf->external[type]; |
| if (!ext_list) |
| continue; |
| |
| for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { |
| rt = ext->external_info; |
| if (!rt) |
| continue; |
| for (rn = route_top(rt); rn; rn = route_next(rn)) |
| if ((ei = rn->info) != NULL) { |
| if (is_prefix_default(&ei->p)) |
| default_refresh = 1; |
| else if ( |
| (lsa = ospf_external_info_find_lsa( |
| ospf, &ei->p))) { |
| int force = |
| LSA_REFRESH_IF_CHANGED; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| if (IS_LSA_MAXAGE(lsa)) |
| force = LSA_REFRESH_FORCE; |
| |
| ospf_external_lsa_refresh( |
| ospf, lsa, ei, force); |
| } else |
| ospf_external_lsa_originate( |
| ospf, ei); |
| } |
| } |
| } |
| if (default_refresh) |
| ospf_external_lsa_refresh_default(ospf); |
| |
| XFREE(MTYPE_OSPF_DIST_ARGS, arg); |
| return 0; |
| } |
| |
| |
| void ospf_distribute_list_update(struct ospf *ospf, int type, |
| unsigned short instance) |
| { |
| struct ospf_external *ext; |
| void **args = XCALLOC(MTYPE_OSPF_DIST_ARGS, sizeof(void *) * 2); |
| |
| args[0] = ospf; |
| args[1] = (void *)((ptrdiff_t)type); |
| |
| |
| ext = ospf_external_lookup(ospf, type, instance); |
| if (!ext || !EXTERNAL_INFO(ext)) { |
| XFREE(MTYPE_OSPF_DIST_ARGS, args); |
| return; |
| } |
| |
| |
| if (ospf->t_distribute_update) { |
| XFREE(MTYPE_OSPF_DIST_ARGS, args); |
| return; |
| } |
| |
| |
| ospf->t_distribute_update = NULL; |
| thread_add_timer_msec(master, ospf_distribute_list_update_timer, args, |
| ospf->min_ls_interval, |
| &ospf->t_distribute_update); |
| } |
| |
| |
| static void ospf_filter_update(struct access_list *access) |
| { |
| struct ospf *ospf; |
| int type; |
| int abr_inv = 0; |
| struct ospf_area *area; |
| struct listnode *node, *n1; |
| |
| |
| if (listcount(om->ospf) == 0) |
| return; |
| |
| |
| for (ALL_LIST_ELEMENTS_RO(om->ospf, n1, ospf)) { |
| |
| for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { |
| struct list *red_list; |
| struct ospf_redist *red; |
| |
| red_list = ospf->redist[type]; |
| if (red_list) |
| for (ALL_LIST_ELEMENTS_RO(red_list, node, |
| red)) { |
| if (ROUTEMAP(red)) { |
| |
| |
| |
| ospf_distribute_list_update( |
| ospf, type, |
| red->instance); |
| } |
| } |
| |
| |
| |
| |
| if (type == ZEBRA_ROUTE_MAX) |
| break; |
| |
| if (DISTRIBUTE_NAME(ospf, type)) { |
| |
| struct access_list *old = |
| DISTRIBUTE_LIST(ospf, type); |
| |
| |
| DISTRIBUTE_LIST(ospf, type) = |
| access_list_lookup( |
| AFI_IP, |
| DISTRIBUTE_NAME(ospf, type)); |
| |
| |
| if (old == NULL |
| && DISTRIBUTE_LIST(ospf, type) == NULL) |
| continue; |
| |
| |
| if (DISTRIBUTE_LIST(ospf, type) == NULL |
| || strcmp(DISTRIBUTE_NAME(ospf, type), |
| access->name) |
| == 0) |
| ospf_distribute_list_update(ospf, type, |
| 0); |
| } |
| } |
| |
| |
| for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) { |
| if (EXPORT_NAME(area)) { |
| EXPORT_LIST(area) = NULL; |
| abr_inv++; |
| } |
| |
| if (IMPORT_NAME(area)) { |
| IMPORT_LIST(area) = NULL; |
| abr_inv++; |
| } |
| } |
| |
| |
| if (IS_OSPF_ABR(ospf) && abr_inv) |
| ospf_schedule_abr_task(ospf); |
| } |
| } |
| |
| |
| void ospf_prefix_list_update(struct prefix_list *plist) |
| { |
| struct ospf *ospf = NULL; |
| int type; |
| int abr_inv = 0; |
| struct ospf_area *area; |
| struct listnode *node, *n1; |
| |
| |
| if (listcount(om->ospf) == 0) |
| return; |
| |
| |
| for (ALL_LIST_ELEMENTS_RO(om->ospf, n1, ospf)) { |
| |
| |
| |
| |
| |
| for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { |
| struct list *red_list; |
| struct ospf_redist *red; |
| |
| red_list = ospf->redist[type]; |
| if (red_list) { |
| for (ALL_LIST_ELEMENTS_RO(red_list, node, |
| red)) { |
| if (ROUTEMAP(red)) { |
| |
| |
| |
| ospf_distribute_list_update( |
| ospf, type, |
| red->instance); |
| } |
| } |
| } |
| } |
| |
| |
| for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) { |
| |
| if (PREFIX_NAME_IN(area)) |
| if (strcmp(PREFIX_NAME_IN(area), |
| prefix_list_name(plist)) |
| == 0) { |
| PREFIX_LIST_IN(area) = |
| prefix_list_lookup( |
| AFI_IP, |
| PREFIX_NAME_IN(area)); |
| abr_inv++; |
| } |
| |
| |
| if (PREFIX_NAME_OUT(area)) |
| if (strcmp(PREFIX_NAME_OUT(area), |
| prefix_list_name(plist)) |
| == 0) { |
| PREFIX_LIST_IN(area) = |
| prefix_list_lookup( |
| AFI_IP, |
| PREFIX_NAME_OUT(area)); |
| abr_inv++; |
| } |
| } |
| |
| |
| if (IS_OSPF_ABR(ospf) && abr_inv) |
| ospf_schedule_abr_task(ospf); |
| } |
| } |
| |
| static struct ospf_distance *ospf_distance_new(void) |
| { |
| return XCALLOC(MTYPE_OSPF_DISTANCE, sizeof(struct ospf_distance)); |
| } |
| |
| static void ospf_distance_free(struct ospf_distance *odistance) |
| { |
| XFREE(MTYPE_OSPF_DISTANCE, odistance); |
| } |
| |
| int ospf_distance_set(struct vty *vty, struct ospf *ospf, |
| const char *distance_str, const char *ip_str, |
| const char *access_list_str) |
| { |
| int ret; |
| struct prefix_ipv4 p; |
| uint8_t distance; |
| struct route_node *rn; |
| struct ospf_distance *odistance; |
| |
| ret = str2prefix_ipv4(ip_str, &p); |
| if (ret == 0) { |
| vty_out(vty, "Malformed prefix\n"); |
| return CMD_WARNING_CONFIG_FAILED; |
| } |
| |
| distance = atoi(distance_str); |
| |
| |
| rn = route_node_get(ospf->distance_table, (struct prefix *)&p); |
| if (rn->info) { |
| odistance = rn->info; |
| route_unlock_node(rn); |
| } else { |
| odistance = ospf_distance_new(); |
| rn->info = odistance; |
| } |
| |
| |
| odistance->distance = distance; |
| |
| |
| if (odistance->access_list) { |
| free(odistance->access_list); |
| odistance->access_list = NULL; |
| } |
| if (access_list_str) |
| odistance->access_list = strdup(access_list_str); |
| |
| return CMD_SUCCESS; |
| } |
| |
| int ospf_distance_unset(struct vty *vty, struct ospf *ospf, |
| const char *distance_str, const char *ip_str, |
| char const *access_list_str) |
| { |
| int ret; |
| struct prefix_ipv4 p; |
| struct route_node *rn; |
| struct ospf_distance *odistance; |
| |
| ret = str2prefix_ipv4(ip_str, &p); |
| if (ret == 0) { |
| vty_out(vty, "Malformed prefix\n"); |
| return CMD_WARNING_CONFIG_FAILED; |
| } |
| |
| rn = route_node_lookup(ospf->distance_table, (struct prefix *)&p); |
| if (!rn) { |
| vty_out(vty, "Can't find specified prefix\n"); |
| return CMD_WARNING_CONFIG_FAILED; |
| } |
| |
| odistance = rn->info; |
| |
| if (odistance->access_list) |
| free(odistance->access_list); |
| ospf_distance_free(odistance); |
| |
| rn->info = NULL; |
| route_unlock_node(rn); |
| route_unlock_node(rn); |
| |
| return CMD_SUCCESS; |
| } |
| |
| void ospf_distance_reset(struct ospf *ospf) |
| { |
| struct route_node *rn; |
| struct ospf_distance *odistance; |
| |
| for (rn = route_top(ospf->distance_table); rn; rn = route_next(rn)) |
| if ((odistance = rn->info) != NULL) { |
| if (odistance->access_list) |
| free(odistance->access_list); |
| ospf_distance_free(odistance); |
| rn->info = NULL; |
| route_unlock_node(rn); |
| } |
| } |
| |
| uint8_t ospf_distance_apply(struct ospf *ospf, struct prefix_ipv4 *p, |
| struct ospf_route * or) |
| { |
| |
| if (ospf == NULL) |
| return 0; |
| |
| if (ospf->distance_intra) |
| if (or->path_type == OSPF_PATH_INTRA_AREA) |
| return ospf->distance_intra; |
| |
| if (ospf->distance_inter) |
| if (or->path_type == OSPF_PATH_INTER_AREA) |
| return ospf->distance_inter; |
| |
| if (ospf->distance_external) |
| if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL || |
| or->path_type == OSPF_PATH_TYPE2_EXTERNAL) |
| return ospf->distance_external; |
| |
| if (ospf->distance_all) |
| return ospf->distance_all; |
| |
| return 0; |
| } |
| |
| void ospf_zebra_vrf_register(struct ospf *ospf) |
| { |
| if (!zclient || zclient->sock < 0 || !ospf) |
| return; |
| |
| if (ospf->vrf_id != VRF_UNKNOWN) { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_debug("%s: Register VRF %s id %u", __func__, |
| ospf_vrf_id_to_name(ospf->vrf_id), |
| ospf->vrf_id); |
| zclient_send_reg_requests(zclient, ospf->vrf_id); |
| } |
| } |
| |
| void ospf_zebra_vrf_deregister(struct ospf *ospf) |
| { |
| if (!zclient || zclient->sock < 0 || !ospf) |
| return; |
| |
| if (ospf->vrf_id != VRF_DEFAULT && ospf->vrf_id != VRF_UNKNOWN) { |
| if (IS_DEBUG_OSPF_EVENT) |
| zlog_debug("%s: De-Register VRF %s id %u to Zebra.", |
| __func__, ospf_vrf_id_to_name(ospf->vrf_id), |
| ospf->vrf_id); |
| |
| |
| zclient_send_dereg_requests(zclient, ospf->vrf_id); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| bool ospf_zebra_label_manager_ready(void) |
| { |
| return (zclient_sync->sock > 0); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| int ospf_zebra_request_label_range(uint32_t base, uint32_t chunk_size) |
| { |
| int ret; |
| uint32_t start, end; |
| |
| if (zclient_sync->sock < 0) |
| return -1; |
| |
| ret = lm_get_label_chunk(zclient_sync, 0, base, chunk_size, &start, |
| &end); |
| if (ret < 0) { |
| zlog_warn("%s: error getting label range!", __func__); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| int ospf_zebra_release_label_range(uint32_t start, uint32_t end) |
| { |
| int ret; |
| |
| if (zclient_sync->sock < 0) |
| return -1; |
| |
| ret = lm_release_label_chunk(zclient_sync, start, end); |
| if (ret < 0) { |
| zlog_warn("%s: error releasing label range!", __func__); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| |
| |
| |
| int ospf_zebra_label_manager_connect(void) |
| { |
| |
| if (zclient_socket_connect(zclient_sync) < 0) { |
| zlog_warn("%s: failed connecting synchronous zclient!", |
| __func__); |
| return -1; |
| } |
| |
| set_nonblocking(zclient_sync->sock); |
| |
| |
| if (zclient_send_hello(zclient_sync) < 0) { |
| zlog_warn("%s: failed sending hello for synchronous zclient!", |
| __func__); |
| close(zclient_sync->sock); |
| zclient_sync->sock = -1; |
| return -1; |
| } |
| |
| |
| if (lm_label_manager_connect(zclient_sync, 0) != 0) { |
| zlog_warn("%s: failed connecting to label manager!", __func__); |
| if (zclient_sync->sock > 0) { |
| close(zclient_sync->sock); |
| zclient_sync->sock = -1; |
| } |
| return -1; |
| } |
| |
| osr_debug("SR (%s): Successfully connected to the Label Manager", |
| __func__); |
| |
| return 0; |
| } |
| |
| static void ospf_zebra_connected(struct zclient *zclient) |
| { |
| |
| bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT); |
| |
| zclient_send_reg_requests(zclient, VRF_DEFAULT); |
| } |
| |
| void ospf_zebra_init(struct thread_master *master, unsigned short instance) |
| { |
| |
| zclient = zclient_new(master, &zclient_options_default); |
| zclient_init(zclient, ZEBRA_ROUTE_OSPF, instance, &ospfd_privs); |
| zclient->zebra_connected = ospf_zebra_connected; |
| zclient->router_id_update = ospf_router_id_update_zebra; |
| zclient->interface_address_add = ospf_interface_address_add; |
| zclient->interface_address_delete = ospf_interface_address_delete; |
| zclient->interface_link_params = ospf_interface_link_params; |
| zclient->interface_vrf_update = ospf_interface_vrf_update; |
| |
| zclient->redistribute_route_add = ospf_zebra_read_route; |
| zclient->redistribute_route_del = ospf_zebra_read_route; |
| |
| |
| struct zclient_options options = zclient_options_default; |
| options.synchronous = true; |
| zclient_sync = zclient_new(master, &options); |
| zclient_sync->sock = -1; |
| zclient_sync->redist_default = ZEBRA_ROUTE_OSPF; |
| zclient_sync->instance = instance; |
| |
| |
| |
| |
| zclient_sync->session_id = 1; |
| zclient_sync->privs = &ospfd_privs; |
| |
| access_list_add_hook(ospf_filter_update); |
| access_list_delete_hook(ospf_filter_update); |
| prefix_list_add_hook(ospf_prefix_list_update); |
| prefix_list_delete_hook(ospf_prefix_list_update); |
| } |
| |
| void ospf_zebra_send_arp(const struct interface *ifp, const struct prefix *p) |
| { |
| zclient_send_neigh_discovery_req(zclient, ifp, p); |
| } |