diff options
Diffstat (limited to 'ospf6d/ospf6_top.c')
| -rw-r--r-- | ospf6d/ospf6_top.c | 496 |
1 files changed, 495 insertions, 1 deletions
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 92f1e50c65..6105e2c24b 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -409,13 +409,31 @@ static struct ospf6 *ospf6_create(const char *name) 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->external_id_table = route_table_init(); 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->t_external_aggr = NULL; + o->aggr_action = OSPF6_ROUTE_AGGR_NONE; + o->fd = -1; o->max_multipath = MULTIPATH_NUM; @@ -461,6 +479,7 @@ struct ospf6 *ospf6_instance_create(const char *name) void ospf6_delete(struct ospf6 *o) { struct listnode *node, *nnode; + struct route_node *rn = NULL; struct ospf6_area *oa; struct vrf *vrf; @@ -499,6 +518,11 @@ void ospf6_delete(struct ospf6 *o) ospf6_vrf_unlink(o, vrf); } + for (rn = route_top(o->rt_aggr_tbl); rn; rn = route_next(rn)) + if (rn->info) + ospf6_external_aggregator_free(rn->info); + route_table_finish(o->rt_aggr_tbl); + XFREE(MTYPE_OSPF6_TOP, o->name); XFREE(MTYPE_OSPF6_TOP, o); } @@ -527,6 +551,7 @@ static void ospf6_disable(struct ospf6 *o) THREAD_OFF(o->t_ase_calc); THREAD_OFF(o->t_distribute_update); THREAD_OFF(o->t_ospf6_receive); + THREAD_OFF(o->t_external_aggr); } } @@ -690,6 +715,7 @@ 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); @@ -1654,6 +1680,424 @@ DEFUN(show_ipv6_ospf6_route_type_detail, show_ipv6_ospf6_route_type_detail_cmd, return CMD_SUCCESS; } +bool ospf6_is_valid_summary_addr(struct vty *vty, struct prefix *p) +{ + struct in6_addr addr_zero; + + memset(&addr_zero, 0, sizeof(struct in6_addr)); + + /* Default prefix validation*/ + if ((is_default_prefix((struct prefix *)p)) + || (!memcmp(&p->u.prefix6, &addr_zero, sizeof(struct in6_addr)))) { + 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((struct prefix *)&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((struct prefix *)&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((struct prefix *)&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((struct prefix *)&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 :%d(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, "aggregation delay interval", + 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, + "Summary address", + buf); + + json_object_string_add( + json_aggr, "Metric-type", + (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, + "External route count", + 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 informtion\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_CMD_CHECK_RUNNING(); + 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_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} + static void ospf6_stub_router_config_write(struct vty *vty, struct ospf6 *ospf6) { if (CHECK_FLAG(ospf6->flag, OSPF6_STUB_ROUTER)) { @@ -1693,6 +2137,44 @@ static int ospf6_distance_config_write(struct vty *vty, struct ospf6 *ospf6) 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) { @@ -1750,6 +2232,7 @@ static int config_write_ospf6(struct vty *vty) 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); vty_out(vty, "!\n"); } @@ -1808,6 +2291,17 @@ void ospf6_top_init(void) 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); |
