diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index b47c390088..738ac6d8cf 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -168,6 +168,38 @@ void ospf_external_info_delete(struct ospf *ospf, uint8_t type, } } +/* + * ospf_external_info_delete_multi_instance + * + * Delete instances of the external route information for a given route type. + * The preserve_instance parameter may be used to prevent the current instance + * from being deleted. + */ +void ospf_external_info_delete_multi_instance(struct ospf *ospf, uint8_t type, struct prefix_ipv4 p, + unsigned long preserve_instance) +{ + struct route_node *rn; + struct ospf_external *ext; + struct list *ext_list; + struct listnode *node; + + ext_list = ospf->external[type]; + if (!ext_list) + return; + + for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { + if (ext->instance != preserve_instance) { + 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) @@ -189,6 +221,44 @@ struct external_info *ospf_external_info_lookup(struct ospf *ospf, uint8_t type, return NULL; } +/* + * ospf_external_info_default_lookup + * + * For default information criteria, we really don't care about the + * source of the route and there only should be one. + */ +struct external_info *ospf_external_info_default_lookup(struct ospf *ospf) +{ + struct ospf_external *ext; + struct external_info *ei; + struct list *ext_list; + struct listnode *node; + struct route_node *rn; + struct prefix_ipv4 p = { + .family = AF_INET, + .prefixlen = 0, + .prefix.s_addr = INADDR_ANY, + }; + + ext_list = ospf->external[DEFAULT_ROUTE]; + if (!ext_list) + return (NULL); + + for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { + rn = route_node_lookup(EXTERNAL_INFO(ext), (struct prefix *)&p); + if (rn) { + route_unlock_node(rn); + if (rn->info) { + ei = rn->info; + if (ei->type != ZEBRA_ROUTE_OSPF || ei->instance != ospf->instance) + return ei; + } + } + } + + return NULL; +} + struct ospf_lsa *ospf_external_info_find_lsa(struct ospf *ospf, struct prefix_ipv4 *p) { diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h index 6158d65f22..648a5a11ae 100644 --- a/ospfd/ospf_asbr.h +++ b/ospfd/ospf_asbr.h @@ -109,6 +109,10 @@ ospf_external_info_add(struct ospf *, uint8_t, unsigned short, route_tag_t, uint32_t metric); extern void ospf_external_info_delete(struct ospf *, uint8_t, unsigned short, struct prefix_ipv4); +extern void ospf_external_info_delete_multi_instance(struct ospf *ospf, uint8_t type, + struct prefix_ipv4 p, + unsigned long preserve_instance); +#define OSPF_DELETE_ANY_INSTANCE 0xffffffff extern struct external_info *ospf_external_info_lookup(struct ospf *, uint8_t, unsigned short, struct prefix_ipv4 *); diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 1350487898..7354223397 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2407,15 +2407,10 @@ struct ospf_lsa *ospf_nssa_lsa_refresh(struct ospf_area *area, static struct external_info *ospf_default_external_info(struct ospf *ospf) { int type; - struct prefix_ipv4 p; struct external_info *default_ei; int ret = 0; - p.family = AF_INET; - p.prefix.s_addr = 0; - p.prefixlen = 0; - - default_ei = ospf_external_info_lookup(ospf, DEFAULT_ROUTE, 0, &p); + default_ei = ospf_external_info_default_lookup(ospf); if (!default_ei) return NULL; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 0457b13337..27528f6594 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -7347,6 +7347,9 @@ DEFPY (show_ip_ospf_database, struct in_addr *adv_router_p = NULL; json_object *json = NULL; + if (instance_id != ospf_instance) + return CMD_NOT_MY_INSTANCE; + if (uj) json = json_object_new_object(); if (lsid_str) diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index c7cba1e20f..b718d498ae 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -1292,15 +1292,14 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) * originate)ZEBRA_ROUTE_MAX is used to delete the ex-info. * Resolved this inconsistency by maintaining same route type. */ - if ((is_default_prefix(&pgen)) && (api.type != ZEBRA_ROUTE_OSPF)) + if ((is_default_prefix(&pgen)) && + ((api.type != ZEBRA_ROUTE_OSPF) || (api.instance != ospf->instance))) rt_type = DEFAULT_ROUTE; if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug("%s: cmd %s from client %s: vrf %s(%u), p %pFX, metric %d", - __func__, zserv_command_string(cmd), - zebra_route_string(api.type), - ospf_vrf_id_to_name(vrf_id), vrf_id, &api.prefix, - api.metric); + zlog_debug("%s: cmd %s from client %s-%d: vrf %s(%u), p %pFX, metric %d", __func__, + zserv_command_string(cmd), zebra_route_string(api.type), api.instance, + ospf_vrf_id_to_name(vrf_id), vrf_id, &api.prefix, api.metric); if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) { /* XXX|HACK|TODO|FIXME: @@ -1315,16 +1314,17 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) api.tag = ospf->dtag[rt_type]; /* - * Given zebra sends update for a prefix via ADD message, it - * should - * be considered as an implicit DEL for that prefix with other - * source - * types. + * Given zebra sends an update for a prefix via an ADD message, it + * will be considered as an impilict DELETE for that prefix for other + * types and instances other than the type and instance associated with + * the prefix. */ - for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) - if (i != rt_type) - ospf_external_info_delete(ospf, i, api.instance, - p); + for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) { + unsigned long preserve_instance; + + preserve_instance = (i == rt_type) ? api.instance : OSPF_DELETE_ANY_INSTANCE; + ospf_external_info_delete_multi_instance(ospf, i, p, preserve_instance); + } ei = ospf_external_info_add(ospf, rt_type, api.instance, p, ifindex, nexthop, api.tag, diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h index 86a5678fc4..b83524303f 100644 --- a/ospfd/ospf_zebra.h +++ b/ospfd/ospf_zebra.h @@ -47,6 +47,9 @@ extern uint8_t ospf_distance_apply(struct ospf *ospf, struct prefix_ipv4 *, struct ospf_route *); extern struct ospf_external *ospf_external_lookup(struct ospf *, uint8_t, unsigned short); + +extern struct external_info *ospf_external_info_default_lookup(struct ospf *ospf); + extern struct ospf_external *ospf_external_add(struct ospf *, uint8_t, unsigned short);