]> git.proxmox.com Git - mirror_frr.git/blobdiff - ospf6d/ospf6_top.c
Merge pull request #9028 from mobash-rasool/ospfv3-asbr-summarisation
[mirror_frr.git] / ospf6d / ospf6_top.c
index 92f1e50c65dd037900d95099cde4a72750991617..6105e2c24be29dca0b17e699205f17e3a3a82ee6 100644 (file)
@@ -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);