diff options
Diffstat (limited to 'ospf6d/ospf6_top.c')
-rw-r--r-- | ospf6d/ospf6_top.c | 2373 |
1 files changed, 2373 insertions, 0 deletions
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c new file mode 100644 index 0000000..216837d --- /dev/null +++ b/ospf6d/ospf6_top.c @@ -0,0 +1,2373 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2003 Yasuhiro Ohara + */ + +#include <zebra.h> + +#include "log.h" +#include "memory.h" +#include "vty.h" +#include "linklist.h" +#include "prefix.h" +#include "table.h" +#include "frrevent.h" +#include "command.h" +#include "defaults.h" +#include "lib/json.h" +#include "lib_errors.h" + +#include "ospf6_proto.h" +#include "ospf6_message.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_route.h" +#include "ospf6_zebra.h" + +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_interface.h" +#include "ospf6_neighbor.h" +#include "ospf6_network.h" + +#include "ospf6_flood.h" +#include "ospf6_asbr.h" +#include "ospf6_abr.h" +#include "ospf6_intra.h" +#include "ospf6_spf.h" +#include "ospf6d.h" +#include "ospf6_gr.h" +#include "lib/json.h" +#include "ospf6_nssa.h" +#include "ospf6_auth_trailer.h" + +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_TOP, "OSPF6 top"); + +DEFINE_QOBJ_TYPE(ospf6); + +FRR_CFG_DEFAULT_BOOL(OSPF6_LOG_ADJACENCY_CHANGES, + { .val_bool = true, .match_profile = "datacenter", }, + { .val_bool = false }, +); + +#include "ospf6d/ospf6_top_clippy.c" + +/* global ospf6d variable */ +static struct ospf6_master ospf6_master; +struct ospf6_master *om6; + +static void ospf6_disable(struct ospf6 *o); + +static void ospf6_add(struct ospf6 *ospf6) +{ + listnode_add(om6->ospf6, ospf6); +} + +static void ospf6_del(struct ospf6 *ospf6) +{ + listnode_delete(om6->ospf6, ospf6); +} + +const char *ospf6_vrf_id_to_name(vrf_id_t vrf_id) +{ + struct vrf *vrf = vrf_lookup_by_id(vrf_id); + + return vrf ? vrf->name : "NIL"; +} + +/* Link OSPF instance to VRF. */ +void ospf6_vrf_link(struct ospf6 *ospf6, struct vrf *vrf) +{ + ospf6->vrf_id = vrf->vrf_id; + if (vrf->info != (void *)ospf6) + vrf->info = (void *)ospf6; +} + +/* Unlink OSPF instance from VRF. */ +void ospf6_vrf_unlink(struct ospf6 *ospf6, struct vrf *vrf) +{ + if (vrf->info == (void *)ospf6) + vrf->info = NULL; + ospf6->vrf_id = VRF_UNKNOWN; +} + +struct ospf6 *ospf6_lookup_by_vrf_id(vrf_id_t vrf_id) +{ + struct vrf *vrf = NULL; + + vrf = vrf_lookup_by_id(vrf_id); + if (!vrf) + return NULL; + return (vrf->info) ? (struct ospf6 *)vrf->info : NULL; +} + +struct ospf6 *ospf6_lookup_by_vrf_name(const char *name) +{ + struct ospf6 *o = NULL; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, o)) { + if (((o->name == NULL && name == NULL) + || (o->name && name && strcmp(o->name, name) == 0))) + return o; + } + return NULL; +} + +/* This is hook function for vrf create called as part of vrf_init */ +static int ospf6_vrf_new(struct vrf *vrf) +{ + return 0; +} + +/* This is hook function for vrf delete call as part of vrf_init */ +static int ospf6_vrf_delete(struct vrf *vrf) +{ + return 0; +} + +static void ospf6_set_redist_vrf_bitmaps(struct ospf6 *ospf6, bool set) +{ + int type; + struct list *red_list; + + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { + red_list = ospf6->redist[type]; + if (!red_list) + continue; + if (IS_OSPF6_DEBUG_ZEBRA(RECV)) + zlog_debug( + "%s: setting redist vrf %d bitmap for type %d", + __func__, ospf6->vrf_id, type); + if (set) + vrf_bitmap_set(&zclient->redist[AFI_IP6][type], + ospf6->vrf_id); + else + vrf_bitmap_unset(&zclient->redist[AFI_IP6][type], + ospf6->vrf_id); + } + + red_list = ospf6->redist[DEFAULT_ROUTE]; + if (red_list) { + if (set) + vrf_bitmap_set(&zclient->default_information[AFI_IP6], + ospf6->vrf_id); + else + vrf_bitmap_unset(&zclient->default_information[AFI_IP6], + ospf6->vrf_id); + } +} + +/* Disable OSPF6 VRF instance */ +static int ospf6_vrf_disable(struct vrf *vrf) +{ + struct ospf6 *ospf6 = NULL; + + if (vrf->vrf_id == VRF_DEFAULT) + return 0; + + ospf6 = ospf6_lookup_by_vrf_name(vrf->name); + if (ospf6) { + ospf6_zebra_vrf_deregister(ospf6); + + ospf6_set_redist_vrf_bitmaps(ospf6, false); + + /* We have instance configured, unlink + * from VRF and make it "down". + */ + ospf6_vrf_unlink(ospf6, vrf); + event_cancel(&ospf6->t_ospf6_receive); + close(ospf6->fd); + ospf6->fd = -1; + } + + /* Note: This is a callback, the VRF will be deleted by the caller. */ + return 0; +} + +/* Enable OSPF6 VRF instance */ +static int ospf6_vrf_enable(struct vrf *vrf) +{ + struct ospf6 *ospf6 = NULL; + vrf_id_t old_vrf_id; + int ret = 0; + + ospf6 = ospf6_lookup_by_vrf_name(vrf->name); + if (ospf6) { + old_vrf_id = ospf6->vrf_id; + /* We have instance configured, link to VRF and make it "up". */ + ospf6_vrf_link(ospf6, vrf); + + if (old_vrf_id != ospf6->vrf_id) { + ospf6_set_redist_vrf_bitmaps(ospf6, true); + + /* start zebra redist to us for new vrf */ + ospf6_zebra_vrf_register(ospf6); + + ret = ospf6_serv_sock(ospf6); + if (ret < 0 || ospf6->fd <= 0) + return 0; + event_add_read(master, ospf6_receive, ospf6, ospf6->fd, + &ospf6->t_ospf6_receive); + + ospf6_router_id_update(ospf6, true); + } + } + + return 0; +} + +void ospf6_vrf_init(void) +{ + vrf_init(ospf6_vrf_new, ospf6_vrf_enable, ospf6_vrf_disable, + ospf6_vrf_delete); + + vrf_cmd_init(NULL); +} + +static void ospf6_top_lsdb_hook_add(struct ospf6_lsa *lsa) +{ + switch (ntohs(lsa->header->type)) { + case OSPF6_LSTYPE_AS_EXTERNAL: + ospf6_asbr_lsa_add(lsa); + break; + + default: + break; + } +} + +static void ospf6_top_lsdb_hook_remove(struct ospf6_lsa *lsa) +{ + switch (ntohs(lsa->header->type)) { + case OSPF6_LSTYPE_AS_EXTERNAL: + ospf6_asbr_lsa_remove(lsa, NULL); + break; + + default: + break; + } +} + +static void ospf6_top_route_hook_add(struct ospf6_route *route) +{ + struct ospf6 *ospf6 = NULL; + struct ospf6_area *oa = NULL; + + if (route->table->scope_type == OSPF6_SCOPE_TYPE_GLOBAL) + ospf6 = route->table->scope; + else if (route->table->scope_type == OSPF6_SCOPE_TYPE_AREA) { + oa = (struct ospf6_area *)route->table->scope; + ospf6 = oa->ospf6; + } else { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) + || IS_OSPF6_DEBUG_BROUTER) + zlog_debug( + "%s: Route is not GLOBAL or scope is not of TYPE_AREA: %pFX", + __func__, &route->prefix); + return; + } + + ospf6_abr_originate_summary(route, ospf6); + ospf6_zebra_route_update_add(route, ospf6); +} + +static void ospf6_top_route_hook_remove(struct ospf6_route *route) +{ + struct ospf6 *ospf6 = NULL; + struct ospf6_area *oa = NULL; + + if (route->table->scope_type == OSPF6_SCOPE_TYPE_GLOBAL) + ospf6 = route->table->scope; + else if (route->table->scope_type == OSPF6_SCOPE_TYPE_AREA) { + oa = (struct ospf6_area *)route->table->scope; + ospf6 = oa->ospf6; + } else { + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) + || IS_OSPF6_DEBUG_BROUTER) + zlog_debug( + "%s: Route is not GLOBAL or scope is not of TYPE_AREA: %pFX", + __func__, &route->prefix); + return; + } + + route->flag |= OSPF6_ROUTE_REMOVE; + ospf6_abr_originate_summary(route, ospf6); + ospf6_zebra_route_update_remove(route, ospf6); +} + +static void ospf6_top_brouter_hook_add(struct ospf6_route *route) +{ + struct ospf6 *ospf6 = route->table->scope; + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) || + IS_OSPF6_DEBUG_BROUTER) { + uint32_t brouter_id; + char brouter_name[16]; + + brouter_id = ADV_ROUTER_IN_PREFIX(&route->prefix); + inet_ntop(AF_INET, &brouter_id, brouter_name, + sizeof(brouter_name)); + zlog_debug("%s: brouter %s add with adv router %x nh count %u", + __func__, brouter_name, + route->path.origin.adv_router, + listcount(route->nh_list)); + } + ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix), route, + ospf6); + ospf6_asbr_lsentry_add(route, ospf6); + ospf6_abr_originate_summary(route, ospf6); +} + +static void ospf6_top_brouter_hook_remove(struct ospf6_route *route) +{ + struct ospf6 *ospf6 = route->table->scope; + + if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) || + IS_OSPF6_DEBUG_BROUTER) { + uint32_t brouter_id; + char brouter_name[16]; + + brouter_id = ADV_ROUTER_IN_PREFIX(&route->prefix); + inet_ntop(AF_INET, &brouter_id, brouter_name, + sizeof(brouter_name)); + zlog_debug("%s: brouter %p %s del with adv router %x nh %u", + __func__, (void *)route, brouter_name, + route->path.origin.adv_router, + listcount(route->nh_list)); + } + route->flag |= OSPF6_ROUTE_REMOVE; + ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix), route, + ospf6); + ospf6_asbr_lsentry_remove(route, ospf6); + ospf6_abr_originate_summary(route, ospf6); +} + +static struct ospf6 *ospf6_create(const char *name) +{ + struct ospf6 *o; + struct vrf *vrf = NULL; + + o = XCALLOC(MTYPE_OSPF6_TOP, sizeof(struct ospf6)); + + vrf = vrf_lookup_by_name(name); + if (vrf) { + o->vrf_id = vrf->vrf_id; + } else + o->vrf_id = VRF_UNKNOWN; + + /* Freed in ospf6_delete */ + o->name = XSTRDUP(MTYPE_OSPF6_TOP, name); + if (vrf) + ospf6_vrf_link(o, vrf); + + ospf6_zebra_vrf_register(o); + + /* initialize */ + monotime(&o->starttime); + o->area_list = list_new(); + o->area_list->cmp = ospf6_area_cmp; + o->lsdb = ospf6_lsdb_create(o); + o->lsdb_self = ospf6_lsdb_create(o); + o->lsdb->hook_add = ospf6_top_lsdb_hook_add; + o->lsdb->hook_remove = ospf6_top_lsdb_hook_remove; + + o->spf_delay = OSPF_SPF_DELAY_DEFAULT; + o->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT; + o->spf_max_holdtime = OSPF_SPF_MAX_HOLDTIME_DEFAULT; + o->spf_hold_multiplier = 1; + + o->default_originate = DEFAULT_ORIGINATE_NONE; + o->redistribute = 0; + /* LSA timers value init */ + o->lsa_minarrival = OSPF_MIN_LS_ARRIVAL; + + o->route_table = OSPF6_ROUTE_TABLE_CREATE(GLOBAL, ROUTES); + o->route_table->scope = o; + o->route_table->hook_add = ospf6_top_route_hook_add; + o->route_table->hook_remove = ospf6_top_route_hook_remove; + + o->brouter_table = OSPF6_ROUTE_TABLE_CREATE(GLOBAL, BORDER_ROUTERS); + o->brouter_table->scope = o; + o->brouter_table->hook_add = ospf6_top_brouter_hook_add; + o->brouter_table->hook_remove = ospf6_top_brouter_hook_remove; + + o->external_table = OSPF6_ROUTE_TABLE_CREATE(GLOBAL, EXTERNAL_ROUTES); + o->external_table->scope = o; + /* Setting this to 1, so that the LS ID 0 can be considered as invalid + * for self originated external LSAs. This helps in differentiating if + * an LSA is originated for any route or not in the route data. + * rt->route_option->id is by default 0 + * Consider a route having id as 0 and prefix as 1::1, an external LSA + * is originated with ID 0.0.0.0. Now consider another route 2::2 + * and for this LSA was not originated because of some configuration + * but the ID field rt->route_option->id is still 0.Consider now this + * 2::2 is being deleted, it will search LSA with LS ID as 0 and it + * will find the LSA and hence delete it but the LSA belonged to prefix + * 1::1, this happened because of LS ID 0. + */ + o->external_id = OSPF6_EXT_INIT_LS_ID; + + o->write_oi_count = OSPF6_WRITE_INTERFACE_COUNT_DEFAULT; + o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH; + + o->distance_table = route_table_init(); + + o->rt_aggr_tbl = route_table_init(); + o->aggr_delay_interval = OSPF6_EXTL_AGGR_DEFAULT_DELAY; + o->aggr_action = OSPF6_ROUTE_AGGR_NONE; + + o->fd = -1; + + o->max_multipath = MULTIPATH_NUM; + + o->oi_write_q = list_new(); + + ospf6_gr_helper_init(o); + QOBJ_REG(o, ospf6); + + /* Make ospf protocol socket. */ + ospf6_serv_sock(o); + + /* If sequence number is stored in persistent storage, read it. + */ + if (ospf6_auth_nvm_file_exist() == OSPF6_AUTH_FILE_EXIST) { + ospf6_auth_seqno_nvm_read(o); + o->seqnum_h = o->seqnum_h + 1; + ospf6_auth_seqno_nvm_update(o); + } else { + o->seqnum_l = o->seqnum_h = 0; + ospf6_auth_seqno_nvm_update(o); + } + + return o; +} + +struct ospf6 *ospf6_instance_create(const char *name) +{ + struct ospf6 *ospf6; + struct vrf *vrf; + struct interface *ifp; + + ospf6 = ospf6_create(name); + if (DFLT_OSPF6_LOG_ADJACENCY_CHANGES) + SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); + if (ospf6->router_id == 0) + ospf6_router_id_update(ospf6, true); + ospf6_add(ospf6); + + /* + * Read from non-volatile memory whether this instance is performing a + * graceful restart or not. + */ + ospf6_gr_nvm_read(ospf6); + + if (ospf6->vrf_id != VRF_UNKNOWN) { + vrf = vrf_lookup_by_id(ospf6->vrf_id); + FOR_ALL_INTERFACES (vrf, ifp) { + if (ifp->info) + ospf6_interface_start(ifp->info); + } + } + if (ospf6->fd < 0) + return ospf6; + + event_add_read(master, ospf6_receive, ospf6, ospf6->fd, + &ospf6->t_ospf6_receive); + + return ospf6; +} + +void ospf6_delete(struct ospf6 *o) +{ + struct listnode *node, *nnode; + struct route_node *rn = NULL; + struct ospf6_area *oa; + struct vrf *vrf; + struct ospf6_external_aggr_rt *aggr; + + QOBJ_UNREG(o); + + ospf6_gr_helper_deinit(o); + if (!o->gr_info.prepare_in_progress) + ospf6_flush_self_originated_lsas_now(o); + XFREE(MTYPE_TMP, o->gr_info.exit_reason); + ospf6_disable(o); + ospf6_del(o); + + ospf6_zebra_vrf_deregister(o); + + ospf6_serv_close(&o->fd); + + for (ALL_LIST_ELEMENTS(o->area_list, node, nnode, oa)) + ospf6_area_delete(oa); + + + list_delete(&o->area_list); + + ospf6_lsdb_delete(o->lsdb); + ospf6_lsdb_delete(o->lsdb_self); + + ospf6_route_table_delete(o->route_table); + ospf6_route_table_delete(o->brouter_table); + + ospf6_route_table_delete(o->external_table); + + ospf6_distance_reset(o); + route_table_finish(o->distance_table); + list_delete(&o->oi_write_q); + + if (o->vrf_id != VRF_UNKNOWN) { + vrf = vrf_lookup_by_id(o->vrf_id); + if (vrf) + ospf6_vrf_unlink(o, vrf); + } + + for (rn = route_top(o->rt_aggr_tbl); rn; rn = route_next(rn)) + if (rn->info) { + aggr = rn->info; + ospf6_asbr_summary_config_delete(o, rn); + ospf6_external_aggregator_free(aggr); + } + route_table_finish(o->rt_aggr_tbl); + + XFREE(MTYPE_OSPF6_TOP, o->name); + XFREE(MTYPE_OSPF6_TOP, o); +} + +static void ospf6_disable(struct ospf6 *o) +{ + struct listnode *node, *nnode; + struct ospf6_area *oa; + + if (!CHECK_FLAG(o->flag, OSPF6_DISABLED)) { + SET_FLAG(o->flag, OSPF6_DISABLED); + + for (ALL_LIST_ELEMENTS(o->area_list, node, nnode, oa)) + ospf6_area_disable(oa); + + /* XXX: This also changes persistent settings */ + /* Unregister redistribution */ + ospf6_asbr_redistribute_disable(o); + + ospf6_lsdb_remove_all(o->lsdb); + ospf6_route_remove_all(o->route_table); + ospf6_route_remove_all(o->brouter_table); + + EVENT_OFF(o->maxage_remover); + EVENT_OFF(o->t_spf_calc); + EVENT_OFF(o->t_ase_calc); + EVENT_OFF(o->t_distribute_update); + EVENT_OFF(o->t_ospf6_receive); + EVENT_OFF(o->t_external_aggr); + EVENT_OFF(o->gr_info.t_grace_period); + EVENT_OFF(o->t_write); + EVENT_OFF(o->t_abr_task); + } +} + +void ospf6_master_init(struct event_loop *master) +{ + memset(&ospf6_master, 0, sizeof(ospf6_master)); + + om6 = &ospf6_master; + om6->ospf6 = list_new(); + om6->master = master; +} + +static void ospf6_maxage_remover(struct event *thread) +{ + struct ospf6 *o = (struct ospf6 *)EVENT_ARG(thread); + struct ospf6_area *oa; + struct ospf6_interface *oi; + struct ospf6_neighbor *on; + struct listnode *i, *j, *k; + int reschedule = 0; + + for (ALL_LIST_ELEMENTS_RO(o->area_list, i, oa)) { + for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { + for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, on)) { + if (on->state != OSPF6_NEIGHBOR_EXCHANGE + && on->state != OSPF6_NEIGHBOR_LOADING) + continue; + + ospf6_maxage_remove(o); + return; + } + } + } + + for (ALL_LIST_ELEMENTS_RO(o->area_list, i, oa)) { + for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { + if (ospf6_lsdb_maxage_remover(oi->lsdb)) { + reschedule = 1; + } + } + + if (ospf6_lsdb_maxage_remover(oa->lsdb)) { + reschedule = 1; + } + } + + if (ospf6_lsdb_maxage_remover(o->lsdb)) { + reschedule = 1; + } + + if (reschedule) { + ospf6_maxage_remove(o); + } +} + +void ospf6_maxage_remove(struct ospf6 *o) +{ + if (o) + event_add_timer(master, ospf6_maxage_remover, o, + OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT, + &o->maxage_remover); +} + +bool ospf6_router_id_update(struct ospf6 *ospf6, bool init) +{ + in_addr_t new_router_id; + struct listnode *node; + struct ospf6_area *oa; + + if (!ospf6) + return true; + + if (ospf6->router_id_static != 0) + new_router_id = ospf6->router_id_static; + else + new_router_id = ospf6->router_id_zebra; + + if (ospf6->router_id == new_router_id) + return true; + + if (!init) + for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) { + if (oa->full_nbrs) { + zlog_err( + "%s: cannot update router-id. Run the \"clear ipv6 ospf6 process\" command", + __func__); + return false; + } + } + + ospf6->router_id = new_router_id; + return true; +} + +/* start ospf6 */ +DEFUN_NOSH(router_ospf6, router_ospf6_cmd, "router ospf6 [vrf NAME]", + ROUTER_STR OSPF6_STR VRF_CMD_HELP_STR) +{ + struct ospf6 *ospf6; + const char *vrf_name = VRF_DEFAULT_NAME; + int idx_vrf = 0; + + if (argv_find(argv, argc, "vrf", &idx_vrf)) { + vrf_name = argv[idx_vrf + 1]->arg; + } + + ospf6 = ospf6_lookup_by_vrf_name(vrf_name); + if (ospf6 == NULL) + ospf6 = ospf6_instance_create(vrf_name); + + /* set current ospf point. */ + VTY_PUSH_CONTEXT(OSPF6_NODE, ospf6); + + return CMD_SUCCESS; +} + +/* stop ospf6 */ +DEFUN(no_router_ospf6, no_router_ospf6_cmd, "no router ospf6 [vrf NAME]", + NO_STR ROUTER_STR OSPF6_STR VRF_CMD_HELP_STR) +{ + struct ospf6 *ospf6; + const char *vrf_name = VRF_DEFAULT_NAME; + int idx_vrf = 0; + + if (argv_find(argv, argc, "vrf", &idx_vrf)) { + vrf_name = argv[idx_vrf + 1]->arg; + } + + ospf6 = ospf6_lookup_by_vrf_name(vrf_name); + if (ospf6 == NULL) + vty_out(vty, "OSPFv3 is not configured\n"); + else { + if (ospf6->gr_info.restart_support) + ospf6_gr_nvm_delete(ospf6); + + ospf6_delete(ospf6); + ospf6 = NULL; + } + + /* return to config node . */ + VTY_PUSH_CONTEXT_NULL(CONFIG_NODE); + + return CMD_SUCCESS; +} + +static void ospf6_db_clear(struct ospf6 *ospf6) +{ + struct ospf6_interface *oi; + struct interface *ifp; + struct vrf *vrf = vrf_lookup_by_id(ospf6->vrf_id); + struct listnode *node, *nnode; + struct ospf6_area *oa; + + FOR_ALL_INTERFACES (vrf, ifp) { + if (if_is_operative(ifp) && ifp->info != NULL) { + oi = (struct ospf6_interface *)ifp->info; + ospf6_lsdb_remove_all(oi->lsdb); + ospf6_lsdb_remove_all(oi->lsdb_self); + ospf6_lsdb_remove_all(oi->lsupdate_list); + ospf6_lsdb_remove_all(oi->lsack_list); + } + } + + for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) { + ospf6_lsdb_remove_all(oa->lsdb); + ospf6_lsdb_remove_all(oa->lsdb_self); + + ospf6_spf_table_finish(oa->spf_table); + ospf6_route_remove_all(oa->route_table); + } + + ospf6_lsdb_remove_all(ospf6->lsdb); + ospf6_lsdb_remove_all(ospf6->lsdb_self); + ospf6_route_remove_all(ospf6->route_table); + ospf6_route_remove_all(ospf6->brouter_table); +} + +static void ospf6_process_reset(struct ospf6 *ospf6) +{ + struct interface *ifp; + struct vrf *vrf = vrf_lookup_by_id(ospf6->vrf_id); + + ospf6_unset_all_aggr_flag(ospf6); + ospf6_flush_self_originated_lsas_now(ospf6); + ospf6->inst_shutdown = 0; + ospf6_db_clear(ospf6); + + ospf6_asbr_redistribute_reset(ospf6); + FOR_ALL_INTERFACES (vrf, ifp) + ospf6_interface_clear(ifp); +} + +DEFPY (clear_router_ospf6, + clear_router_ospf6_cmd, + "clear ipv6 ospf6 process [vrf NAME$name]", + CLEAR_STR + IP6_STR + OSPF6_STR + "Reset OSPF Process\n" + VRF_CMD_HELP_STR) +{ + struct ospf6 *ospf6; + const char *vrf_name = VRF_DEFAULT_NAME; + + if (name != NULL) + vrf_name = name; + + ospf6 = ospf6_lookup_by_vrf_name(vrf_name); + if (ospf6 == NULL) { + vty_out(vty, "OSPFv3 is not configured\n"); + } else { + ospf6_router_id_update(ospf6, true); + ospf6_process_reset(ospf6); + } + + return CMD_SUCCESS; +} + +/* change Router_ID commands. */ +DEFUN(ospf6_router_id, + ospf6_router_id_cmd, + "ospf6 router-id A.B.C.D", + OSPF6_STR + "Configure OSPF6 Router-ID\n" + V4NOTATION_STR) +{ + VTY_DECLVAR_CONTEXT(ospf6, o); + int idx = 0; + int ret; + const char *router_id_str; + uint32_t router_id; + + argv_find(argv, argc, "A.B.C.D", &idx); + router_id_str = argv[idx]->arg; + + ret = inet_pton(AF_INET, router_id_str, &router_id); + if (ret == 0) { + vty_out(vty, "malformed OSPF Router-ID: %s\n", router_id_str); + return CMD_SUCCESS; + } + + o->router_id_static = router_id; + + if (ospf6_router_id_update(o, false)) + ospf6_process_reset(o); + else + vty_out(vty, + "For this router-id change to take effect run the \"clear ipv6 ospf6 process\" command\n"); + + return CMD_SUCCESS; +} + +DEFUN(no_ospf6_router_id, + no_ospf6_router_id_cmd, + "no ospf6 router-id [A.B.C.D]", + NO_STR OSPF6_STR + "Configure OSPF6 Router-ID\n" + V4NOTATION_STR) +{ + VTY_DECLVAR_CONTEXT(ospf6, o); + + o->router_id_static = 0; + + + if (ospf6_router_id_update(o, false)) + ospf6_process_reset(o); + else + vty_out(vty, + "For this router-id change to take effect run the \"clear ipv6 ospf6 process\" command\n"); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_log_adjacency_changes, + ospf6_log_adjacency_changes_cmd, + "log-adjacency-changes", + "Log changes in adjacency state\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); + UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL); + return CMD_SUCCESS; +} + +DEFUN (ospf6_log_adjacency_changes_detail, + ospf6_log_adjacency_changes_detail_cmd, + "log-adjacency-changes detail", + "Log changes in adjacency state\n" + "Log all state changes\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); + SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL); + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_log_adjacency_changes, + no_ospf6_log_adjacency_changes_cmd, + "no log-adjacency-changes", + NO_STR + "Log changes in adjacency state\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL); + UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_log_adjacency_changes_detail, + no_ospf6_log_adjacency_changes_detail_cmd, + "no log-adjacency-changes detail", + NO_STR + "Log changes in adjacency state\n" + "Log all state changes\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL); + return CMD_SUCCESS; +} + +static void ospf6_reinstall_routes(struct ospf6 *ospf6) +{ + struct ospf6_route *route; + + for (route = ospf6_route_head(ospf6->route_table); route; + route = ospf6_route_next(route)) + ospf6_zebra_route_update_add(route, ospf6); +} + +DEFPY (ospf6_send_extra_data, + ospf6_send_extra_data_cmd, + "[no] ospf6 send-extra-data zebra", + NO_STR + OSPF6_STR + "Extra data to Zebra for display/use\n" + "To zebra\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + if (no + && CHECK_FLAG(ospf6->config_flags, + OSPF6_SEND_EXTRA_DATA_TO_ZEBRA)) { + UNSET_FLAG(ospf6->config_flags, OSPF6_SEND_EXTRA_DATA_TO_ZEBRA); + ospf6_reinstall_routes(ospf6); + } else if (!CHECK_FLAG(ospf6->config_flags, + OSPF6_SEND_EXTRA_DATA_TO_ZEBRA)) { + SET_FLAG(ospf6->config_flags, OSPF6_SEND_EXTRA_DATA_TO_ZEBRA); + ospf6_reinstall_routes(ospf6); + } + + return CMD_SUCCESS; +} + +DEFUN (ospf6_timers_lsa, + ospf6_timers_lsa_cmd, + "timers lsa min-arrival (0-600000)", + "Adjust routing timers\n" + "OSPF6 LSA timers\n" + "Minimum delay in receiving new version of a LSA\n" + "Delay in milliseconds\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf); + int idx_number = 3; + unsigned int minarrival; + + minarrival = strtoul(argv[idx_number]->arg, NULL, 10); + ospf->lsa_minarrival = minarrival; + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_timers_lsa, + no_ospf6_timers_lsa_cmd, + "no timers lsa min-arrival [(0-600000)]", + NO_STR + "Adjust routing timers\n" + "OSPF6 LSA timers\n" + "Minimum delay in receiving new version of a LSA\n" + "Delay in milliseconds\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf); + int idx_number = 4; + unsigned int minarrival; + + if (argc == 5) { + minarrival = strtoul(argv[idx_number]->arg, NULL, 10); + + if (ospf->lsa_minarrival != minarrival + || minarrival == OSPF_MIN_LS_ARRIVAL) + return CMD_SUCCESS; + } + + ospf->lsa_minarrival = OSPF_MIN_LS_ARRIVAL; + + return CMD_SUCCESS; +} + + +DEFUN (ospf6_distance, + ospf6_distance_cmd, + "distance (1-255)", + "Administrative distance\n" + "OSPF6 Administrative distance\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, o); + uint8_t distance; + + distance = atoi(argv[1]->arg); + if (o->distance_all != distance) { + o->distance_all = distance; + ospf6_restart_spf(o); + } + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_distance, + no_ospf6_distance_cmd, + "no distance (1-255)", + NO_STR + "Administrative distance\n" + "OSPF6 Administrative distance\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, o); + + if (o->distance_all) { + o->distance_all = 0; + ospf6_restart_spf(o); + } + return CMD_SUCCESS; +} + +DEFUN (ospf6_distance_ospf6, + ospf6_distance_ospf6_cmd, + "distance ospf6 {intra-area (1-255)|inter-area (1-255)|external (1-255)}", + "Administrative distance\n" + "OSPF6 administrative distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, o); + int idx = 0; + + o->distance_intra = 0; + o->distance_inter = 0; + o->distance_external = 0; + + if (argv_find(argv, argc, "intra-area", &idx)) + o->distance_intra = atoi(argv[idx + 1]->arg); + idx = 0; + if (argv_find(argv, argc, "inter-area", &idx)) + o->distance_inter = atoi(argv[idx + 1]->arg); + idx = 0; + if (argv_find(argv, argc, "external", &idx)) + o->distance_external = atoi(argv[idx + 1]->arg); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_distance_ospf6, + no_ospf6_distance_ospf6_cmd, + "no distance ospf6 [{intra-area [(1-255)]|inter-area [(1-255)]|external [(1-255)]}]", + NO_STR + "Administrative distance\n" + "OSPF6 distance\n" + "Intra-area routes\n" + "Distance for intra-area routes\n" + "Inter-area routes\n" + "Distance for inter-area routes\n" + "External routes\n" + "Distance for external routes\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, o); + int idx = 0; + + if (argv_find(argv, argc, "intra-area", &idx) || argc == 3) + idx = o->distance_intra = 0; + if (argv_find(argv, argc, "inter-area", &idx) || argc == 3) + idx = o->distance_inter = 0; + if (argv_find(argv, argc, "external", &idx) || argc == 3) + o->distance_external = 0; + + return CMD_SUCCESS; +} + +DEFUN_HIDDEN (ospf6_interface_area, + ospf6_interface_area_cmd, + "interface IFNAME area <A.B.C.D|(0-4294967295)>", + "Enable routing on an IPv6 interface\n" + IFNAME_STR + "Specify the OSPF6 area ID\n" + "OSPF6 area ID in IPv4 address notation\n" + "OSPF6 area ID in decimal notation\n" + ) +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + int idx_ifname = 1; + int idx_ipv4 = 3; + struct ospf6_area *oa; + struct ospf6_interface *oi; + struct interface *ifp; + uint32_t area_id; + int format; + + vty_out(vty, + "This command is deprecated, because it is not VRF-aware.\n"); + vty_out(vty, + "Please, use \"ipv6 ospf6 area\" on an interface instead.\n"); + + /* find/create ospf6 interface */ + ifp = if_get_by_name(argv[idx_ifname]->arg, ospf6->vrf_id, ospf6->name); + oi = (struct ospf6_interface *)ifp->info; + if (oi == NULL) + oi = ospf6_interface_create(ifp); + if (oi->area) { + vty_out(vty, "%s already attached to Area %s\n", + oi->interface->name, oi->area->name); + return CMD_SUCCESS; + } + + if (str2area_id(argv[idx_ipv4]->arg, &area_id, &format)) { + vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + + oi->area_id = area_id; + oi->area_id_format = format; + + oa = ospf6_area_lookup(area_id, ospf6); + if (oa == NULL) + oa = ospf6_area_create(area_id, ospf6, format); + + /* attach interface to area */ + listnode_add(oa->if_list, oi); /* sort ?? */ + oi->area = oa; + + SET_FLAG(oa->flag, OSPF6_AREA_ENABLE); + + /* ospf6 process is currently disabled, not much more to do */ + if (CHECK_FLAG(ospf6->flag, OSPF6_DISABLED)) + return CMD_SUCCESS; + + /* start up */ + ospf6_interface_enable(oi); + + /* If the router is ABR, originate summary routes */ + if (ospf6_check_and_set_router_abr(ospf6)) { + ospf6_abr_enable_area(oa); + ospf6_schedule_abr_task(oa->ospf6); + } + + return CMD_SUCCESS; +} + +DEFUN_HIDDEN (no_ospf6_interface_area, + no_ospf6_interface_area_cmd, + "no interface IFNAME area <A.B.C.D|(0-4294967295)>", + NO_STR + "Disable routing on an IPv6 interface\n" + IFNAME_STR + "Specify the OSPF6 area ID\n" + "OSPF6 area ID in IPv4 address notation\n" + "OSPF6 area ID in decimal notation\n" + ) +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + int idx_ifname = 2; + int idx_ipv4 = 4; + struct ospf6_interface *oi; + struct ospf6_area *oa; + struct interface *ifp; + uint32_t area_id; + + vty_out(vty, + "This command is deprecated, because it is not VRF-aware.\n"); + vty_out(vty, + "Please, use \"no ipv6 ospf6 area\" on an interface instead.\n"); + + /* find/create ospf6 interface */ + ifp = if_get_by_name(argv[idx_ifname]->arg, ospf6->vrf_id, ospf6->name); + + if (ifp == NULL) { + vty_out(vty, "No such interface %s\n", argv[idx_ifname]->arg); + return CMD_SUCCESS; + } + + oi = (struct ospf6_interface *)ifp->info; + if (oi == NULL) { + vty_out(vty, "Interface %s not enabled\n", ifp->name); + return CMD_SUCCESS; + } + + /* parse Area-ID */ + if (inet_pton(AF_INET, argv[idx_ipv4]->arg, &area_id) != 1) + area_id = htonl(strtoul(argv[idx_ipv4]->arg, NULL, 10)); + + /* Verify Area */ + if (oi->area == NULL) { + vty_out(vty, "%s not attached to area %s\n", + oi->interface->name, argv[idx_ipv4]->arg); + return CMD_SUCCESS; + } + + if (oi->area->area_id != area_id) { + vty_out(vty, "Wrong Area-ID: %s is attached to area %s\n", + oi->interface->name, oi->area->name); + return CMD_SUCCESS; + } + + ospf6_interface_disable(oi); + + oa = oi->area; + listnode_delete(oi->area->if_list, oi); + oi->area = (struct ospf6_area *)NULL; + + /* Withdraw inter-area routes from this area, if necessary */ + if (oa->if_list->count == 0) { + UNSET_FLAG(oa->flag, OSPF6_AREA_ENABLE); + ospf6_abr_disable_area(oa); + } + + oi->area_id = 0; + oi->area_id_format = OSPF6_AREA_FMT_UNSET; + + return CMD_SUCCESS; +} + +DEFUN (ospf6_stub_router_admin, + ospf6_stub_router_admin_cmd, + "stub-router administrative", + "Make router a stub router\n" + "Administratively applied, for an indefinite period\n") +{ + struct listnode *node; + struct ospf6_area *oa; + + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + if (!CHECK_FLAG(ospf6->flag, OSPF6_STUB_ROUTER)) { + for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) { + OSPF6_OPT_CLEAR(oa->options, OSPF6_OPT_V6); + OSPF6_OPT_CLEAR(oa->options, OSPF6_OPT_R); + OSPF6_ROUTER_LSA_SCHEDULE(oa); + } + SET_FLAG(ospf6->flag, OSPF6_STUB_ROUTER); + } + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_stub_router_admin, + no_ospf6_stub_router_admin_cmd, + "no stub-router administrative", + NO_STR + "Make router a stub router\n" + "Administratively applied, for an indefinite period\n") +{ + struct listnode *node; + struct ospf6_area *oa; + + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + if (CHECK_FLAG(ospf6->flag, OSPF6_STUB_ROUTER)) { + for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) { + OSPF6_OPT_SET(oa->options, OSPF6_OPT_V6); + OSPF6_OPT_SET(oa->options, OSPF6_OPT_R); + OSPF6_ROUTER_LSA_SCHEDULE(oa); + } + UNSET_FLAG(ospf6->flag, OSPF6_STUB_ROUTER); + } + + return CMD_SUCCESS; +} + +/* Restart OSPF SPF algorithm*/ +void ospf6_restart_spf(struct ospf6 *ospf6) +{ + ospf6_route_remove_all(ospf6->route_table); + ospf6_route_remove_all(ospf6->brouter_table); + + /* Trigger SPF */ + ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_CONFIG_CHANGE); +} + +/* Set the max paths */ +static void ospf6_maxpath_set(struct ospf6 *ospf6, uint16_t paths) +{ + if (ospf6->max_multipath == paths) + return; + + ospf6->max_multipath = paths; + + /* Send deletion to zebra to delete all + * ospf specific routes and reinitiate + * SPF to reflect the new max multipath. + */ + ospf6_restart_spf(ospf6); +} + +/* Ospf Maximum-paths config support */ +DEFUN(ospf6_max_multipath, + ospf6_max_multipath_cmd, + "maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM), + "Max no of multiple paths for ECMP support\n" + "Number of paths\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + int idx_number = 1; + int maximum_paths = strtol(argv[idx_number]->arg, NULL, 10); + + ospf6_maxpath_set(ospf6, maximum_paths); + + return CMD_SUCCESS; +} + +DEFUN(no_ospf6_max_multipath, + no_ospf6_max_multipath_cmd, + "no maximum-paths [" CMD_RANGE_STR(1, MULTIPATH_NUM)"]", + NO_STR + "Max no of multiple paths for ECMP support\n" + "Number of paths\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + ospf6_maxpath_set(ospf6, MULTIPATH_NUM); + + return CMD_SUCCESS; +} + +static void ospf6_show(struct vty *vty, struct ospf6 *o, json_object *json, + bool use_json) +{ + struct listnode *n; + struct ospf6_area *oa; + char router_id[16], duration[32]; + struct timeval now, running, result; + char buf[32], rbuf[32]; + json_object *json_areas = NULL; + const char *adjacency; + + if (use_json) { + json_areas = json_object_new_object(); + + /* process id, router id */ + inet_ntop(AF_INET, &o->router_id, router_id, sizeof(router_id)); + json_object_string_add(json, "routerId", router_id); + + /* running time */ + monotime(&now); + timersub(&now, &o->starttime, &running); + timerstring(&running, duration, sizeof(duration)); + json_object_string_add(json, "running", duration); + + /* Redistribute configuration */ + /* XXX */ + json_object_int_add(json, "lsaMinimumArrivalMsecs", + o->lsa_minarrival); + + /* Show SPF parameters */ + json_object_int_add(json, "spfScheduleDelayMsecs", + o->spf_delay); + json_object_int_add(json, "holdTimeMinMsecs", o->spf_holdtime); + json_object_int_add(json, "holdTimeMaxMsecs", + o->spf_max_holdtime); + json_object_int_add(json, "holdTimeMultiplier", + o->spf_hold_multiplier); + + json_object_int_add(json, "maximumPaths", o->max_multipath); + json_object_int_add(json, "preference", + o->distance_all + ? o->distance_all + : ZEBRA_OSPF6_DISTANCE_DEFAULT); + + if (o->ts_spf.tv_sec || o->ts_spf.tv_usec) { + timersub(&now, &o->ts_spf, &result); + timerstring(&result, buf, sizeof(buf)); + ospf6_spf_reason_string(o->last_spf_reason, rbuf, + sizeof(rbuf)); + json_object_boolean_true_add(json, "spfHasRun"); + json_object_string_add(json, "spfLastExecutedMsecs", + buf); + json_object_string_add(json, "spfLastExecutedReason", + rbuf); + + json_object_int_add( + json, "spfLastDurationSecs", + (long long)o->ts_spf_duration.tv_sec); + + json_object_int_add( + json, "spfLastDurationMsecs", + (long long)o->ts_spf_duration.tv_usec); + } else + json_object_boolean_false_add(json, "spfHasRun"); + + if (event_is_scheduled(o->t_spf_calc)) { + long time_store; + + json_object_boolean_true_add(json, "spfTimerActive"); + time_store = + monotime_until(&o->t_spf_calc->u.sands, NULL) + / 1000LL; + json_object_int_add(json, "spfTimerDueInMsecs", + time_store); + } else + json_object_boolean_false_add(json, "spfTimerActive"); + + json_object_boolean_add(json, "routerIsStubRouter", + CHECK_FLAG(o->flag, OSPF6_STUB_ROUTER)); + + /* LSAs */ + json_object_int_add(json, "numberOfAsScopedLsa", + o->lsdb->count); + /* Areas */ + json_object_int_add(json, "numberOfAreaInRouter", + listcount(o->area_list)); + + json_object_int_add(json, "AuthTrailerHigherSeqNo", + o->seqnum_h); + json_object_int_add(json, "AuthTrailerLowerSeqNo", o->seqnum_l); + + if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) { + if (CHECK_FLAG(o->config_flags, + OSPF6_LOG_ADJACENCY_DETAIL)) + adjacency = "LoggedAll"; + else + adjacency = "Logged"; + } else + adjacency = "NotLogged"; + json_object_string_add(json, "adjacencyChanges", adjacency); + + for (ALL_LIST_ELEMENTS_RO(o->area_list, n, oa)) + ospf6_area_show(vty, oa, json_areas, use_json); + + json_object_object_add(json, "areas", json_areas); + + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + + } else { + /* process id, router id */ + inet_ntop(AF_INET, &o->router_id, router_id, sizeof(router_id)); + vty_out(vty, " OSPFv3 Routing Process (0) with Router-ID %s\n", + router_id); + + /* running time */ + monotime(&now); + timersub(&now, &o->starttime, &running); + timerstring(&running, duration, sizeof(duration)); + vty_out(vty, " Running %s\n", duration); + + /* Redistribute configuration */ + /* XXX */ + vty_out(vty, " LSA minimum arrival %d msecs\n", + o->lsa_minarrival); + + vty_out(vty, " Maximum-paths %u\n", o->max_multipath); + vty_out(vty, " Administrative distance %u\n", + o->distance_all ? o->distance_all + : ZEBRA_OSPF6_DISTANCE_DEFAULT); + + /* Show SPF parameters */ + vty_out(vty, + " Initial SPF scheduling delay %d millisec(s)\n" + " Minimum hold time between consecutive SPFs %d millsecond(s)\n" + " Maximum hold time between consecutive SPFs %d millsecond(s)\n" + " Hold time multiplier is currently %d\n", + o->spf_delay, o->spf_holdtime, o->spf_max_holdtime, + o->spf_hold_multiplier); + + + vty_out(vty, " SPF algorithm "); + if (o->ts_spf.tv_sec || o->ts_spf.tv_usec) { + timersub(&now, &o->ts_spf, &result); + timerstring(&result, buf, sizeof(buf)); + ospf6_spf_reason_string(o->last_spf_reason, rbuf, + sizeof(rbuf)); + vty_out(vty, "last executed %s ago, reason %s\n", buf, + rbuf); + vty_out(vty, " Last SPF duration %lld sec %lld usec\n", + (long long)o->ts_spf_duration.tv_sec, + (long long)o->ts_spf_duration.tv_usec); + } else + vty_out(vty, "has not been run\n"); + + threadtimer_string(now, o->t_spf_calc, buf, sizeof(buf)); + vty_out(vty, " SPF timer %s%s\n", + (event_is_scheduled(o->t_spf_calc) ? "due in " : "is "), + buf); + + if (CHECK_FLAG(o->flag, OSPF6_STUB_ROUTER)) + vty_out(vty, " Router Is Stub Router\n"); + + /* LSAs */ + vty_out(vty, " Number of AS scoped LSAs is %u\n", + o->lsdb->count); + + /* Areas */ + vty_out(vty, " Number of areas in this router is %u\n", + listcount(o->area_list)); + + vty_out(vty, " Authentication Sequence number info\n"); + vty_out(vty, " Higher sequence no %u, Lower sequence no %u\n", + o->seqnum_h, o->seqnum_l); + + if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) { + if (CHECK_FLAG(o->config_flags, + OSPF6_LOG_ADJACENCY_DETAIL)) + vty_out(vty, + " All adjacency changes are logged\n"); + else + vty_out(vty, " Adjacency changes are logged\n"); + } + + + vty_out(vty, "\n"); + + for (ALL_LIST_ELEMENTS_RO(o->area_list, n, oa)) + ospf6_area_show(vty, oa, json_areas, use_json); + } +} + +DEFUN(show_ipv6_ospf6_vrfs, show_ipv6_ospf6_vrfs_cmd, + "show ipv6 ospf6 vrfs [json]", + SHOW_STR IP6_STR OSPF6_STR "Show OSPF6 VRFs \n" JSON_STR) +{ + bool uj = use_json(argc, argv); + json_object *json = NULL; + json_object *json_vrfs = NULL; + struct ospf6 *ospf6 = NULL; + struct listnode *node = NULL; + int count = 0; + char buf[PREFIX_STRLEN]; + static const char header[] = + "Name Id RouterId "; + + if (uj) { + json = json_object_new_object(); + json_vrfs = json_object_new_object(); + } + + for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { + json_object *json_vrf = NULL; + const char *name = NULL; + int64_t vrf_id_ui = 0; + struct in_addr router_id; + + router_id.s_addr = ospf6->router_id; + count++; + + if (!uj && count == 1) + vty_out(vty, "%s\n", header); + if (uj) + json_vrf = json_object_new_object(); + + if (ospf6->vrf_id == VRF_DEFAULT) + name = VRF_DEFAULT_NAME; + else + name = ospf6->name; + + vrf_id_ui = (ospf6->vrf_id == VRF_UNKNOWN) + ? -1 + : (int64_t)ospf6->vrf_id; + + if (uj) { + json_object_int_add(json_vrf, "vrfId", vrf_id_ui); + json_object_string_addf(json_vrf, "routerId", "%pI4", + &router_id); + json_object_object_add(json_vrfs, name, json_vrf); + + } else { + vty_out(vty, "%-25s %-5d %-16s \n", name, + ospf6->vrf_id, + inet_ntop(AF_INET, &router_id, buf, + sizeof(buf))); + } + } + + if (uj) { + json_object_object_add(json, "vrfs", json_vrfs); + json_object_int_add(json, "totalVrfs", count); + + vty_json(vty, json); + } else { + if (count) + vty_out(vty, "\nTotal number of OSPF VRFs: %d\n", + count); + } + + return CMD_SUCCESS; +} + +/* show top level structures */ +DEFUN(show_ipv6_ospf6, show_ipv6_ospf6_cmd, + "show ipv6 ospf6 [vrf <NAME|all>] [json]", + SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR "All VRFs\n" JSON_STR) +{ + struct ospf6 *ospf6; + struct listnode *node; + const char *vrf_name = NULL; + bool all_vrf = false; + int idx_vrf = 0; + + bool uj = use_json(argc, argv); + json_object *json = NULL; + + OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + + for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { + if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) { + if (uj) + json = json_object_new_object(); + ospf6_show(vty, ospf6, json, uj); + + if (!all_vrf) + break; + } + } + + if (uj) + json_object_free(json); + + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + + return CMD_SUCCESS; +} + +DEFUN(show_ipv6_ospf6_route, show_ipv6_ospf6_route_cmd, + "show ipv6 ospf6 [vrf <NAME|all>] route [<intra-area|inter-area|external-1|external-2|X:X::X:X|X:X::X:X/M|detail|summary>] [json]", + SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR + "All VRFs\n" ROUTE_STR + "Display Intra-Area routes\n" + "Display Inter-Area routes\n" + "Display Type-1 External routes\n" + "Display Type-2 External routes\n" + "Specify IPv6 address\n" + "Specify IPv6 prefix\n" + "Detailed information\n" + "Summary of route table\n" JSON_STR) +{ + struct ospf6 *ospf6; + struct listnode *node; + const char *vrf_name = NULL; + bool all_vrf = false; + int idx_vrf = 0; + int idx_arg_start = 4; + bool uj = use_json(argc, argv); + + OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (idx_vrf > 0) + idx_arg_start += 2; + + for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { + if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) { + ospf6_route_table_show(vty, idx_arg_start, argc, argv, + ospf6->route_table, uj); + + if (!all_vrf) + break; + } + } + + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + + return CMD_SUCCESS; +} + +DEFUN(show_ipv6_ospf6_route_match, show_ipv6_ospf6_route_match_cmd, + "show ipv6 ospf6 [vrf <NAME|all>] route X:X::X:X/M <match|longer> [json]", + SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR + "All VRFs\n" ROUTE_STR + "Specify IPv6 prefix\n" + "Display routes which match the specified route\n" + "Display routes longer than the specified route\n" JSON_STR) +{ + struct ospf6 *ospf6; + struct listnode *node; + const char *vrf_name = NULL; + bool all_vrf = false; + int idx_vrf = 0; + int idx_start_arg = 4; + bool uj = use_json(argc, argv); + + OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (idx_vrf > 0) + idx_start_arg += 2; + + for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { + if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) { + ospf6_route_table_show(vty, idx_start_arg, argc, argv, + ospf6->route_table, uj); + + if (!all_vrf) + break; + } + } + + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + + return CMD_SUCCESS; +} + +DEFUN(show_ipv6_ospf6_route_match_detail, + show_ipv6_ospf6_route_match_detail_cmd, + "show ipv6 ospf6 [vrf <NAME|all>] route X:X::X:X/M match detail [json]", + SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR + "All VRFs\n" ROUTE_STR + "Specify IPv6 prefix\n" + "Display routes which match the specified route\n" + "Detailed information\n" JSON_STR) +{ + struct ospf6 *ospf6; + struct listnode *node; + const char *vrf_name = NULL; + bool all_vrf = false; + int idx_vrf = 0; + int idx_start_arg = 4; + bool uj = use_json(argc, argv); + + OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (idx_vrf > 0) + idx_start_arg += 2; + + for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { + if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) { + ospf6_route_table_show(vty, idx_start_arg, argc, argv, + ospf6->route_table, uj); + + if (!all_vrf) + break; + } + } + + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + + return CMD_SUCCESS; +} + +DEFUN(show_ipv6_ospf6_route_type_detail, show_ipv6_ospf6_route_type_detail_cmd, + "show ipv6 ospf6 [vrf <NAME|all>] route <intra-area|inter-area|external-1|external-2> detail [json]", + SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR + "All VRFs\n" ROUTE_STR + "Display Intra-Area routes\n" + "Display Inter-Area routes\n" + "Display Type-1 External routes\n" + "Display Type-2 External routes\n" + "Detailed information\n" JSON_STR) +{ + struct ospf6 *ospf6; + struct listnode *node; + const char *vrf_name = NULL; + bool all_vrf = false; + int idx_vrf = 0; + int idx_start_arg = 4; + bool uj = use_json(argc, argv); + + OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (idx_vrf > 0) + idx_start_arg += 2; + + for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { + if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) { + ospf6_route_table_show(vty, idx_start_arg, argc, argv, + ospf6->route_table, uj); + + if (!all_vrf) + break; + } + } + + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + + return CMD_SUCCESS; +} + +bool ospf6_is_valid_summary_addr(struct vty *vty, struct prefix *p) +{ + /* Default prefix validation*/ + if (is_default_prefix(p)) { + vty_out(vty, + "Default address should not be configured as summary address.\n"); + return false; + } + + /* Host route should not be configured as summary address */ + if (p->prefixlen == IPV6_MAX_BITLEN) { + vty_out(vty, "Host route should not be configured as summary address.\n"); + return false; + } + + return true; +} + +/* External Route Aggregation */ +DEFPY (ospf6_external_route_aggregation, + ospf6_external_route_aggregation_cmd, + "summary-address X:X::X:X/M$prefix [tag (1-4294967295)] [{metric (0-16777215) | metric-type (1-2)$mtype}]", + "External summary address\n" + "Specify IPv6 prefix\n" + "Router tag \n" + "Router tag value\n" + "Metric \n" + "Advertised metric for this route\n" + "OSPFv3 exterior metric type for summarised routes\n" + "Set OSPFv3 External Type 1/2 metrics\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + struct prefix p; + int ret = CMD_SUCCESS; + + p.family = AF_INET6; + ret = str2prefix(prefix_str, &p); + if (ret == 0) { + vty_out(vty, "Malformed prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Apply mask for given prefix. */ + apply_mask(&p); + + if (!ospf6_is_valid_summary_addr(vty, &p)) + return CMD_WARNING_CONFIG_FAILED; + + if (!tag_str) + tag = 0; + + if (!metric_str) + metric = -1; + + if (!mtype_str) + mtype = DEFAULT_METRIC_TYPE; + + ret = ospf6_external_aggr_config_set(ospf6, &p, tag, metric, mtype); + if (ret == OSPF6_FAILURE) { + vty_out(vty, "Invalid configuration!!\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return CMD_SUCCESS; +} + +DEFPY(no_ospf6_external_route_aggregation, + no_ospf6_external_route_aggregation_cmd, + "no summary-address X:X::X:X/M$prefix [tag (1-4294967295)] [{metric (0-16777215) | metric-type (1-2)}]", + NO_STR + "External summary address\n" + "Specify IPv6 prefix\n" + "Router tag\n" + "Router tag value\n" + "Metric \n" + "Advertised metric for this route\n" + "OSPFv3 exterior metric type for summarised routes\n" + "Set OSPFv3 External Type 1/2 metrics\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + struct prefix p; + int ret = CMD_SUCCESS; + + ret = str2prefix(prefix_str, &p); + if (ret == 0) { + vty_out(vty, "Malformed prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Apply mask for given prefix. */ + apply_mask(&p); + + if (!ospf6_is_valid_summary_addr(vty, &p)) + return CMD_WARNING_CONFIG_FAILED; + + ret = ospf6_external_aggr_config_unset(ospf6, &p); + if (ret == OSPF6_INVALID) + vty_out(vty, "Invalid configuration!!\n"); + + return CMD_SUCCESS; +} + +DEFPY (ospf6_external_route_aggregation_no_advertise, + ospf6_external_route_aggregation_no_advertise_cmd, + "summary-address X:X::X:X/M$prefix no-advertise", + "External summary address\n" + "Specify IPv6 prefix\n" + "Don't advertise summary route \n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + struct prefix p; + int ret = CMD_SUCCESS; + + ret = str2prefix(prefix_str, &p); + if (ret == 0) { + vty_out(vty, "Malformed prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Apply mask for given prefix. */ + apply_mask(&p); + + if (!ospf6_is_valid_summary_addr(vty, &p)) + return CMD_WARNING_CONFIG_FAILED; + + ret = ospf6_asbr_external_rt_no_advertise(ospf6, &p); + if (ret == OSPF6_INVALID) + vty_out(vty, "!!Invalid configuration\n"); + + return CMD_SUCCESS; +} + +DEFPY (no_ospf6_external_route_aggregation_no_advertise, + no_ospf6_external_route_aggregation_no_advertise_cmd, + "no summary-address X:X::X:X/M$prefix no-advertise", + NO_STR + "External summary address\n" + "Specify IPv6 prefix\n" + "Adverise summary route to the AS \n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + struct prefix p; + int ret = CMD_SUCCESS; + + ret = str2prefix(prefix_str, &p); + if (ret == 0) { + vty_out(vty, "Malformed prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Apply mask for given prefix. */ + apply_mask(&p); + + if (!ospf6_is_valid_summary_addr(vty, &p)) + return CMD_WARNING_CONFIG_FAILED; + + ret = ospf6_asbr_external_rt_advertise(ospf6, &p); + if (ret == OSPF6_INVALID) + vty_out(vty, "!!Invalid configuration\n"); + + return CMD_SUCCESS; +} + +DEFPY (ospf6_route_aggregation_timer, + ospf6_route_aggregation_timer_cmd, + "aggregation timer (5-1800)", + "External route aggregation\n" + "Delay timer (in seconds)\n" + "Timer interval(in seconds)\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + ospf6_external_aggr_delay_timer_set(ospf6, timer); + + return CMD_SUCCESS; +} + +DEFPY (no_ospf6_route_aggregation_timer, + no_ospf6_route_aggregation_timer_cmd, + "no aggregation timer [5-1800]", + NO_STR + "External route aggregation\n" + "Delay timer\n" + "Timer interval(in seconds)\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + ospf6_external_aggr_delay_timer_set(ospf6, + OSPF6_EXTL_AGGR_DEFAULT_DELAY); + return CMD_SUCCESS; +} + +static int +ospf6_print_vty_external_routes_walkcb(struct hash_bucket *bucket, void *arg) +{ + struct ospf6_route *rt = bucket->data; + struct vty *vty = (struct vty *)arg; + static unsigned int count; + + vty_out(vty, "%pFX ", &rt->prefix); + + count++; + + if (count%5 == 0) + vty_out(vty, "\n"); + + if (OSPF6_EXTERNAL_RT_COUNT(rt->aggr_route) == count) + count = 0; + + return HASHWALK_CONTINUE; +} + +static int +ospf6_print_json_external_routes_walkcb(struct hash_bucket *bucket, void *arg) +{ + struct ospf6_route *rt = bucket->data; + struct json_object *json = (struct json_object *)arg; + char buf[PREFIX2STR_BUFFER]; + char exnalbuf[20]; + static unsigned int count; + + prefix2str(&rt->prefix, buf, sizeof(buf)); + + snprintf(exnalbuf, sizeof(exnalbuf), "Exnl Addr-%d", count); + + json_object_string_add(json, exnalbuf, buf); + + count++; + + if (OSPF6_EXTERNAL_RT_COUNT(rt->aggr_route) == count) + count = 0; + + return HASHWALK_CONTINUE; +} + +static void +ospf6_show_vrf_name(struct vty *vty, struct ospf6 *ospf6, + json_object *json) +{ + if (json) { + if (ospf6->vrf_id == VRF_DEFAULT) + json_object_string_add(json, "vrfName", + "default"); + else + json_object_string_add(json, "vrfName", + ospf6->name); + json_object_int_add(json, "vrfId", ospf6->vrf_id); + } else { + if (ospf6->vrf_id == VRF_DEFAULT) + vty_out(vty, "VRF Name: %s\n", "default"); + else if (ospf6->name) + vty_out(vty, "VRF Name: %s\n", ospf6->name); + } +} + +static int +ospf6_show_summary_address(struct vty *vty, struct ospf6 *ospf6, + json_object *json, + bool uj, const char *detail) +{ + struct route_node *rn; + static const char header[] = "Summary-address Metric-type Metric Tag External_Rt_count\n"; + json_object *json_vrf = NULL; + + if (!uj) { + ospf6_show_vrf_name(vty, ospf6, json_vrf); + vty_out(vty, "aggregation delay interval: %u(in seconds)\n\n", + ospf6->aggr_delay_interval); + vty_out(vty, "%s\n", header); + } else { + json_vrf = json_object_new_object(); + + ospf6_show_vrf_name(vty, ospf6, json_vrf); + + json_object_int_add(json_vrf, "aggregationDelayInterval", + ospf6->aggr_delay_interval); + } + + + for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) { + if (!rn->info) + continue; + + struct ospf6_external_aggr_rt *aggr = rn->info; + json_object *json_aggr = NULL; + char buf[PREFIX2STR_BUFFER]; + + prefix2str(&aggr->p, buf, sizeof(buf)); + + if (uj) { + + json_aggr = json_object_new_object(); + + json_object_object_add(json_vrf, + buf, + json_aggr); + + json_object_string_add(json_aggr, "summaryAddress", + buf); + + json_object_string_add( + json_aggr, "metricType", + (aggr->mtype == DEFAULT_METRIC_TYPE) ? "E2" + : "E1"); + + json_object_int_add(json_aggr, "Metric", + (aggr->metric != -1) + ? aggr->metric + : DEFAULT_DEFAULT_METRIC); + + json_object_int_add(json_aggr, "Tag", + aggr->tag); + + json_object_int_add(json_aggr, "externalRouteCount", + OSPF6_EXTERNAL_RT_COUNT(aggr)); + + if (OSPF6_EXTERNAL_RT_COUNT(aggr) && detail) { + json_object_int_add(json_aggr, "ID", + aggr->id); + json_object_int_add(json_aggr, "Flags", + aggr->aggrflags); + hash_walk(aggr->match_extnl_hash, + ospf6_print_json_external_routes_walkcb, + json_aggr); + } + + } else { + vty_out(vty, "%-22s", buf); + + (aggr->mtype == DEFAULT_METRIC_TYPE) + ? vty_out(vty, "%-16s", "E2") + : vty_out(vty, "%-16s", "E1"); + vty_out(vty, "%-11d", (aggr->metric != -1) + ? aggr->metric + : DEFAULT_DEFAULT_METRIC); + + vty_out(vty, "%-12u", aggr->tag); + + vty_out(vty, "%-5ld\n", + OSPF6_EXTERNAL_RT_COUNT(aggr)); + + if (OSPF6_EXTERNAL_RT_COUNT(aggr) && detail) { + vty_out(vty, + "Matched External routes:\n"); + hash_walk(aggr->match_extnl_hash, + ospf6_print_vty_external_routes_walkcb, + vty); + vty_out(vty, "\n"); + } + + vty_out(vty, "\n"); + } + } + + if (uj) + json_object_object_add(json, ospf6->name, + json_vrf); + + return CMD_SUCCESS; +} + +DEFPY (show_ipv6_ospf6_external_aggregator, + show_ipv6_ospf6_external_aggregator_cmd, + "show ipv6 ospf6 [vrf <NAME|all>] summary-address [detail$detail] [json]", + SHOW_STR + IP6_STR + OSPF6_STR + VRF_CMD_HELP_STR + "All VRFs\n" + "Show external summary addresses\n" + "detailed information\n" + JSON_STR) +{ + bool uj = use_json(argc, argv); + struct ospf6 *ospf6 = NULL; + json_object *json = NULL; + const char *vrf_name = NULL; + struct listnode *node; + bool all_vrf = false; + int idx_vrf = 0; + + if (uj) + json = json_object_new_object(); + + OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + + for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { + if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) { + + ospf6_show_summary_address(vty, ospf6, json, uj, + detail); + + if (!all_vrf) + break; + } + } + + if (uj) { + vty_json(vty, json); + } + + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + + return CMD_SUCCESS; +} + +static void ospf6_stub_router_config_write(struct vty *vty, struct ospf6 *ospf6) +{ + if (CHECK_FLAG(ospf6->flag, OSPF6_STUB_ROUTER)) + vty_out(vty, " stub-router administrative\n"); + return; +} + +static int ospf6_distance_config_write(struct vty *vty, struct ospf6 *ospf6) +{ + struct route_node *rn; + struct ospf6_distance *odistance; + + if (ospf6->distance_all) + vty_out(vty, " distance %u\n", ospf6->distance_all); + + if (ospf6->distance_intra || ospf6->distance_inter + || ospf6->distance_external) { + vty_out(vty, " distance ospf6"); + + if (ospf6->distance_intra) + vty_out(vty, " intra-area %u", ospf6->distance_intra); + if (ospf6->distance_inter) + vty_out(vty, " inter-area %u", ospf6->distance_inter); + if (ospf6->distance_external) + vty_out(vty, " external %u", ospf6->distance_external); + + vty_out(vty, "\n"); + } + + for (rn = route_top(ospf6->distance_table); rn; rn = route_next(rn)) + if ((odistance = rn->info) != NULL) + vty_out(vty, " distance %u %pFX %s\n", + odistance->distance, &rn->p, + odistance->access_list ? odistance->access_list + : ""); + return 0; +} + +static int ospf6_asbr_summary_config_write(struct vty *vty, struct ospf6 *ospf6) +{ + struct route_node *rn; + struct ospf6_external_aggr_rt *aggr; + char buf[PREFIX2STR_BUFFER]; + + if (ospf6->aggr_delay_interval != OSPF6_EXTL_AGGR_DEFAULT_DELAY) + vty_out(vty, " aggregation timer %u\n", + ospf6->aggr_delay_interval); + + /* print 'summary-address A:B::C:D/M' */ + for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) { + if (!rn->info) + continue; + + aggr = rn->info; + + prefix2str(&aggr->p, buf, sizeof(buf)); + vty_out(vty, " summary-address %s", buf); + if (aggr->tag) + vty_out(vty, " tag %u", aggr->tag); + + if (aggr->metric != -1) + vty_out(vty, " metric %d", aggr->metric); + + if (aggr->mtype != DEFAULT_METRIC_TYPE) + vty_out(vty, " metric-type %d", aggr->mtype); + + if (CHECK_FLAG(aggr->aggrflags, + OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) + vty_out(vty, " no-advertise"); + + vty_out(vty, "\n"); + } + + return 0; +} + +/* OSPF configuration write function. */ +static int config_write_ospf6(struct vty *vty) +{ + struct ospf6 *ospf6; + struct listnode *node, *nnode; + + /* OSPFv3 configuration. */ + if (om6 == NULL) + return CMD_SUCCESS; + + for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) { + if (ospf6->name && strcmp(ospf6->name, VRF_DEFAULT_NAME)) + vty_out(vty, "router ospf6 vrf %s\n", ospf6->name); + else + vty_out(vty, "router ospf6\n"); + + if (ospf6->router_id_static != 0) + vty_out(vty, " ospf6 router-id %pI4\n", + &ospf6->router_id_static); + + if (CHECK_FLAG(ospf6->config_flags, + OSPF6_SEND_EXTRA_DATA_TO_ZEBRA)) + vty_out(vty, " ospf6 send-extra-data zebra\n"); + + /* log-adjacency-changes flag print. */ + if (CHECK_FLAG(ospf6->config_flags, + OSPF6_LOG_ADJACENCY_CHANGES)) { + if (CHECK_FLAG(ospf6->config_flags, + OSPF6_LOG_ADJACENCY_DETAIL)) + vty_out(vty, " log-adjacency-changes detail\n"); + else if (!SAVE_OSPF6_LOG_ADJACENCY_CHANGES) + vty_out(vty, " log-adjacency-changes\n"); + } else if (SAVE_OSPF6_LOG_ADJACENCY_CHANGES) { + vty_out(vty, " no log-adjacency-changes\n"); + } + + if (ospf6->ref_bandwidth != OSPF6_REFERENCE_BANDWIDTH) + vty_out(vty, " auto-cost reference-bandwidth %d\n", + ospf6->ref_bandwidth); + + if (ospf6->write_oi_count + != OSPF6_WRITE_INTERFACE_COUNT_DEFAULT) + vty_out(vty, " write-multiplier %d\n", + ospf6->write_oi_count); + + /* LSA timers print. */ + if (ospf6->lsa_minarrival != OSPF_MIN_LS_ARRIVAL) + vty_out(vty, " timers lsa min-arrival %d\n", + ospf6->lsa_minarrival); + + /* ECMP max path config */ + if (ospf6->max_multipath != MULTIPATH_NUM) + vty_out(vty, " maximum-paths %d\n", + ospf6->max_multipath); + + ospf6_stub_router_config_write(vty, ospf6); + ospf6_redistribute_config_write(vty, ospf6); + ospf6_area_config_write(vty, ospf6); + ospf6_spf_config_write(vty, ospf6); + ospf6_distance_config_write(vty, ospf6); + ospf6_distribute_config_write(vty, ospf6); + ospf6_asbr_summary_config_write(vty, ospf6); + config_write_ospf6_gr(vty, ospf6); + config_write_ospf6_gr_helper(vty, ospf6); + + vty_out(vty, "exit\n"); + vty_out(vty, "!\n"); + } + return 0; +} + +static int config_write_ospf6(struct vty *vty); +/* OSPF6 node structure. */ +static struct cmd_node ospf6_node = { + .name = "ospf6", + .node = OSPF6_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-ospf6)# ", + .config_write = config_write_ospf6, +}; + +void install_element_ospf6_clear_process(void) +{ + install_element(ENABLE_NODE, &clear_router_ospf6_cmd); +} + +/* Install ospf related commands. */ +void ospf6_top_init(void) +{ + /* Install ospf6 top node. */ + install_node(&ospf6_node); + + install_element(VIEW_NODE, &show_ipv6_ospf6_cmd); + install_element(VIEW_NODE, &show_ipv6_ospf6_vrfs_cmd); + install_element(CONFIG_NODE, &router_ospf6_cmd); + install_element(CONFIG_NODE, &no_router_ospf6_cmd); + + install_element(VIEW_NODE, &show_ipv6_ospf6_route_cmd); + install_element(VIEW_NODE, &show_ipv6_ospf6_route_match_cmd); + install_element(VIEW_NODE, &show_ipv6_ospf6_route_match_detail_cmd); + install_element(VIEW_NODE, &show_ipv6_ospf6_route_type_detail_cmd); + + install_default(OSPF6_NODE); + install_element(OSPF6_NODE, &ospf6_router_id_cmd); + install_element(OSPF6_NODE, &no_ospf6_router_id_cmd); + install_element(OSPF6_NODE, &ospf6_log_adjacency_changes_cmd); + install_element(OSPF6_NODE, &ospf6_log_adjacency_changes_detail_cmd); + install_element(OSPF6_NODE, &no_ospf6_log_adjacency_changes_cmd); + install_element(OSPF6_NODE, &no_ospf6_log_adjacency_changes_detail_cmd); + install_element(OSPF6_NODE, &ospf6_send_extra_data_cmd); + + /* LSA timers commands */ + install_element(OSPF6_NODE, &ospf6_timers_lsa_cmd); + install_element(OSPF6_NODE, &no_ospf6_timers_lsa_cmd); + + install_element(OSPF6_NODE, &ospf6_interface_area_cmd); + install_element(OSPF6_NODE, &no_ospf6_interface_area_cmd); + install_element(OSPF6_NODE, &ospf6_stub_router_admin_cmd); + install_element(OSPF6_NODE, &no_ospf6_stub_router_admin_cmd); + + /* maximum-paths command */ + install_element(OSPF6_NODE, &ospf6_max_multipath_cmd); + install_element(OSPF6_NODE, &no_ospf6_max_multipath_cmd); + + /* ASBR Summarisation */ + install_element(OSPF6_NODE, &ospf6_external_route_aggregation_cmd); + install_element(OSPF6_NODE, &no_ospf6_external_route_aggregation_cmd); + install_element(OSPF6_NODE, + &ospf6_external_route_aggregation_no_advertise_cmd); + install_element(OSPF6_NODE, + &no_ospf6_external_route_aggregation_no_advertise_cmd); + install_element(OSPF6_NODE, &ospf6_route_aggregation_timer_cmd); + install_element(OSPF6_NODE, &no_ospf6_route_aggregation_timer_cmd); + install_element(VIEW_NODE, &show_ipv6_ospf6_external_aggregator_cmd); + + install_element(OSPF6_NODE, &ospf6_distance_cmd); + install_element(OSPF6_NODE, &no_ospf6_distance_cmd); + install_element(OSPF6_NODE, &ospf6_distance_ospf6_cmd); + install_element(OSPF6_NODE, &no_ospf6_distance_ospf6_cmd); +} |