From 0c0e73045b1898610eef9309b9f5927254356710 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Fri, 27 Sep 2019 19:32:10 -0300 Subject: [PATCH 01/10] yang: update route map model Important changes: * Rename top container `route-map` to `lib`; * Rename list `instance` to `route-map`; * Move route map repeated data to list `entry`; * Use interface reference instead of typedef'ed string; * Remove some zebra specific route map conditions; * Protect `tag` set value with `when "./action = 'tag'"`; Signed-off-by: Rafael Zalamena --- From a7282663eff6f036a427165b7fa73c75dccd47ff Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 30 Sep 2019 10:17:33 -0300 Subject: [PATCH 02/10] lib: export route map structures and functions These exported items are going to be used by the new northbound CLI. Signed-off-by: Rafael Zalamena --- lib/routemap.c | 213 ++----------------------------------------------- lib/routemap.h | 209 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+), 206 deletions(-) diff --git a/lib/routemap.c b/lib/routemap.c index 14fec0283c..a8feebd313 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -50,178 +50,7 @@ static vector route_match_vec; /* Vector for route set rules. */ static vector route_set_vec; -struct route_map_match_set_hooks { - /* match interface */ - int (*match_interface)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg, - route_map_event_t type); - - /* no match interface */ - int (*no_match_interface)(struct vty *vty, - struct route_map_index *index, - const char *command, const char *arg, - route_map_event_t type); - - /* match ip address */ - int (*match_ip_address)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg, - route_map_event_t type); - - /* no match ip address */ - int (*no_match_ip_address)(struct vty *vty, - struct route_map_index *index, - const char *command, const char *arg, - route_map_event_t type); - - /* match ip address prefix list */ - int (*match_ip_address_prefix_list)(struct vty *vty, - struct route_map_index *index, - const char *command, - const char *arg, - route_map_event_t type); - - /* no match ip address prefix list */ - int (*no_match_ip_address_prefix_list)(struct vty *vty, - struct route_map_index *index, - const char *command, - const char *arg, - route_map_event_t type); - - /* match ip next hop */ - int (*match_ip_next_hop)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg, - route_map_event_t type); - - /* no match ip next hop */ - int (*no_match_ip_next_hop)(struct vty *vty, - struct route_map_index *index, - const char *command, const char *arg, - route_map_event_t type); - - /* match ip next hop prefix list */ - int (*match_ip_next_hop_prefix_list)(struct vty *vty, - struct route_map_index *index, - const char *command, - const char *arg, - route_map_event_t type); - - /* no match ip next hop prefix list */ - int (*no_match_ip_next_hop_prefix_list)(struct vty *vty, - struct route_map_index *index, - const char *command, - const char *arg, - route_map_event_t type); - - /* match ip next-hop type */ - int (*match_ip_next_hop_type)(struct vty *vty, - struct route_map_index *index, - const char *command, - const char *arg, - route_map_event_t type); - - /* no match ip next-hop type */ - int (*no_match_ip_next_hop_type)(struct vty *vty, - struct route_map_index *index, - const char *command, - const char *arg, - route_map_event_t type); - - /* match ipv6 address */ - int (*match_ipv6_address)(struct vty *vty, - struct route_map_index *index, - const char *command, const char *arg, - route_map_event_t type); - - /* no match ipv6 address */ - int (*no_match_ipv6_address)(struct vty *vty, - struct route_map_index *index, - const char *command, const char *arg, - route_map_event_t type); - - - /* match ipv6 address prefix list */ - int (*match_ipv6_address_prefix_list)(struct vty *vty, - struct route_map_index *index, - const char *command, - const char *arg, - route_map_event_t type); - - /* no match ipv6 address prefix list */ - int (*no_match_ipv6_address_prefix_list)(struct vty *vty, - struct route_map_index *index, - const char *command, - const char *arg, - route_map_event_t type); - - /* match ipv6 next-hop type */ - int (*match_ipv6_next_hop_type)(struct vty *vty, - struct route_map_index *index, - const char *command, - const char *arg, - route_map_event_t type); - - /* no match ipv6 next-hop type */ - int (*no_match_ipv6_next_hop_type)(struct vty *vty, - struct route_map_index *index, - const char *command, const char *arg, - route_map_event_t type); - - /* match metric */ - int (*match_metric)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg, - route_map_event_t type); - - /* no match metric */ - int (*no_match_metric)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg, - route_map_event_t type); - - /* match tag */ - int (*match_tag)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg, - route_map_event_t type); - - /* no match tag */ - int (*no_match_tag)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg, - route_map_event_t type); - - /* set ip nexthop */ - int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); - - /* no set ip nexthop */ - int (*no_set_ip_nexthop)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); - - /* set ipv6 nexthop local */ - int (*set_ipv6_nexthop_local)(struct vty *vty, - struct route_map_index *index, - const char *command, const char *arg); - - /* no set ipv6 nexthop local */ - int (*no_set_ipv6_nexthop_local)(struct vty *vty, - struct route_map_index *index, - const char *command, const char *arg); - - /* set metric */ - int (*set_metric)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); - - /* no set metric */ - int (*no_set_metric)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); - - /* set tag */ - int (*set_tag)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); - - /* no set tag */ - int (*no_set_tag)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); -}; - -static struct route_map_match_set_hooks rmap_match_set_hook; +struct route_map_match_set_hooks rmap_match_set_hook; /* match interface */ void route_map_match_interface_hook(int (*func)( @@ -595,35 +424,9 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index, } -/* Route map rule. This rule has both `match' rule and `set' rule. */ -struct route_map_rule { - /* Rule type. */ - const struct route_map_rule_cmd *cmd; - - /* For pretty printing. */ - char *rule_str; - - /* Pre-compiled match rule. */ - void *value; - - /* Linked list. */ - struct route_map_rule *next; - struct route_map_rule *prev; -}; - -/* Making route map list. */ -struct route_map_list { - struct route_map *head; - struct route_map *tail; - - void (*add_hook)(const char *); - void (*delete_hook)(const char *); - void (*event_hook)(const char *); -}; - /* Master list of route map. */ -static struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL}; -static struct hash *route_map_master_hash = NULL; +struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL}; +struct hash *route_map_master_hash = NULL; static unsigned int route_map_hash_key_make(const void *p) { @@ -691,8 +494,6 @@ static void route_map_rule_delete(struct route_map_rule_list *, struct route_map_rule *); static bool rmap_debug; -static void route_map_index_delete(struct route_map_index *, int); - /* New route map allocation. Please note route map's name must be specified. */ static struct route_map *route_map_new(const char *name) @@ -784,7 +585,7 @@ static void route_map_free_map(struct route_map *map) } /* Route map delete from list. */ -static void route_map_delete(struct route_map *map) +void route_map_delete(struct route_map *map) { struct route_map_index *index; char *name; @@ -883,7 +684,7 @@ static int route_map_clear_updated(struct route_map *map) /* Lookup route map. If there isn't route map create one and return it. */ -static struct route_map *route_map_get(const char *name) +struct route_map *route_map_get(const char *name) { struct route_map *map; @@ -1097,7 +898,7 @@ static struct route_map_index *route_map_index_new(void) } /* Free route map index. */ -static void route_map_index_delete(struct route_map_index *index, int notify) +void route_map_index_delete(struct route_map_index *index, int notify) { struct route_map_rule *rule; @@ -1202,7 +1003,7 @@ route_map_index_add(struct route_map *map, enum route_map_type type, int pref) } /* Get route map index. */ -static struct route_map_index * +struct route_map_index * route_map_index_get(struct route_map *map, enum route_map_type type, int pref) { struct route_map_index *index; diff --git a/lib/routemap.h b/lib/routemap.h index 1ffd0525ae..41959c24e5 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -140,6 +140,22 @@ enum rmap_compile_rets { }; +/* Route map rule. This rule has both `match' rule and `set' rule. */ +struct route_map_rule { + /* Rule type. */ + const struct route_map_rule_cmd *cmd; + + /* For pretty printing. */ + char *rule_str; + + /* Pre-compiled match rule. */ + void *value; + + /* Linked list. */ + struct route_map_rule *next; + struct route_map_rule *prev; +}; + /* Route map rule list. */ struct route_map_rule_list { struct route_map_rule *head; @@ -435,6 +451,199 @@ extern void route_map_counter_increment(struct route_map *map); /* Decrement the route-map used counter */ extern void route_map_counter_decrement(struct route_map *map); +/* Route map hooks data structure. */ +struct route_map_match_set_hooks { + /* match interface */ + int (*match_interface)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type); + + /* no match interface */ + int (*no_match_interface)(struct vty *vty, + struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type); + + /* match ip address */ + int (*match_ip_address)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type); + + /* no match ip address */ + int (*no_match_ip_address)(struct vty *vty, + struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type); + + /* match ip address prefix list */ + int (*match_ip_address_prefix_list)(struct vty *vty, + struct route_map_index *index, + const char *command, + const char *arg, + route_map_event_t type); + + /* no match ip address prefix list */ + int (*no_match_ip_address_prefix_list)(struct vty *vty, + struct route_map_index *index, + const char *command, + const char *arg, + route_map_event_t type); + + /* match ip next hop */ + int (*match_ip_next_hop)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type); + + /* no match ip next hop */ + int (*no_match_ip_next_hop)(struct vty *vty, + struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type); + + /* match ip next hop prefix list */ + int (*match_ip_next_hop_prefix_list)(struct vty *vty, + struct route_map_index *index, + const char *command, + const char *arg, + route_map_event_t type); + + /* no match ip next hop prefix list */ + int (*no_match_ip_next_hop_prefix_list)(struct vty *vty, + struct route_map_index *index, + const char *command, + const char *arg, + route_map_event_t type); + + /* match ip next-hop type */ + int (*match_ip_next_hop_type)(struct vty *vty, + struct route_map_index *index, + const char *command, + const char *arg, + route_map_event_t type); + + /* no match ip next-hop type */ + int (*no_match_ip_next_hop_type)(struct vty *vty, + struct route_map_index *index, + const char *command, + const char *arg, + route_map_event_t type); + + /* match ipv6 address */ + int (*match_ipv6_address)(struct vty *vty, + struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type); + + /* no match ipv6 address */ + int (*no_match_ipv6_address)(struct vty *vty, + struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type); + + + /* match ipv6 address prefix list */ + int (*match_ipv6_address_prefix_list)(struct vty *vty, + struct route_map_index *index, + const char *command, + const char *arg, + route_map_event_t type); + + /* no match ipv6 address prefix list */ + int (*no_match_ipv6_address_prefix_list)(struct vty *vty, + struct route_map_index *index, + const char *command, + const char *arg, + route_map_event_t type); + + /* match ipv6 next-hop type */ + int (*match_ipv6_next_hop_type)(struct vty *vty, + struct route_map_index *index, + const char *command, + const char *arg, + route_map_event_t type); + + /* no match ipv6 next-hop type */ + int (*no_match_ipv6_next_hop_type)(struct vty *vty, + struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type); + + /* match metric */ + int (*match_metric)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type); + + /* no match metric */ + int (*no_match_metric)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type); + + /* match tag */ + int (*match_tag)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type); + + /* no match tag */ + int (*no_match_tag)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type); + + /* set ip nexthop */ + int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg); + + /* no set ip nexthop */ + int (*no_set_ip_nexthop)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg); + + /* set ipv6 nexthop local */ + int (*set_ipv6_nexthop_local)(struct vty *vty, + struct route_map_index *index, + const char *command, const char *arg); + + /* no set ipv6 nexthop local */ + int (*no_set_ipv6_nexthop_local)(struct vty *vty, + struct route_map_index *index, + const char *command, const char *arg); + + /* set metric */ + int (*set_metric)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg); + + /* no set metric */ + int (*no_set_metric)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg); + + /* set tag */ + int (*set_tag)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg); + + /* no set tag */ + int (*no_set_tag)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg); +}; + +extern struct route_map_match_set_hooks rmap_match_set_hook; + +/* Making route map list. */ +struct route_map_list { + struct route_map *head; + struct route_map *tail; + + void (*add_hook)(const char *); + void (*delete_hook)(const char *); + void (*event_hook)(const char *); +}; + +extern struct route_map_list route_map_master; + +extern struct route_map *route_map_get(const char *name); +extern void route_map_delete(struct route_map *map); +extern struct route_map_index *route_map_index_get(struct route_map *map, + enum route_map_type type, + int pref); +extern void route_map_index_delete(struct route_map_index *index, int notify); + #ifdef __cplusplus } #endif From 686d244f00d87fa0b76c8e4644550d413fc3400b Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 30 Sep 2019 10:34:49 -0300 Subject: [PATCH 03/10] lib: implement route map northbound Based on the route map old CLI, implement the route map handling using the exported functions. Use a curry-like programming pattern avoid code repetition when destroying match/set entries. This is needed by other daemons that implement custom route map functions and need to pass to lib their specific destroy functions. Signed-off-by: Rafael Zalamena --- lib/routemap.h | 24 + lib/routemap_northbound.c | 1393 +++++++++++++++++++++++++++++++++++++ lib/subdir.am | 2 + yang/subdir.am | 1 + 4 files changed, 1420 insertions(+) create mode 100644 lib/routemap_northbound.c diff --git a/lib/routemap.h b/lib/routemap.h index 41959c24e5..d9e7f73f81 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -644,6 +644,30 @@ extern struct route_map_index *route_map_index_get(struct route_map *map, int pref); extern void route_map_index_delete(struct route_map_index *index, int notify); +/* routemap_northbound.c */ +typedef int (*routemap_match_hook_fun)(struct vty *vty, + struct route_map_index *rmi, + const char *command, const char *arg, + route_map_event_t event); + +typedef int (*routemap_set_hook_fun)(struct vty *vty, + struct route_map_index *rmi, + const char *command, const char *arg); + +struct routemap_hook_context { + struct route_map_index *rhc_rmi; + const char *rhc_rule; + route_map_event_t rhc_event; + routemap_set_hook_fun rhc_shook; + routemap_match_hook_fun rhc_mhook; +}; + +int lib_route_map_entry_match_destroy(enum nb_event event, + const struct lyd_node *dnode); +int lib_route_map_entry_set_destroy(enum nb_event event, + const struct lyd_node *dnode); +extern const struct frr_yang_module_info frr_route_map_info; + #ifdef __cplusplus } #endif diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c new file mode 100644 index 0000000000..02eb756334 --- /dev/null +++ b/lib/routemap_northbound.c @@ -0,0 +1,1393 @@ +/* + * Route map northbound implementation. + * + * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF") + * Rafael Zalamena + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ + +#include + +#include "lib/command.h" +#include "lib/log.h" +#include "lib/northbound.h" +#include "lib/routemap.h" + +/* + * Auxiliary functions to avoid code duplication: + * + * lib_route_map_entry_set_destroy: unset `set` commands. + * lib_route_map_entry_match_destroy: unset `match` commands. + */ +int lib_route_map_entry_match_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct routemap_hook_context *rhc; + int rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + rhc = nb_running_get_entry(dnode, NULL, true); + if (rhc->rhc_mhook == NULL) + return NB_OK; + + rv = rhc->rhc_mhook(NULL, rhc->rhc_rmi, rhc->rhc_rule, NULL, + rhc->rhc_event); + if (rv != CMD_SUCCESS) + return NB_ERR_INCONSISTENCY; + + return NB_OK; +} + +int lib_route_map_entry_set_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct routemap_hook_context *rhc; + int rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + rhc = nb_running_get_entry(dnode, NULL, true); + if (rhc->rhc_shook == NULL) + return NB_OK; + + rv = rhc->rhc_shook(NULL, rhc->rhc_rmi, rhc->rhc_rule, NULL); + if (rv != CMD_SUCCESS) + return NB_ERR_INCONSISTENCY; + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map + */ +static int lib_route_map_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct route_map *rm; + const char *rm_name; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + rm_name = yang_dnode_get_string(dnode, "./name"); + rm = route_map_get(rm_name); + nb_running_set_entry(dnode, rm); + break; + } + + return NB_OK; +} + +static int lib_route_map_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct route_map *rm; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + rm = nb_running_unset_entry(dnode); + route_map_delete(rm); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry + */ +static int lib_route_map_entry_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct route_map_index *rmi; + struct route_map *rm; + uint16_t sequence; + int action; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + sequence = yang_dnode_get_uint16(dnode, "./sequence"); + action = yang_dnode_get_enum(dnode, "./action") == 0 + ? RMAP_PERMIT + : RMAP_DENY; + rm = nb_running_get_entry(dnode, NULL, true); + rmi = route_map_index_get(rm, action, sequence); + nb_running_set_entry(dnode, rmi); + break; + } + + return NB_OK; +} + +static int lib_route_map_entry_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct route_map_index *rmi; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + rmi = nb_running_unset_entry(dnode); + route_map_index_delete(rmi, 1); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/description + */ +static int lib_route_map_entry_description_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct route_map_index *rmi; + const char *description; + + switch (event) { + case NB_EV_VALIDATE: + /* NOTHING */ + break; + case NB_EV_PREPARE: + description = yang_dnode_get_string(dnode, NULL); + resource->ptr = XSTRDUP(MTYPE_TMP, description); + if (resource->ptr == NULL) + return NB_ERR_RESOURCE; + break; + case NB_EV_ABORT: + XFREE(MTYPE_TMP, resource->ptr); + break; + case NB_EV_APPLY: + rmi = nb_running_get_entry(dnode, NULL, true); + if (rmi->description != NULL) + XFREE(MTYPE_TMP, rmi->description); + rmi->description = resource->ptr; + break; + } + + return NB_OK; +} + +static int lib_route_map_entry_description_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct route_map_index *rmi; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + rmi = nb_running_get_entry(dnode, NULL, true); + if (rmi->description != NULL) + XFREE(MTYPE_TMP, rmi->description); + rmi->description = NULL; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/action + */ +static int lib_route_map_entry_action_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct route_map_index *rmi; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + rmi = nb_running_get_entry(dnode, NULL, true); + rmi->type = yang_dnode_get_enum(dnode, NULL); + /* TODO: notify? */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/call + */ +static int lib_route_map_entry_call_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct route_map_index *rmi; + const char *rm_name, *rmn_name; + + switch (event) { + case NB_EV_VALIDATE: + rm_name = yang_dnode_get_string(dnode, "../../name"); + rmn_name = yang_dnode_get_string(dnode, NULL); + /* Don't allow to jump to the same route map instance. */ + if (strcmp(rm_name, rmn_name) == 0) + return NB_ERR_VALIDATION; + + /* TODO: detect circular route map sequences. */ + break; + case NB_EV_PREPARE: + rmn_name = yang_dnode_get_string(dnode, NULL); + resource->ptr = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmn_name); + break; + case NB_EV_ABORT: + XFREE(MTYPE_ROUTE_MAP_NAME, resource->ptr); + break; + case NB_EV_APPLY: + rmi = nb_running_get_entry(dnode, NULL, true); + if (rmi->nextrm) { + route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED, + rmi->nextrm, rmi->map->name); + XFREE(MTYPE_ROUTE_MAP_NAME, rmi->nextrm); + } + rmi->nextrm = resource->ptr; + route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, rmi->nextrm, + rmi->map->name); + break; + } + + return NB_OK; +} + +static int lib_route_map_entry_call_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct route_map_index *rmi; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + rmi = nb_running_get_entry(dnode, NULL, true); + route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED, rmi->nextrm, + rmi->map->name); + XFREE(MTYPE_ROUTE_MAP_NAME, rmi->nextrm); + rmi->nextrm = NULL; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/exit-policy + */ +static int lib_route_map_entry_exit_policy_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct route_map_index *rmi; + int rm_action; + int policy; + + switch (event) { + case NB_EV_VALIDATE: + policy = yang_dnode_get_enum(dnode, NULL); + switch (policy) { + case 0: /* permit-or-deny */ + break; + case 1: /* next */ + /* FALLTHROUGH */ + case 2: /* goto */ + rm_action = yang_dnode_get_enum(dnode, "../action"); + if (rm_action == 1 /* deny */) { + /* + * On deny it is not possible to 'goto' + * anywhere. + */ + return NB_ERR_VALIDATION; + } + break; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + rmi = nb_running_get_entry(dnode, NULL, true); + policy = yang_dnode_get_enum(dnode, NULL); + + switch (policy) { + case 0: /* permit-or-deny */ + rmi->exitpolicy = RMAP_EXIT; + break; + case 1: /* next */ + rmi->exitpolicy = RMAP_NEXT; + break; + case 2: /* goto */ + rmi->exitpolicy = RMAP_GOTO; + break; + } + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/goto-value + */ +static int lib_route_map_entry_goto_value_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct route_map_index *rmi; + uint16_t rmi_index; + uint16_t rmi_next; + + switch (event) { + case NB_EV_VALIDATE: + rmi_index = yang_dnode_get_uint16(dnode, "../sequence"); + rmi_next = yang_dnode_get_uint16(dnode, NULL); + if (rmi_next <= rmi_index) { + /* Can't jump backwards on a route map. */ + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + rmi = nb_running_get_entry(dnode, NULL, true); + rmi->nextpref = yang_dnode_get_uint16(dnode, NULL); + break; + } + + return NB_OK; +} + +static int lib_route_map_entry_goto_value_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct route_map_index *rmi; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + rmi = nb_running_get_entry(dnode, NULL, true); + rmi->nextpref = 0; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition + */ +static int +lib_route_map_entry_match_condition_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + + switch (event) { + case NB_EV_VALIDATE: + /* NOTHING */ + break; + case NB_EV_PREPARE: + resource->ptr = XCALLOC(MTYPE_TMP, sizeof(*rhc)); + break; + case NB_EV_ABORT: + XFREE(MTYPE_TMP, resource->ptr); + break; + case NB_EV_APPLY: + rhc = resource->ptr; + rhc->rhc_rmi = nb_running_get_entry(dnode, NULL, true); + nb_running_set_entry(dnode, rhc); + break; + } + + return NB_OK; +} + +static int +lib_route_map_entry_match_condition_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct routemap_hook_context *rhc; + int rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + rv = lib_route_map_entry_match_destroy(event, dnode); + rhc = nb_running_unset_entry(dnode); + XFREE(MTYPE_TMP, rhc); + + return rv; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/interface + */ +static int lib_route_map_entry_match_condition_interface_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + const char *ifname; + int rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + /* Check for hook function. */ + if (rmap_match_set_hook.match_interface == NULL) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + ifname = yang_dnode_get_string(dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = rmap_match_set_hook.no_match_interface; + rhc->rhc_rule = "interface"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + rv = rmap_match_set_hook.match_interface(NULL, rhc->rhc_rmi, + "interface", ifname, + RMAP_EVENT_MATCH_ADDED); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int lib_route_map_entry_match_condition_interface_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_match_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/access-list-num + */ +static int lib_route_map_entry_match_condition_access_list_num_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + const char *acl; + int condition, rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + /* Check for hook function. */ + rv = CMD_SUCCESS; + acl = yang_dnode_get_string(dnode, NULL); + rhc = nb_running_get_entry(dnode, NULL, true); + condition = yang_dnode_get_enum(dnode, "../condition"); + switch (condition) { + case 1: /* ipv4-address-list */ + if (rmap_match_set_hook.match_ip_address == NULL) + break; + rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_address; + rhc->rhc_rule = "ip address"; + rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; + rv = rmap_match_set_hook.match_ip_address( + NULL, rhc->rhc_rmi, "ip address", acl, + RMAP_EVENT_FILTER_ADDED); + break; + case 3: /* ipv4-next-hop-list */ + if (rmap_match_set_hook.match_ip_next_hop == NULL) + break; + rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop; + rhc->rhc_rule = "ip next-hop"; + rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; + rv = rmap_match_set_hook.match_ip_next_hop( + NULL, rhc->rhc_rmi, "ip next-hop", acl, + RMAP_EVENT_FILTER_ADDED); + break; + } + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int lib_route_map_entry_match_condition_access_list_num_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_match_destroy(event, dnode); +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/match-condition/access-list-num-extended + */ +static int lib_route_map_entry_match_condition_access_list_num_extended_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + return lib_route_map_entry_match_condition_access_list_num_modify( + event, dnode, resource); +} + +static int lib_route_map_entry_match_condition_access_list_num_extended_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_match_condition_access_list_num_destroy( + event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/list-name + */ +static int lib_route_map_entry_match_condition_list_name_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + const char *acl; + int condition; + int rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + /* Check for hook installation, otherwise we can just stop. */ + acl = yang_dnode_get_string(dnode, NULL); + rhc = nb_running_get_entry(dnode, NULL, true); + condition = yang_dnode_get_enum(dnode, "../condition"); + switch (condition) { + case 1: /* ipv4-address-list */ + if (rmap_match_set_hook.match_ip_address == NULL) + return NB_OK; + rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_address; + rhc->rhc_rule = "ip address"; + rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; + rv = rmap_match_set_hook.match_ip_address( + NULL, rhc->rhc_rmi, "ip address", acl, + RMAP_EVENT_FILTER_ADDED); + break; + case 2: /* ipv4-prefix-list */ + if (rmap_match_set_hook.match_ip_address_prefix_list == NULL) + return NB_OK; + rhc->rhc_mhook = + rmap_match_set_hook.no_match_ip_address_prefix_list; + rhc->rhc_rule = "ip address prefix-list"; + rhc->rhc_event = RMAP_EVENT_PLIST_DELETED; + rv = rmap_match_set_hook.match_ip_address_prefix_list( + NULL, rhc->rhc_rmi, "ip address prefix-list", acl, + RMAP_EVENT_PLIST_ADDED); + break; + case 3: /* ipv4-next-hop-list */ + if (rmap_match_set_hook.match_ip_next_hop == NULL) + return NB_OK; + rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop; + rhc->rhc_rule = "ip next-hop"; + rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; + rv = rmap_match_set_hook.match_ip_next_hop( + NULL, rhc->rhc_rmi, "ip next-hop", acl, + RMAP_EVENT_FILTER_ADDED); + break; + case 4: /* ipv4-next-hop-prefix-list */ + if (rmap_match_set_hook.match_ip_next_hop_prefix_list == NULL) + return NB_OK; + rhc->rhc_mhook = + rmap_match_set_hook.no_match_ip_next_hop_prefix_list; + rhc->rhc_rule = "ip next-hop prefix-list"; + rhc->rhc_event = RMAP_EVENT_PLIST_DELETED; + rv = rmap_match_set_hook.match_ip_next_hop_prefix_list( + NULL, rhc->rhc_rmi, "ip next-hop prefix-list", acl, + RMAP_EVENT_PLIST_ADDED); + break; + case 6: /* ipv6-address-list */ + if (rmap_match_set_hook.match_ipv6_address == NULL) + return NB_OK; + rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_address; + rhc->rhc_rule = "ipv6 address"; + rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; + rv = rmap_match_set_hook.match_ipv6_address( + NULL, rhc->rhc_rmi, "ipv6 address", acl, + RMAP_EVENT_FILTER_ADDED); + break; + case 7: /* ipv6-prefix-list */ + if (rmap_match_set_hook.match_ipv6_address_prefix_list == NULL) + return NB_OK; + rhc->rhc_mhook = + rmap_match_set_hook.no_match_ipv6_address_prefix_list; + rhc->rhc_rule = "ipv6 address prefix-list"; + rhc->rhc_event = RMAP_EVENT_PLIST_DELETED; + rv = rmap_match_set_hook.match_ipv6_address_prefix_list( + NULL, rhc->rhc_rmi, "ipv6 address prefix-list", acl, + RMAP_EVENT_PLIST_ADDED); + break; + default: + rv = CMD_ERR_NO_MATCH; + break; + } + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int lib_route_map_entry_match_condition_list_name_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_match_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/ipv4-next-hop-type + */ +static int lib_route_map_entry_match_condition_ipv4_next_hop_type_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + /* Check for hook function. */ + if (rmap_match_set_hook.match_ip_next_hop_type == NULL) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + type = yang_dnode_get_string(dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop_type; + rhc->rhc_rule = "ip next-hop type"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + rv = rmap_match_set_hook.match_ip_next_hop_type( + NULL, rhc->rhc_rmi, "ip next-hop type", type, + RMAP_EVENT_MATCH_ADDED); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_match_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/ipv6-next-hop-type + */ +static int lib_route_map_entry_match_condition_ipv6_next_hop_type_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + /* Check for hook function. */ + if (rmap_match_set_hook.match_ipv6_next_hop_type == NULL) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + type = yang_dnode_get_string(dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_next_hop_type; + rhc->rhc_rule = "ipv6 next-hop type"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + rv = rmap_match_set_hook.match_ipv6_next_hop_type( + NULL, rhc->rhc_rmi, "ipv6 next-hop type", type, + RMAP_EVENT_MATCH_ADDED); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_match_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/metric + */ +static int +lib_route_map_entry_match_condition_metric_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + /* Check for hook function. */ + if (rmap_match_set_hook.match_metric == NULL) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + type = yang_dnode_get_string(dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = rmap_match_set_hook.no_match_metric; + rhc->rhc_rule = "metric"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + rv = rmap_match_set_hook.match_metric(NULL, rhc->rhc_rmi, "metric", + type, RMAP_EVENT_MATCH_ADDED); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int +lib_route_map_entry_match_condition_metric_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + return lib_route_map_entry_match_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/tag + */ +static int +lib_route_map_entry_match_condition_tag_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + const char *tag; + int rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + /* Check for hook function. */ + if (rmap_match_set_hook.match_tag == NULL) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + tag = yang_dnode_get_string(dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = rmap_match_set_hook.no_match_tag; + rhc->rhc_rule = "tag"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + rv = rmap_match_set_hook.match_tag(NULL, rhc->rhc_rmi, "tag", tag, + RMAP_EVENT_MATCH_ADDED); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int +lib_route_map_entry_match_condition_tag_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + return lib_route_map_entry_match_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action + */ +static int lib_route_map_entry_set_action_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + return lib_route_map_entry_match_condition_create(event, dnode, + resource); +} + +static int lib_route_map_entry_set_action_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct routemap_hook_context *rhc; + int rv; + + if (event != NB_EV_APPLY) + return NB_OK; + + rv = lib_route_map_entry_set_destroy(event, dnode); + rhc = nb_running_unset_entry(dnode); + XFREE(MTYPE_TMP, rhc); + + return rv; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/ipv4-address + */ +static int +lib_route_map_entry_set_action_ipv4_address_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + const char *address; + struct in_addr ia; + int rv; + + switch (event) { + case NB_EV_VALIDATE: + /* + * NOTE: validate if 'action' is 'ipv4-next-hop', + * currently it is not necessary because this is the + * only implemented action. + */ + yang_dnode_get_ipv4(&ia, dnode, NULL); + if (ia.s_addr == 0 || IPV4_CLASS_DE(ntohl(ia.s_addr))) + return NB_ERR_VALIDATION; + /* FALLTHROUGH */ + case NB_EV_PREPARE: + case NB_EV_ABORT: + return NB_OK; + case NB_EV_APPLY: + break; + } + + /* Check for hook function. */ + if (rmap_match_set_hook.set_ip_nexthop == NULL) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + address = yang_dnode_get_string(dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = rmap_match_set_hook.no_set_ip_nexthop; + rhc->rhc_rule = "ip next-hop"; + + rv = rmap_match_set_hook.set_ip_nexthop(NULL, rhc->rhc_rmi, + "ip next-hop", address); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int lib_route_map_entry_set_action_ipv4_address_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_set_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/ipv6-address + */ +static int +lib_route_map_entry_set_action_ipv6_address_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + const char *address; + struct in6_addr i6a; + int rv; + + switch (event) { + case NB_EV_VALIDATE: + /* + * NOTE: validate if 'action' is 'ipv6-next-hop', + * currently it is not necessary because this is the + * only implemented action. Other actions might have + * different validations. + */ + yang_dnode_get_ipv6(&i6a, dnode, NULL); + if (!IN6_IS_ADDR_LINKLOCAL(&i6a)) + return NB_ERR_VALIDATION; + /* FALLTHROUGH */ + case NB_EV_PREPARE: + case NB_EV_ABORT: + return NB_OK; + case NB_EV_APPLY: + break; + } + + /* Check for hook function. */ + if (rmap_match_set_hook.set_ipv6_nexthop_local == NULL) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + address = yang_dnode_get_string(dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = rmap_match_set_hook.no_set_ipv6_nexthop_local; + rhc->rhc_rule = "ipv6 next-hop local"; + + rv = rmap_match_set_hook.set_ipv6_nexthop_local( + NULL, rhc->rhc_rmi, "ipv6 next-hop local", address); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int lib_route_map_entry_set_action_ipv6_address_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_set_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/value + */ +static int set_action_modify(enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource, const char *value) +{ + struct routemap_hook_context *rhc; + int rv; + + /* + * NOTE: validate if 'action' is 'metric', currently it is not + * necessary because this is the only implemented action. Other + * actions might have different validations. + */ + if (event != NB_EV_APPLY) + return NB_OK; + + /* Check for hook function. */ + if (rmap_match_set_hook.set_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_metric; + rhc->rhc_rule = "metric"; + + rv = rmap_match_set_hook.set_metric(NULL, rhc->rhc_rmi, "metric", + value); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int +lib_route_map_entry_set_action_value_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + const char *metric = yang_dnode_get_string(dnode, NULL); + + return set_action_modify(event, dnode, resource, metric); +} + +static int +lib_route_map_entry_set_action_value_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + return lib_route_map_entry_set_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/add-metric + */ +static int +lib_route_map_entry_set_action_add_metric_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + return set_action_modify(event, dnode, resource, "+metric"); +} + +static int +lib_route_map_entry_set_action_add_metric_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + return lib_route_map_entry_set_action_value_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/subtract-metric + */ +static int lib_route_map_entry_set_action_subtract_metric_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + return set_action_modify(event, dnode, resource, "-metric"); +} + +static int lib_route_map_entry_set_action_subtract_metric_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_set_action_value_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/use-round-trip-time + */ +static int lib_route_map_entry_set_action_use_round_trip_time_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + return set_action_modify(event, dnode, resource, "rtt"); +} + +static int lib_route_map_entry_set_action_use_round_trip_time_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_set_action_value_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/add-round-trip-time + */ +static int lib_route_map_entry_set_action_add_round_trip_time_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + return set_action_modify(event, dnode, resource, "+rtt"); +} + +static int lib_route_map_entry_set_action_add_round_trip_time_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_set_action_value_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/subtract-round-trip-time + */ +static int lib_route_map_entry_set_action_subtract_round_trip_time_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + return set_action_modify(event, dnode, resource, "-rtt"); +} + +static int lib_route_map_entry_set_action_subtract_round_trip_time_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return lib_route_map_entry_set_action_value_destroy(event, dnode); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/tag + */ +static int +lib_route_map_entry_set_action_tag_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct routemap_hook_context *rhc; + const char *tag; + int rv; + + /* + * NOTE: validate if 'action' is 'tag', currently it is not + * necessary because this is the only implemented action. Other + * actions might have different validations. + */ + if (event != NB_EV_APPLY) + return NB_OK; + + /* Check for hook function. */ + if (rmap_match_set_hook.set_tag == NULL) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(dnode, NULL, true); + tag = yang_dnode_get_string(dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = rmap_match_set_hook.no_set_tag; + rhc->rhc_rule = "tag"; + + rv = rmap_match_set_hook.set_tag(NULL, rhc->rhc_rmi, "tag", tag); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int +lib_route_map_entry_set_action_tag_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + return lib_route_map_entry_set_destroy(event, dnode); +} + +/* clang-format off */ +const struct frr_yang_module_info frr_route_map_info = { + .name = "frr-route-map", + .nodes = { + { + .xpath = "/frr-route-map:lib/route-map", + .cbs = { + .create = lib_route_map_create, + .destroy = lib_route_map_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry", + .cbs = { + .create = lib_route_map_entry_create, + .destroy = lib_route_map_entry_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/description", + .cbs = { + .modify = lib_route_map_entry_description_modify, + .destroy = lib_route_map_entry_description_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/action", + .cbs = { + .modify = lib_route_map_entry_action_modify, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/call", + .cbs = { + .modify = lib_route_map_entry_call_modify, + .destroy = lib_route_map_entry_call_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/exit-policy", + .cbs = { + .modify = lib_route_map_entry_exit_policy_modify, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/goto-value", + .cbs = { + .modify = lib_route_map_entry_goto_value_modify, + .destroy = lib_route_map_entry_goto_value_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition", + .cbs = { + .create = lib_route_map_entry_match_condition_create, + .destroy = lib_route_map_entry_match_condition_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/interface", + .cbs = { + .modify = lib_route_map_entry_match_condition_interface_modify, + .destroy = lib_route_map_entry_match_condition_interface_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/access-list-num", + .cbs = { + .modify = lib_route_map_entry_match_condition_access_list_num_modify, + .destroy = lib_route_map_entry_match_condition_access_list_num_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/access-list-num-extended", + .cbs = { + .modify = lib_route_map_entry_match_condition_access_list_num_extended_modify, + .destroy = lib_route_map_entry_match_condition_access_list_num_extended_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/list-name", + .cbs = { + .modify = lib_route_map_entry_match_condition_list_name_modify, + .destroy = lib_route_map_entry_match_condition_list_name_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/ipv4-next-hop-type", + .cbs = { + .modify = lib_route_map_entry_match_condition_ipv4_next_hop_type_modify, + .destroy = lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/ipv6-next-hop-type", + .cbs = { + .modify = lib_route_map_entry_match_condition_ipv6_next_hop_type_modify, + .destroy = lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/metric", + .cbs = { + .modify = lib_route_map_entry_match_condition_metric_modify, + .destroy = lib_route_map_entry_match_condition_metric_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/tag", + .cbs = { + .modify = lib_route_map_entry_match_condition_tag_modify, + .destroy = lib_route_map_entry_match_condition_tag_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action", + .cbs = { + .create = lib_route_map_entry_set_action_create, + .destroy = lib_route_map_entry_set_action_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/ipv4-address", + .cbs = { + .modify = lib_route_map_entry_set_action_ipv4_address_modify, + .destroy = lib_route_map_entry_set_action_ipv4_address_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/ipv6-address", + .cbs = { + .modify = lib_route_map_entry_set_action_ipv6_address_modify, + .destroy = lib_route_map_entry_set_action_ipv6_address_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/value", + .cbs = { + .modify = lib_route_map_entry_set_action_value_modify, + .destroy = lib_route_map_entry_set_action_value_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/add-metric", + .cbs = { + .modify = lib_route_map_entry_set_action_add_metric_modify, + .destroy = lib_route_map_entry_set_action_add_metric_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/subtract-metric", + .cbs = { + .modify = lib_route_map_entry_set_action_subtract_metric_modify, + .destroy = lib_route_map_entry_set_action_subtract_metric_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/use-round-trip-time", + .cbs = { + .modify = lib_route_map_entry_set_action_use_round_trip_time_modify, + .destroy = lib_route_map_entry_set_action_use_round_trip_time_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/add-round-trip-time", + .cbs = { + .modify = lib_route_map_entry_set_action_add_round_trip_time_modify, + .destroy = lib_route_map_entry_set_action_add_round_trip_time_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/subtract-round-trip-time", + .cbs = { + .modify = lib_route_map_entry_set_action_subtract_round_trip_time_modify, + .destroy = lib_route_map_entry_set_action_subtract_round_trip_time_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/tag", + .cbs = { + .modify = lib_route_map_entry_set_action_tag_modify, + .destroy = lib_route_map_entry_set_action_tag_destroy, + } + }, + { + .xpath = NULL, + }, + } +}; diff --git a/lib/subdir.am b/lib/subdir.am index d804d839db..94b3d933ac 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -71,6 +71,7 @@ lib_libfrr_la_SOURCES = \ lib/qobj.c \ lib/ringbuf.c \ lib/routemap.c \ + lib/routemap_northbound.c \ lib/sbuf.c \ lib/seqlock.c \ lib/sha256.c \ @@ -105,6 +106,7 @@ lib_libfrr_la_SOURCES = \ nodist_lib_libfrr_la_SOURCES = \ yang/frr-interface.yang.c \ + yang/frr-route-map.yang.c \ yang/frr-route-types.yang.c \ yang/ietf/ietf-routing-types.yang.c \ yang/frr-module-translator.yang.c \ diff --git a/yang/subdir.am b/yang/subdir.am index cfaf1a6401..7a15a6a309 100644 --- a/yang/subdir.am +++ b/yang/subdir.am @@ -22,6 +22,7 @@ EXTRA_DIST += yang/embedmodel.py dist_yangmodels_DATA += yang/frr-module-translator.yang dist_yangmodels_DATA += yang/frr-test-module.yang dist_yangmodels_DATA += yang/frr-interface.yang +dist_yangmodels_DATA += yang/frr-route-map.yang dist_yangmodels_DATA += yang/frr-route-types.yang dist_yangmodels_DATA += yang/ietf/ietf-routing-types.yang From 2b3e4807ecf4d2586fe4d651b904967ea8d759c0 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 30 Sep 2019 15:01:46 -0300 Subject: [PATCH 04/10] lib: implement new route map CLI Use the northbound back-end instead of the old route map CLI. Signed-off-by: Rafael Zalamena --- lib/routemap.c | 1103 +------------------------------------ lib/routemap.h | 19 + lib/routemap_cli.c | 1075 ++++++++++++++++++++++++++++++++++++ lib/routemap_northbound.c | 7 + lib/subdir.am | 4 + vtysh/extract.pl.in | 2 +- 6 files changed, 1108 insertions(+), 1102 deletions(-) create mode 100644 lib/routemap_cli.c diff --git a/lib/routemap.c b/lib/routemap.c index a8feebd313..e07ad08123 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -759,14 +759,6 @@ static const char *route_map_result_str(route_map_result_t res) return "invalid"; } -static int route_map_empty(struct route_map *map) -{ - if (map->head == NULL && map->tail == NULL) - return 1; - else - return 0; -} - /* show route-map */ static void vty_show_route_map_entry(struct vty *vty, struct route_map *map) { @@ -2010,871 +2002,6 @@ void route_map_notify_dependencies(const char *affected_name, /* VTY related functions. */ -DEFUN (match_interface, - match_interface_cmd, - "match interface WORD", - MATCH_STR - "match first hop interface of route\n" - "Interface name\n") -{ - int idx_word = 2; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.match_interface) - return rmap_match_set_hook.match_interface( - vty, index, "interface", argv[idx_word]->arg, - RMAP_EVENT_MATCH_ADDED); - return CMD_SUCCESS; -} - -DEFUN (no_match_interface, - no_match_interface_cmd, - "no match interface [WORD]", - NO_STR - MATCH_STR - "Match first hop interface of route\n" - "Interface name\n") -{ - char *iface = (argc == 4) ? argv[3]->arg : NULL; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.no_match_interface) - return rmap_match_set_hook.no_match_interface( - vty, index, "interface", iface, - RMAP_EVENT_MATCH_DELETED); - return CMD_SUCCESS; -} - - -DEFUN (match_ip_address, - match_ip_address_cmd, - "match ip address <(1-199)|(1300-2699)|WORD>", - MATCH_STR - IP_STR - "Match address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" - "IP Access-list name\n") -{ - int idx_acl = 3; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.match_ip_address) - return rmap_match_set_hook.match_ip_address( - vty, index, "ip address", argv[idx_acl]->arg, - RMAP_EVENT_FILTER_ADDED); - return CMD_SUCCESS; -} - - -DEFUN (no_match_ip_address, - no_match_ip_address_cmd, - "no match ip address [<(1-199)|(1300-2699)|WORD>]", - NO_STR - MATCH_STR - IP_STR - "Match address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" - "IP Access-list name\n") -{ - int idx_word = 4; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.no_match_ip_address) { - if (argc <= idx_word) - return rmap_match_set_hook.no_match_ip_address( - vty, index, "ip address", NULL, - RMAP_EVENT_FILTER_DELETED); - return rmap_match_set_hook.no_match_ip_address( - vty, index, "ip address", argv[idx_word]->arg, - RMAP_EVENT_FILTER_DELETED); - } - return CMD_SUCCESS; -} - - -DEFUN (match_ip_address_prefix_list, - match_ip_address_prefix_list_cmd, - "match ip address prefix-list WORD", - MATCH_STR - IP_STR - "Match address of route\n" - "Match entries of prefix-lists\n" - "IP prefix-list name\n") -{ - int idx_word = 4; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.match_ip_address_prefix_list) - return rmap_match_set_hook.match_ip_address_prefix_list( - vty, index, "ip address prefix-list", - argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED); - return CMD_SUCCESS; -} - - -DEFUN (no_match_ip_address_prefix_list, - no_match_ip_address_prefix_list_cmd, - "no match ip address prefix-list [WORD]", - NO_STR - MATCH_STR - IP_STR - "Match address of route\n" - "Match entries of prefix-lists\n" - "IP prefix-list name\n") -{ - int idx_word = 5; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.no_match_ip_address_prefix_list) { - if (argc <= idx_word) - return rmap_match_set_hook - .no_match_ip_address_prefix_list( - vty, index, "ip address prefix-list", - NULL, RMAP_EVENT_PLIST_DELETED); - return rmap_match_set_hook.no_match_ip_address_prefix_list( - vty, index, "ip address prefix-list", - argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED); - } - return CMD_SUCCESS; -} - - -DEFUN (match_ip_next_hop, - match_ip_next_hop_cmd, - "match ip next-hop <(1-199)|(1300-2699)|WORD>", - MATCH_STR - IP_STR - "Match next-hop address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" - "IP Access-list name\n") -{ - int idx_acl = 3; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.match_ip_next_hop) - return rmap_match_set_hook.match_ip_next_hop( - vty, index, "ip next-hop", argv[idx_acl]->arg, - RMAP_EVENT_FILTER_ADDED); - return CMD_SUCCESS; -} - - -DEFUN (no_match_ip_next_hop, - no_match_ip_next_hop_cmd, - "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]", - NO_STR - MATCH_STR - IP_STR - "Match next-hop address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" - "IP Access-list name\n") -{ - int idx_word = 4; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.no_match_ip_next_hop) { - if (argc <= idx_word) - return rmap_match_set_hook.no_match_ip_next_hop( - vty, index, "ip next-hop", NULL, - RMAP_EVENT_FILTER_DELETED); - return rmap_match_set_hook.no_match_ip_next_hop( - vty, index, "ip next-hop", argv[idx_word]->arg, - RMAP_EVENT_FILTER_DELETED); - } - return CMD_SUCCESS; -} - - -DEFUN (match_ip_next_hop_prefix_list, - match_ip_next_hop_prefix_list_cmd, - "match ip next-hop prefix-list WORD", - MATCH_STR - IP_STR - "Match next-hop address of route\n" - "Match entries of prefix-lists\n" - "IP prefix-list name\n") -{ - int idx_word = 4; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.match_ip_next_hop_prefix_list) - return rmap_match_set_hook.match_ip_next_hop_prefix_list( - vty, index, "ip next-hop prefix-list", - argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED); - return CMD_SUCCESS; -} - -DEFUN (no_match_ip_next_hop_prefix_list, - no_match_ip_next_hop_prefix_list_cmd, - "no match ip next-hop prefix-list [WORD]", - NO_STR - MATCH_STR - IP_STR - "Match next-hop address of route\n" - "Match entries of prefix-lists\n" - "IP prefix-list name\n") -{ - int idx_word = 5; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.no_match_ip_next_hop) { - if (argc <= idx_word) - return rmap_match_set_hook.no_match_ip_next_hop( - vty, index, "ip next-hop prefix-list", NULL, - RMAP_EVENT_PLIST_DELETED); - return rmap_match_set_hook.no_match_ip_next_hop( - vty, index, "ip next-hop prefix-list", - argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED); - } - return CMD_SUCCESS; -} - -DEFUN(match_ip_next_hop_type, match_ip_next_hop_type_cmd, - "match ip next-hop type ", - MATCH_STR IP_STR - "Match next-hop address of route\n" - "Match entries by type\n" - "Blackhole\n") -{ - int idx_word = 4; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.match_ip_next_hop_type) - return rmap_match_set_hook.match_ip_next_hop_type( - vty, index, "ip next-hop type", argv[idx_word]->arg, - RMAP_EVENT_MATCH_ADDED); - return CMD_SUCCESS; -} - -DEFUN(no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd, - "no match ip next-hop type []", - NO_STR MATCH_STR IP_STR - "Match next-hop address of route\n" - "Match entries by type\n" - "Blackhole\n") -{ - int idx_word = 5; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.no_match_ip_next_hop) { - if (argc <= idx_word) - return rmap_match_set_hook.no_match_ip_next_hop( - vty, index, "ip next-hop type", NULL, - RMAP_EVENT_MATCH_DELETED); - return rmap_match_set_hook.no_match_ip_next_hop( - vty, index, "ip next-hop type", argv[idx_word]->arg, - RMAP_EVENT_MATCH_DELETED); - } - return CMD_SUCCESS; -} - - -DEFUN (match_ipv6_address, - match_ipv6_address_cmd, - "match ipv6 address WORD", - MATCH_STR - IPV6_STR - "Match IPv6 address of route\n" - "IPv6 access-list name\n") -{ - int idx_word = 3; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.match_ipv6_address) - return rmap_match_set_hook.match_ipv6_address( - vty, index, "ipv6 address", argv[idx_word]->arg, - RMAP_EVENT_FILTER_ADDED); - return CMD_SUCCESS; -} - -DEFUN (no_match_ipv6_address, - no_match_ipv6_address_cmd, - "no match ipv6 address WORD", - NO_STR - MATCH_STR - IPV6_STR - "Match IPv6 address of route\n" - "IPv6 access-list name\n") -{ - int idx_word = 4; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.no_match_ipv6_address) - return rmap_match_set_hook.no_match_ipv6_address( - vty, index, "ipv6 address", argv[idx_word]->arg, - RMAP_EVENT_FILTER_DELETED); - return CMD_SUCCESS; -} - - -DEFUN (match_ipv6_address_prefix_list, - match_ipv6_address_prefix_list_cmd, - "match ipv6 address prefix-list WORD", - MATCH_STR - IPV6_STR - "Match address of route\n" - "Match entries of prefix-lists\n" - "IP prefix-list name\n") -{ - int idx_word = 4; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.match_ipv6_address_prefix_list) - return rmap_match_set_hook.match_ipv6_address_prefix_list( - vty, index, "ipv6 address prefix-list", - argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED); - return CMD_SUCCESS; -} - -DEFUN (no_match_ipv6_address_prefix_list, - no_match_ipv6_address_prefix_list_cmd, - "no match ipv6 address prefix-list WORD", - NO_STR - MATCH_STR - IPV6_STR - "Match address of route\n" - "Match entries of prefix-lists\n" - "IP prefix-list name\n") -{ - int idx_word = 5; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.no_match_ipv6_address_prefix_list) - return rmap_match_set_hook.no_match_ipv6_address_prefix_list( - vty, index, "ipv6 address prefix-list", - argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED); - return CMD_SUCCESS; -} - -DEFUN(match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd, - "match ipv6 next-hop type ", - MATCH_STR IPV6_STR - "Match next-hop address of route\n" - "Match entries by type\n" - "Blackhole\n") -{ - int idx_word = 4; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.match_ipv6_next_hop_type) - return rmap_match_set_hook.match_ipv6_next_hop_type( - vty, index, "ipv6 next-hop type", argv[idx_word]->arg, - RMAP_EVENT_MATCH_ADDED); - return CMD_SUCCESS; -} - -DEFUN(no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd, - "no match ipv6 next-hop type []", - NO_STR MATCH_STR IPV6_STR - "Match address of route\n" - "Match entries by type\n" - "Blackhole\n") -{ - int idx_word = 5; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.no_match_ipv6_next_hop_type) - return rmap_match_set_hook.no_match_ipv6_next_hop_type( - vty, index, "ipv6 next-hop type", - (argc <= idx_word) ? NULL : argv[idx_word]->arg, - RMAP_EVENT_MATCH_DELETED); - return CMD_SUCCESS; -} - -DEFUN (match_metric, - match_metric_cmd, - "match metric (0-4294967295)", - MATCH_STR - "Match metric of route\n" - "Metric value\n") -{ - int idx_number = 2; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.match_metric) - return rmap_match_set_hook.match_metric(vty, index, "metric", - argv[idx_number]->arg, - RMAP_EVENT_MATCH_ADDED); - return CMD_SUCCESS; -} - - -DEFUN (no_match_metric, - no_match_metric_cmd, - "no match metric [(0-4294967295)]", - NO_STR - MATCH_STR - "Match metric of route\n" - "Metric value\n") -{ - int idx_number = 3; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.no_match_metric) { - if (argc <= idx_number) - return rmap_match_set_hook.no_match_metric( - vty, index, "metric", NULL, - RMAP_EVENT_MATCH_DELETED); - return rmap_match_set_hook.no_match_metric( - vty, index, "metric", argv[idx_number]->arg, - RMAP_EVENT_MATCH_DELETED); - } - return CMD_SUCCESS; -} - - -DEFUN (match_tag, - match_tag_cmd, - "match tag (1-4294967295)", - MATCH_STR - "Match tag of route\n" - "Tag value\n") -{ - int idx_number = 2; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.match_tag) - return rmap_match_set_hook.match_tag(vty, index, "tag", - argv[idx_number]->arg, - RMAP_EVENT_MATCH_ADDED); - return CMD_SUCCESS; -} - - -DEFUN (no_match_tag, - no_match_tag_cmd, - "no match tag [(1-4294967295)]", - NO_STR - MATCH_STR - "Match tag of route\n" - "Tag value\n") -{ - VTY_DECLVAR_CONTEXT(route_map_index, index); - - int idx = 0; - char *arg = argv_find(argv, argc, "(1-4294967295)", &idx) - ? argv[idx]->arg - : NULL; - - if (rmap_match_set_hook.no_match_tag) - return rmap_match_set_hook.no_match_tag( - vty, index, "tag", arg, RMAP_EVENT_MATCH_DELETED); - return CMD_SUCCESS; -} - - -DEFUN (set_ip_nexthop, - set_ip_nexthop_cmd, - "set ip next-hop A.B.C.D", - SET_STR - IP_STR - "Next hop address\n" - "IP address of next hop\n") -{ - int idx_ipv4 = 3; - union sockunion su; - int ret; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - ret = str2sockunion(argv[idx_ipv4]->arg, &su); - if (ret < 0) { - vty_out(vty, "%% Malformed nexthop address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (su.sin.sin_addr.s_addr == 0 - || IPV4_CLASS_DE(ntohl(su.sin.sin_addr.s_addr))) { - vty_out(vty, - "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (rmap_match_set_hook.set_ip_nexthop) - return rmap_match_set_hook.set_ip_nexthop( - vty, index, "ip next-hop", argv[idx_ipv4]->arg); - return CMD_SUCCESS; -} - - -DEFUN (no_set_ip_nexthop, - no_set_ip_nexthop_cmd, - "no set ip next-hop [A.B.C.D]", - NO_STR - SET_STR - IP_STR - "Next hop address\n" - "IP address of next hop\n") -{ - int idx = 0; - VTY_DECLVAR_CONTEXT(route_map_index, index); - const char *arg = NULL; - - if (argv_find(argv, argc, "A.B.C.D", &idx)) - arg = argv[idx]->arg; - - if (rmap_match_set_hook.no_set_ip_nexthop) - return rmap_match_set_hook.no_set_ip_nexthop( - vty, index, "ip next-hop", arg); - - return CMD_SUCCESS; -} - - -DEFUN (set_ipv6_nexthop_local, - set_ipv6_nexthop_local_cmd, - "set ipv6 next-hop local X:X::X:X", - SET_STR - IPV6_STR - "IPv6 next-hop address\n" - "IPv6 local address\n" - "IPv6 address of next hop\n") -{ - int idx_ipv6 = 4; - struct in6_addr addr; - int ret; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr); - if (!ret) { - vty_out(vty, "%% Malformed nexthop address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (!IN6_IS_ADDR_LINKLOCAL(&addr)) { - vty_out(vty, "%% Invalid link-local nexthop address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (rmap_match_set_hook.set_ipv6_nexthop_local) - return rmap_match_set_hook.set_ipv6_nexthop_local( - vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg); - return CMD_SUCCESS; -} - - -DEFUN (no_set_ipv6_nexthop_local, - no_set_ipv6_nexthop_local_cmd, - "no set ipv6 next-hop local [X:X::X:X]", - NO_STR - SET_STR - IPV6_STR - "IPv6 next-hop address\n" - "IPv6 local address\n" - "IPv6 address of next hop\n") -{ - int idx_ipv6 = 5; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.no_set_ipv6_nexthop_local) { - if (argc <= idx_ipv6) - return rmap_match_set_hook.no_set_ipv6_nexthop_local( - vty, index, "ipv6 next-hop local", NULL); - return rmap_match_set_hook.no_set_ipv6_nexthop_local( - vty, index, "ipv6 next-hop local", argv[5]->arg); - } - return CMD_SUCCESS; -} - -DEFUN (set_metric, - set_metric_cmd, - "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>", - SET_STR - "Metric value for destination routing protocol\n" - "Metric value\n" - "Assign round trip time\n" - "Add round trip time\n" - "Subtract round trip time\n" - "Add metric\n" - "Subtract metric\n") -{ - int idx_number = 2; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - const char *pass = (argv[idx_number]->type == RANGE_TKN) - ? argv[idx_number]->arg - : argv[idx_number]->text; - - if (rmap_match_set_hook.set_metric) - return rmap_match_set_hook.set_metric(vty, index, "metric", - pass); - return CMD_SUCCESS; -} - - -DEFUN (no_set_metric, - no_set_metric_cmd, - "no set metric [(0-4294967295)]", - NO_STR - SET_STR - "Metric value for destination routing protocol\n" - "Metric value\n") -{ - int idx_number = 3; - VTY_DECLVAR_CONTEXT(route_map_index, index); - - if (rmap_match_set_hook.no_set_metric) { - if (argc <= idx_number) - return rmap_match_set_hook.no_set_metric( - vty, index, "metric", NULL); - return rmap_match_set_hook.no_set_metric(vty, index, "metric", - argv[idx_number]->arg); - } - return CMD_SUCCESS; -} - - -DEFUN (set_tag, - set_tag_cmd, - "set tag (1-4294967295)", - SET_STR - "Tag value for routing protocol\n" - "Tag value\n") -{ - VTY_DECLVAR_CONTEXT(route_map_index, index); - - int idx_number = 2; - if (rmap_match_set_hook.set_tag) - return rmap_match_set_hook.set_tag(vty, index, "tag", - argv[idx_number]->arg); - return CMD_SUCCESS; -} - - -DEFUN (no_set_tag, - no_set_tag_cmd, - "no set tag [(1-4294967295)]", - NO_STR - SET_STR - "Tag value for routing protocol\n" - "Tag value\n") -{ - VTY_DECLVAR_CONTEXT(route_map_index, index); - - int idx_number = 3; - if (rmap_match_set_hook.no_set_tag) { - if (argc <= idx_number) - return rmap_match_set_hook.no_set_tag(vty, index, "tag", - NULL); - return rmap_match_set_hook.no_set_tag(vty, index, "tag", - argv[idx_number]->arg); - } - return CMD_SUCCESS; -} - - -DEFUN_NOSH (route_map, - route_map_cmd, - "route-map WORD (1-65535)", - "Create route-map or enter route-map command mode\n" - "Route map tag\n" - "Route map denies set operations\n" - "Route map permits set operations\n" - "Sequence to insert to/delete from existing route-map entry\n") -{ - int idx_word = 1; - int idx_permit_deny = 2; - int idx_number = 3; - struct route_map *map; - struct route_map_index *index; - char *endptr = NULL; - int permit = - argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY; - unsigned long pref = strtoul(argv[idx_number]->arg, &endptr, 10); - const char *mapname = argv[idx_word]->arg; - - /* Get route map. */ - map = route_map_get(mapname); - index = route_map_index_get(map, permit, pref); - - VTY_PUSH_CONTEXT(RMAP_NODE, index); - return CMD_SUCCESS; -} - -DEFUN (no_route_map_all, - no_route_map_all_cmd, - "no route-map WORD", - NO_STR - "Create route-map or enter route-map command mode\n" - "Route map tag\n") -{ - int idx_word = 2; - const char *mapname = argv[idx_word]->arg; - struct route_map *map; - - map = route_map_lookup_by_name(mapname); - if (map == NULL) { - vty_out(vty, "%% Could not find route-map %s\n", mapname); - return CMD_WARNING_CONFIG_FAILED; - } - - route_map_delete(map); - - return CMD_SUCCESS; -} - -DEFUN (no_route_map, - no_route_map_cmd, - "no route-map WORD (1-65535)", - NO_STR - "Create route-map or enter route-map command mode\n" - "Route map tag\n" - "Route map denies set operations\n" - "Route map permits set operations\n" - "Sequence to insert to/delete from existing route-map entry\n") -{ - int idx_word = 2; - int idx_permit_deny = 3; - int idx_number = 4; - struct route_map *map; - struct route_map_index *index; - char *endptr = NULL; - int permit = strmatch(argv[idx_permit_deny]->text, "permit") - ? RMAP_PERMIT - : RMAP_DENY; - const char *prefstr = argv[idx_number]->arg; - const char *mapname = argv[idx_word]->arg; - unsigned long pref = strtoul(prefstr, &endptr, 10); - - /* Existence check. */ - map = route_map_lookup_by_name(mapname); - if (map == NULL) { - vty_out(vty, "%% Could not find route-map %s\n", mapname); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Lookup route map index. */ - index = route_map_index_lookup(map, permit, pref); - if (index == NULL) { - vty_out(vty, "%% Could not find route-map entry %s %s\n", - mapname, prefstr); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Delete index from route map. */ - route_map_index_delete(index, 1); - - /* If this route rule is the last one, delete route map itself. */ - if (route_map_empty(map)) - route_map_delete(map); - - return CMD_SUCCESS; -} - -DEFUN (rmap_onmatch_next, - rmap_onmatch_next_cmd, - "on-match next", - "Exit policy on matches\n" - "Next clause\n") -{ - struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); - - if (index) { - if (index->type == RMAP_DENY) { - /* Under a deny clause, match means it's finished. No - * need to set next */ - vty_out(vty, - "on-match next not supported under route-map deny\n"); - return CMD_WARNING_CONFIG_FAILED; - } - index->exitpolicy = RMAP_NEXT; - } - return CMD_SUCCESS; -} - -DEFUN (no_rmap_onmatch_next, - no_rmap_onmatch_next_cmd, - "no on-match next", - NO_STR - "Exit policy on matches\n" - "Next clause\n") -{ - struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); - - if (index) - index->exitpolicy = RMAP_EXIT; - - return CMD_SUCCESS; -} - -DEFUN (rmap_onmatch_goto, - rmap_onmatch_goto_cmd, - "on-match goto (1-65535)", - "Exit policy on matches\n" - "Goto Clause number\n" - "Number\n") -{ - int idx = 0; - char *num = argv_find(argv, argc, "(1-65535)", &idx) ? argv[idx]->arg - : NULL; - - struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); - int d = 0; - - if (index) { - if (index->type == RMAP_DENY) { - /* Under a deny clause, match means it's finished. No - * need to go anywhere */ - vty_out(vty, - "on-match goto not supported under route-map deny\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (num) - d = strtoul(num, NULL, 10); - else - d = index->pref + 1; - - if (d <= index->pref) { - /* Can't allow you to do that, Dave */ - vty_out(vty, "can't jump backwards in route-maps\n"); - return CMD_WARNING_CONFIG_FAILED; - } else { - index->exitpolicy = RMAP_GOTO; - index->nextpref = d; - } - } - return CMD_SUCCESS; -} - -DEFUN (no_rmap_onmatch_goto, - no_rmap_onmatch_goto_cmd, - "no on-match goto", - NO_STR - "Exit policy on matches\n" - "Goto Clause number\n") -{ - struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); - - if (index) - index->exitpolicy = RMAP_EXIT; - - return CMD_SUCCESS; -} - -/* Cisco/GNU Zebra compatibility aliases */ -/* ALIAS_FIXME */ -DEFUN (rmap_continue, - rmap_continue_cmd, - "continue (1-65535)", - "Continue on a different entry within the route-map\n" - "Route-map entry sequence number\n") -{ - return rmap_onmatch_goto(self, vty, argc, argv); -} - -/* ALIAS_FIXME */ -DEFUN (no_rmap_continue, - no_rmap_continue_cmd, - "no continue [(1-65535)]", - NO_STR - "Continue on a different entry within the route-map\n" - "Route-map entry sequence number\n") -{ - return no_rmap_onmatch_goto(self, vty, argc, argv); -} - static void clear_route_map_helper(struct route_map *map) { struct route_map_index *index; @@ -2937,89 +2064,6 @@ DEFUN (rmap_show_unused, return vty_show_unused_route_map(vty); } -DEFUN (rmap_call, - rmap_call_cmd, - "call WORD", - "Jump to another Route-Map after match+set\n" - "Target route-map name\n") -{ - int idx_word = 1; - struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); - const char *rmap = argv[idx_word]->arg; - - assert(index); - - /* If "call" is invoked with the same route-map name as - * the one previously configured then, ignore the duplicate - * configuration. - */ - if (index->nextrm && (strcmp(index->nextrm, rmap) == 0)) - return CMD_SUCCESS; - - if (index->nextrm) { - route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED, - index->nextrm, index->map->name); - XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm); - } - index->nextrm = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); - - /* Execute event hook. */ - route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, index->nextrm, - index->map->name); - return CMD_SUCCESS; -} - -DEFUN (no_rmap_call, - no_rmap_call_cmd, - "no call", - NO_STR - "Jump to another Route-Map after match+set\n") -{ - struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); - - if (index->nextrm) { - route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED, - index->nextrm, index->map->name); - XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm); - index->nextrm = NULL; - } - - return CMD_SUCCESS; -} - -DEFUN (rmap_description, - rmap_description_cmd, - "description LINE...", - "Route-map comment\n" - "Comment describing this route-map rule\n") -{ - int idx_line = 1; - struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); - - if (index) { - if (index->description) - XFREE(MTYPE_TMP, index->description); - index->description = argv_concat(argv, argc, idx_line); - } - return CMD_SUCCESS; -} - -DEFUN (no_rmap_description, - no_rmap_description_cmd, - "no description", - NO_STR - "Route-map comment\n") -{ - struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); - - if (index) { - if (index->description) - XFREE(MTYPE_TMP, index->description); - index->description = NULL; - } - return CMD_SUCCESS; -} - DEFUN (debug_rmap, debug_rmap_cmd, "debug route-map", @@ -3045,59 +2089,6 @@ DEFUN (no_debug_rmap, static struct cmd_node rmap_debug_node = {RMAP_DEBUG_NODE, "", 1}; /* Configuration write function. */ -static int route_map_config_write(struct vty *vty) -{ - struct route_map *map; - struct route_map_index *index; - struct route_map_rule *rule; - int first = 1; - int write = 0; - struct listnode *ln; - struct list *maplist = list_new(); - - for (map = route_map_master.head; map; map = map->next) - listnode_add(maplist, map); - - list_sort(maplist, sort_route_map); - - for (ALL_LIST_ELEMENTS_RO(maplist, ln, map)) - for (index = map->head; index; index = index->next) { - if (!first) - vty_out(vty, "!\n"); - else - first = 0; - - vty_out(vty, "route-map %s %s %d\n", map->name, - route_map_type_str(index->type), index->pref); - - if (index->description) - vty_out(vty, " description %s\n", - index->description); - - for (rule = index->match_list.head; rule; - rule = rule->next) - vty_out(vty, " match %s %s\n", rule->cmd->str, - rule->rule_str ? rule->rule_str : ""); - - for (rule = index->set_list.head; rule; - rule = rule->next) - vty_out(vty, " set %s %s\n", rule->cmd->str, - rule->rule_str ? rule->rule_str : ""); - if (index->nextrm) - vty_out(vty, " call %s\n", index->nextrm); - if (index->exitpolicy == RMAP_GOTO) - vty_out(vty, " on-match goto %d\n", - index->nextpref); - if (index->exitpolicy == RMAP_NEXT) - vty_out(vty, " on-match next\n"); - - write++; - } - - list_delete(&maplist); - return write; -} - static int rmap_config_write_debug(struct vty *vty) { int write = 0; @@ -3110,9 +2101,6 @@ static int rmap_config_write_debug(struct vty *vty) return write; } -/* Route map node structure. */ -static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1}; - /* Common route map rules */ void *route_map_rule_tag_compile(const char *arg) @@ -3171,14 +2159,6 @@ void route_map_finish(void) route_map_master_hash = NULL; } -static void rmap_autocomplete(vector comps, struct cmd_token *token) -{ - struct route_map *map; - - for (map = route_map_master.head; map; map = map->next) - vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name)); -} - /* Increment the use_count counter while attaching the route map */ void route_map_counter_increment(struct route_map *map) { @@ -3196,14 +2176,6 @@ void route_map_counter_decrement(struct route_map *map) } } -static const struct cmd_variable_handler rmap_var_handlers[] = { - {/* "route-map WORD" */ - .varname = "route_map", - .completions = rmap_autocomplete}, - {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete}, - {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete}, - {.completions = NULL}}; - /* Initialization of route map vector. */ void route_map_init(void) { @@ -3221,43 +2193,17 @@ void route_map_init(void) 8, route_map_dep_hash_make_key, route_map_dep_hash_cmp, "Route Map Dep Hash"); - cmd_variable_handler_register(rmap_var_handlers); - rmap_debug = false; - /* Install route map top node. */ - install_node(&rmap_node, route_map_config_write); + route_map_cli_init(); + /* Install route map top node. */ install_node(&rmap_debug_node, rmap_config_write_debug); /* Install route map commands. */ - install_default(RMAP_NODE); - install_element(CONFIG_NODE, &route_map_cmd); - install_element(CONFIG_NODE, &no_route_map_cmd); - install_element(CONFIG_NODE, &no_route_map_all_cmd); - install_element(CONFIG_NODE, &debug_rmap_cmd); install_element(CONFIG_NODE, &no_debug_rmap_cmd); - /* Install the on-match stuff */ - install_element(RMAP_NODE, &route_map_cmd); - install_element(RMAP_NODE, &rmap_onmatch_next_cmd); - install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd); - install_element(RMAP_NODE, &rmap_onmatch_goto_cmd); - install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd); - install_element(RMAP_NODE, &rmap_continue_cmd); - install_element(RMAP_NODE, &no_rmap_continue_cmd); - - /* Install the continue stuff (ALIAS of on-match). */ - - /* Install the call stuff. */ - install_element(RMAP_NODE, &rmap_call_cmd); - install_element(RMAP_NODE, &no_rmap_call_cmd); - - /* Install description commands. */ - install_element(RMAP_NODE, &rmap_description_cmd); - install_element(RMAP_NODE, &no_rmap_description_cmd); - /* Install show command */ install_element(ENABLE_NODE, &rmap_clear_counters_cmd); @@ -3266,49 +2212,4 @@ void route_map_init(void) install_element(ENABLE_NODE, &debug_rmap_cmd); install_element(ENABLE_NODE, &no_debug_rmap_cmd); - - install_element(RMAP_NODE, &match_interface_cmd); - install_element(RMAP_NODE, &no_match_interface_cmd); - - install_element(RMAP_NODE, &match_ip_address_cmd); - install_element(RMAP_NODE, &no_match_ip_address_cmd); - - install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd); - install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd); - - install_element(RMAP_NODE, &match_ip_next_hop_cmd); - install_element(RMAP_NODE, &no_match_ip_next_hop_cmd); - - install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); - install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); - - install_element(RMAP_NODE, &match_ip_next_hop_type_cmd); - install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd); - - install_element(RMAP_NODE, &match_ipv6_address_cmd); - install_element(RMAP_NODE, &no_match_ipv6_address_cmd); - - install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd); - install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd); - - install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd); - install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd); - - install_element(RMAP_NODE, &match_metric_cmd); - install_element(RMAP_NODE, &no_match_metric_cmd); - - install_element(RMAP_NODE, &match_tag_cmd); - install_element(RMAP_NODE, &no_match_tag_cmd); - - install_element(RMAP_NODE, &set_ip_nexthop_cmd); - install_element(RMAP_NODE, &no_set_ip_nexthop_cmd); - - install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd); - install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd); - - install_element(RMAP_NODE, &set_metric_cmd); - install_element(RMAP_NODE, &no_set_metric_cmd); - - install_element(RMAP_NODE, &set_tag_cmd); - install_element(RMAP_NODE, &no_set_tag_cmd); } diff --git a/lib/routemap.h b/lib/routemap.h index d9e7f73f81..70e150c981 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -666,8 +666,27 @@ int lib_route_map_entry_match_destroy(enum nb_event event, const struct lyd_node *dnode); int lib_route_map_entry_set_destroy(enum nb_event event, const struct lyd_node *dnode); + extern const struct frr_yang_module_info frr_route_map_info; +/* routemap_cli.c */ +extern void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void route_map_instance_show_end(struct vty *vty, + struct lyd_node *dnode); +extern void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void route_map_action_show(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void route_map_call_show(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void route_map_description_show(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void route_map_cli_init(void); + #ifdef __cplusplus } #endif diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c new file mode 100644 index 0000000000..987693c961 --- /dev/null +++ b/lib/routemap_cli.c @@ -0,0 +1,1075 @@ +/* + * Route map northbound CLI implementation. + * + * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF") + * Rafael Zalamena + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ + +#include + +#include "lib/command.h" +#include "lib/northbound_cli.h" +#include "lib/routemap.h" + +#ifndef VTYSH_EXTRACT_PL +#include "lib/routemap_cli_clippy.c" +#endif /* VTYSH_EXTRACT_PL */ + +#define ROUTE_MAP_CMD_STR \ + "Create route-map or enter route-map command mode\n" \ + "Route map tag\n" +#define ROUTE_MAP_OP_CMD_STR \ + "Route map denies set operations\n" \ + "Route map permits set operations\n" +#define ROUTE_MAP_SEQUENCE_CMD_STR \ + "Sequence to insert to/delete from existing route-map entry\n" + +DEFPY_NOSH( + route_map, route_map_cmd, + "route-map WORD$name $action (1-65535)$sequence", + ROUTE_MAP_CMD_STR + ROUTE_MAP_OP_CMD_STR + ROUTE_MAP_SEQUENCE_CMD_STR) +{ + char xpath_action[XPATH_MAXLEN + 64]; + char xpath_index[XPATH_MAXLEN + 32]; + char xpath[XPATH_MAXLEN]; + int rv; + + snprintf(xpath, sizeof(xpath), + "/frr-route-map:lib/route-map[name='%s']", name); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_index, sizeof(xpath_index), "%s/entry[sequence='%lu']", + xpath, sequence); + nb_cli_enqueue_change(vty, xpath_index, NB_OP_CREATE, NULL); + + snprintf(xpath_action, sizeof(xpath_action), "%s/action", xpath_index); + nb_cli_enqueue_change(vty, xpath_action, NB_OP_MODIFY, action); + + rv = nb_cli_apply_changes(vty, NULL); + if (rv == CMD_SUCCESS) + VTY_PUSH_XPATH(RMAP_NODE, xpath_index); + + return rv; +} + +DEFPY( + no_route_map_all, no_route_map_all_cmd, + "no route-map WORD$name", + NO_STR + ROUTE_MAP_CMD_STR) +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), + "/frr-route-map:lib/route-map[name='%s']", name); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_route_map, no_route_map_cmd, + "no route-map WORD$name $action (1-65535)$sequence", + NO_STR + ROUTE_MAP_CMD_STR + ROUTE_MAP_OP_CMD_STR + ROUTE_MAP_SEQUENCE_CMD_STR) +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), + "/frr-route-map:lib/route-map[name='%s']/entry[sequence='%lu']", + name, sequence); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *name = yang_dnode_get_string(dnode, "../name"); + const char *action = yang_dnode_get_string(dnode, "./action"); + const char *sequence = yang_dnode_get_string(dnode, "./sequence"); + + vty_out(vty, "route-map %s %s %s\n", name, action, sequence); +} + +void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode) +{ + vty_out(vty, "!\n"); +} + +DEFPY( + match_interface, match_interface_cmd, + "match interface IFNAME", + MATCH_STR + "Match first hop interface of route\n" + INTERFACE_STR) +{ + const char *xpath = "./match-condition[condition='interface']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), "%s/interface", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ifname); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_match_interface, no_match_interface_cmd, + "no match interface [IFNAME]", + NO_STR + MATCH_STR + "Match first hop interface of route\n" + INTERFACE_STR) +{ + const char *xpath = "./match-condition[condition='interface']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + match_ip_address, match_ip_address_cmd, + "match ip address <(1-199)$acll|(1300-2699)$aclh|WORD$name>", + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") +{ + const char *xpath = "./match-condition[condition='ipv4-address-list']"; + char xpath_value[XPATH_MAXLEN + 32]; + int acln = acll ? acll : aclh; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (name) { + snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); + } else /* if (acll || aclh) */ { + if ((acln >= 1 && acln <= 99) + || (acln >= 1300 && acln <= 1999)) { + snprintf(xpath_value, sizeof(xpath_value), + "%s/access-list-num", xpath); + } else { + /* + * if ((acln >= 100 && acln <= 199) + * || (acln >= 2000 && acln <= 2699)) + */ + snprintf(xpath_value, sizeof(xpath_value), + "%s/access-list-num-extended", xpath); + } + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + acll_str ? acll_str : aclh_str); + } + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_match_ip_address, no_match_ip_address_cmd, + "no match ip address [<(1-199)|(1300-2699)|WORD>]", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") +{ + const char *xpath = "./match-condition[condition='ipv4-address-list']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + match_ip_address_prefix_list, + match_ip_address_prefix_list_cmd, + "match ip address prefix-list WORD$name", + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + const char *xpath = "./match-condition[condition='ipv4-prefix-list']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd, + "no match ip address prefix-list [WORD]", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + const char *xpath = "./match-condition[condition='ipv4-prefix-list']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + match_ip_next_hop, match_ip_next_hop_cmd, + "match ip next-hop <(1-199)$acll|(1300-2699)$aclh|WORD$name>", + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") +{ + const char *xpath = "./match-condition[condition='ipv4-next-hop-list']"; + char xpath_value[XPATH_MAXLEN + 32]; + int acln = acll ? acll : aclh; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (name) { + snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); + } else /* if (acll || aclh) */ { + if ((acln >= 1 && acln <= 99) + || (acln >= 1300 && acln <= 1999)) { + snprintf(xpath_value, sizeof(xpath_value), + "%s/access-list-num", xpath); + } else { + /* + * if ((acln >= 100 && acln <= 199) + * || (acln >= 2000 && acln <= 2699)) + */ + snprintf(xpath_value, sizeof(xpath_value), + "%s/access-list-num-extended", xpath); + } + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + acll_str ? acll_str : aclh_str); + } + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_match_ip_next_hop, no_match_ip_next_hop_cmd, + "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]", + NO_STR + MATCH_STR + IP_STR + "Match address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP Access-list name\n") +{ + const char *xpath = "./match-condition[condition='ipv4-next-hop-list']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + match_ip_next_hop_prefix_list, + match_ip_next_hop_prefix_list_cmd, + "match ip next-hop prefix-list WORD$name", + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + const char *xpath = + "./match-condition[condition='ipv4-next-hop-prefix-list']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_match_ip_next_hop_prefix_list, + no_match_ip_next_hop_prefix_list_cmd, + "no match ip next-hop prefix-list [WORD]", + NO_STR + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + const char *xpath = + "./match-condition[condition='ipv4-next-hop-prefix-list']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + match_ip_next_hop_type, match_ip_next_hop_type_cmd, + "match ip next-hop type $type", + MATCH_STR + IP_STR + "Match next-hop address of route\n" + "Match entries by type\n" + "Blackhole\n") +{ + const char *xpath = "./match-condition[condition='ipv4-next-hop-type']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-next-hop-type", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd, + "no match ip next-hop type []", + NO_STR MATCH_STR IP_STR + "Match next-hop address of route\n" + "Match entries by type\n" + "Blackhole\n") +{ + const char *xpath = "./match-condition[condition='ipv4-next-hop-type']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + match_ipv6_address, match_ipv6_address_cmd, + "match ipv6 address WORD$name", + MATCH_STR + IPV6_STR + "Match IPv6 address of route\n" + "IPv6 access-list name\n") +{ + const char *xpath = "./match-condition[condition='ipv6-address-list']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_match_ipv6_address, no_match_ipv6_address_cmd, + "no match ipv6 address [WORD]", + NO_STR + MATCH_STR + IPV6_STR + "Match IPv6 address of route\n" + "IPv6 access-list name\n") +{ + const char *xpath = "./match-condition[condition='ipv6-address-list']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + match_ipv6_address_prefix_list, match_ipv6_address_prefix_list_cmd, + "match ipv6 address prefix-list WORD$name", + MATCH_STR + IPV6_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + const char *xpath = "./match-condition[condition='ipv6-prefix-list']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_match_ipv6_address_prefix_list, + no_match_ipv6_address_prefix_list_cmd, + "no match ipv6 address prefix-list [WORD]", + NO_STR + MATCH_STR + IPV6_STR + "Match address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") +{ + const char *xpath = "./match-condition[condition='ipv6-prefix-list']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd, + "match ipv6 next-hop type $type", + MATCH_STR IPV6_STR + "Match next-hop address of route\n" + "Match entries by type\n" + "Blackhole\n") +{ + const char *xpath = "./match-condition[condition='ipv6-next-hop-type']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-next-hop-type", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd, + "no match ipv6 next-hop type []", + NO_STR MATCH_STR IPV6_STR + "Match address of route\n" + "Match entries by type\n" + "Blackhole\n") +{ + const char *xpath = "./match-condition[condition='ipv6-next-hop-type']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + match_metric, match_metric_cmd, + "match metric (0-4294967295)$metric", + MATCH_STR + "Match metric of route\n" + "Metric value\n") +{ + const char *xpath = "./match-condition[condition='metric']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), "%s/metric", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, metric_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_match_metric, no_match_metric_cmd, + "no match metric [(0-4294967295)]", + NO_STR + MATCH_STR + "Match metric of route\n" + "Metric value\n") +{ + const char *xpath = "./match-condition[condition='metric']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + match_tag, match_tag_cmd, + "match tag (1-4294967295)$tag", + MATCH_STR + "Match tag of route\n" + "Tag value\n") +{ + const char *xpath = "./match-condition[condition='tag']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_match_tag, no_match_tag_cmd, + "no match tag [(1-4294967295)]", + NO_STR + MATCH_STR + "Match tag of route\n" + "Tag value\n") +{ + const char *xpath = "./match-condition[condition='tag']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + int condition = yang_dnode_get_enum(dnode, "./condition"); + struct lyd_node *ln; + const char *acl; + + switch (condition) { + case 0: /* interface */ + vty_out(vty, " match interface %s\n", + yang_dnode_get_string(dnode, "./interface")); + break; + case 1: /* ipv4-address-list */ + case 3: /* ipv4-next-hop-list */ + acl = NULL; + if ((ln = yang_dnode_get(dnode, "./list-name")) != NULL) + acl = yang_dnode_get_string(ln, NULL); + else if ((ln = yang_dnode_get(dnode, "./access-list-num")) + != NULL) + acl = yang_dnode_get_string(ln, NULL); + else if ((ln = yang_dnode_get(dnode, + "./access-list-num-extended")) + != NULL) + acl = yang_dnode_get_string(ln, NULL); + + assert(acl); + + switch (condition) { + case 1: + vty_out(vty, " match ip address %s\n", acl); + break; + case 3: + vty_out(vty, " match ip next-hop %s\n", acl); + break; + } + break; + case 2: /* ipv4-prefix-list */ + vty_out(vty, " match ip address prefix-list %s\n", + yang_dnode_get_string(dnode, "./list-name")); + break; + case 4: /* ipv4-next-hop-prefix-list */ + vty_out(vty, " match ip next-hop prefix-list %s\n", + yang_dnode_get_string(dnode, "./list-name")); + break; + case 5: /* ipv4-next-hop-type */ + vty_out(vty, " match ip next-hop type %s\n", + yang_dnode_get_string(dnode, "./ipv4-next-hop-type")); + break; + case 6: /* ipv6-address-list */ + vty_out(vty, " match ipv6 address %s\n", + yang_dnode_get_string(dnode, "./list-name")); + break; + case 7: /* ipv6-prefix-list */ + vty_out(vty, " match ipv6 address prefix-list %s\n", + yang_dnode_get_string(dnode, "./list-name")); + break; + case 8: /* ipv6-next-hop-type */ + vty_out(vty, " match ipv6 next-hop type %s\n", + yang_dnode_get_string(dnode, "./ipv6-next-hop-type")); + break; + case 9: /* metric */ + vty_out(vty, " match metric %s\n", + yang_dnode_get_string(dnode, "./metric")); + break; + case 10: /* tag */ + vty_out(vty, " match tag %s\n", + yang_dnode_get_string(dnode, "./tag")); + break; + case 100: + /* NOTHING: custom field, should be handled by daemon. */ + break; + } +} + +DEFPY( + set_ip_nexthop, set_ip_nexthop_cmd, + "set ip next-hop A.B.C.D$addr", + SET_STR + IP_STR + "Next hop address\n" + "IP address of next hop\n") +{ + const char *xpath = "./set-action[action='ipv4-next-hop']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-address", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_set_ip_nexthop, no_set_ip_nexthop_cmd, + "no set ip next-hop [A.B.C.D]", + NO_STR + SET_STR + IP_STR + "Next hop address\n" + "IP address of next hop\n") +{ + const char *xpath = "./set-action[action='ipv4-next-hop']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + set_ipv6_nexthop_local, set_ipv6_nexthop_local_cmd, + "set ipv6 next-hop local X:X::X:X$addr", + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 local address\n" + "IPv6 address of next hop\n") +{ + const char *xpath = "./set-action[action='ipv6-next-hop']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-address", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_cmd, + "no set ipv6 next-hop local [X:X::X:X]", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 local address\n" + "IPv6 address of next hop\n") +{ + const char *xpath = "./set-action[action='ipv6-next-hop']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + set_metric, set_metric_cmd, + "set metric <(0-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt|+metric$ametric|-metric$smetric>", + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n" + "Assign round trip time\n" + "Add round trip time\n" + "Subtract round trip time\n" + "Add metric\n" + "Subtract metric\n") +{ + const char *xpath = "./set-action[action='metric']"; + char xpath_value[XPATH_MAXLEN]; + char value[64]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (rtt) { + snprintf(xpath_value, sizeof(xpath_value), + "%s/use-round-trip-time", xpath); + snprintf(value, sizeof(value), "true"); + } else if (artt) { + snprintf(xpath_value, sizeof(xpath_value), + "%s/add-round-trip-time", xpath); + snprintf(value, sizeof(value), "true"); + } else if (srtt) { + snprintf(xpath_value, sizeof(xpath_value), + "%s/subtract-round-trip-time", xpath); + snprintf(value, sizeof(value), "true"); + } else if (ametric) { + snprintf(xpath_value, sizeof(xpath_value), "%s/add-metric", + xpath); + snprintf(value, sizeof(value), "true"); + } else if (smetric) { + snprintf(xpath_value, sizeof(xpath_value), "%s/subtract-metric", + xpath); + snprintf(value, sizeof(value), "true"); + } else { + snprintf(xpath_value, sizeof(xpath_value), "%s/value", xpath); + snprintf(value, sizeof(value), "%lu", metric); + } + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, value); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_set_metric, no_set_metric_cmd, + "no set metric [(0-4294967295)]", + NO_STR + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n") +{ + const char *xpath = "./set-action[action='metric']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + set_tag, set_tag_cmd, + "set tag (1-4294967295)$tag", + SET_STR + "Tag value for routing protocol\n" + "Tag value\n") +{ + const char *xpath = "./set-action[action='tag']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_set_tag, no_set_tag_cmd, + "no set tag [(1-4294967295)]", + NO_STR + SET_STR + "Tag value for routing protocol\n" + "Tag value\n") +{ + const char *xpath = "./set-action[action='tag']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void route_map_action_show(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + int action = yang_dnode_get_enum(dnode, "./action"); + + switch (action) { + case 0: /* ipv4-next-hop */ + vty_out(vty, " set ip next-hop %s\n", + yang_dnode_get_string(dnode, "./ipv4-address")); + break; + case 1: /* ipv6-next-hop */ + vty_out(vty, " set ipv6 next-hop local %s\n", + yang_dnode_get_string(dnode, "./ipv6-address")); + break; + case 2: /* metric */ + if (yang_dnode_get(dnode, "./use-round-trip-time")) { + vty_out(vty, " set metric rtt\n"); + } else if (yang_dnode_get(dnode, "./add-round-trip-time")) { + vty_out(vty, " set metric +rtt\n"); + } else if (yang_dnode_get(dnode, "./subtract-round-trip-time")) { + vty_out(vty, " set metric -rtt\n"); + } else if (yang_dnode_get(dnode, "./add-metric")) { + vty_out(vty, " set metric +metric\n"); + } else if (yang_dnode_get(dnode, "./subtract-metric")) { + vty_out(vty, " set metric -metric\n"); + } else { + vty_out(vty, " set metric %s\n", + yang_dnode_get_string(dnode, "./value")); + } + break; + case 3: /* tag */ + vty_out(vty, " set tag %s\n", + yang_dnode_get_string(dnode, "./tag")); + break; + case 100: + /* NOTHING: custom field, should be handled by daemon. */ + break; + } +} + +DEFPY( + rmap_onmatch_next, rmap_onmatch_next_cmd, + "on-match next", + "Exit policy on matches\n" + "Next clause\n") +{ + nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_MODIFY, "next"); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_rmap_onmatch_next, + no_rmap_onmatch_next_cmd, + "no on-match next", + NO_STR + "Exit policy on matches\n" + "Next clause\n") +{ + nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + rmap_onmatch_goto, rmap_onmatch_goto_cmd, + "on-match goto (1-65535)$rm_num", + "Exit policy on matches\n" + "Goto Clause number\n" + "Number\n") +{ + nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_MODIFY, "goto"); + nb_cli_enqueue_change(vty, "./goto-value", NB_OP_MODIFY, rm_num_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_rmap_onmatch_goto, no_rmap_onmatch_goto_cmd, + "no on-match goto", + NO_STR + "Exit policy on matches\n" + "Goto Clause number\n") +{ + nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +/* Cisco/GNU Zebra compatibility aliases */ +ALIAS( + rmap_onmatch_goto, rmap_continue_cmd, + "continue (1-65535)$rm_num", + "Continue on a different entry within the route-map\n" + "Route-map entry sequence number\n") + +ALIAS( + no_rmap_onmatch_goto, no_rmap_continue_cmd, + "no continue [(1-65535)]", + NO_STR + "Continue on a different entry within the route-map\n" + "Route-map entry sequence number\n") + +void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + int exit_policy = yang_dnode_get_enum(dnode, NULL); + + switch (exit_policy) { + case 0: /* permit-or-deny */ + /* NOTHING: default option. */ + break; + case 1: /* next */ + vty_out(vty, " on-match next\n"); + break; + case 2: /* goto */ + vty_out(vty, " on-match goto %s\n", + yang_dnode_get_string(dnode, "../goto-value")); + break; + } +} + +DEFPY( + rmap_call, rmap_call_cmd, + "call WORD$name", + "Jump to another Route-Map after match+set\n" + "Target route-map name\n") +{ + nb_cli_enqueue_change(vty, "./call", NB_OP_MODIFY, name); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_rmap_call, no_rmap_call_cmd, + "no call", + NO_STR + "Jump to another Route-Map after match+set\n") +{ + nb_cli_enqueue_change(vty, "./call", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void route_map_call_show(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " call %s\n", yang_dnode_get_string(dnode, NULL)); +} + +DEFPY( + rmap_description, rmap_description_cmd, + "description LINE...", + "Route-map comment\n" + "Comment describing this route-map rule\n") +{ + char *desc; + int rv; + + desc = argv_concat(argv, argc, 1); + nb_cli_enqueue_change(vty, "./description", NB_OP_MODIFY, desc); + rv = nb_cli_apply_changes(vty, NULL); + XFREE(MTYPE_TMP, desc); + + return rv; +} + +DEFUN (no_rmap_description, + no_rmap_description_cmd, + "no description", + NO_STR + "Route-map comment\n") +{ + nb_cli_enqueue_change(vty, "./description", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void route_map_description_show(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL)); +} + +static int route_map_config_write(struct vty *vty) +{ + struct lyd_node *dnode; + int written = 0; + + dnode = yang_dnode_get(running_config->dnode, + "/frr-route-map:lib"); + if (dnode) { + nb_cli_show_dnode_cmds(vty, dnode, false); + written = 1; + } + + return written; +} + +/* Route map node structure. */ +static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1}; + +static void rmap_autocomplete(vector comps, struct cmd_token *token) +{ + struct route_map *map; + + for (map = route_map_master.head; map; map = map->next) + vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name)); +} + +static const struct cmd_variable_handler rmap_var_handlers[] = { + {.varname = "route_map", .completions = rmap_autocomplete}, + {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete}, + {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete}, + {.completions = NULL} +}; + +void route_map_cli_init(void) +{ + /* Auto complete handler. */ + cmd_variable_handler_register(rmap_var_handlers); + + /* CLI commands. */ + install_node(&rmap_node, route_map_config_write); + install_default(RMAP_NODE); + install_element(CONFIG_NODE, &route_map_cmd); + install_element(CONFIG_NODE, &no_route_map_cmd); + install_element(CONFIG_NODE, &no_route_map_all_cmd); + + /* Install the on-match stuff */ + install_element(RMAP_NODE, &route_map_cmd); + install_element(RMAP_NODE, &rmap_onmatch_next_cmd); + install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd); + install_element(RMAP_NODE, &rmap_onmatch_goto_cmd); + install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd); + install_element(RMAP_NODE, &rmap_continue_cmd); + install_element(RMAP_NODE, &no_rmap_continue_cmd); + + /* Install the call stuff. */ + install_element(RMAP_NODE, &rmap_call_cmd); + install_element(RMAP_NODE, &no_rmap_call_cmd); + + /* Install description commands. */ + install_element(RMAP_NODE, &rmap_description_cmd); + install_element(RMAP_NODE, &no_rmap_description_cmd); + + /* Install 'match' commands. */ + install_element(RMAP_NODE, &match_interface_cmd); + install_element(RMAP_NODE, &no_match_interface_cmd); + + install_element(RMAP_NODE, &match_ip_address_cmd); + install_element(RMAP_NODE, &no_match_ip_address_cmd); + + install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd); + install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd); + + install_element(RMAP_NODE, &match_ip_next_hop_cmd); + install_element(RMAP_NODE, &no_match_ip_next_hop_cmd); + + install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); + install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); + + install_element(RMAP_NODE, &match_ip_next_hop_type_cmd); + install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd); + + install_element(RMAP_NODE, &match_ipv6_address_cmd); + install_element(RMAP_NODE, &no_match_ipv6_address_cmd); + + install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd); + install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd); + + install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd); + install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd); + + install_element(RMAP_NODE, &match_metric_cmd); + install_element(RMAP_NODE, &no_match_metric_cmd); + + install_element(RMAP_NODE, &match_tag_cmd); + install_element(RMAP_NODE, &no_match_tag_cmd); + + /* Install 'set' commands. */ + install_element(RMAP_NODE, &set_ip_nexthop_cmd); + install_element(RMAP_NODE, &no_set_ip_nexthop_cmd); + + install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd); + install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd); + + install_element(RMAP_NODE, &set_metric_cmd); + install_element(RMAP_NODE, &no_set_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 02eb756334..b9ac01e865 100644 --- a/lib/routemap_northbound.c +++ b/lib/routemap_northbound.c @@ -1218,6 +1218,8 @@ const struct frr_yang_module_info frr_route_map_info = { .cbs = { .create = lib_route_map_entry_create, .destroy = lib_route_map_entry_destroy, + .cli_show = route_map_instance_show, + .cli_show_end = route_map_instance_show_end, } }, { @@ -1225,6 +1227,7 @@ const struct frr_yang_module_info frr_route_map_info = { .cbs = { .modify = lib_route_map_entry_description_modify, .destroy = lib_route_map_entry_description_destroy, + .cli_show = route_map_description_show, } }, { @@ -1238,12 +1241,14 @@ const struct frr_yang_module_info frr_route_map_info = { .cbs = { .modify = lib_route_map_entry_call_modify, .destroy = lib_route_map_entry_call_destroy, + .cli_show = route_map_call_show, } }, { .xpath = "/frr-route-map:lib/route-map/entry/exit-policy", .cbs = { .modify = lib_route_map_entry_exit_policy_modify, + .cli_show = route_map_exit_policy_show, } }, { @@ -1258,6 +1263,7 @@ const struct frr_yang_module_info frr_route_map_info = { .cbs = { .create = lib_route_map_entry_match_condition_create, .destroy = lib_route_map_entry_match_condition_destroy, + .cli_show = route_map_condition_show, } }, { @@ -1321,6 +1327,7 @@ const struct frr_yang_module_info frr_route_map_info = { .cbs = { .create = lib_route_map_entry_set_action_create, .destroy = lib_route_map_entry_set_action_destroy, + .cli_show = route_map_action_show, } }, { diff --git a/lib/subdir.am b/lib/subdir.am index 94b3d933ac..ffac721256 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -71,6 +71,7 @@ lib_libfrr_la_SOURCES = \ lib/qobj.c \ lib/ringbuf.c \ lib/routemap.c \ + lib/routemap_cli.c \ lib/routemap_northbound.c \ lib/sbuf.c \ lib/seqlock.c \ @@ -122,6 +123,7 @@ vtysh_scan += \ $(top_srcdir)/lib/nexthop_group.c \ $(top_srcdir)/lib/plist.c \ $(top_srcdir)/lib/routemap.c \ + $(top_srcdir)/lib/routemap_cli.c \ $(top_srcdir)/lib/vrf.c \ $(top_srcdir)/lib/vty.c \ # end @@ -141,6 +143,8 @@ lib/nexthop_group_clippy.c: $(CLIPPY_DEPS) lib/nexthop_group.lo: lib/nexthop_group_clippy.c lib/northbound_cli_clippy.c: $(CLIPPY_DEPS) lib/northbound_cli.lo: lib/northbound_cli_clippy.c +lib/routemap_cli_clippy.c: $(CLIPPY_DEPS) +lib/routemap_cli.lo: lib/routemap_cli_clippy.c lib/vty_clippy.c: $(CLIPPY_DEPS) lib/vty.lo: lib/vty_clippy.c lib/log_vty_clippy.c: $(CLIPPY_DEPS) diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 13413888bf..b7ac0abe02 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -87,7 +87,7 @@ sub scan_file { if ($file =~ /lib\/keychain\.c$/) { $protocol = "VTYSH_RIPD|VTYSH_EIGRPD"; } - elsif ($file =~ /lib\/routemap\.c$/) { + elsif ($file =~ /lib\/routemap\.c$/ || $file =~ /lib\/routemap_cli\.c$/) { $protocol = "VTYSH_RMAP"; } elsif ($file =~ /lib\/vrf\.c$/) { From a513824c343971e51603471948c958430b602371 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 1 Oct 2019 17:56:16 -0300 Subject: [PATCH 05/10] yang/lib: add filter model to code This fixes a warning on daemons that use route map about filter yang model not being included in the binary. Signed-off-by: Rafael Zalamena --- lib/subdir.am | 1 + yang/subdir.am | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/subdir.am b/lib/subdir.am index ffac721256..4f62eb2264 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -106,6 +106,7 @@ lib_libfrr_la_SOURCES = \ # end nodist_lib_libfrr_la_SOURCES = \ + yang/frr-filter.yang.c \ yang/frr-interface.yang.c \ yang/frr-route-map.yang.c \ yang/frr-route-types.yang.c \ diff --git a/yang/subdir.am b/yang/subdir.am index 7a15a6a309..c1297dafd5 100644 --- a/yang/subdir.am +++ b/yang/subdir.am @@ -19,6 +19,7 @@ EXTRA_DIST += yang/embedmodel.py # global symbols :(. Just put it in the daemon. Dynamic libraries.so work # without problems, as seen in libfrr. +dist_yangmodels_DATA += yang/frr-filter.yang dist_yangmodels_DATA += yang/frr-module-translator.yang dist_yangmodels_DATA += yang/frr-test-module.yang dist_yangmodels_DATA += yang/frr-interface.yang From a162869ef0798ef98d756238c6b89108a69f5a5d Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 30 Sep 2019 15:02:15 -0300 Subject: [PATCH 06/10] lib: fix route map generic error output Two fixes here: * Don't attempt to use `vty` pointer in vty; * When `vty` is unavailable output to log; Signed-off-by: Rafael Zalamena --- lib/routemap.c | 68 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/lib/routemap.c b/lib/routemap.c index e07ad08123..5369fa771f 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -308,15 +308,21 @@ int generic_match_add(struct vty *vty, struct route_map_index *index, ret = route_map_add_match(index, command, arg, type); switch (ret) { case RMAP_RULE_MISSING: - vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); + if (vty) + vty_out(vty, "%% [%s] Can't find rule.\n", + frr_protonameinst); + else + zlog_warn("Can't find rule: %s", command); return CMD_WARNING_CONFIG_FAILED; - break; case RMAP_COMPILE_ERROR: - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); + if (vty) + vty_out(vty, + "%% [%s] Argument form is unsupported or malformed.\n", + frr_protonameinst); + else + zlog_warn("Argument form is unsupported or malformed: " + "%s %s", command, arg); return CMD_WARNING_CONFIG_FAILED; - break; case RMAP_COMPILE_SUCCESS: /* * Nothing to do here move along @@ -353,13 +359,21 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index, ret = route_map_delete_match(index, command, dep_name, type); switch (ret) { case RMAP_RULE_MISSING: - vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); + if (vty) + vty_out(vty, "%% [%s] Can't find rule.\n", + frr_protonameinst); + else + zlog_warn("Can't find rule: %s", command); retval = CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_ERROR: - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); + if (vty) + vty_out(vty, + "%% [%s] Argument form is unsupported or malformed.\n", + frr_protonameinst); + else + zlog_warn("Argument form is unsupported or malformed: " + "%s %s", command, arg); retval = CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: @@ -383,15 +397,20 @@ int generic_set_add(struct vty *vty, struct route_map_index *index, ret = route_map_add_set(index, command, arg); switch (ret) { case RMAP_RULE_MISSING: - vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); + if (vty) + vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); + else + zlog_warn("Can't find rule: %s", command); return CMD_WARNING_CONFIG_FAILED; - break; case RMAP_COMPILE_ERROR: - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); + if (vty) + vty_out(vty, + "%% [%s] Argument form is unsupported or malformed.\n", + frr_protonameinst); + else + zlog_warn("Argument form is unsupported or malformed: " + "%s %s", command, arg); return CMD_WARNING_CONFIG_FAILED; - break; case RMAP_COMPILE_SUCCESS: break; } @@ -407,15 +426,20 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index, ret = route_map_delete_set(index, command, arg); switch (ret) { case RMAP_RULE_MISSING: - vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); + if (vty) + vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); + else + zlog_warn("Can't find rule: %s", command); return CMD_WARNING_CONFIG_FAILED; - break; case RMAP_COMPILE_ERROR: - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); + if (vty) + vty_out(vty, + "%% [%s] Argument form is unsupported or malformed.\n", + frr_protonameinst); + else + zlog_warn("Argument form is unsupported or malformed: " + "%s %s", command, arg); return CMD_WARNING_CONFIG_FAILED; - break; case RMAP_COMPILE_SUCCESS: break; } From e324ef433ca611ddf8274015c0b36c8de1fb3075 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 1 Oct 2019 15:52:51 -0300 Subject: [PATCH 07/10] lib: add backward compatibility for route map Allow old CLI users to still print their configuration without migrating to northbound. Signed-off-by: Rafael Zalamena --- lib/routemap_cli.c | 56 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index 987693c961..7023710564 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -46,6 +46,9 @@ DEFPY_NOSH( ROUTE_MAP_OP_CMD_STR ROUTE_MAP_SEQUENCE_CMD_STR) { + struct route_map_index *rmi; + struct route_map *rm; + int action_type; char xpath_action[XPATH_MAXLEN + 64]; char xpath_index[XPATH_MAXLEN + 32]; char xpath[XPATH_MAXLEN]; @@ -63,9 +66,16 @@ DEFPY_NOSH( nb_cli_enqueue_change(vty, xpath_action, NB_OP_MODIFY, action); rv = nb_cli_apply_changes(vty, NULL); - if (rv == CMD_SUCCESS) + if (rv == CMD_SUCCESS) { VTY_PUSH_XPATH(RMAP_NODE, xpath_index); + /* Add support for non-migrated route map users. */ + rm = route_map_get(name); + action_type = (action[0] == 'p') ? RMAP_PERMIT : RMAP_DENY; + rmi = route_map_index_get(rm, action_type, sequence); + VTY_PUSH_CONTEXT(RMAP_NODE, rmi); + } + return rv; } @@ -105,11 +115,55 @@ DEFPY( void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { + const struct route_map_rule *rmr; + const struct route_map_index *rmi; const char *name = yang_dnode_get_string(dnode, "../name"); const char *action = yang_dnode_get_string(dnode, "./action"); const char *sequence = yang_dnode_get_string(dnode, "./sequence"); vty_out(vty, "route-map %s %s %s\n", name, action, sequence); + + rmi = nb_running_get_entry(dnode, NULL, false); + if (rmi == NULL) { + /* + * We can't have outdated rules if route map hasn't + * been created yet. + */ + return; + } + +#define SKIP_RULE(name) if (strcmp((name), rmr->cmd->str) == 0) continue + + /* Print route map `match` for old CLI users. */ + for (rmr = rmi->match_list.head; rmr; rmr = rmr->next) { + /* Skip all matches implemented by northbound. */ + SKIP_RULE("interface"); + SKIP_RULE("ip address"); + SKIP_RULE("ip address prefix-list"); + SKIP_RULE("ip next-hop"); + SKIP_RULE("ip next-hop prefix-list"); + SKIP_RULE("ip next-hop type"); + SKIP_RULE("ipv6 address"); + SKIP_RULE("ipv6 address prefix-list"); + SKIP_RULE("ipv6 next-hop type"); + SKIP_RULE("metric"); + SKIP_RULE("tag"); + + vty_out(vty, " match %s %s\n", rmr->cmd->str, + rmr->rule_str ? rmr->rule_str : ""); + } + + /* Print route map `set` for old CLI users. */ + for (rmr = rmi->set_list.head; rmr; rmr = rmr->next) { + /* Skip all sets implemented by northbound. */ + SKIP_RULE("metric"); + SKIP_RULE("tag"); + + vty_out(vty, " set %s %s\n", rmr->cmd->str, + rmr->rule_str ? rmr->rule_str : ""); + } + +#undef SKIP_RULE } void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode) From 91835f1fd2a8dd05a5ba03c8961b699aaabed7e7 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Tue, 1 Oct 2019 17:56:41 -0300 Subject: [PATCH 08/10] *: fix route map integration Add the appropriated code to bootstrap route map northbound for all daemons. Signed-off-by: Rafael Zalamena --- bgpd/bgp_main.c | 2 ++ eigrpd/eigrp_main.c | 1 + isisd/isis_main.c | 2 ++ ospf6d/ospf6_main.c | 1 + ospfd/ospf_main.c | 2 ++ ripd/rip_main.c | 2 ++ ripngd/ripng_main.c | 2 ++ zebra/main.c | 1 + 8 files changed, 13 insertions(+) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index fab2a584c0..0b33f7e9d9 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -360,6 +360,8 @@ static void bgp_vrf_terminate(void) } static const struct frr_yang_module_info *const bgpd_yang_modules[] = { + &frr_interface_info, + &frr_route_map_info, }; FRR_DAEMON_INFO(bgpd, BGP, .vty_port = BGP_VTY_PORT, diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c index 0746b04edb..922c0fe3e7 100644 --- a/eigrpd/eigrp_main.c +++ b/eigrpd/eigrp_main.c @@ -140,6 +140,7 @@ struct quagga_signal_t eigrp_signals[] = { static const struct frr_yang_module_info *const eigrpd_yang_modules[] = { &frr_eigrpd_info, &frr_interface_info, + &frr_route_map_info, }; FRR_DAEMON_INFO(eigrpd, EIGRP, .vty_port = EIGRP_VTY_PORT, diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 364441f79d..f7fe089b99 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -39,6 +39,7 @@ #include "vrf.h" #include "qobj.h" #include "libfrr.h" +#include "routemap.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" @@ -166,6 +167,7 @@ static const struct frr_yang_module_info *const isisd_yang_modules[] = { #ifndef FABRICD &frr_isisd_info, #endif /* ifndef FABRICD */ + &frr_route_map_info, }; #ifdef FABRICD diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 0aaefeb3c2..e4bed7a79d 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -167,6 +167,7 @@ struct quagga_signal_t ospf6_signals[] = { static const struct frr_yang_module_info *const ospf6d_yang_modules[] = { &frr_interface_info, + &frr_route_map_info, }; FRR_DAEMON_INFO(ospf6d, OSPF6, .vty_port = OSPF6_VTY_PORT, diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index d02ffe0448..7caa79d207 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -40,6 +40,7 @@ #include "zclient.h" #include "vrf.h" #include "libfrr.h" +#include "routemap.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -126,6 +127,7 @@ struct quagga_signal_t ospf_signals[] = { static const struct frr_yang_module_info *const ospfd_yang_modules[] = { &frr_interface_info, + &frr_route_map_info, }; FRR_DAEMON_INFO(ospfd, OSPF, .vty_port = OSPF_VTY_PORT, diff --git a/ripd/rip_main.c b/ripd/rip_main.c index 060bb76585..ca41afaea6 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -35,6 +35,7 @@ #include "vrf.h" #include "if_rmap.h" #include "libfrr.h" +#include "routemap.h" #include "ripd/ripd.h" #include "ripd/rip_nb.h" @@ -115,6 +116,7 @@ static struct quagga_signal_t ripd_signals[] = { static const struct frr_yang_module_info *const ripd_yang_modules[] = { &frr_interface_info, &frr_ripd_info, + &frr_route_map_info, }; FRR_DAEMON_INFO(ripd, RIP, .vty_port = RIP_VTY_PORT, diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index 9daeeb9580..99adb2cba7 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -36,6 +36,7 @@ #include "vrf.h" #include "if_rmap.h" #include "libfrr.h" +#include "routemap.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_nb.h" @@ -115,6 +116,7 @@ struct quagga_signal_t ripng_signals[] = { static const struct frr_yang_module_info *const ripngd_yang_modules[] = { &frr_interface_info, &frr_ripngd_info, + &frr_route_map_info, }; FRR_DAEMON_INFO(ripngd, RIPNG, .vty_port = RIPNG_VTY_PORT, diff --git a/zebra/main.c b/zebra/main.c index f23702d878..5951c7e280 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -237,6 +237,7 @@ struct quagga_signal_t zebra_signals[] = { static const struct frr_yang_module_info *const zebra_yang_modules[] = { &frr_interface_info, + &frr_route_map_info, }; FRR_DAEMON_INFO( From 54a35ff48b600cd59b715b6e5aea4e69de1b995f Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 14 Oct 2019 23:29:19 -0300 Subject: [PATCH 09/10] lib: fix route map northbound memory leak Keep a list of hook contexts used by northbound so we don't lose the pointer when free()ing the route map index entry data. Signed-off-by: Rafael Zalamena --- lib/routemap.c | 5 +++++ lib/routemap.h | 11 +++++++++++ lib/routemap_northbound.c | 39 ++++++++++++++++++++++++++++++--------- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/lib/routemap.c b/lib/routemap.c index 5369fa771f..912cf28202 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -909,6 +909,7 @@ static struct route_map_index *route_map_index_new(void) new = XCALLOC(MTYPE_ROUTE_MAP_INDEX, sizeof(struct route_map_index)); new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */ + TAILQ_INIT(&new->rhclist); QOBJ_REG(new, route_map_index); return new; } @@ -924,6 +925,10 @@ void route_map_index_delete(struct route_map_index *index, int notify) zlog_debug("Deleting route-map %s sequence %d", index->map->name, index->pref); + /* Free route map northbound hook contexts. */ + while (!TAILQ_EMPTY(&index->rhclist)) + routemap_hook_context_free(TAILQ_FIRST(&index->rhclist)); + /* Free route match. */ while ((rule = index->match_list.head) != NULL) route_map_rule_delete(&index->match_list, rule); diff --git a/lib/routemap.h b/lib/routemap.h index 70e150c981..05c958967c 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -162,6 +162,9 @@ struct route_map_rule_list { struct route_map_rule *tail; }; +/* Forward struct declaration: the complete can be found later this file. */ +struct routemap_hook_context; + /* Route map index structure. */ struct route_map_index { struct route_map *map; @@ -194,6 +197,9 @@ struct route_map_index { uint64_t applied; uint64_t applied_clear; + /* List of match/sets contexts. */ + TAILQ_HEAD(, routemap_hook_context) rhclist; + QOBJ_FIELDS }; DECLARE_QOBJ_TYPE(route_map_index) @@ -660,6 +666,7 @@ struct routemap_hook_context { route_map_event_t rhc_event; routemap_set_hook_fun rhc_shook; routemap_match_hook_fun rhc_mhook; + TAILQ_ENTRY(routemap_hook_context) rhc_entry; }; int lib_route_map_entry_match_destroy(enum nb_event event, @@ -667,6 +674,10 @@ int lib_route_map_entry_match_destroy(enum nb_event event, int lib_route_map_entry_set_destroy(enum nb_event event, const struct lyd_node *dnode); +struct routemap_hook_context * +routemap_hook_context_insert(struct route_map_index *rmi); +void routemap_hook_context_free(struct routemap_hook_context *rhc); + extern const struct frr_yang_module_info frr_route_map_info; /* routemap_cli.c */ diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c index b9ac01e865..3173a708e4 100644 --- a/lib/routemap_northbound.c +++ b/lib/routemap_northbound.c @@ -74,6 +74,30 @@ int lib_route_map_entry_set_destroy(enum nb_event event, return NB_OK; } +/* + * Auxiliary hook context list manipulation functions. + */ +struct routemap_hook_context * +routemap_hook_context_insert(struct route_map_index *rmi) +{ + struct routemap_hook_context *rhc; + + rhc = XCALLOC(MTYPE_TMP, sizeof(*rhc)); + rhc->rhc_rmi = rmi; + TAILQ_INSERT_TAIL(&rmi->rhclist, rhc, rhc_entry); + + return rhc; +} + +void +routemap_hook_context_free(struct routemap_hook_context *rhc) +{ + struct route_map_index *rmi = rhc->rhc_rmi; + + TAILQ_REMOVE(&rmi->rhclist, rhc, rhc_entry); + XFREE(MTYPE_TMP, rhc); +} + /* * XPath: /frr-route-map:lib/route-map */ @@ -436,20 +460,17 @@ lib_route_map_entry_match_condition_create(enum nb_event event, union nb_resource *resource) { struct routemap_hook_context *rhc; + struct route_map_index *rmi; switch (event) { case NB_EV_VALIDATE: - /* NOTHING */ - break; case NB_EV_PREPARE: - resource->ptr = XCALLOC(MTYPE_TMP, sizeof(*rhc)); - break; case NB_EV_ABORT: - XFREE(MTYPE_TMP, resource->ptr); + /* NOTHING */ break; case NB_EV_APPLY: - rhc = resource->ptr; - rhc->rhc_rmi = nb_running_get_entry(dnode, NULL, true); + rmi = nb_running_get_entry(dnode, NULL, true); + rhc = routemap_hook_context_insert(rmi); nb_running_set_entry(dnode, rhc); break; } @@ -469,7 +490,7 @@ lib_route_map_entry_match_condition_destroy(enum nb_event event, rv = lib_route_map_entry_match_destroy(event, dnode); rhc = nb_running_unset_entry(dnode); - XFREE(MTYPE_TMP, rhc); + routemap_hook_context_free(rhc); return rv; } @@ -893,7 +914,7 @@ static int lib_route_map_entry_set_action_destroy(enum nb_event event, rv = lib_route_map_entry_set_destroy(event, dnode); rhc = nb_running_unset_entry(dnode); - XFREE(MTYPE_TMP, rhc); + routemap_hook_context_free(rhc); return rv; } From 79661106763d4f6d9c200a4f4d25439f1cfecf3a Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Wed, 5 Feb 2020 11:09:31 -0300 Subject: [PATCH 10/10] lib: fix route-map YANG module on old gcc versions Copy the fix made in 'lib/if.c' to 'lib/routemap_northbound.c' so we can have a working YANG model when compiled with GCC version less than 5. Signed-off-by: Rafael Zalamena --- lib/routemap_northbound.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c index 3173a708e4..78f2a5a018 100644 --- a/lib/routemap_northbound.c +++ b/lib/routemap_northbound.c @@ -1224,7 +1224,32 @@ lib_route_map_entry_set_action_tag_destroy(enum nb_event event, } /* clang-format off */ +#if defined(__GNUC__) && ((__GNUC__ - 0) < 5) && !defined(__clang__) +/* + * gcc versions before 5.x miscalculate the size for structs with variable + * length arrays (they just count it as size 0) + */ +struct frr_yang_module_info_sizen { + /* YANG module name. */ + const char *name; + + /* Northbound callbacks. */ + const struct { + /* Data path of this YANG node. */ + const char *xpath; + + /* Callbacks implemented for this node. */ + struct nb_callbacks cbs; + + /* Priority - lower priorities are processed first. */ + uint32_t priority; + } nodes[28]; +}; + +const struct frr_yang_module_info_sizen frr_route_map_info_sizen asm("frr_route_map_info") = { +#else const struct frr_yang_module_info frr_route_map_info = { +#endif .name = "frr-route-map", .nodes = { {