From 0c0e73045b1898610eef9309b9f5927254356710 Mon Sep 17 00:00:00 2001
|
|
From: Rafael Zalamena <rzalamena@opensourcerouting.org>
|
|
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 <rzalamena@opensourcerouting.org>
|
|
---
|
|
From a7282663eff6f036a427165b7fa73c75dccd47ff Mon Sep 17 00:00:00 2001
|
|
From: Rafael Zalamena <rzalamena@opensourcerouting.org>
|
|
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 <rzalamena@opensourcerouting.org>
|
|
---
|
|
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 <rzalamena@opensourcerouting.org>
|
|
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 <rzalamena@opensourcerouting.org>
|
|
---
|
|
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 <zebra.h>
|
|
+
|
|
+#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 <rzalamena@opensourcerouting.org>
|
|
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 <rzalamena@opensourcerouting.org>
|
|
---
|
|
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 <blackhole>",
|
|
- 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 [<blackhole>]",
|
|
- 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 <blackhole>",
|
|
- 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 [<blackhole>]",
|
|
- 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 <deny|permit> (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 <deny|permit> (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 <zebra.h>
|
|
+
|
|
+#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 <deny|permit>$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 <deny|permit>$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 <blackhole>$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 [<blackhole>]",
|
|
+ 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 <blackhole>$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 [<blackhole>]",
|
|
+ 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 <rzalamena@opensourcerouting.org>
|
|
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 <rzalamena@opensourcerouting.org>
|
|
---
|
|
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 <rzalamena@opensourcerouting.org>
|
|
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 <rzalamena@opensourcerouting.org>
|
|
---
|
|
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 <rzalamena@opensourcerouting.org>
|
|
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 <rzalamena@opensourcerouting.org>
|
|
---
|
|
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 <rzalamena@opensourcerouting.org>
|
|
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 <rzalamena@opensourcerouting.org>
|
|
---
|
|
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 <rzalamena@opensourcerouting.org>
|
|
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 <rzalamena@opensourcerouting.org>
|
|
---
|
|
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 <rzalamena@opensourcerouting.org>
|
|
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 <rzalamena@opensourcerouting.org>
|
|
---
|
|
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 = {
|
|
{
|