diff options
Diffstat (limited to 'ospf6d')
| -rw-r--r-- | ospf6d/ospf6_abr.c | 10 | ||||
| -rw-r--r-- | ospf6d/ospf6_area.c | 6 | ||||
| -rw-r--r-- | ospf6d/ospf6_area.h | 1 | ||||
| -rw-r--r-- | ospf6d/ospf6_asbr.c | 275 | ||||
| -rw-r--r-- | ospf6d/ospf6_asbr.h | 2 | ||||
| -rw-r--r-- | ospf6d/ospf6_interface.c | 99 | ||||
| -rw-r--r-- | ospf6d/ospf6_interface.h | 13 | ||||
| -rw-r--r-- | ospf6d/ospf6_intra.c | 3 | ||||
| -rw-r--r-- | ospf6d/ospf6_lsa.c | 2 | ||||
| -rw-r--r-- | ospf6d/ospf6_lsa.h | 1 | ||||
| -rw-r--r-- | ospf6d/ospf6_memory.c | 1 | ||||
| -rw-r--r-- | ospf6d/ospf6_memory.h | 1 | ||||
| -rw-r--r-- | ospf6d/ospf6_message.c | 32 | ||||
| -rw-r--r-- | ospf6d/ospf6_route.c | 50 | ||||
| -rw-r--r-- | ospf6d/ospf6_route.h | 9 | ||||
| -rw-r--r-- | ospf6d/ospf6_spf.c | 356 | ||||
| -rw-r--r-- | ospf6d/ospf6_spf.h | 4 | ||||
| -rw-r--r-- | ospf6d/ospf6_top.c | 14 | ||||
| -rw-r--r-- | ospf6d/ospf6_zebra.c | 3 | ||||
| -rw-r--r-- | ospf6d/ospf6d.c | 44 |
20 files changed, 765 insertions, 161 deletions
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index d270b9547e..8847611492 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -901,6 +901,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) ospf6_route_copy_nexthops(route, abr_entry); + /* (7) If the routes are identical, copy the next hops over to existing route. ospf6's route table implementation will otherwise string both routes, but keep the older one as the best route since the routes @@ -910,6 +911,12 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) if (old && (ospf6_route_cmp(route, old) == 0)) { ospf6_route_merge_nexthops(old, route); + + if (is_debug) + zlog_debug("%s: Update route: %s nh count %u", + __PRETTY_FUNCTION__, + buf, listcount(route->nh_list)); + /* Update RIB/FIB */ if (table->hook_add) (*table->hook_add)(old); @@ -918,7 +925,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) ospf6_route_delete(route); } else { if (is_debug) - zlog_debug("Install route: %s", buf); + zlog_debug("Install route: %s nh count %u", + buf, listcount(route->nh_list)); /* ospf6_ia_add_nw_route (table, &prefix, route); */ ospf6_route_add(route, table); } diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index bd5e2bd1d3..ed624c6ae4 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -117,7 +117,9 @@ static void ospf6_area_lsdb_hook_remove(struct ospf6_lsa *lsa) static void ospf6_area_route_hook_add(struct ospf6_route *route) { - struct ospf6_route *copy = ospf6_route_copy(route); + struct ospf6_route *copy; + + copy = ospf6_route_copy(route); ospf6_route_add(copy, ospf6->route_table); } @@ -219,6 +221,7 @@ struct ospf6_area *ospf6_area_create(u_int32_t area_id, struct ospf6 *o, int df) oa->lsdb->hook_add = ospf6_area_lsdb_hook_add; oa->lsdb->hook_remove = ospf6_area_lsdb_hook_remove; oa->lsdb_self = ospf6_lsdb_create(oa); + oa->temp_router_lsa_lsdb = ospf6_lsdb_create(oa); oa->spf_table = OSPF6_ROUTE_TABLE_CREATE(AREA, SPF_RESULTS); oa->spf_table->scope = oa; @@ -277,6 +280,7 @@ void ospf6_area_delete(struct ospf6_area *oa) ospf6_lsdb_delete(oa->lsdb); ospf6_lsdb_delete(oa->lsdb_self); + ospf6_lsdb_delete(oa->temp_router_lsa_lsdb); ospf6_spf_table_finish(oa->spf_table); ospf6_route_table_delete(oa->spf_table); diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h index d212d92387..b7cd9b4b09 100644 --- a/ospf6d/ospf6_area.h +++ b/ospf6d/ospf6_area.h @@ -55,6 +55,7 @@ struct ospf6_area { struct ospf6_lsdb *lsdb; struct ospf6_lsdb *lsdb_self; + struct ospf6_lsdb *temp_router_lsa_lsdb; struct ospf6_route_table *spf_table; struct ospf6_route_table *route_table; diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 5fbf2dafa5..745b87b890 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -173,11 +173,136 @@ static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa) return ntohl(network_order); } +void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, + struct ospf6_route *route) +{ + struct ospf6_route *old_route; + struct ospf6_path *ecmp_path, *o_path = NULL; + struct listnode *anode; + struct listnode *nnode, *rnode, *rnext; + struct ospf6_nexthop *nh, *rnh; + char buf[PREFIX2STR_BUFFER]; + bool route_found = false; + + for (old_route = old; old_route; old_route = old_route->next) { + if (ospf6_route_is_same(old_route, route) && + (old_route->path.type == route->path.type) && + (old_route->path.cost == route->path.cost) && + (old_route->path.u.cost_e2 == route->path.u.cost_e2)) { + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&old_route->prefix, buf, + sizeof(buf)); + zlog_debug("%s: old route %s path cost %u [%u]", + __PRETTY_FUNCTION__, buf, + old_route->path.cost, + ospf6_route_is_same(old_route, + route)); + } + route_found = true; + /* check if this path exists already in + * route->paths list, if so, replace nh_list + * from asbr_entry. + */ + for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode, + o_path)) { + if ((o_path->origin.id == route->path.origin.id) + && (o_path->origin.adv_router == + route->path.origin.adv_router)) + break; + } + /* If path is not found in old_route paths's list, + * add a new path to route paths list and merge + * nexthops in route->path->nh_list. + * Otherwise replace existing path's nh_list. + */ + if (o_path == NULL) { + ecmp_path = ospf6_path_dup(&route->path); + + /* Add a nh_list to new ecmp path */ + ospf6_copy_nexthops(ecmp_path->nh_list, + route->nh_list); + /* Merge nexthop to existing route's nh_list */ + ospf6_route_merge_nexthops(old_route, route); + + /* Update RIB/FIB */ + if (ospf6->route_table->hook_add) + (*ospf6->route_table->hook_add) + (old_route); + + /* Add the new path to route's path list */ + listnode_add_sort(old_route->paths, ecmp_path); + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&route->prefix, buf, + sizeof(buf)); + zlog_debug("%s: route %s another path added with nh %u, Paths %u", + __PRETTY_FUNCTION__, buf, + listcount(ecmp_path->nh_list), + old_route->paths ? + listcount(old_route->paths) + : 0); + } + } else { + for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, + nnode, nh)) { + for (ALL_LIST_ELEMENTS( + old_route->nh_list, + rnode, rnext, rnh)) { + if (!ospf6_nexthop_is_same(rnh, + nh)) + continue; + + listnode_delete( + old_route->nh_list, + rnh); + ospf6_nexthop_delete(rnh); + } + } + list_delete_all_node(o_path->nh_list); + ospf6_copy_nexthops(o_path->nh_list, + route->nh_list); + + /* Merge nexthop to existing route's nh_list */ + ospf6_route_merge_nexthops(old_route, + route); + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&route->prefix, + buf, sizeof(buf)); + zlog_debug("%s: existing route %s with effective nh count %u", + __PRETTY_FUNCTION__, buf, + old_route->nh_list ? + listcount(old_route->nh_list) + : 0); + } + + /* Update RIB/FIB */ + if (ospf6->route_table->hook_add) + (*ospf6->route_table->hook_add) + (old_route); + + } + /* Delete the new route its info added to existing + * route. + */ + ospf6_route_delete(route); + break; + } + } + + if (!route_found) { + /* Add new route to existing node in ospf6 route table. */ + ospf6_route_add(route, ospf6->route_table); + } +} + void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa) { struct ospf6_as_external_lsa *external; struct prefix asbr_id; - struct ospf6_route *asbr_entry, *route; + struct ospf6_route *asbr_entry, *route, *old; + struct ospf6_path *path; char buf[PREFIX2STR_BUFFER]; external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( @@ -245,12 +370,34 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa) ospf6_route_copy_nexthops(route, asbr_entry); + path = ospf6_path_dup(&route->path); + ospf6_copy_nexthops(path->nh_list, asbr_entry->nh_list); + listnode_add_sort(route->paths, path); + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { prefix2str(&route->prefix, buf, sizeof(buf)); - zlog_debug("AS-External route add: %s", buf); + zlog_debug("%s: AS-External %u route add %s cost %u(%u) nh %u", + __PRETTY_FUNCTION__, + (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1) + ? 1 : 2, buf, route->path.cost, + route->path.u.cost_e2, + listcount(route->nh_list)); + } + + old = ospf6_route_lookup(&route->prefix, ospf6->route_table); + if (!old) { + /* Add the new route to ospf6 instance route table. */ + ospf6_route_add(route, ospf6->route_table); + } else { + /* RFC 2328 16.4 (6) + * ECMP: Keep new equal preference path in current + * route's path list, update zebra with new effective + * list along with addition of ECMP path. + */ + ospf6_asbr_update_route_ecmp_path(old, route); } - ospf6_route_add(route, ospf6->route_table); } void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) @@ -291,16 +438,126 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa) nroute = ospf6_route_next(route); if (route->type != OSPF6_DEST_TYPE_NETWORK) continue; - if (route->path.origin.type != lsa->header->type) - continue; - if (route->path.origin.id != lsa->header->id) - continue; - if (route->path.origin.adv_router != lsa->header->adv_router) + + /* Route has multiple ECMP paths remove, + * matching path and update effective route's nh list. + */ + if (listcount(route->paths) > 1) { + struct listnode *anode, *anext; + struct listnode *nnode, *rnode, *rnext; + struct ospf6_nexthop *nh, *rnh; + struct ospf6_path *o_path; + bool nh_updated = false; + + /* Iterate all paths of route to find maching with LSA + * remove from route path list. If route->path is same, + * replace from paths list. + */ + for (ALL_LIST_ELEMENTS(route->paths, anode, anext, + o_path)) { + if (o_path->origin.type != lsa->header->type) + continue; + if (o_path->origin.id != lsa->header->id) + continue; + if (o_path->origin.adv_router != + lsa->header->adv_router) + continue; + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&prefix, buf, sizeof(buf)); + zlog_debug( + "%s: route %s path found with nh %u", + __PRETTY_FUNCTION__, buf, + listcount(o_path->nh_list)); + } + + /* Remove found path's nh_list from + * the route's nh_list. + */ + for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, + nnode, nh)) { + for (ALL_LIST_ELEMENTS(route->nh_list, + rnode, rnext, rnh)) { + if (!ospf6_nexthop_is_same(rnh, + nh)) + continue; + listnode_delete(route->nh_list, + rnh); + ospf6_nexthop_delete(rnh); + } + } + /* Delete the path from route's path list */ + listnode_delete(route->paths, o_path); + ospf6_path_free(o_path); + nh_updated = true; + } + + if (nh_updated) { + /* Iterate all paths and merge nexthop, + * unlesss any of the nexthop similar to + * ones deleted as part of path deletion. + */ + + for (ALL_LIST_ELEMENTS(route->paths, anode, + anext, o_path)) { + ospf6_merge_nexthops(route->nh_list, + o_path->nh_list); + } + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + prefix2str(&route->prefix, buf, + sizeof(buf)); + zlog_debug("%s: AS-External %u route %s update paths %u nh %u" + , __PRETTY_FUNCTION__, + (route->path.type == + OSPF6_PATH_TYPE_EXTERNAL1) + ? 1 : 2, buf, + listcount(route->paths), + listcount(route->nh_list)); + } + + /* Update RIB/FIB w/ effective nh_list */ + if (ospf6->route_table->hook_add) + (*ospf6->route_table->hook_add)(route); + + /* route's path is similar to lsa header, + * replace route's path with route's + * paths list head. + */ + if (route->path.origin.id == lsa->header->id && + route->path.origin.adv_router == + lsa->header->adv_router) { + struct ospf6_path *h_path; + + h_path = (struct ospf6_path *) + listgetdata(listhead(route->paths)); + route->path.origin.type = + h_path->origin.type; + route->path.origin.id = + h_path->origin.id; + route->path.origin.adv_router = + h_path->origin.adv_router; + } + } continue; + } else { + if (route->path.origin.type != lsa->header->type) + continue; + if (route->path.origin.id != lsa->header->id) + continue; + if (route->path.origin.adv_router != + lsa->header->adv_router) + continue; + } if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { prefix2str(&route->prefix, buf, sizeof(buf)); - zlog_debug("AS-External route remove: %s", buf); + zlog_debug("%s: AS-External %u route remove %s cost %u(%u) nh %u", + __PRETTY_FUNCTION__, + route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 + ? 1 : 2, buf, route->path.cost, + route->path.u.cost_e2, + listcount(route->nh_list)); } ospf6_route_remove(route, ospf6->route_table); } diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index 73053452e6..7f4665ac2b 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -93,5 +93,7 @@ extern void ospf6_asbr_send_externals_to_area(struct ospf6_area *); extern int config_write_ospf6_debug_asbr(struct vty *vty); extern void install_element_ospf6_debug_asbr(void); +extern void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, + struct ospf6_route *route); #endif /* OSPF6_ASBR_H */ diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 98f93b06e6..fc6c46c7e7 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -1008,6 +1008,103 @@ DEFUN (show_ipv6_ospf6_interface, return CMD_SUCCESS; } +static int ospf6_interface_show_traffic(struct vty *vty, + uint32_t vrf_id, + struct interface *intf_ifp, + int display_once) +{ + struct interface *ifp; + struct vrf *vrf = NULL; + struct ospf6_interface *oi = NULL; + + vrf = vrf_lookup_by_id(vrf_id); + + if (!display_once) { + vty_out(vty, "\n"); + vty_out(vty, "%-12s%-17s%-17s%-17s%-17s%-17s\n", + "Interface", " HELLO", " DB-Desc", " LS-Req", + " LS-Update", " LS-Ack"); + vty_out(vty, "%-10s%-18s%-18s%-17s%-17s%-17s\n", "", + " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx"); + vty_out(vty, + "--------------------------------------------------------------------------------------------\n"); + } + + if (intf_ifp == NULL) { + FOR_ALL_INTERFACES (vrf, ifp) { + if (ifp->info) + oi = (struct ospf6_interface *)ifp->info; + else + continue; + + vty_out(vty, + "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u\n", + oi->interface->name, oi->hello_in, + oi->hello_out, + oi->db_desc_in, oi->db_desc_out, + oi->ls_req_in, oi->ls_req_out, + oi->ls_upd_in, oi->ls_upd_out, + oi->ls_ack_in, oi->ls_ack_out); + } + } else { + oi = intf_ifp->info; + if (oi == NULL) + return CMD_WARNING; + + vty_out(vty, + "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u\n", + oi->interface->name, oi->hello_in, + oi->hello_out, + oi->db_desc_in, oi->db_desc_out, + oi->ls_req_in, oi->ls_req_out, + oi->ls_upd_in, oi->ls_upd_out, + oi->ls_ack_in, oi->ls_ack_out); + } + + return CMD_SUCCESS; +} + +/* show interface */ +DEFUN (show_ipv6_ospf6_interface_traffic, + show_ipv6_ospf6_interface_traffic_cmd, + "show ipv6 ospf6 interface traffic [IFNAME]", + SHOW_STR + IP6_STR + OSPF6_STR + INTERFACE_STR + "Protocol Packet counters\n" + IFNAME_STR) +{ + int idx_ifname = 0; + int display_once = 0; + char *intf_name = NULL; + struct interface *ifp = NULL; + + if (argv_find(argv, argc, "IFNAME", &idx_ifname)) { + intf_name = argv[idx_ifname]->arg; + ifp = if_lookup_by_name(intf_name, VRF_DEFAULT); + if (ifp == NULL) { + vty_out(vty, + "No such Interface: %s\n", + intf_name); + return CMD_WARNING; + } + if (ifp->info == NULL) { + vty_out(vty, + " OSPF not enabled on this interface %s\n", + intf_name); + return 0; + } + } + + ospf6_interface_show_traffic(vty, VRF_DEFAULT, ifp, + display_once); + + + return CMD_SUCCESS; +} + + DEFUN (show_ipv6_ospf6_interface_ifname_prefix, show_ipv6_ospf6_interface_ifname_prefix_cmd, "show ipv6 ospf6 interface IFNAME prefix [<X:X::X:X|X:X::X:X/M>] [<match|detail>]", @@ -1841,6 +1938,8 @@ void ospf6_interface_init(void) install_element(VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd); install_element(VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd); + install_element(VIEW_NODE, + &show_ipv6_ospf6_interface_traffic_cmd); install_element(INTERFACE_NODE, &ipv6_ospf6_cost_cmd); install_element(INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd); diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 3844132366..b67d9a9f2e 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -117,6 +117,19 @@ struct ospf6_interface { /* BFD information */ void *bfd_info; + /* Statistics Fields */ + u_int32_t hello_in; + u_int32_t hello_out; + u_int32_t db_desc_in; + u_int32_t db_desc_out; + u_int32_t ls_req_in; + u_int32_t ls_req_out; + u_int32_t ls_upd_in; + u_int32_t ls_upd_out; + u_int32_t ls_ack_in; + u_int32_t ls_ack_out; + u_int32_t discarded; + QOBJ_FIELDS }; DECLARE_QOBJ_TYPE(ospf6_interface) diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index b1d940952c..77653ea33f 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -1404,7 +1404,8 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa) if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) { prefix2str(&route->prefix, buf, sizeof(buf)); - zlog_debug(" route %s add", buf); + zlog_debug(" route %s add with nh count %u", buf, + listcount(route->nh_list)); } ospf6_route_add(route, oa->route_table); diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 82f75b153e..cca4616c16 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -191,7 +191,7 @@ int ospf6_lsa_is_changed(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2) /* ospf6 age functions */ /* calculate birth */ -static void ospf6_lsa_age_set(struct ospf6_lsa *lsa) +void ospf6_lsa_age_set(struct ospf6_lsa *lsa) { struct timeval now; diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 3536d33d19..db446a3287 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -252,5 +252,6 @@ extern void ospf6_lsa_terminate(void); extern int config_write_ospf6_debug_lsa(struct vty *vty); extern void install_element_ospf6_debug_lsa(void); +extern void ospf6_lsa_age_set(struct ospf6_lsa *lsa); #endif /* OSPF6_LSA_H */ diff --git a/ospf6d/ospf6_memory.c b/ospf6d/ospf6_memory.c index 56c232d6da..1c3523b43d 100644 --- a/ospf6d/ospf6_memory.c +++ b/ospf6d/ospf6_memory.c @@ -41,4 +41,5 @@ DEFINE_MTYPE(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex") DEFINE_MTYPE(OSPF6D, OSPF6_SPFTREE, "OSPF6 SPF tree") DEFINE_MTYPE(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop") DEFINE_MTYPE(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info") +DEFINE_MTYPE(OSPF6D, OSPF6_PATH, "OSPF6 Path") DEFINE_MTYPE(OSPF6D, OSPF6_OTHER, "OSPF6 other") diff --git a/ospf6d/ospf6_memory.h b/ospf6d/ospf6_memory.h index fe72ee3669..548af5e321 100644 --- a/ospf6d/ospf6_memory.h +++ b/ospf6d/ospf6_memory.h @@ -40,6 +40,7 @@ DECLARE_MTYPE(OSPF6_VERTEX) DECLARE_MTYPE(OSPF6_SPFTREE) DECLARE_MTYPE(OSPF6_NEXTHOP) DECLARE_MTYPE(OSPF6_EXTERNAL_INFO) +DECLARE_MTYPE(OSPF6_PATH) DECLARE_MTYPE(OSPF6_OTHER) #endif /* _QUAGGA_OSPF6_MEMORY_H */ diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 1307b374a5..d76438ea50 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -321,6 +321,8 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, backupseen++; } + oi->hello_in++; + /* Execute neighbor events */ thread_execute(master, hello_received, on, 0); if (twoway) @@ -776,6 +778,8 @@ static void ospf6_dbdesc_recv(struct in6_addr *src, struct in6_addr *dst, dbdesc->reserved2 = 0; } + oi->db_desc_in++; + if (ntohl(oh->router_id) < ntohl(ospf6->router_id)) ospf6_dbdesc_recv_master(oh, on); else if (ntohl(ospf6->router_id) < ntohl(oh->router_id)) @@ -811,6 +815,8 @@ static void ospf6_lsreq_recv(struct in6_addr *src, struct in6_addr *dst, return; } + oi->ls_req_in++; + /* Process each request */ for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header)); p + sizeof(struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END(oh); @@ -1370,6 +1376,8 @@ static void ospf6_lsupdate_recv(struct in6_addr *src, struct in6_addr *dst, lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh + sizeof(struct ospf6_header)); + oi->ls_upd_in++; + /* Process LSAs */ for (p = (char *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate)); p < OSPF6_MESSAGE_END(oh) @@ -1407,6 +1415,8 @@ static void ospf6_lsack_recv(struct in6_addr *src, struct in6_addr *dst, return; } + oi->ls_ack_in++; + for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header)); p + sizeof(struct ospf6_lsa_header) <= OSPF6_MESSAGE_END(oh); p += sizeof(struct ospf6_lsa_header)) { @@ -1777,6 +1787,8 @@ int ospf6_hello_send(struct thread *thread) oh->type = OSPF6_MESSAGE_TYPE_HELLO; oh->length = htons(p - sendbuf); + oi->hello_out++; + ospf6_send(oi->linklocal_addr, &allspfrouters6, oi, oh); return 0; } @@ -1852,6 +1864,8 @@ int ospf6_dbdesc_send(struct thread *thread) else dst = &on->linklocal_addr; + on->ospf6_if->db_desc_out++; + ospf6_send(on->ospf6_if->linklocal_addr, dst, on->ospf6_if, oh); return 0; @@ -1955,6 +1969,8 @@ int ospf6_lsreq_send(struct thread *thread) oh->type = OSPF6_MESSAGE_TYPE_LSREQ; oh->length = htons(p - sendbuf); + on->ospf6_if->ls_req_out++; + if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) ospf6_send(on->ospf6_if->linklocal_addr, &allspfrouters6, on->ospf6_if, oh); @@ -1979,6 +1995,8 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on, { if (on) { + on->ospf6_if->ls_upd_out++; + if ((on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) || (on->ospf6_if->state == OSPF6_INTERFACE_DR) || (on->ospf6_if->state == OSPF6_INTERFACE_BDR)) { @@ -1989,6 +2007,9 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on, &on->linklocal_addr, on->ospf6_if, oh); } } else if (oi) { + + oi->ls_upd_out++; + if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT) || (oi->state == OSPF6_INTERFACE_DR) || (oi->state == OSPF6_INTERFACE_BDR)) { @@ -2185,8 +2206,11 @@ int ospf6_lsupdate_send_interface(struct thread *thread) lsupdate->lsa_number = htonl(lsa_cnt); ospf6_send_lsupdate(NULL, oi, oh); - zlog_debug("%s: LSUpdate length %d", - __PRETTY_FUNCTION__, ntohs(oh->length)); + if (IS_OSPF6_DEBUG_MESSAGE( + OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) + zlog_debug("%s: LSUpdate length %d", + __PRETTY_FUNCTION__, + ntohs(oh->length)); memset(sendbuf, 0, iobuflen); oh = (struct ospf6_header *)sendbuf; @@ -2263,6 +2287,8 @@ int ospf6_lsack_send_neighbor(struct thread *thread) oh->type = OSPF6_MESSAGE_TYPE_LSACK; oh->length = htons(p - sendbuf); + on->ospf6_if->ls_ack_out++; + ospf6_send(on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); @@ -2288,6 +2314,8 @@ int ospf6_lsack_send_neighbor(struct thread *thread) oh->type = OSPF6_MESSAGE_TYPE_LSACK; oh->length = htons(p - sendbuf); + on->ospf6_if->ls_ack_out++; + ospf6_send(on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); } diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 281757222d..735b28a693 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -215,7 +215,7 @@ void ospf6_copy_nexthops(struct list *dst, struct list *src) if (ospf6_nexthop_is_set(nh)) { nh_new = ospf6_nexthop_create(); ospf6_nexthop_copy(nh_new, nh); - listnode_add(dst, nh_new); + listnode_add_sort(dst, nh_new); } } } @@ -231,7 +231,7 @@ void ospf6_merge_nexthops(struct list *dst, struct list *src) if (!ospf6_route_find_nexthop(dst, nh)) { nh_new = ospf6_nexthop_create(); ospf6_nexthop_copy(nh_new, nh); - listnode_add(dst, nh_new); + listnode_add_sort(dst, nh_new); } } } @@ -338,7 +338,7 @@ int ospf6_route_get_first_nh_index(struct ospf6_route *route) return (-1); } -static int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b) +int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b) { if (a->ifindex < b->ifindex) return -1; @@ -351,6 +351,36 @@ static int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b) return 0; } +static int ospf6_path_cmp(struct ospf6_path *a, struct ospf6_path *b) +{ + if (a->origin.adv_router < b->origin.adv_router) + return -1; + else if (a->origin.adv_router > b->origin.adv_router) + return 1; + else + return 0; +} + +void ospf6_path_free(struct ospf6_path *op) +{ + if (op->nh_list) + list_delete_and_null(&op->nh_list); + XFREE(MTYPE_OSPF6_PATH, op); +} + +struct ospf6_path *ospf6_path_dup(struct ospf6_path *path) +{ + struct ospf6_path *new; + + new = XCALLOC(MTYPE_OSPF6_PATH, sizeof(struct ospf6_path)); + memcpy(new, path, sizeof(struct ospf6_path)); + new->nh_list = list_new(); + new->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp; + new->nh_list->del = (void (*) (void *))ospf6_nexthop_delete; + + return new; +} + struct ospf6_route *ospf6_route_create(void) { struct ospf6_route *route; @@ -358,6 +388,9 @@ struct ospf6_route *ospf6_route_create(void) route->nh_list = list_new(); route->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp; route->nh_list->del = (void (*) (void *))ospf6_nexthop_delete; + route->paths = list_new(); + route->paths->cmp = (int (*)(void *, void *))ospf6_path_cmp; + route->paths->del = (void (*)(void *))ospf6_path_free; return route; } @@ -366,6 +399,8 @@ void ospf6_route_delete(struct ospf6_route *route) if (route) { if (route->nh_list) list_delete_and_null(&route->nh_list); + if (route->paths) + list_delete_and_null(&route->paths); XFREE(MTYPE_OSPF6_ROUTE, route); } } @@ -464,7 +499,13 @@ ospf6_route_lookup_identical(struct ospf6_route *route, for (target = ospf6_route_lookup(&route->prefix, table); target; target = target->next) { - if (ospf6_route_is_identical(target, route)) + if (target->type == route->type && + (memcmp(&target->prefix, &route->prefix, + sizeof(struct prefix)) == 0) && + target->path.type == route->path.type && + target->path.cost == route->path.cost && + target->path.u.cost_e2 == route->path.u.cost_e2 && + ospf6_route_cmp_nexthops(target, route) == 0) return target; } return NULL; @@ -1083,6 +1124,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route) vty_out(vty, "Metric: %d (%d)\n", route->path.cost, route->path.u.cost_e2); + vty_out(vty, "Paths count: %u\n", route->paths->count); vty_out(vty, "Nexthop count: %u\n", route->nh_list->count); /* Nexthops */ vty_out(vty, "Nexthop:\n"); diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index 9eacadbdb7..b759828c39 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -96,6 +96,9 @@ struct ospf6_path { u_int32_t cost_config; } u; u_int32_t tag; + + /* nh list for this path */ + struct list *nh_list; }; #define OSPF6_PATH_TYPE_NONE 0 @@ -149,6 +152,9 @@ struct ospf6_route { /* path */ struct ospf6_path path; + /* List of Paths. */ + struct list *paths; + /* nexthop */ struct list *nh_list; }; @@ -256,6 +262,7 @@ extern void ospf6_linkstate_prefix2str(struct prefix *prefix, char *buf, int size); extern struct ospf6_nexthop *ospf6_nexthop_create(void); +extern int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b); extern void ospf6_nexthop_delete(struct ospf6_nexthop *nh); extern void ospf6_clear_nexthops(struct list *nh_list); extern int ospf6_num_nexthops(struct list *nh_list); @@ -331,5 +338,7 @@ extern int config_write_ospf6_debug_route(struct vty *vty); extern void install_element_ospf6_debug_route(void); extern void ospf6_route_init(void); extern void ospf6_clean(void); +extern void ospf6_path_free(struct ospf6_path *op); +extern struct ospf6_path *ospf6_path_dup(struct ospf6_path *path); #endif /* OSPF6_ROUTE_H */ diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 340d90159f..17ce1771e2 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -145,6 +145,7 @@ static struct ospf6_vertex *ospf6_vertex_create(struct ospf6_lsa *lsa) v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END(lsa->header) + 3); v->nh_list = list_new(); + v->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp; v->nh_list->del = (void (*) (void *))ospf6_nexthop_delete; v->parent = NULL; @@ -162,21 +163,20 @@ static void ospf6_vertex_delete(struct ospf6_vertex *v) } static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc, - struct ospf6_vertex *v, - uint32_t link_id) + struct ospf6_vertex *v) { - struct ospf6_lsa *lsa; + struct ospf6_lsa *lsa = NULL; u_int16_t type = 0; u_int32_t id = 0, adv_router = 0; if (VERTEX_IS_TYPE(NETWORK, v)) { type = htons(OSPF6_LSTYPE_ROUTER); - id = link_id; + id = htonl(0); adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc); } else { if (ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, lsdesc)) { type = htons(OSPF6_LSTYPE_ROUTER); - id = link_id; + id = htonl(0); adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc); } else if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, lsdesc)) { type = htons(OSPF6_LSTYPE_NETWORK); @@ -185,19 +185,22 @@ static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc, } } - lsa = ospf6_lsdb_lookup(type, id, adv_router, v->area->lsdb); - + if (type == htons(OSPF6_LSTYPE_NETWORK)) + lsa = ospf6_lsdb_lookup(type, id, adv_router, v->area->lsdb); + else + lsa = ospf6_create_single_router_lsa(v->area, v->area->lsdb, + adv_router); if (IS_OSPF6_DEBUG_SPF(PROCESS)) { char ibuf[16], abuf[16]; inet_ntop(AF_INET, &id, ibuf, sizeof(ibuf)); inet_ntop(AF_INET, &adv_router, abuf, sizeof(abuf)); if (lsa) - zlog_debug(" Link to: %s , V %s id %u", lsa->name, - v->name, link_id); + zlog_debug(" Link to: %s len %u, V %s", lsa->name, + ntohs(lsa->header->length), v->name); else - zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA , V %s id %u", + zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA , V %s", ospf6_lstype_name(type), ibuf, abuf, - v->name, link_id); + v->name); } return lsa; @@ -460,17 +463,14 @@ void ospf6_spf_calculation(u_int32_t router_id, struct ospf6_vertex *root, *v, *w; int size; caddr_t lsdesc; - struct ospf6_lsa *lsa, *self_rtr_lsa = NULL, *rtr_lsa = NULL; - const struct route_node *end = NULL; + struct ospf6_lsa *lsa; struct in6_addr address; - struct ospf6_lsdb *lsdb = NULL; ospf6_spf_table_finish(result_table); /* Install the calculating router itself as the root of the SPF tree */ /* construct root vertex */ - lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_ROUTER), htonl(0), router_id, - oa->lsdb_self); + lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id); if (lsa == NULL) { if (IS_OSPF6_DEBUG_SPF(PROCESS)) zlog_debug("%s: No router LSA for area %s\n", __func__, @@ -478,8 +478,6 @@ void ospf6_spf_calculation(u_int32_t router_id, return; } - self_rtr_lsa = lsa; - /* initialize */ candidate_list = pqueue_create(); candidate_list->cmp = ospf6_vertex_cmp; @@ -509,139 +507,63 @@ void ospf6_spf_calculation(u_int32_t router_id, && ospf6_router_is_stub_router(v->lsa))) continue; - if (VERTEX_IS_TYPE(ROUTER, v)) { - /* First fetch root Router LSAs from lsdb_self */ - if (v->lsa == self_rtr_lsa) - lsdb = oa->lsdb_self; - else - lsdb = v->area->lsdb; - - /* Iterating multiple ROUTER LSAs from same adv router - * with different Link State ID */ - end = ospf6_lsdb_head(lsdb, 2, - htons(OSPF6_LSTYPE_ROUTER), - v->lsa->header->adv_router, - &rtr_lsa); - while (rtr_lsa) { - if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug("%s: Next LSA %s to process" - ,__PRETTY_FUNCTION__, - rtr_lsa->name); - size = sizeof(struct ospf6_router_lsdesc); - /* For each LS description in the just-added vertex V's LSA */ - for (lsdesc = OSPF6_LSA_HEADER_END( - rtr_lsa->header) + 4; - lsdesc + size <= OSPF6_LSA_END( - rtr_lsa->header); - lsdesc += size) { - lsa = ospf6_lsdesc_lsa(lsdesc, v, - rtr_lsa->header->id); - if (lsa == NULL) - continue; - - if (OSPF6_LSA_IS_MAXAGE(lsa)) - continue; - - if (!ospf6_lsdesc_backlink(lsa, - lsdesc, v)) - continue; - - w = ospf6_vertex_create(lsa); - w->area = oa; - w->parent = v; - w->link_id = rtr_lsa->header->id; - - if (VERTEX_IS_TYPE(ROUTER, v)) { - w->cost = v->cost - + ROUTER_LSDESC_GET_METRIC(lsdesc); - w->hops = - v->hops - + (VERTEX_IS_TYPE(NETWORK, w) - ? 0 : 1); - } else /* NETWORK */ { - w->cost = v->cost; - w->hops = v->hops + 1; - } - - /* nexthop calculation */ - if (w->hops == 0) - ospf6_add_nexthop(w->nh_list, - ROUTER_LSDESC_GET_IFID(lsdesc) - , NULL); - else if (w->hops == 1 && v->hops == 0) - ospf6_nexthop_calc(w, v, lsdesc); - else { - ospf6_copy_nexthops(w->nh_list, - v->nh_list); - } - - /* add new candidate to the candidate_list */ - if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug( - " New candidate: %s hops %d cost %d", - w->name, w->hops, - w->cost); - pqueue_enqueue(w, candidate_list); - } - /* Fetch next Link state ID Router LSA */ - rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); - } - } else { - /* For each LS description in the just-added vertex V's LSA */ - size = (VERTEX_IS_TYPE(ROUTER, v) - ? sizeof(struct ospf6_router_lsdesc) - : sizeof(struct ospf6_network_lsdesc)); - for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4; - lsdesc + size <= OSPF6_LSA_END(v->lsa->header); - lsdesc += size) { - lsa = ospf6_lsdesc_lsa(lsdesc, v, v->link_id); - if (lsa == NULL) - continue; - - if (OSPF6_LSA_IS_MAXAGE(lsa)) - continue; - - if (!ospf6_lsdesc_backlink(lsa, lsdesc, v)) - continue; - - w = ospf6_vertex_create(lsa); - w->area = oa; - w->parent = v; - if (VERTEX_IS_TYPE(ROUTER, v)) { - w->cost = v->cost + /* For each LS description in the just-added vertex V's LSA */ + size = (VERTEX_IS_TYPE(ROUTER, v) + ? sizeof(struct ospf6_router_lsdesc) + : sizeof(struct ospf6_network_lsdesc)); + for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4; + lsdesc + size <= OSPF6_LSA_END(v->lsa->header); + lsdesc += size) { + lsa = ospf6_lsdesc_lsa(lsdesc, v); + if (lsa == NULL) + continue; + + if (OSPF6_LSA_IS_MAXAGE(lsa)) + continue; + + if (!ospf6_lsdesc_backlink(lsa, lsdesc, v)) + continue; + + w = ospf6_vertex_create(lsa); + w->area = oa; + w->parent = v; + if (VERTEX_IS_TYPE(ROUTER, v)) { + w->cost = v->cost + ROUTER_LSDESC_GET_METRIC(lsdesc); - w->hops = - v->hops - + (VERTEX_IS_TYPE(NETWORK, w) ? - 0 : 1); - } else /* NETWORK */ { - w->cost = v->cost; - w->hops = v->hops + 1; - } - - /* nexthop calculation */ - if (w->hops == 0) - ospf6_add_nexthop(w->nh_list, + w->hops = + v->hops + + (VERTEX_IS_TYPE(NETWORK, w) ? 0 : 1); + } else { + /* NETWORK */ + w->cost = v->cost; + w->hops = v->hops + 1; + } + + /* nexthop calculation */ + if (w->hops == 0) + ospf6_add_nexthop( + w->nh_list, ROUTER_LSDESC_GET_IFID(lsdesc), NULL); - else if (w->hops == 1 && v->hops == 0) - ospf6_nexthop_calc(w, v, lsdesc); - else { - ospf6_copy_nexthops(w->nh_list, - v->nh_list); - } - - /* add new candidate to the candidate_list */ - if (IS_OSPF6_DEBUG_SPF(PROCESS)) - zlog_debug( + else if (w->hops == 1 && v->hops == 0) + ospf6_nexthop_calc(w, v, lsdesc); + else + ospf6_copy_nexthops(w->nh_list, v->nh_list); + + + /* add new candidate to the candidate_list */ + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug( " New candidate: %s hops %d cost %d", w->name, w->hops, w->cost); - pqueue_enqueue(w, candidate_list); - } + pqueue_enqueue(w, candidate_list); } } + pqueue_delete(candidate_list); + ospf6_remove_temp_router_lsa(oa); + oa->spf_calculation++; } @@ -1028,3 +950,153 @@ void ospf6_spf_init(void) install_element(OSPF6_NODE, &ospf6_timers_throttle_spf_cmd); install_element(OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd); } + +/* Create Aggregated Large Router-LSA from multiple Link-State IDs + * RFC 5340 A 4.3: + * When more than one router-LSA is received from a single router, + * the links are processed as if concatenated into a single LSA.*/ +struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area, + struct ospf6_lsdb *lsdb, + uint32_t adv_router) +{ + struct ospf6_lsa *lsa = NULL; + struct ospf6_lsa *rtr_lsa = NULL; + struct ospf6_lsa_header *lsa_header = NULL; + uint8_t *new_header = NULL; + const struct route_node *end = NULL; + uint16_t lsa_length, total_lsa_length = 0, num_lsa = 0; + u_int16_t type = 0; + char ifbuf[16]; + uint32_t interface_id; + caddr_t lsd; + + lsa_length = sizeof(struct ospf6_lsa_header) + + sizeof(struct ospf6_router_lsa); + total_lsa_length = lsa_length; + type = htons(OSPF6_LSTYPE_ROUTER); + + /* First check Aggregated LSA formed earlier in Cache */ + lsa = ospf6_lsdb_lookup(type, htonl(0), adv_router, + area->temp_router_lsa_lsdb); + if (lsa) + return lsa; + + inet_ntop(AF_INET, &adv_router, ifbuf, sizeof(ifbuf)); + + /* Determine total LSA length from all link state ids */ + end = ospf6_lsdb_head(lsdb, 2, type, adv_router, &rtr_lsa); + while (rtr_lsa) { + lsa = rtr_lsa; + if (OSPF6_LSA_IS_MAXAGE(rtr_lsa)) { + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + continue; + } + lsa_header = (struct ospf6_lsa_header *) rtr_lsa->header; + total_lsa_length += (ntohs(lsa_header->length) + - lsa_length); + num_lsa++; + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + } + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug("%s: adv_router %s num_lsa %u to convert.", + __PRETTY_FUNCTION__, ifbuf, num_lsa); + if (num_lsa == 1) + return lsa; + + if (num_lsa == 0) { + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug("%s: adv_router %s not found in LSDB.", + __PRETTY_FUNCTION__, ifbuf); + return NULL; + } + + /* Allocate memory for this LSA */ + new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, total_lsa_length); + if (!new_header) + return NULL; + + /* LSA information structure */ + lsa = (struct ospf6_lsa *)XCALLOC(MTYPE_OSPF6_LSA, + sizeof(struct ospf6_lsa)); + if (!lsa) { + free(new_header); + return NULL; + } + + lsa->header = (struct ospf6_lsa_header *)new_header; + + lsa->lsdb = area->temp_router_lsa_lsdb; + + /* Fill Larger LSA Payload */ + end = ospf6_lsdb_head(lsdb, 2, type, adv_router, &rtr_lsa); + if (rtr_lsa) { + if (!OSPF6_LSA_IS_MAXAGE(rtr_lsa)) { + /* Append first Link State ID LSA */ + lsa_header = (struct ospf6_lsa_header *)rtr_lsa->header; + memcpy(new_header, lsa_header, + ntohs(lsa_header->length)); + /* Assign new lsa length as aggregated length. */ + ((struct ospf6_lsa_header *)new_header)->length = + htons(total_lsa_length); + new_header += ntohs(lsa_header->length); + num_lsa--; + } + } + + /* Print LSA Name */ + ospf6_lsa_printbuf(lsa, lsa->name, sizeof(lsa->name)); + + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + while (rtr_lsa) { + if (OSPF6_LSA_IS_MAXAGE(rtr_lsa)) { + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + continue; + } + + if (IS_OSPF6_DEBUG_SPF(PROCESS)) { + lsd = OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4; + interface_id = ROUTER_LSDESC_GET_IFID(lsd); + inet_ntop(AF_INET, &interface_id, ifbuf, sizeof(ifbuf)); + zlog_debug("%s: Next Router LSA %s to aggreat with len %u interface_id %s", + __PRETTY_FUNCTION__, rtr_lsa->name, + ntohs(lsa_header->length), ifbuf); + } + + /* Append Next Link State ID LSA */ + lsa_header = (struct ospf6_lsa_header *) rtr_lsa->header; + memcpy(new_header, (OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4), + (ntohs(lsa_header->length) - lsa_length)); + new_header += (ntohs(lsa_header->length) - lsa_length); + num_lsa--; + + rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); + } + + /* Calculate birth of this lsa */ + ospf6_lsa_age_set(lsa); + + /* Store Aggregated LSA into area temp lsdb */ + ospf6_lsdb_add(lsa, area->temp_router_lsa_lsdb); + + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug("%s: LSA %s id %u type 0%x len %u num_lsa %u", + __PRETTY_FUNCTION__, lsa->name, + ntohl(lsa->header->id), ntohs(lsa->header->type), + ntohs(lsa->header->length), num_lsa); + + return lsa; +} + +void ospf6_remove_temp_router_lsa(struct ospf6_area *area) +{ + struct ospf6_lsa *lsa = NULL; + + for (ALL_LSDB(area->temp_router_lsa_lsdb, lsa)) { + if (IS_OSPF6_DEBUG_SPF(PROCESS)) + zlog_debug("%s Remove LSA %s lsa->lock %u lsdb count %u", + __PRETTY_FUNCTION__, + lsa->name, lsa->lock, + area->temp_router_lsa_lsdb->count); + ospf6_lsdb_remove(lsa, area->temp_router_lsa_lsdb); + } +} diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h index dbb88d12ba..f294b8d34f 100644 --- a/ospf6d/ospf6_spf.h +++ b/ospf6d/ospf6_spf.h @@ -149,5 +149,9 @@ extern int config_write_ospf6_debug_spf(struct vty *vty); extern void install_element_ospf6_debug_spf(void); extern void ospf6_spf_init(void); extern void ospf6_spf_reason_string(unsigned int reason, char *buf, int size); +extern struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area, + struct ospf6_lsdb *lsdb, + uint32_t adv_router); +extern void ospf6_remove_temp_router_lsa(struct ospf6_area *area); #endif /* OSPF6_SPF_H */ diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index e0844765d3..5d1144335b 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -95,6 +95,13 @@ static void ospf6_top_route_hook_remove(struct ospf6_route *route) static void ospf6_top_brouter_hook_add(struct ospf6_route *route) { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + char buf[PREFIX2STR_BUFFER]; + + prefix2str(&route->prefix, buf, sizeof(buf)); + zlog_debug("%s: brouter %s add with nh count %u", + __PRETTY_FUNCTION__, buf, listcount(route->nh_list)); + } ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix)); ospf6_asbr_lsentry_add(route); ospf6_abr_originate_summary(route); @@ -102,6 +109,13 @@ static void ospf6_top_brouter_hook_add(struct ospf6_route *route) static void ospf6_top_brouter_hook_remove(struct ospf6_route *route) { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) { + char buf[PREFIX2STR_BUFFER]; + + prefix2str(&route->prefix, buf, sizeof(buf)); + zlog_debug("%s: brouter %s del with nh count %u", + __PRETTY_FUNCTION__, buf, listcount(route->nh_list)); + } route->flag |= OSPF6_ROUTE_REMOVE; ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix)); ospf6_asbr_lsentry_remove(route); diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index cc87c499ee..2a419ddfc6 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -337,6 +337,7 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request) memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF6; api.safi = SAFI_UNICAST; api.prefix = *dest; @@ -387,6 +388,7 @@ void ospf6_zebra_add_discard(struct ospf6_route *request) if (!CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) { memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF6; api.safi = SAFI_UNICAST; api.prefix = *dest; @@ -420,6 +422,7 @@ void ospf6_zebra_delete_discard(struct ospf6_route *request) if (CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) { memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; + api.nh_vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF6; api.safi = SAFI_UNICAST; api.prefix = *dest; diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index d28d9dd064..bbc1cc18f6 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -360,6 +360,49 @@ DEFUN (show_ipv6_ospf6_database_router, return CMD_SUCCESS; } +DEFUN_HIDDEN (show_ipv6_ospf6_database_aggr_router, + show_ipv6_ospf6_database_aggr_router_cmd, + "show ipv6 ospf6 database aggr adv-router A.B.C.D", + SHOW_STR + IPV6_STR + OSPF6_STR + "Display Link state database\n" + "Aggregated Router LSA\n" + "Search by Advertising Router\n" + "Specify Advertising Router as IPv4 address notation\n") +{ + int level = OSPF6_LSDB_SHOW_LEVEL_DETAIL; + uint16_t type = htons(OSPF6_LSTYPE_ROUTER); + int idx_ipv4 = 6; + struct listnode *i; + struct ospf6 *o = ospf6; + struct ospf6_area *oa; + struct ospf6_lsdb *lsdb; + uint32_t adv_router = 0; + + inet_pton(AF_INET, argv[idx_ipv4]->arg, &adv_router); + + for (ALL_LIST_ELEMENTS_RO(o->area_list, i, oa)) { + if (adv_router == o->router_id) + lsdb = oa->lsdb_self; + else + lsdb = oa->lsdb; + if (ospf6_create_single_router_lsa(oa, lsdb, + adv_router) == NULL) { + vty_out(vty, "Adv router is not found in LSDB."); + return CMD_SUCCESS; + } + ospf6_lsdb_show(vty, level, &type, NULL, NULL, + oa->temp_router_lsa_lsdb); + /* Remove the temp cache */ + ospf6_remove_temp_router_lsa(oa); + } + + vty_out(vty, "\n"); + + return CMD_SUCCESS; +} + DEFUN (show_ipv6_ospf6_database_type_id, show_ipv6_ospf6_database_type_id_cmd, "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> linkstate-id A.B.C.D [<detail|dump|internal>]", @@ -1219,6 +1262,7 @@ void ospf6_init(void) install_element( VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd); + install_element(VIEW_NODE, &show_ipv6_ospf6_database_aggr_router_cmd); /* Make ospf protocol socket. */ ospf6_serv_sock(); |
