From 055355e10432fcbf37038f3116ef7ac388013b3b Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Wed, 5 Apr 2023 23:55:13 -0500 Subject: [PATCH] lib, ospfd, yang: add route map set for min/max metric Signed-off-by: Jafar Al-Gharaibeh --- lib/routemap.c | 34 ++++++++++ lib/routemap.h | 37 +++++++++++ lib/routemap_cli.c | 84 +++++++++++++++++++++++ lib/routemap_northbound.c | 118 +++++++++++++++++++++++++++++++++ ospfd/ospf_asbr.c | 2 + ospfd/ospf_asbr.h | 2 + ospfd/ospf_routemap.c | 136 +++++++++++++++++++++++++++++++++++--- yang/frr-route-map.yang | 45 +++++++++++++ 8 files changed, 448 insertions(+), 10 deletions(-) diff --git a/lib/routemap.c b/lib/routemap.c index 20dcd2a53d..39455841e3 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -394,6 +394,40 @@ void route_map_no_set_metric_hook(int (*func)(struct route_map_index *index, { rmap_match_set_hook.no_set_metric = func; } +/* set min-metric */ +void route_map_set_min_metric_hook(int (*func)(struct route_map_index *index, + const char *command, + const char *arg, char *errmsg, + size_t errmsg_len)) +{ + rmap_match_set_hook.set_min_metric = func; +} + +/* no set min-metric */ +void route_map_no_set_min_metric_hook(int (*func)(struct route_map_index *index, + const char *command, + const char *arg, char *errmsg, + size_t errmsg_len)) +{ + rmap_match_set_hook.no_set_min_metric = func; +} +/* set max-metric */ +void route_map_set_max_metric_hook(int (*func)(struct route_map_index *index, + const char *command, + const char *arg, char *errmsg, + size_t errmsg_len)) +{ + rmap_match_set_hook.set_max_metric = func; +} + +/* no set max-metric */ +void route_map_no_set_max_metric_hook(int (*func)(struct route_map_index *index, + const char *command, + const char *arg, char *errmsg, + size_t errmsg_len)) +{ + rmap_match_set_hook.no_set_max_metric = func; +} /* set tag */ void route_map_set_tag_hook(int (*func)(struct route_map_index *index, diff --git a/lib/routemap.h b/lib/routemap.h index 2197a49e76..770d705837 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -312,6 +312,8 @@ DECLARE_QOBJ_TYPE(route_map); (strmatch(A, "frr-route-map:ipv6-next-hop")) #define IS_SET_METRIC(A) \ (strmatch(A, "frr-route-map:set-metric")) +#define IS_SET_MIN_METRIC(A) (strmatch(A, "frr-route-map:set-min-metric")) +#define IS_SET_MAX_METRIC(A) (strmatch(A, "frr-route-map:set-max-metric")) #define IS_SET_TAG(A) (strmatch(A, "frr-route-map:set-tag")) #define IS_SET_SR_TE_COLOR(A) \ (strmatch(A, "frr-route-map:set-sr-te-color")) @@ -684,6 +686,22 @@ extern void route_map_no_set_metric_hook( int (*func)(struct route_map_index *index, const char *command, const char *arg, char *errmsg, size_t errmsg_len)); +/* set metric */ +extern void route_map_set_max_metric_hook( + int (*func)(struct route_map_index *index, const char *command, + const char *arg, char *errmsg, size_t errmsg_len)); +/* no set metric */ +extern void route_map_no_set_max_metric_hook( + int (*func)(struct route_map_index *index, const char *command, + const char *arg, char *errmsg, size_t errmsg_len)); +/* set metric */ +extern void route_map_set_min_metric_hook( + int (*func)(struct route_map_index *index, const char *command, + const char *arg, char *errmsg, size_t errmsg_len)); +/* no set metric */ +extern void route_map_no_set_min_metric_hook( + int (*func)(struct route_map_index *index, const char *command, + const char *arg, char *errmsg, size_t errmsg_len)); /* set tag */ extern void route_map_set_tag_hook(int (*func)(struct route_map_index *index, const char *command, @@ -920,6 +938,25 @@ struct route_map_match_set_hooks { int (*no_set_metric)(struct route_map_index *index, const char *command, const char *arg, char *errmsg, size_t errmsg_len); + /* set min-metric */ + int (*set_min_metric)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); + + /* no set min-metric */ + int (*no_set_min_metric)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); + + /* set max-metric */ + int (*set_max_metric)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); + + /* no set max-metric */ + int (*no_set_max_metric)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); /* set tag */ int (*set_tag)(struct route_map_index *index, diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index 4345b74bc0..75d1175886 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -890,6 +890,76 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } +DEFPY_YANG(set_min_metric, set_min_metric_cmd, + "set min-metric <(0-4294967295)$metric>", + SET_STR + "Minimum metric value for destination routing protocol\n" + "Minimum metric value\n") +{ + const char *xpath = + "./set-action[action='frr-route-map:set-min-metric']"; + char xpath_value[XPATH_MAXLEN]; + char value[64]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/min-metric", xpath); + snprintf(value, sizeof(value), "%s", metric_str); + + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, value); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG(no_set_min_metric, no_set_min_metric_cmd, + "no set min-metric [(0-4294967295)]", + NO_STR SET_STR + "Minimum metric value for destination routing protocol\n" + "Minumum metric value\n") +{ + const char *xpath = + "./set-action[action='frr-route-map:set-min-metric']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG(set_max_metric, set_max_metric_cmd, + "set max-metric <(0-4294967295)$metric>", + SET_STR + "Maximum metric value for destination routing protocol\n" + "Miximum metric value\n") +{ + const char *xpath = + "./set-action[action='frr-route-map:set-max-metric']"; + char xpath_value[XPATH_MAXLEN]; + char value[64]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/max-metric", xpath); + snprintf(value, sizeof(value), "%s", metric_str); + + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, value); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG(no_set_max_metric, no_set_max_metric_cmd, + "no set max-metric [(0-4294967295)]", + NO_STR SET_STR + "Maximum Metric value for destination routing protocol\n" + "Maximum metric value\n") +{ + const char *xpath = + "./set-action[action='frr-route-map:set-max-metric']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + DEFPY_YANG( set_tag, set_tag_cmd, "set tag (1-4294967295)$tag", @@ -1011,6 +1081,14 @@ void route_map_action_show(struct vty *vty, const struct lyd_node *dnode, yang_dnode_get_string( dnode, "./rmap-set-action/value")); } + } else if (IS_SET_MIN_METRIC(action)) { + vty_out(vty, " set min-metric %s\n", + yang_dnode_get_string(dnode, + "./rmap-set-action/min-metric")); + } else if (IS_SET_MAX_METRIC(action)) { + vty_out(vty, " set max-metric %s\n", + yang_dnode_get_string(dnode, + "./rmap-set-action/max-metric")); } else if (IS_SET_TAG(action)) { vty_out(vty, " set tag %s\n", yang_dnode_get_string(dnode, "./rmap-set-action/tag")); @@ -1551,6 +1629,12 @@ void route_map_cli_init(void) install_element(RMAP_NODE, &set_metric_cmd); install_element(RMAP_NODE, &no_set_metric_cmd); + install_element(RMAP_NODE, &set_min_metric_cmd); + install_element(RMAP_NODE, &no_set_min_metric_cmd); + + install_element(RMAP_NODE, &set_max_metric_cmd); + install_element(RMAP_NODE, &no_set_max_metric_cmd); + install_element(RMAP_NODE, &set_tag_cmd); install_element(RMAP_NODE, &no_set_tag_cmd); diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c index ab127dd0fc..4659850994 100644 --- a/lib/routemap_northbound.c +++ b/lib/routemap_northbound.c @@ -1027,6 +1027,110 @@ lib_route_map_entry_set_action_value_destroy(struct nb_cb_destroy_args *args) return lib_route_map_entry_set_destroy(args); } +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/min-metric + */ +static int set_action_min_metric_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource, + const char *value, char *errmsg, + size_t errmsg_len) +{ + struct routemap_hook_context *rhc; + int rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + /* Check for hook function. */ + if (rmap_match_set_hook.set_min_metric == NULL) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + + /* Set destroy information. */ + rhc->rhc_shook = rmap_match_set_hook.no_set_min_metric; + rhc->rhc_rule = "min-metric"; + + rv = rmap_match_set_hook.set_min_metric(rhc->rhc_rmi, "min-metric", + value, errmsg, errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int +lib_route_map_entry_set_action_min_metric_modify(struct nb_cb_modify_args *args) +{ + const char *min_metric = yang_dnode_get_string(args->dnode, NULL); + + return set_action_min_metric_modify(args->event, args->dnode, + args->resource, min_metric, + args->errmsg, args->errmsg_len); +} + +static int lib_route_map_entry_set_action_min_metric_destroy( + struct nb_cb_destroy_args *args) +{ + return lib_route_map_entry_set_destroy(args); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/max-metric + */ +static int set_action_max_metric_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource, + const char *value, char *errmsg, + size_t errmsg_len) +{ + struct routemap_hook_context *rhc; + int rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + /* Check for hook function. */ + if (rmap_match_set_hook.set_max_metric == NULL) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + + /* Set destroy information. */ + rhc->rhc_shook = rmap_match_set_hook.no_set_max_metric; + rhc->rhc_rule = "max-metric"; + + rv = rmap_match_set_hook.set_max_metric(rhc->rhc_rmi, "max-metric", + value, errmsg, errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int +lib_route_map_entry_set_action_max_metric_modify(struct nb_cb_modify_args *args) +{ + const char *max_metric = yang_dnode_get_string(args->dnode, NULL); + + return set_action_max_metric_modify(args->event, args->dnode, + args->resource, max_metric, + args->errmsg, args->errmsg_len); +} + +static int lib_route_map_entry_set_action_max_metric_destroy( + struct nb_cb_destroy_args *args) +{ + return lib_route_map_entry_set_destroy(args); +} + /* * XPath: /frr-route-map:lib/route-map/entry/set-action/add-metric */ @@ -1368,6 +1472,20 @@ const struct frr_yang_module_info frr_route_map_info = { .destroy = lib_route_map_entry_set_action_value_destroy, } }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/min-metric", + .cbs = { + .modify = lib_route_map_entry_set_action_min_metric_modify, + .destroy = lib_route_map_entry_set_action_min_metric_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/max-metric", + .cbs = { + .modify = lib_route_map_entry_set_action_max_metric_modify, + .destroy = lib_route_map_entry_set_action_max_metric_destroy, + } + }, { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/add-metric", .cbs = { diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 516ee80c5b..1b68f6e022 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -132,6 +132,8 @@ ospf_external_info_add(struct ospf *ospf, uint8_t type, unsigned short instance, new->orig_tag = tag; new->aggr_route = NULL; new->metric = metric; + new->min_metric = 0; + new->max_metric = OSPF_LS_INFINITY; /* we don't unlock rn from the get() because we're attaching the info */ if (rn) diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h index 256a6c8b5b..dfb9d965c5 100644 --- a/ospfd/ospf_asbr.h +++ b/ospfd/ospf_asbr.h @@ -37,6 +37,8 @@ struct external_info { route_tag_t orig_tag; uint32_t metric; + uint32_t min_metric; + uint32_t max_metric; struct route_map_set_values route_map_set; #define ROUTEMAP_METRIC(E) (E)->route_map_set.metric diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index 9656867745..d2f639031b 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -398,17 +398,19 @@ route_set_metric(void *rule, const struct prefix *prefix, void *object) if (!metric->used) return RMAP_OKAY; - ei->route_map_set.metric = ei->metric; + ROUTEMAP_METRIC(ei) = ei->metric; if (metric->type == metric_increment) - ei->route_map_set.metric += metric->metric; + ROUTEMAP_METRIC(ei) += metric->metric; else if (metric->type == metric_decrement) - ei->route_map_set.metric -= metric->metric; + ROUTEMAP_METRIC(ei) -= metric->metric; else if (metric->type == metric_absolute) - ei->route_map_set.metric = metric->metric; + ROUTEMAP_METRIC(ei) = metric->metric; - if (ei->route_map_set.metric > OSPF_LS_INFINITY) - ei->route_map_set.metric = OSPF_LS_INFINITY; + if ((uint32_t)ROUTEMAP_METRIC(ei) < ei->min_metric) + ROUTEMAP_METRIC(ei) = ei->min_metric; + if ((uint32_t)ROUTEMAP_METRIC(ei) > ei->max_metric) + ROUTEMAP_METRIC(ei) = ei->max_metric; return RMAP_OKAY; } @@ -462,6 +464,115 @@ static const struct route_map_rule_cmd route_set_metric_cmd = { route_set_metric_free, }; +/* `set min-metric METRIC' */ +/* Set min-metric to attribute. */ +static enum route_map_cmd_result_t +route_set_min_metric(void *rule, const struct prefix *prefix, void *object) +{ + uint32_t *min_metric; + struct external_info *ei; + + /* Fetch routemap's rule information. */ + min_metric = rule; + ei = object; + + ei->min_metric = *min_metric; + + if (ei->min_metric > OSPF_LS_INFINITY) + ei->min_metric = OSPF_LS_INFINITY; + + if ((uint32_t)ROUTEMAP_METRIC(ei) < ei->min_metric) + ROUTEMAP_METRIC(ei) = ei->min_metric; + + return RMAP_OKAY; +} + +/* set min-metric compilation. */ +static void *route_set_min_metric_compile(const char *arg) +{ + + uint32_t *min_metric; + + min_metric = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t)); + + *min_metric = strtoul(arg, NULL, 10); + + if (*min_metric) + return min_metric; + + XFREE(MTYPE_ROUTE_MAP_COMPILED, min_metric); + return NULL; +} + +/* Free route map's compiled `set min-metric' value. */ +static void route_set_min_metric_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +static const struct route_map_rule_cmd route_set_min_metric_cmd = { + "min-metric", + route_set_min_metric, + route_set_min_metric_compile, + route_set_min_metric_free, +}; + + +/* `set max-metric METRIC' */ +/* Set max-metric to attribute. */ +static enum route_map_cmd_result_t +route_set_max_metric(void *rule, const struct prefix *prefix, void *object) +{ + uint32_t *max_metric; + struct external_info *ei; + + /* Fetch routemap's rule information. */ + max_metric = rule; + ei = object; + + ei->max_metric = *max_metric; + + if (ei->max_metric > OSPF_LS_INFINITY) + ei->max_metric = OSPF_LS_INFINITY; + + if ((uint32_t)ROUTEMAP_METRIC(ei) > ei->max_metric) + ROUTEMAP_METRIC(ei) = ei->max_metric; + + return RMAP_OKAY; +} + +/* set max-metric compilation. */ +static void *route_set_max_metric_compile(const char *arg) +{ + + uint32_t *max_metric; + + max_metric = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t)); + + *max_metric = strtoul(arg, NULL, 10); + + if (*max_metric) + return max_metric; + + XFREE(MTYPE_ROUTE_MAP_COMPILED, max_metric); + return NULL; +} + +/* Free route map's compiled `set max-metric' value. */ +static void route_set_max_metric_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set metric rule structure. */ +static const struct route_map_rule_cmd route_set_max_metric_cmd = { + "max-metric", + route_set_max_metric, + route_set_max_metric_compile, + route_set_max_metric_free, +}; + /* `set metric-type TYPE' */ /* Set metric-type to attribute. */ static enum route_map_cmd_result_t @@ -475,7 +586,7 @@ route_set_metric_type(void *rule, const struct prefix *prefix, void *object) ei = object; /* Set metric out value. */ - ei->route_map_set.metric_type = *metric_type; + ROUTEMAP_METRIC_TYPE(ei) = *metric_type; return RMAP_OKAY; } @@ -582,9 +693,6 @@ void ospf_route_map_init(void) route_map_delete_hook(ospf_route_map_update); route_map_event_hook(ospf_route_map_event); - route_map_set_metric_hook(generic_set_add); - route_map_no_set_metric_hook(generic_set_delete); - route_map_match_ip_next_hop_hook(generic_match_add); route_map_no_match_ip_next_hop_hook(generic_match_delete); @@ -609,6 +717,12 @@ void ospf_route_map_init(void) route_map_set_metric_hook(generic_set_add); route_map_no_set_metric_hook(generic_set_delete); + route_map_set_min_metric_hook(generic_set_add); + route_map_no_set_min_metric_hook(generic_set_delete); + + route_map_set_max_metric_hook(generic_set_add); + route_map_no_set_max_metric_hook(generic_set_delete); + route_map_set_tag_hook(generic_set_add); route_map_no_set_tag_hook(generic_set_delete); @@ -621,6 +735,8 @@ void ospf_route_map_init(void) route_map_install_match(&route_match_tag_cmd); route_map_install_set(&route_set_metric_cmd); + route_map_install_set(&route_set_min_metric_cmd); + route_map_install_set(&route_set_max_metric_cmd); route_map_install_set(&route_set_metric_type_cmd); route_map_install_set(&route_set_tag_cmd); diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index 224b2caef7..7cb13b60f2 100644 --- a/yang/frr-route-map.yang +++ b/yang/frr-route-map.yang @@ -160,6 +160,18 @@ module frr-route-map { "Set prefix/route metric"; } + identity set-min-metric { + base rmap-set-type; + description + "Set minimum prefix/route metric"; + } + + identity set-max-metric { + base rmap-set-type; + description + "Set maximum prefix/route metric"; + } + identity set-tag { base rmap-set-type; description @@ -346,6 +358,39 @@ module frr-route-map { } } + case set-min-metric { + when "derived-from-or-self(../action, 'set-min-metric')"; + choice minimun-metric-value { + description + "Mimimum metric to set or use"; + case min-metric { + leaf min-metric { + type uint32 { + range "0..4294967295"; + } + description + "Use the following mimumn metric value"; + } + } + } + } + + case set-max-metric { + when "derived-from-or-self(../action, 'set-max-metric')"; + choice maximum-metric-value { + description + "Maximum metric to set or use"; + case max-metric { + leaf max-metric { + type uint32 { + range "0..4294967295"; + } + description + "Use the following maximum metric value"; + } + } + } + } case set-tag { when "derived-from-or-self(../action, 'set-tag')"; leaf tag { -- 2.39.5