From 8c0d17cf5d62deaea6965fd04032d8e04da011d0 Mon Sep 17 00:00:00 2001 From: Lucian Cristian Date: Fri, 24 Jul 2020 18:50:07 +0300 Subject: [PATCH] frr: update to 7.4 and latest backports changelogs: https://github.com/FRRouting/frr/releases/tag/frr-7.4 Signed-off-by: Lucian Cristian --- net/frr/Makefile | 11 +- ...pd_Actually_find_the_sequence_number.patch | 69 + net/frr/patches/001-bgpd_Some_backports.patch | 83 + net/frr/patches/001-vti_interface_fix.patch | 26 - ...ix_route_map_description_memory_leak.patch | 29 + ...nd_to_show_only_established_sessions.patch | 288 + ...Add_BFD_peer_awareness_to_frr-reload.patch | 57 + net/frr/patches/005-vtysh_fixes.patch | 120 + ...6-bgpd_how_the_real_next_hop_address.patch | 835 +++ .../007-bgpd_Fix_the_bug_BGP_MRAI.patch | 30 + net/frr/patches/010-add_yahng_filter.patch | 385 -- net/frr/patches/010-add_yang_routemap.patch | 390 -- .../patches/011-mod_yang_routemap_model.patch | 5045 ----------------- net/frr/patches/012-add_yang_filter.patch | 83 - net/frr/patches/013-backport_northbound.patch | 147 - net/frr/patches/014-backport_northbound.patch | 330 -- net/frr/patches/098-fix_mips_libyang.patch | 14 - 17 files changed, 1518 insertions(+), 6424 deletions(-) create mode 100644 net/frr/patches/000-bgpd_Actually_find_the_sequence_number.patch create mode 100644 net/frr/patches/001-bgpd_Some_backports.patch delete mode 100644 net/frr/patches/001-vti_interface_fix.patch create mode 100644 net/frr/patches/002-lib_fix_route_map_description_memory_leak.patch create mode 100644 net/frr/patches/003-bgpd_Add_command_to_show_only_established_sessions.patch create mode 100644 net/frr/patches/004-Add_BFD_peer_awareness_to_frr-reload.patch create mode 100644 net/frr/patches/005-vtysh_fixes.patch create mode 100644 net/frr/patches/006-bgpd_how_the_real_next_hop_address.patch create mode 100644 net/frr/patches/007-bgpd_Fix_the_bug_BGP_MRAI.patch delete mode 100644 net/frr/patches/010-add_yahng_filter.patch delete mode 100644 net/frr/patches/010-add_yang_routemap.patch delete mode 100644 net/frr/patches/011-mod_yang_routemap_model.patch delete mode 100644 net/frr/patches/012-add_yang_filter.patch delete mode 100644 net/frr/patches/013-backport_northbound.patch delete mode 100644 net/frr/patches/014-backport_northbound.patch delete mode 100644 net/frr/patches/098-fix_mips_libyang.patch diff --git a/net/frr/Makefile b/net/frr/Makefile index eff07ee3c6..c85a3200c6 100644 --- a/net/frr/Makefile +++ b/net/frr/Makefile @@ -7,14 +7,17 @@ include $(TOPDIR)/rules.mk PKG_NAME:=frr -PKG_VERSION:=7.3.1 +PKG_VERSION:=7.4 PKG_RELEASE:=1 -PKG_SOURCE_URL:=https://github.com/FRRouting/frr/releases/download/$(PKG_NAME)-$(PKG_VERSION)/ -PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz -PKG_HASH:=85571b63d2774329b7e97871e4761f852066a17e99a8daae9972c6bd7a533e05 +PKG_SOURCE_URL:=https://github.com/FRRouting/frr/archive/ +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_HASH:=3c8204fda1c9b178d8446562579bbbc49d134b98f3ad02aa56f68724a2f9e40a PKG_MAINTAINER:=Lucian Cristian +HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_NAME)-$(PKG_NAME)-$(PKG_VERSION) +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_NAME)-$(PKG_VERSION) + PKG_LICENSE:=GPL-2.0-only LGPL-2.1-only PKG_DAEMON_AVAILABLE:= \ diff --git a/net/frr/patches/000-bgpd_Actually_find_the_sequence_number.patch b/net/frr/patches/000-bgpd_Actually_find_the_sequence_number.patch new file mode 100644 index 0000000000..ac3a7b4f61 --- /dev/null +++ b/net/frr/patches/000-bgpd_Actually_find_the_sequence_number.patch @@ -0,0 +1,69 @@ +From 34f6d0c67a48e2117c061f6ccdcf1f512982fe8f Mon Sep 17 00:00:00 2001 +From: Donald Sharp +Date: Tue, 2 Jun 2020 16:10:48 -0400 +Subject: [PATCH] bgpd: Actually find the sequence number for `bgp + extcommunity-list...` + +The code in the bgp extcommunity-list function was using +argv_find to get the correct idx. The problem was that +we had already done argv_finds before and idx was non-zero +thus having us always set the seq pointer to what was last +looked up. This causes us to pass in a value to the +underlying function and it would just wisely ignore it +causing a seq number of 0. + +We would then write this seq number of 0 and then immediately +reject it on read in again. BOO! + +Actually handle argv_find the way it was meant to be. + +Ticket:CM-29926 +Signed-off-by: Donald Sharp +--- + bgpd/bgp_vty.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c +index 3669205ee3..9c8f1e1def 100644 +--- a/bgpd/bgp_vty.c ++++ b/bgpd/bgp_vty.c +@@ -17617,8 +17617,7 @@ DEFUN (extcommunity_list_standard, + argv_find(argv, argc, "WORD", &idx); + cl_number_or_name = argv[idx]->arg; + +- argv_find(argv, argc, "(1-4294967295)", &idx); +- if (idx) ++ if (argv_find(argv, argc, "(1-4294967295)", &idx)) + seq = argv[idx]->arg; + + direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT +@@ -17663,8 +17662,7 @@ DEFUN (extcommunity_list_name_expanded, + argv_find(argv, argc, "WORD", &idx); + cl_number_or_name = argv[idx]->arg; + +- argv_find(argv, argc, "(1-4294967295)", &idx); +- if (idx) ++ if (argv_find(argv, argc, "(1-4294967295)", &idx)) + seq = argv[idx]->arg; + + direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT +@@ -17707,8 +17705,7 @@ DEFUN (no_extcommunity_list_standard_all, + char *seq = NULL; + int idx = 0; + +- argv_find(argv, argc, "(1-4294967295)", &idx); +- if (idx) ++ if (argv_find(argv, argc, "(1-4294967295)", &idx)) + seq = argv[idx]->arg; + + idx = 0; +@@ -17772,8 +17769,7 @@ DEFUN (no_extcommunity_list_expanded_all, + char *seq = NULL; + int idx = 0; + +- argv_find(argv, argc, "(1-4294967295)", &idx); +- if (idx) ++ if (argv_find(argv, argc, "(1-4294967295)", &idx)) + seq = argv[idx]->arg; + + idx = 0; diff --git a/net/frr/patches/001-bgpd_Some_backports.patch b/net/frr/patches/001-bgpd_Some_backports.patch new file mode 100644 index 0000000000..b67593a735 --- /dev/null +++ b/net/frr/patches/001-bgpd_Some_backports.patch @@ -0,0 +1,83 @@ +From acf6f22d150b0050afbdaf5887b8e25d1614db4c Mon Sep 17 00:00:00 2001 +From: Donatas Abraitis +Date: Thu, 2 Jul 2020 11:08:29 +0300 +Subject: [PATCH 1/2] bgpd: Return bool type for ecommunity_add_val and + subgroup_announce_check + +Signed-off-by: Donatas Abraitis +--- + bgpd/bgp_ecommunity.c | 6 +++--- + bgpd/bgp_route.c | 2 +- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c +index d13da74b04..7d5cac4d62 100644 +--- a/bgpd/bgp_ecommunity.c ++++ b/bgpd/bgp_ecommunity.c +@@ -107,14 +107,14 @@ bool ecommunity_add_val(struct ecommunity *ecom, struct ecommunity_val *eval, + p[1] == eval->val[1]) { + if (overwrite) { + memcpy(p, eval->val, ECOMMUNITY_SIZE); +- return 1; ++ return true; + } +- return 0; ++ return false; + } + } + int ret = memcmp(p, eval->val, ECOMMUNITY_SIZE); + if (ret == 0) +- return 0; ++ return false; + if (ret > 0) { + if (!unique) + break; +diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c +index 6ae7a59a14..7bfefde482 100644 +--- a/bgpd/bgp_route.c ++++ b/bgpd/bgp_route.c +@@ -1941,7 +1941,7 @@ bool subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, + + /* Codification of AS 0 Processing */ + if (aspath_check_as_zero(attr->aspath)) +- return 0; ++ return false; + + if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN)) { + if (peer->sort == BGP_PEER_IBGP + +From d5a157b7c377081d23b136b5ba4849abdcbecd97 Mon Sep 17 00:00:00 2001 +From: Donatas Abraitis +Date: Thu, 2 Jul 2020 11:39:40 +0300 +Subject: [PATCH 2/2] bgpd: Actually find the sequence number for + large-community-list + +Signed-off-by: Donatas Abraitis +--- + bgpd/bgp_vty.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c +index 9c8f1e1def..67ff31df8f 100644 +--- a/bgpd/bgp_vty.c ++++ b/bgpd/bgp_vty.c +@@ -17235,8 +17235,7 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc, + char *cl_name; + char *seq = NULL; + +- argv_find(argv, argc, "(1-4294967295)", &idx); +- if (idx) ++ if (argv_find(argv, argc, "(1-4294967295)", &idx)) + seq = argv[idx]->arg; + + idx = 0; +@@ -17285,8 +17284,7 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc, + int idx = 0; + char *seq = NULL; + +- argv_find(argv, argc, "(1-4294967295)", &idx); +- if (idx) ++ if (argv_find(argv, argc, "(1-4294967295)", &idx)) + seq = argv[idx]->arg; + + idx = 0; diff --git a/net/frr/patches/001-vti_interface_fix.patch b/net/frr/patches/001-vti_interface_fix.patch deleted file mode 100644 index 5f9573e3f8..0000000000 --- a/net/frr/patches/001-vti_interface_fix.patch +++ /dev/null @@ -1,26 +0,0 @@ ---- a/zebra/zebra_nhg.c 2019-10-18 01:59:17.582282539 +0300 -+++ b/zebra/zebra_nhg.c 2019-10-18 02:00:17.501997253 +0300 -@@ -1456,20 +1456,9 @@ - while (rn) { - route_unlock_node(rn); - -- /* Lookup should halt if we've matched against ourselves ('top', -- * if specified) - i.e., we cannot have a nexthop NH1 is -- * resolved by a route NH1. The exception is if the route is a -- * host route. -- */ -- if (top && rn == top) -- if (((afi == AFI_IP) && (rn->p.prefixlen != 32)) -- || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) { -- if (IS_ZEBRA_DEBUG_RIB_DETAILED) -- zlog_debug( -- "\t%s: Matched against ourself and prefix length is not max bit length", -- __PRETTY_FUNCTION__); -- return 0; -- } -+ /* If lookup self prefix return immediately. */ -+ if (rn == top) -+ return 0; - - /* Pick up selected route. */ - /* However, do not resolve over default route unless explicitly diff --git a/net/frr/patches/002-lib_fix_route_map_description_memory_leak.patch b/net/frr/patches/002-lib_fix_route_map_description_memory_leak.patch new file mode 100644 index 0000000000..abdfe34490 --- /dev/null +++ b/net/frr/patches/002-lib_fix_route_map_description_memory_leak.patch @@ -0,0 +1,29 @@ +From cc45875e0d2af0b53100ec78364dc51b39a12ac9 Mon Sep 17 00:00:00 2001 +From: Rafael Zalamena +Date: Mon, 6 Jul 2020 11:39:27 -0300 +Subject: [PATCH] lib: fix route map description memory leak + +Route map entries are not getting a chance to call `description` string +deallocation on shutdown or when the parent entry is destroyed, so lets +add a code to handle this in the `route_map_index_delete` function. + +Signed-off-by: Rafael Zalamena +(cherry picked from commit f0951335830203426074ddca4317f84b477e4afb) +--- + lib/routemap.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/lib/routemap.c b/lib/routemap.c +index 3d69a3495a..3b45133450 100644 +--- a/lib/routemap.c ++++ b/lib/routemap.c +@@ -971,6 +971,9 @@ 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 entry description. */ ++ XFREE(MTYPE_TMP, index->description); ++ + /* Free route map northbound hook contexts. */ + while ((rhc = TAILQ_FIRST(&index->rhclist)) != NULL) + routemap_hook_context_free(rhc); diff --git a/net/frr/patches/003-bgpd_Add_command_to_show_only_established_sessions.patch b/net/frr/patches/003-bgpd_Add_command_to_show_only_established_sessions.patch new file mode 100644 index 0000000000..c2b121421a --- /dev/null +++ b/net/frr/patches/003-bgpd_Add_command_to_show_only_established_sessions.patch @@ -0,0 +1,288 @@ +From 2939f712d152f7e3ae438cc0f1d96dd9485e7487 Mon Sep 17 00:00:00 2001 +From: Donatas Abraitis +Date: Thu, 9 Jul 2020 16:00:27 +0300 +Subject: [PATCH 1/2] bgpd: Add command to show only established sessions + +``` +exit1-debian-9# show bgp summary + +IPv4 Unicast Summary: +BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0 +BGP table version 8 +RIB entries 15, using 2880 bytes of memory +Peers 2, using 43 KiB of memory + +Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt +192.168.0.2 4 200 10 6 0 0 0 00:00:35 8 8 +2a02:4780::2 4 0 0 1 0 0 0 never Active 0 + +Total number of neighbors 2 +exit1-debian-9# show bgp summary established + +IPv4 Unicast Summary: +BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0 +BGP table version 8 +RIB entries 15, using 2880 bytes of memory +Peers 2, using 43 KiB of memory + +Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt +192.168.0.2 4 200 10 6 0 0 0 00:00:39 8 8 + +Total number of neighbors 2 +exit1-debian-9# show bgp summary failed + +IPv4 Unicast Summary: +BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0 +BGP table version 8 +RIB entries 15, using 2880 bytes of memory +Peers 2, using 43 KiB of memory + +Neighbor EstdCnt DropCnt ResetTime Reason +2a02:4780::2 0 0 never Waiting for peer OPEN + +Total number of neighbors 2 +exit1-debian-9# +``` + +Signed-off-by: Donatas Abraitis +--- + bgpd/bgp_evpn_vty.c | 11 ++++++++--- + bgpd/bgp_vty.c | 43 +++++++++++++++++++++++++++++++------------ + bgpd/bgp_vty.h | 3 ++- + 3 files changed, 41 insertions(+), 16 deletions(-) + +diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c +index 85604d856d..42987117d4 100644 +--- a/bgpd/bgp_evpn_vty.c ++++ b/bgpd/bgp_evpn_vty.c +@@ -4077,7 +4077,7 @@ DEFUN(show_bgp_l2vpn_evpn_es, + */ + DEFUN(show_bgp_l2vpn_evpn_summary, + show_bgp_l2vpn_evpn_summary_cmd, +- "show bgp [vrf VRFNAME] l2vpn evpn summary [failed] [json]", ++ "show bgp [vrf VRFNAME] l2vpn evpn summary [established|failed] [json]", + SHOW_STR + BGP_STR + "bgp vrf\n" +@@ -4085,6 +4085,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, + L2VPN_HELP_STR + EVPN_HELP_STR + "Summary of BGP neighbor status\n" ++ "Show only sessions in Established state\n" + "Show only sessions not in Established state\n" + JSON_STR) + { +@@ -4092,13 +4093,17 @@ DEFUN(show_bgp_l2vpn_evpn_summary, + bool uj = use_json(argc, argv); + char *vrf = NULL; + bool show_failed = false; ++ bool show_established = false; + + if (argv_find(argv, argc, "vrf", &idx_vrf)) + vrf = argv[++idx_vrf]->arg; + if (argv_find(argv, argc, "failed", &idx_vrf)) + show_failed = true; +- return bgp_show_summary_vty(vty, vrf, AFI_L2VPN, SAFI_EVPN, +- show_failed, uj); ++ if (argv_find(argv, argc, "established", &idx_vrf)) ++ show_established = true; ++ ++ return bgp_show_summary_vty(vty, vrf, AFI_L2VPN, SAFI_EVPN, show_failed, ++ show_established, uj); + } + + /* +diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c +index 67ff31df8f..78521457fd 100644 +--- a/bgpd/bgp_vty.c ++++ b/bgpd/bgp_vty.c +@@ -8772,7 +8772,8 @@ static void bgp_show_failed_summary(struct vty *vty, struct bgp *bgp, + + /* Show BGP peer's summary information. */ + static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, +- bool show_failed, bool use_json) ++ bool show_failed, bool show_established, ++ bool use_json) + { + struct peer *peer; + struct listnode *node, *nnode; +@@ -9104,6 +9105,10 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, + bgp_show_failed_summary(vty, bgp, peer, + json_peer, 0, use_json); + } else if (!show_failed) { ++ if (show_established ++ && bgp_has_peer_failed(peer, afi, safi)) ++ continue; ++ + json_peer = json_object_new_object(); + if (peer_dynamic_neighbor(peer)) { + json_object_boolean_true_add(json_peer, +@@ -9193,6 +9198,10 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, + max_neighbor_width, + use_json); + } else if (!show_failed) { ++ if (show_established ++ && bgp_has_peer_failed(peer, afi, safi)) ++ continue; ++ + memset(dn_flag, '\0', sizeof(dn_flag)); + if (peer_dynamic_neighbor(peer)) { + dn_flag[0] = '*'; +@@ -9315,7 +9324,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, + } + + static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, +- int safi, bool show_failed, bool use_json) ++ int safi, bool show_failed, ++ bool show_established, bool use_json) + { + int is_first = 1; + int afi_wildcard = (afi == AFI_MAX); +@@ -9358,7 +9368,8 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, + false)); + } + } +- bgp_show_summary(vty, bgp, afi, safi, show_failed, ++ bgp_show_summary(vty, bgp, afi, safi, ++ show_failed, show_established, + use_json); + } + safi++; +@@ -9382,6 +9393,7 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, + + static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, + safi_t safi, bool show_failed, ++ bool show_established, + bool use_json) + { + struct listnode *node, *nnode; +@@ -9411,7 +9423,7 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, + : bgp->name); + } + bgp_show_summary_afi_safi(vty, bgp, afi, safi, show_failed, +- use_json); ++ show_established, use_json); + } + + if (use_json) +@@ -9421,15 +9433,16 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, + } + + int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, +- safi_t safi, bool show_failed, bool use_json) ++ safi_t safi, bool show_failed, bool show_established, ++ bool use_json) + { + struct bgp *bgp; + + if (name) { + if (strmatch(name, "all")) { +- bgp_show_all_instances_summary_vty(vty, afi, safi, +- show_failed, +- use_json); ++ bgp_show_all_instances_summary_vty( ++ vty, afi, safi, show_failed, show_established, ++ use_json); + return CMD_SUCCESS; + } else { + bgp = bgp_lookup_by_name(name); +@@ -9444,7 +9457,8 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, + } + + bgp_show_summary_afi_safi(vty, bgp, afi, safi, +- show_failed, use_json); ++ show_failed, show_established, ++ use_json); + return CMD_SUCCESS; + } + } +@@ -9453,7 +9467,7 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, + + if (bgp) + bgp_show_summary_afi_safi(vty, bgp, afi, safi, show_failed, +- use_json); ++ show_established, use_json); + else { + if (use_json) + vty_out(vty, "{}\n"); +@@ -9468,7 +9482,7 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, + /* `show [ip] bgp summary' commands. */ + DEFUN (show_ip_bgp_summary, + show_ip_bgp_summary_cmd, +- "show [ip] bgp [ VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] summary [failed] [json]", ++ "show [ip] bgp [ VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] summary [established|failed] [json]", + SHOW_STR + IP_STR + BGP_STR +@@ -9476,6 +9490,7 @@ DEFUN (show_ip_bgp_summary, + BGP_AFI_HELP_STR + BGP_SAFI_WITH_LABEL_HELP_STR + "Summary of BGP neighbor status\n" ++ "Show only sessions in Established state\n" + "Show only sessions not in Established state\n" + JSON_STR) + { +@@ -9483,6 +9498,7 @@ DEFUN (show_ip_bgp_summary, + afi_t afi = AFI_MAX; + safi_t safi = SAFI_MAX; + bool show_failed = false; ++ bool show_established = false; + + int idx = 0; + +@@ -9504,10 +9520,13 @@ DEFUN (show_ip_bgp_summary, + + if (argv_find(argv, argc, "failed", &idx)) + show_failed = true; ++ if (argv_find(argv, argc, "established", &idx)) ++ show_established = true; + + bool uj = use_json(argc, argv); + +- return bgp_show_summary_vty(vty, vrf, afi, safi, show_failed, uj); ++ return bgp_show_summary_vty(vty, vrf, afi, safi, show_failed, ++ show_established, uj); + } + + const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json) +diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h +index d6ca198d09..95eefbc36f 100644 +--- a/bgpd/bgp_vty.h ++++ b/bgpd/bgp_vty.h +@@ -178,6 +178,7 @@ extern int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty, + int bgp_vty_find_and_parse_bgp(struct vty *vty, struct cmd_token **argv, + int argc, struct bgp **bgp, bool use_json); + extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, +- safi_t safi, bool show_failed, bool use_json); ++ safi_t safi, bool show_failed, ++ bool show_established, bool use_json); + + #endif /* _QUAGGA_BGP_VTY_H */ + +From 2600443342d8e21d30df2b6ca095a5f2d0d4de2d Mon Sep 17 00:00:00 2001 +From: Donatas Abraitis +Date: Thu, 9 Jul 2020 16:05:08 +0300 +Subject: [PATCH 2/2] doc: Add 'show bgp summary established' command + +Signed-off-by: Donatas Abraitis +--- + doc/user/bgp.rst | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst +index cb343e8dad..36227db604 100644 +--- a/doc/user/bgp.rst ++++ b/doc/user/bgp.rst +@@ -2710,6 +2710,12 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`. + Show a bgp peer summary for peers that are not succesfully exchanging routes + for the specified address family, and subsequent address-family. + ++.. index:: show bgp [afi] [safi] summary established [json] ++.. clicmd:: show bgp [afi] [safi] summary established [json] ++ ++ Show a bgp peer summary for peers that are succesfully exchanging routes ++ for the specified address family, and subsequent address-family. ++ + .. index:: show bgp [afi] [safi] neighbor [PEER] + .. clicmd:: show bgp [afi] [safi] neighbor [PEER] + diff --git a/net/frr/patches/004-Add_BFD_peer_awareness_to_frr-reload.patch b/net/frr/patches/004-Add_BFD_peer_awareness_to_frr-reload.patch new file mode 100644 index 0000000000..a8a612bcfc --- /dev/null +++ b/net/frr/patches/004-Add_BFD_peer_awareness_to_frr-reload.patch @@ -0,0 +1,57 @@ +From 692ce87393de9497a7821e9e0856ff70a7973ff6 Mon Sep 17 00:00:00 2001 +From: Paul Manley +Date: Thu, 9 Jul 2020 11:21:16 -0500 +Subject: [PATCH 1/2] tools: create sub-context for bfd peers + +add lines starting with 'peer' to the list of sub-contexts that are handled by frr-reload.py. + +https://github.com/FRRouting/frr/issues/6511#issuecomment-655163833 + +Signed-off-by: Paul Manley +(cherry picked from commit 1c23a0aaa1c5d20af50af75b070e93e1eff21222) +--- + tools/frr-reload.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tools/frr-reload.py b/tools/frr-reload.py +index d4020cdfc9..e9641b2b13 100755 +--- a/tools/frr-reload.py ++++ b/tools/frr-reload.py +@@ -496,6 +496,7 @@ def load_contexts(self): + line.startswith("vnc defaults") or + line.startswith("vnc l2-group") or + line.startswith("vnc nve-group") or ++ line.startswith("peer") or + line.startswith("member pseudowire")): + main_ctx_key = [] + + +From 2604086c3d9face0aca2497a982782c865bb2b59 Mon Sep 17 00:00:00 2001 +From: Paul Manley +Date: Thu, 9 Jul 2020 11:25:34 -0500 +Subject: [PATCH 2/2] vtysh: properly exit BFD_PEER_NODE when marking file + +vtysh needs to be aware of how to properly exit a bfd peer when subsequent commands only succeed in a higher context. + +https://github.com/FRRouting/frr/issues/6511#issuecomment-656166206 + +Signed-off-by: Paul Manley +(cherry picked from commit b727c12aabf1afc2b6e33f8590c9786e349e4fcb) +--- + vtysh/vtysh.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c +index 15ec866fc9..4fdf68c0e6 100644 +--- a/vtysh/vtysh.c ++++ b/vtysh/vtysh.c +@@ -809,6 +809,9 @@ int vtysh_mark_file(const char *filename) + } else if ((prev_node == KEYCHAIN_KEY_NODE) + && (tried == 1)) { + vty_out(vty, "exit\n"); ++ } else if ((prev_node == BFD_PEER_NODE) ++ && (tried == 1)) { ++ vty_out(vty, "exit\n"); + } else if (tried) { + vty_out(vty, "end\n"); + } diff --git a/net/frr/patches/005-vtysh_fixes.patch b/net/frr/patches/005-vtysh_fixes.patch new file mode 100644 index 0000000000..83983a0999 --- /dev/null +++ b/net/frr/patches/005-vtysh_fixes.patch @@ -0,0 +1,120 @@ +From cc5934ed5939315ba5d95bfaf052625762107205 Mon Sep 17 00:00:00 2001 +From: Donald Sharp +Date: Tue, 30 Jun 2020 08:59:46 -0400 +Subject: [PATCH 1/2] vtysh: master is a non-sorted list + +The commit: +a798241265a5808083a06b14ce1637d1ddf6a45a + +attempted to use sorted master lists to do faster lookups +by using a RB Tree. Unfortunately the original code +was creating a list->cmp function *but* never using it. +If you look at the commit, it clearly shows that the +function listnode_add is used to insert but when you +look at that function it is a tail push. + +Fixes: #6573 + +Namely now this ordering is preserved: +bgp as-path access-list originate-only permit ^$ +bgp as-path access-list originate-only deny .* + +Signed-off-by: Donald Sharp +--- + vtysh/vtysh_config.c | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c +index abbb111f9d..2ab9dd5a9a 100644 +--- a/vtysh/vtysh_config.c ++++ b/vtysh/vtysh_config.c +@@ -34,7 +34,7 @@ DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line") + + vector configvec; + +-PREDECL_RBTREE_UNIQ(config_master); ++PREDECL_LIST(config_master); + + struct config { + /* Configuration node name. */ +@@ -72,11 +72,6 @@ static struct config *config_new(void) + return config; + } + +-static int config_cmp(const struct config *c1, const struct config *c2) +-{ +- return strcmp(c1->name, c2->name); +-} +- + static void config_del(struct config *config) + { + list_delete(&config->line); +@@ -84,13 +79,15 @@ static void config_del(struct config *config) + XFREE(MTYPE_VTYSH_CONFIG, config); + } + +-DECLARE_RBTREE_UNIQ(config_master, struct config, rbt_item, config_cmp) ++DECLARE_LIST(config_master, struct config, rbt_item) + + static struct config *config_get(int index, const char *line) + { +- struct config *config; ++ struct config *config, *config_loop; + struct config_master_head *master; + ++ config = config_loop = NULL; ++ + master = vector_lookup_ensure(configvec, index); + + if (!master) { +@@ -99,8 +96,10 @@ static struct config *config_get(int index, const char *line) + vector_set_index(configvec, index, master); + } + +- const struct config config_ref = { .name = (char *)line }; +- config = config_master_find(master, &config_ref); ++ frr_each (config_master, master, config_loop) { ++ if (strcmp(config_loop->name, line) == 0) ++ config = config_loop; ++ } + + if (!config) { + config = config_new(); +@@ -109,7 +108,7 @@ static struct config *config_get(int index, const char *line) + config->line->cmp = (int (*)(void *, void *))line_cmp; + config->name = XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line); + config->index = index; +- config_master_add(master, config); ++ config_master_add_tail(master, config); + } + return config; + } + +From 3e4d90ec556649e11954f2f56b5282f95e7e013b Mon Sep 17 00:00:00 2001 +From: Donald Sharp +Date: Tue, 30 Jun 2020 09:03:55 -0400 +Subject: [PATCH 2/2] vtysh: Improve lookup performance + +When we find the line we are interested in, stop looking. + +Signed-off-by: Donald Sharp +--- + vtysh/vtysh_config.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c +index 2ab9dd5a9a..61bcf3b658 100644 +--- a/vtysh/vtysh_config.c ++++ b/vtysh/vtysh_config.c +@@ -97,8 +97,10 @@ static struct config *config_get(int index, const char *line) + } + + frr_each (config_master, master, config_loop) { +- if (strcmp(config_loop->name, line) == 0) ++ if (strcmp(config_loop->name, line) == 0) { + config = config_loop; ++ break; ++ } + } + + if (!config) { diff --git a/net/frr/patches/006-bgpd_how_the_real_next_hop_address.patch b/net/frr/patches/006-bgpd_how_the_real_next_hop_address.patch new file mode 100644 index 0000000000..b819d6998c --- /dev/null +++ b/net/frr/patches/006-bgpd_how_the_real_next_hop_address.patch @@ -0,0 +1,835 @@ +From c6a5994609deec62c8aefa1fa15c517e32575ca3 Mon Sep 17 00:00:00 2001 +From: Donatas Abraitis +Date: Wed, 6 May 2020 17:45:31 +0300 +Subject: [PATCH 1/4] tests: Remove bgp_show_ip_bgp_fqdn test + +Not really relevant for now. + +Signed-off-by: Donatas Abraitis +--- + .../bgp_show_ip_bgp_fqdn/__init__.py | 0 + .../bgp_show_ip_bgp_fqdn/r1/bgpd.conf | 5 - + .../bgp_show_ip_bgp_fqdn/r1/zebra.conf | 9 -- + .../bgp_show_ip_bgp_fqdn/r2/bgpd.conf | 5 - + .../bgp_show_ip_bgp_fqdn/r2/zebra.conf | 12 -- + .../bgp_show_ip_bgp_fqdn/r3/bgpd.conf | 3 - + .../bgp_show_ip_bgp_fqdn/r3/zebra.conf | 6 - + .../test_bgp_show_ip_bgp_fqdn.py | 133 ------------------ + 8 files changed, 173 deletions(-) + delete mode 100644 tests/topotests/bgp_show_ip_bgp_fqdn/__init__.py + delete mode 100644 tests/topotests/bgp_show_ip_bgp_fqdn/r1/bgpd.conf + delete mode 100644 tests/topotests/bgp_show_ip_bgp_fqdn/r1/zebra.conf + delete mode 100644 tests/topotests/bgp_show_ip_bgp_fqdn/r2/bgpd.conf + delete mode 100644 tests/topotests/bgp_show_ip_bgp_fqdn/r2/zebra.conf + delete mode 100644 tests/topotests/bgp_show_ip_bgp_fqdn/r3/bgpd.conf + delete mode 100644 tests/topotests/bgp_show_ip_bgp_fqdn/r3/zebra.conf + delete mode 100644 tests/topotests/bgp_show_ip_bgp_fqdn/test_bgp_show_ip_bgp_fqdn.py + +diff --git a/tests/topotests/bgp_show_ip_bgp_fqdn/__init__.py b/tests/topotests/bgp_show_ip_bgp_fqdn/__init__.py +deleted file mode 100644 +index e69de29bb2..0000000000 +diff --git a/tests/topotests/bgp_show_ip_bgp_fqdn/r1/bgpd.conf b/tests/topotests/bgp_show_ip_bgp_fqdn/r1/bgpd.conf +deleted file mode 100644 +index f0df56e947..0000000000 +--- a/tests/topotests/bgp_show_ip_bgp_fqdn/r1/bgpd.conf ++++ /dev/null +@@ -1,5 +0,0 @@ +-router bgp 65000 +- no bgp ebgp-requires-policy +- neighbor 192.168.255.2 remote-as 65001 +- address-family ipv4 unicast +- redistribute connected +diff --git a/tests/topotests/bgp_show_ip_bgp_fqdn/r1/zebra.conf b/tests/topotests/bgp_show_ip_bgp_fqdn/r1/zebra.conf +deleted file mode 100644 +index 0a283c06d5..0000000000 +--- a/tests/topotests/bgp_show_ip_bgp_fqdn/r1/zebra.conf ++++ /dev/null +@@ -1,9 +0,0 @@ +-! +-interface lo +- ip address 172.16.255.254/32 +-! +-interface r1-eth0 +- ip address 192.168.255.1/24 +-! +-ip forwarding +-! +diff --git a/tests/topotests/bgp_show_ip_bgp_fqdn/r2/bgpd.conf b/tests/topotests/bgp_show_ip_bgp_fqdn/r2/bgpd.conf +deleted file mode 100644 +index 422a7345f9..0000000000 +--- a/tests/topotests/bgp_show_ip_bgp_fqdn/r2/bgpd.conf ++++ /dev/null +@@ -1,5 +0,0 @@ +-router bgp 65001 +- no bgp ebgp-requires-policy +- bgp default show-hostname +- neighbor 192.168.255.1 remote-as 65000 +- neighbor 192.168.254.1 remote-as 65001 +diff --git a/tests/topotests/bgp_show_ip_bgp_fqdn/r2/zebra.conf b/tests/topotests/bgp_show_ip_bgp_fqdn/r2/zebra.conf +deleted file mode 100644 +index e9e2e4391f..0000000000 +--- a/tests/topotests/bgp_show_ip_bgp_fqdn/r2/zebra.conf ++++ /dev/null +@@ -1,12 +0,0 @@ +-! +-interface lo +- ip address 172.16.255.253/32 +-! +-interface r2-eth0 +- ip address 192.168.255.2/24 +-! +-interface r2-eth1 +- ip address 192.168.254.2/24 +-! +-ip forwarding +-! +diff --git a/tests/topotests/bgp_show_ip_bgp_fqdn/r3/bgpd.conf b/tests/topotests/bgp_show_ip_bgp_fqdn/r3/bgpd.conf +deleted file mode 100644 +index 8fcf6a736d..0000000000 +--- a/tests/topotests/bgp_show_ip_bgp_fqdn/r3/bgpd.conf ++++ /dev/null +@@ -1,3 +0,0 @@ +-router bgp 65001 +- bgp default show-hostname +- neighbor 192.168.254.2 remote-as 65001 +diff --git a/tests/topotests/bgp_show_ip_bgp_fqdn/r3/zebra.conf b/tests/topotests/bgp_show_ip_bgp_fqdn/r3/zebra.conf +deleted file mode 100644 +index a8b8bc38c5..0000000000 +--- a/tests/topotests/bgp_show_ip_bgp_fqdn/r3/zebra.conf ++++ /dev/null +@@ -1,6 +0,0 @@ +-! +-interface r3-eth0 +- ip address 192.168.254.1/24 +-! +-ip forwarding +-! +diff --git a/tests/topotests/bgp_show_ip_bgp_fqdn/test_bgp_show_ip_bgp_fqdn.py b/tests/topotests/bgp_show_ip_bgp_fqdn/test_bgp_show_ip_bgp_fqdn.py +deleted file mode 100644 +index e8ad180935..0000000000 +--- a/tests/topotests/bgp_show_ip_bgp_fqdn/test_bgp_show_ip_bgp_fqdn.py ++++ /dev/null +@@ -1,133 +0,0 @@ +-#!/usr/bin/env python +- +-# +-# test_bgp_show_ip_bgp_fqdn.py +-# Part of NetDEF Topology Tests +-# +-# Copyright (c) 2019 by +-# Donatas Abraitis +-# +-# Permission to use, copy, modify, and/or distribute this software +-# for any purpose with or without fee is hereby granted, provided +-# that the above copyright notice and this permission notice appear +-# in all copies. +-# +-# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +-# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +-# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +-# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +-# OF THIS SOFTWARE. +-# +- +-""" +-test_bgp_show_ip_bgp_fqdn.py: +-Test if FQND is visible in `show [ip] bgp` output if +-`bgp default show-hostname` is toggled. +- +-Topology: +-r1 <-- eBGP --> r2 <-- iBGP --> r3 +- +-1. Check if both hostname and ip are added to JSON output +-for 172.16.255.254/32 on r2. +-2. Check if only ip is added to JSON output for 172.16.255.254/32 on r3. +-""" +- +-import os +-import sys +-import json +-import time +-import pytest +-import functools +- +-CWD = os.path.dirname(os.path.realpath(__file__)) +-sys.path.append(os.path.join(CWD, "../")) +- +-# pylint: disable=C0413 +-from lib import topotest +-from lib.topogen import Topogen, TopoRouter, get_topogen +-from lib.topolog import logger +-from mininet.topo import Topo +- +- +-class TemplateTopo(Topo): +- def build(self, *_args, **_opts): +- tgen = get_topogen(self) +- +- for routern in range(1, 4): +- tgen.add_router("r{}".format(routern)) +- +- switch = tgen.add_switch("s1") +- switch.add_link(tgen.gears["r1"]) +- switch.add_link(tgen.gears["r2"]) +- +- switch = tgen.add_switch("s2") +- switch.add_link(tgen.gears["r2"]) +- switch.add_link(tgen.gears["r3"]) +- +- +-def setup_module(mod): +- tgen = Topogen(TemplateTopo, mod.__name__) +- tgen.start_topology() +- +- router_list = tgen.routers() +- +- for i, (rname, router) in enumerate(router_list.iteritems(), 1): +- router.load_config( +- TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) +- ) +- router.load_config( +- TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) +- ) +- +- tgen.start_router() +- +- +-def teardown_module(mod): +- tgen = get_topogen() +- tgen.stop_topology() +- +- +-def test_bgp_show_ip_bgp_hostname(): +- tgen = get_topogen() +- +- if tgen.routers_have_failure(): +- pytest.skip(tgen.errors) +- +- def _bgp_converge(router): +- output = json.loads(router.vtysh_cmd("show ip bgp 172.16.255.254/32 json")) +- expected = {"prefix": "172.16.255.254/32"} +- return topotest.json_cmp(output, expected) +- +- def _bgp_show_nexthop_hostname_and_ip(router): +- output = json.loads(router.vtysh_cmd("show ip bgp json")) +- for nh in output["routes"]["172.16.255.254/32"][0]["nexthops"]: +- if "hostname" in nh and "ip" in nh: +- return True +- return False +- +- def _bgp_show_nexthop_ip_only(router): +- output = json.loads(router.vtysh_cmd("show ip bgp json")) +- for nh in output["routes"]["172.16.255.254/32"][0]["nexthops"]: +- if "ip" in nh and not "hostname" in nh: +- return True +- return False +- +- test_func = functools.partial(_bgp_converge, tgen.gears["r2"]) +- success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) +- +- test_func = functools.partial(_bgp_converge, tgen.gears["r3"]) +- success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) +- +- assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r2"]) +- assert _bgp_show_nexthop_hostname_and_ip(tgen.gears["r2"]) == True +- +- assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r3"]) +- assert _bgp_show_nexthop_ip_only(tgen.gears["r3"]) == True +- +- +-if __name__ == "__main__": +- args = ["-s"] + sys.argv[1:] +- sys.exit(pytest.main(args)) + +From e7cc3d21452bd771a97bc46ab5a1e4853c46f944 Mon Sep 17 00:00:00 2001 +From: Donatas Abraitis +Date: Wed, 6 May 2020 17:46:10 +0300 +Subject: [PATCH 2/4] bgpd: Show the real next-hop address in addition to + hostname in `show bgp` + +It's hard to cope with cases when next-hop is changed/unchanged or +peers are non-direct. + +It would be better to show the hostname and nexthop IP address (both) +under `show bgp` to quickly identify the source and the real next-hop +of the route. + +If `bgp default show-nexthop-hostname` is toggled the output looks like: +``` +spine1-debian-9# show bgp +BGP table version is 1, local router ID is 2.2.2.2, vrf id 0 +Default local pref 100, local AS 65002 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +* 2a02:4780::/64 fe80::a00:27ff:fe09:f8a3(exit1-debian-9) + 0 0 65001 ? + +spine1-debian-9# show ip bgp +BGP table version is 5, local router ID is 2.2.2.2, vrf id 0 +Default local pref 100, local AS 65002 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +*> 10.255.255.0/24 192.168.0.1(exit1-debian-9) + 0 0 65001 ? +``` + +Signed-off-by: Donatas Abraitis +--- + bgpd/bgp_route.c | 161 ++++++++++++++++++++++++++++++----------------- + bgpd/bgp_vty.c | 45 +++++++++++++ + bgpd/bgpd.h | 1 + + 3 files changed, 149 insertions(+), 58 deletions(-) + +diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c +index 7bfefde482..f033f525e5 100644 +--- a/bgpd/bgp_route.c ++++ b/bgpd/bgp_route.c +@@ -7559,8 +7559,7 @@ static char *bgp_nexthop_hostname(struct peer *peer, + struct bgp_nexthop_cache *bnc) + { + if (peer->hostname +- && CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SHOW_HOSTNAME) && bnc +- && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) ++ && CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SHOW_NEXTHOP_HOSTNAME)) + return peer->hostname; + return NULL; + } +@@ -7570,6 +7569,7 @@ void route_vty_out(struct vty *vty, const struct prefix *p, + struct bgp_path_info *path, int display, safi_t safi, + json_object *json_paths) + { ++ int len; + struct attr *attr = path->attr; + json_object *json_path = NULL; + json_object *json_nexthops = NULL; +@@ -7681,10 +7681,19 @@ void route_vty_out(struct vty *vty, const struct prefix *p, + : "ipv6"); + json_object_boolean_true_add(json_nexthop_global, + "used"); +- } else +- vty_out(vty, "%s%s", +- nexthop_hostname ? nexthop_hostname : nexthop, +- vrf_id_str); ++ } else { ++ if (nexthop_hostname) ++ len = vty_out(vty, "%s(%s)%s", nexthop, ++ nexthop_hostname, vrf_id_str); ++ else ++ len = vty_out(vty, "%s%s", nexthop, vrf_id_str); ++ ++ len = 16 - len; ++ if (len < 1) ++ vty_out(vty, "\n%*s", 36, " "); ++ else ++ vty_out(vty, "%*s", len, " "); ++ } + } else if (safi == SAFI_EVPN) { + if (json_paths) { + json_nexthop_global = json_object_new_object(); +@@ -7701,11 +7710,20 @@ void route_vty_out(struct vty *vty, const struct prefix *p, + "ipv4"); + json_object_boolean_true_add(json_nexthop_global, + "used"); +- } else +- vty_out(vty, "%-16s%s", +- nexthop_hostname ? nexthop_hostname +- : inet_ntoa(attr->nexthop), +- vrf_id_str); ++ } else { ++ if (nexthop_hostname) ++ len = vty_out(vty, "%pI4(%s)%s", &attr->nexthop, ++ nexthop_hostname, vrf_id_str); ++ else ++ len = vty_out(vty, "%pI4%s", &attr->nexthop, ++ vrf_id_str); ++ ++ len = 16 - len; ++ if (len < 1) ++ vty_out(vty, "\n%*s", 36, " "); ++ else ++ vty_out(vty, "%*s", len, " "); ++ } + } else if (safi == SAFI_FLOWSPEC) { + if (attr->nexthop.s_addr != INADDR_ANY) { + if (json_paths) { +@@ -7726,10 +7744,21 @@ void route_vty_out(struct vty *vty, const struct prefix *p, + json_nexthop_global, + "used"); + } else { +- vty_out(vty, "%-16s", +- nexthop_hostname +- ? nexthop_hostname +- : inet_ntoa(attr->nexthop)); ++ if (nexthop_hostname) ++ len = vty_out(vty, "%pI4(%s)%s", ++ &attr->nexthop, ++ nexthop_hostname, ++ vrf_id_str); ++ else ++ len = vty_out(vty, "%pI4%s", ++ &attr->nexthop, ++ vrf_id_str); ++ ++ len = 16 - len; ++ if (len < 1) ++ vty_out(vty, "\n%*s", 36, " "); ++ else ++ vty_out(vty, "%*s", len, " "); + } + } + } else if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { +@@ -7749,19 +7778,23 @@ void route_vty_out(struct vty *vty, const struct prefix *p, + json_object_boolean_true_add(json_nexthop_global, + "used"); + } else { +- char buf[BUFSIZ]; ++ if (nexthop_hostname) ++ len = vty_out(vty, "%pI4(%s)%s", &attr->nexthop, ++ nexthop_hostname, vrf_id_str); ++ else ++ len = vty_out(vty, "%pI4%s", &attr->nexthop, ++ vrf_id_str); + +- snprintf(buf, sizeof(buf), "%s%s", +- nexthop_hostname ? nexthop_hostname +- : inet_ntoa(attr->nexthop), +- vrf_id_str); +- vty_out(vty, "%-16s", buf); ++ len = 16 - len; ++ if (len < 1) ++ vty_out(vty, "\n%*s", 36, " "); ++ else ++ vty_out(vty, "%*s", len, " "); + } + } + + /* IPv6 Next Hop */ + else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { +- int len; + char buf[BUFSIZ]; + + if (json_paths) { +@@ -7835,15 +7868,18 @@ void route_vty_out(struct vty *vty, const struct prefix *p, + else + vty_out(vty, "%*s", len, " "); + } else { +- len = vty_out( +- vty, "%s%s", +- nexthop_hostname +- ? nexthop_hostname +- : inet_ntop( +- AF_INET6, +- &attr->mp_nexthop_local, +- buf, BUFSIZ), +- vrf_id_str); ++ if (nexthop_hostname) ++ len = vty_out( ++ vty, "%pI6(%s)%s", ++ &attr->mp_nexthop_local, ++ nexthop_hostname, ++ vrf_id_str); ++ else ++ len = vty_out( ++ vty, "%pI6%s", ++ &attr->mp_nexthop_local, ++ vrf_id_str); ++ + len = 16 - len; + + if (len < 1) +@@ -7852,15 +7888,16 @@ void route_vty_out(struct vty *vty, const struct prefix *p, + vty_out(vty, "%*s", len, " "); + } + } else { +- len = vty_out( +- vty, "%s%s", +- nexthop_hostname +- ? nexthop_hostname +- : inet_ntop( +- AF_INET6, +- &attr->mp_nexthop_global, +- buf, BUFSIZ), +- vrf_id_str); ++ if (nexthop_hostname) ++ len = vty_out(vty, "%pI6(%s)%s", ++ &attr->mp_nexthop_global, ++ nexthop_hostname, ++ vrf_id_str); ++ else ++ len = vty_out(vty, "%pI6%s", ++ &attr->mp_nexthop_global, ++ vrf_id_str); ++ + len = 16 - len; + + if (len < 1) +@@ -7986,6 +8023,7 @@ void route_vty_out_tmp(struct vty *vty, const struct prefix *p, + { + json_object *json_status = NULL; + json_object *json_net = NULL; ++ int len; + char buff[BUFSIZ]; + + /* Route status display. */ +@@ -8079,7 +8117,6 @@ void route_vty_out_tmp(struct vty *vty, const struct prefix *p, + inet_ntoa(attr->nexthop)); + } else if (p->family == AF_INET6 + || BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { +- int len; + char buf[BUFSIZ]; + + len = vty_out( +@@ -8823,12 +8860,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, + json_object_string_add( + json_nexthop_global, "hostname", + nexthop_hostname); +- } else +- vty_out(vty, " %s", +- nexthop_hostname +- ? nexthop_hostname +- : inet_ntoa( +- attr->mp_nexthop_global_in)); ++ } else { ++ if (nexthop_hostname) ++ vty_out(vty, " %pI4(%s)", ++ &attr->mp_nexthop_global_in, ++ nexthop_hostname); ++ else ++ vty_out(vty, " %pI4", ++ &attr->mp_nexthop_global_in); ++ } + } else { + if (json_paths) { + json_object_string_add( +@@ -8839,11 +8879,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, + json_object_string_add( + json_nexthop_global, "hostname", + nexthop_hostname); +- } else +- vty_out(vty, " %s", +- nexthop_hostname +- ? nexthop_hostname +- : inet_ntoa(attr->nexthop)); ++ } else { ++ if (nexthop_hostname) ++ vty_out(vty, " %pI4(%s)", ++ &attr->nexthop, ++ nexthop_hostname); ++ else ++ vty_out(vty, " %pI4", ++ &attr->nexthop); ++ } + } + + if (json_paths) +@@ -8866,12 +8910,13 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, + json_object_string_add(json_nexthop_global, "scope", + "global"); + } else { +- vty_out(vty, " %s", +- nexthop_hostname +- ? nexthop_hostname +- : inet_ntop(AF_INET6, +- &attr->mp_nexthop_global, +- buf, INET6_ADDRSTRLEN)); ++ if (nexthop_hostname) ++ vty_out(vty, " %pI6(%s)", ++ &attr->mp_nexthop_global, ++ nexthop_hostname); ++ else ++ vty_out(vty, " %pI6", ++ &attr->mp_nexthop_global); + } + } + +diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c +index 78521457fd..7f00ff3fbe 100644 +--- a/bgpd/bgp_vty.c ++++ b/bgpd/bgp_vty.c +@@ -84,6 +84,10 @@ FRR_CFG_DEFAULT_BOOL(BGP_SHOW_HOSTNAME, + { .val_bool = true, .match_profile = "datacenter", }, + { .val_bool = false }, + ) ++FRR_CFG_DEFAULT_BOOL(BGP_SHOW_NEXTHOP_HOSTNAME, ++ { .val_bool = true, .match_profile = "datacenter", }, ++ { .val_bool = false }, ++) + FRR_CFG_DEFAULT_BOOL(BGP_LOG_NEIGHBOR_CHANGES, + { .val_bool = true, .match_profile = "datacenter", }, + { .val_bool = false }, +@@ -422,6 +426,8 @@ int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name, + SET_FLAG((*bgp)->flags, BGP_FLAG_IMPORT_CHECK); + if (DFLT_BGP_SHOW_HOSTNAME) + SET_FLAG((*bgp)->flags, BGP_FLAG_SHOW_HOSTNAME); ++ if (DFLT_BGP_SHOW_NEXTHOP_HOSTNAME) ++ SET_FLAG((*bgp)->flags, BGP_FLAG_SHOW_NEXTHOP_HOSTNAME); + if (DFLT_BGP_LOG_NEIGHBOR_CHANGES) + SET_FLAG((*bgp)->flags, BGP_FLAG_LOG_NEIGHBOR_CHANGES); + if (DFLT_BGP_DETERMINISTIC_MED) +@@ -3100,6 +3106,32 @@ DEFUN (no_bgp_default_show_hostname, + return CMD_SUCCESS; + } + ++/* Display hostname in certain command outputs */ ++DEFUN (bgp_default_show_nexthop_hostname, ++ bgp_default_show_nexthop_hostname_cmd, ++ "bgp default show-nexthop-hostname", ++ "BGP specific commands\n" ++ "Configure BGP defaults\n" ++ "Show hostname for nexthop in certain command outputs\n") ++{ ++ VTY_DECLVAR_CONTEXT(bgp, bgp); ++ SET_FLAG(bgp->flags, BGP_FLAG_SHOW_NEXTHOP_HOSTNAME); ++ return CMD_SUCCESS; ++} ++ ++DEFUN (no_bgp_default_show_nexthop_hostname, ++ no_bgp_default_show_nexthop_hostname_cmd, ++ "no bgp default show-nexthop-hostname", ++ NO_STR ++ "BGP specific commands\n" ++ "Configure BGP defaults\n" ++ "Show hostname for nexthop in certain command outputs\n") ++{ ++ VTY_DECLVAR_CONTEXT(bgp, bgp); ++ UNSET_FLAG(bgp->flags, BGP_FLAG_SHOW_NEXTHOP_HOSTNAME); ++ return CMD_SUCCESS; ++} ++ + /* "bgp network import-check" configuration. */ + DEFUN (bgp_network_import_check, + bgp_network_import_check_cmd, +@@ -15190,6 +15222,15 @@ int bgp_config_write(struct vty *vty) + ? "" + : "no "); + ++ /* BGP default show-nexthop-hostname */ ++ if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_SHOW_NEXTHOP_HOSTNAME) ++ != SAVE_BGP_SHOW_HOSTNAME) ++ vty_out(vty, " %sbgp default show-nexthop-hostname\n", ++ CHECK_FLAG(bgp->flags, ++ BGP_FLAG_SHOW_NEXTHOP_HOSTNAME) ++ ? "" ++ : "no "); ++ + /* BGP default subgroup-pkt-queue-max. */ + if (bgp->default_subgroup_pkt_queue_max + != BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX) +@@ -15815,6 +15856,10 @@ void bgp_vty_init(void) + install_element(BGP_NODE, &bgp_default_show_hostname_cmd); + install_element(BGP_NODE, &no_bgp_default_show_hostname_cmd); + ++ /* bgp default show-nexthop-hostname */ ++ install_element(BGP_NODE, &bgp_default_show_nexthop_hostname_cmd); ++ install_element(BGP_NODE, &no_bgp_default_show_nexthop_hostname_cmd); ++ + /* "bgp default subgroup-pkt-queue-max" commands. */ + install_element(BGP_NODE, &bgp_default_subgroup_pkt_queue_max_cmd); + install_element(BGP_NODE, &no_bgp_default_subgroup_pkt_queue_max_cmd); +diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h +index 4a5772a53b..4efc068dea 100644 +--- a/bgpd/bgpd.h ++++ b/bgpd/bgpd.h +@@ -447,6 +447,7 @@ struct bgp { + #define BGP_FLAG_SELECT_DEFER_DISABLE (1 << 23) + #define BGP_FLAG_GR_DISABLE_EOR (1 << 24) + #define BGP_FLAG_EBGP_REQUIRES_POLICY (1 << 25) ++#define BGP_FLAG_SHOW_NEXTHOP_HOSTNAME (1 << 26) + + enum global_mode GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE] + [BGP_GLOBAL_GR_EVENT_CMD]; + +From 104dfe5258cbeb0443fa4d6577794a1e5a5dafd3 Mon Sep 17 00:00:00 2001 +From: Donatas Abraitis +Date: Wed, 6 May 2020 17:50:04 +0300 +Subject: [PATCH 3/4] bgpd: Add "hostname" in JSON output for `show bgp` family + outputs + +This adds hostname regardless if `bgp default show-hostname` enabled or not. + +Signed-off-by: Donatas Abraitis +--- + bgpd/bgp_route.c | 40 ++++++++++++++++++++-------------------- + 1 file changed, 20 insertions(+), 20 deletions(-) + +diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c +index f033f525e5..5f645fa871 100644 +--- a/bgpd/bgp_route.c ++++ b/bgpd/bgp_route.c +@@ -7671,10 +7671,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p, + json_object_string_add(json_nexthop_global, "ip", + nexthop); + +- if (nexthop_hostname) ++ if (path->peer->hostname) + json_object_string_add(json_nexthop_global, + "hostname", +- nexthop_hostname); ++ path->peer->hostname); + + json_object_string_add(json_nexthop_global, "afi", + (af == AF_INET) ? "ipv4" +@@ -7701,10 +7701,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p, + json_object_string_add(json_nexthop_global, "ip", + inet_ntoa(attr->nexthop)); + +- if (nexthop_hostname) ++ if (path->peer->hostname) + json_object_string_add(json_nexthop_global, + "hostname", +- nexthop_hostname); ++ path->peer->hostname); + + json_object_string_add(json_nexthop_global, "afi", + "ipv4"); +@@ -7735,10 +7735,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p, + json_nexthop_global, "ip", + inet_ntoa(attr->nexthop)); + +- if (nexthop_hostname) ++ if (path->peer->hostname) + json_object_string_add( + json_nexthop_global, "hostname", +- nexthop_hostname); ++ path->peer->hostname); + + json_object_boolean_true_add( + json_nexthop_global, +@@ -7768,10 +7768,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p, + json_object_string_add(json_nexthop_global, "ip", + inet_ntoa(attr->nexthop)); + +- if (nexthop_hostname) ++ if (path->peer->hostname) + json_object_string_add(json_nexthop_global, + "hostname", +- nexthop_hostname); ++ path->peer->hostname); + + json_object_string_add(json_nexthop_global, "afi", + "ipv4"); +@@ -7804,10 +7804,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p, + inet_ntop(AF_INET6, &attr->mp_nexthop_global, + buf, BUFSIZ)); + +- if (nexthop_hostname) ++ if (path->peer->hostname) + json_object_string_add(json_nexthop_global, + "hostname", +- nexthop_hostname); ++ path->peer->hostname); + + json_object_string_add(json_nexthop_global, "afi", + "ipv6"); +@@ -7826,10 +7826,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p, + &attr->mp_nexthop_local, buf, + BUFSIZ)); + +- if (nexthop_hostname) ++ if (path->peer->hostname) + json_object_string_add( + json_nexthop_ll, "hostname", +- nexthop_hostname); ++ path->peer->hostname); + + json_object_string_add(json_nexthop_ll, "afi", + "ipv6"); +@@ -8856,10 +8856,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, + json_nexthop_global, "ip", + inet_ntoa(attr->mp_nexthop_global_in)); + +- if (nexthop_hostname) ++ if (path->peer->hostname) + json_object_string_add( + json_nexthop_global, "hostname", +- nexthop_hostname); ++ path->peer->hostname); + } else { + if (nexthop_hostname) + vty_out(vty, " %pI4(%s)", +@@ -8875,10 +8875,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, + json_nexthop_global, "ip", + inet_ntoa(attr->nexthop)); + +- if (nexthop_hostname) ++ if (path->peer->hostname) + json_object_string_add( + json_nexthop_global, "hostname", +- nexthop_hostname); ++ path->peer->hostname); + } else { + if (nexthop_hostname) + vty_out(vty, " %pI4(%s)", +@@ -8900,10 +8900,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, + inet_ntop(AF_INET6, &attr->mp_nexthop_global, + buf, INET6_ADDRSTRLEN)); + +- if (nexthop_hostname) ++ if (path->peer->hostname) + json_object_string_add(json_nexthop_global, + "hostname", +- nexthop_hostname); ++ path->peer->hostname); + + json_object_string_add(json_nexthop_global, "afi", + "ipv6"); +@@ -9094,10 +9094,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, + inet_ntop(AF_INET6, &attr->mp_nexthop_local, + buf, INET6_ADDRSTRLEN)); + +- if (nexthop_hostname) ++ if (path->peer->hostname) + json_object_string_add(json_nexthop_ll, + "hostname", +- nexthop_hostname); ++ path->peer->hostname); + + json_object_string_add(json_nexthop_ll, "afi", "ipv6"); + json_object_string_add(json_nexthop_ll, "scope", + +From 8df39282ea64e2a65a7910012627f78d080833b1 Mon Sep 17 00:00:00 2001 +From: Donatas Abraitis +Date: Wed, 24 Jun 2020 17:26:27 +0300 +Subject: [PATCH 4/4] doc: Add some words about `bgp default + show-[nexthop]-hostname` + +Signed-off-by: Donatas Abraitis +--- + doc/user/bgp.rst | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst +index 36227db604..a6c29724b0 100644 +--- a/doc/user/bgp.rst ++++ b/doc/user/bgp.rst +@@ -1366,6 +1366,19 @@ Configuring Peers + on by default or not. This command defaults to on and is not displayed. + The `no bgp default ipv4-unicast` form of the command is displayed. + ++.. index:: [no] bgp default show-hostname ++.. clicmd:: [no] bgp default show-hostname ++ ++ This command shows the hostname of the peer in certain BGP commands ++ outputs. It's easier to troubleshoot if you have a number of BGP peers. ++ ++.. index:: [no] bgp default show-nexthop-hostname ++.. clicmd:: [no] bgp default show-nexthop-hostname ++ ++ This command shows the hostname of the next-hop in certain BGP commands ++ outputs. It's easier to troubleshoot if you have a number of BGP peers ++ and a number of routes to check. ++ + .. index:: [no] neighbor PEER advertisement-interval (0-600) + .. clicmd:: [no] neighbor PEER advertisement-interval (0-600) + diff --git a/net/frr/patches/007-bgpd_Fix_the_bug_BGP_MRAI.patch b/net/frr/patches/007-bgpd_Fix_the_bug_BGP_MRAI.patch new file mode 100644 index 0000000000..a58f26ce56 --- /dev/null +++ b/net/frr/patches/007-bgpd_Fix_the_bug_BGP_MRAI.patch @@ -0,0 +1,30 @@ +From 2bbe7133eb5cb97ba4b745cd251a8615cd2bd008 Mon Sep 17 00:00:00 2001 +From: Richard Wu +Date: Fri, 5 Jun 2020 17:54:57 +0800 +Subject: [PATCH] bgpd: Fix the bug that BGP MRAI does not work. + +Issue: bgp_process_writes will be called when the fd is writable. + And it will bgp_generate_updgrp_packets to generate the + update packets no matter MRAI is set or not. +Fix: bgp_generate_updgrp_packets thread will return without sending + any update when MRAI timer is still running. + +Signed-off-by: Richard Wu +--- + bgpd/bgp_packet.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c +index 29c03f4014..6f1c033f2a 100644 +--- a/bgpd/bgp_packet.c ++++ b/bgpd/bgp_packet.c +@@ -408,6 +408,9 @@ int bgp_generate_updgrp_packets(struct thread *thread) + if (peer->bgp->main_peers_update_hold) + return 0; + ++ if (peer->t_routeadv) ++ return 0; ++ + do { + s = NULL; + FOREACH_AFI_SAFI (afi, safi) { diff --git a/net/frr/patches/010-add_yahng_filter.patch b/net/frr/patches/010-add_yahng_filter.patch deleted file mode 100644 index 2409dd8463..0000000000 --- a/net/frr/patches/010-add_yahng_filter.patch +++ /dev/null @@ -1,385 +0,0 @@ -From 2332428d3c80ac3d3b4e1c0bdba830b098ef440f Mon Sep 17 00:00:00 2001 -From: Rafael Zalamena -Date: Fri, 5 Jul 2019 11:07:30 -0300 -Subject: [PATCH] yang: initial filter YANG model import - -This model contains the description of access-list, prefix-list and -other lists used by route map and other filtering interfaces. - -Signed-off-by: Rafael Zalamena ---- - yang/frr-filter.yang | 365 +++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 365 insertions(+) - create mode 100644 yang/frr-filter.yang - -diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang -new file mode 100644 -index 0000000000..92af6aebfd ---- /dev/null -+++ b/yang/frr-filter.yang -@@ -0,0 +1,365 @@ -+module frr-filter { -+ yang-version 1.1; -+ namespace "http://frrouting.org/yang/filter"; -+ prefix frr-filter; -+ -+ import ietf-inet-types { -+ prefix inet; -+ } -+ import ietf-yang-types { -+ prefix yang; -+ } -+ -+ organization "Free Range Routing"; -+ contact -+ "FRR Users List: -+ FRR Development List: "; -+ description "This module defines filter settings"; -+ -+ revision 2019-07-04 { -+ description "Initial revision"; -+ } -+ -+ /* -+ * Types. -+ */ -+ typedef access-list-standard { -+ description "Standard IPv4 access list (any, host or a prefix)"; -+ type uint16 { -+ range "1..99 | 1300..1999"; -+ } -+ } -+ -+ typedef access-list-extended { -+ description -+ "Extended IPv4 access list (source / destination any, hosts or prefixes)"; -+ type uint16 { -+ range "100..199 | 2000..2699"; -+ } -+ } -+ -+ typedef access-list-legacy { -+ description "Standard/Extended IPv4 access list"; -+ type uint16 { -+ range "1..199 | 1300..2699"; -+ } -+ } -+ -+ typedef access-list-name { -+ description "Access list name formatting"; -+ type string; -+ } -+ -+ typedef access-list-sequence { -+ description "Access list sequence number"; -+ type uint32 { -+ range "1..4294967295"; -+ } -+ } -+ -+ typedef access-list-action { -+ description "Access list return action on match"; -+ type enumeration { -+ enum deny { -+ description "Deny an entry"; -+ value 0; -+ } -+ enum permit { -+ description "Accept an entry"; -+ value 1; -+ } -+ } -+ } -+ -+ /* -+ * Configuration data. -+ */ -+ container filter-list { -+ list access-list-legacy { -+ description "Access list legacy instance"; -+ -+ key "number sequence"; -+ -+ leaf number { -+ description "Access list sequence value"; -+ type access-list-legacy; -+ } -+ -+ leaf sequence { -+ description "Access list sequence value"; -+ type access-list-sequence; -+ } -+ -+ leaf action { -+ description "Access list action on match"; -+ type access-list-action; -+ mandatory true; -+ } -+ -+ leaf remark { -+ description "Access list remark"; -+ type string; -+ } -+ -+ choice value { -+ description -+ "Standard access list: value to match. -+ Extended access list: source value to match."; -+ mandatory true; -+ -+ case host { -+ leaf host { -+ description "Host to match"; -+ type inet:ipv4-address; -+ } -+ } -+ case network { -+ leaf network { -+ description "Network to match"; -+ type inet:ipv4-prefix; -+ } -+ } -+ case any { -+ leaf any { -+ description "Match any"; -+ type empty; -+ } -+ } -+ } -+ -+ choice extended-value { -+ when "./sequence >= 100 and ./sequence <= 199 or -+ ./sequence >= 2000 and ./sequence <= 2699"; -+ description "Destination value to match"; -+ -+ case destination-host { -+ leaf destination-host { -+ description "Host to match"; -+ type inet:ipv4-address; -+ } -+ } -+ case destination-network { -+ leaf destination-network { -+ description "Network to match"; -+ type inet:ipv4-prefix; -+ } -+ } -+ case destination-any { -+ leaf destination-any { -+ description "Match any"; -+ type empty; -+ } -+ } -+ } -+ } -+ -+ list access-list { -+ description "Access list instance"; -+ -+ key "type identifier sequence"; -+ -+ leaf type { -+ description "Access list content type"; -+ type enumeration { -+ enum ipv4 { -+ description "Internet Protocol address version 4"; -+ value 0; -+ } -+ enum ipv6 { -+ description "Internet Protocol address version 6"; -+ value 1; -+ } -+ enum mac { -+ description "Media Access Control address"; -+ value 2; -+ } -+ -+ /* -+ * Protocol YANG models should augment the parent node to -+ * contain the routing protocol specific value. The protocol -+ * must also augment `value` leaf to include its specific -+ * values or expand the `when` statement on the existing cases. -+ */ -+ enum custom { -+ description "Custom data type"; -+ value 100; -+ } -+ } -+ } -+ -+ leaf identifier { -+ description "Access list identifier"; -+ type access-list-name; -+ } -+ -+ leaf sequence { -+ description "Access list sequence value"; -+ type access-list-sequence; -+ } -+ -+ leaf action { -+ description "Access list action on match"; -+ type access-list-action; -+ mandatory true; -+ } -+ -+ leaf remark { -+ description "Access list remark"; -+ type string; -+ } -+ -+ choice value { -+ description "Access list value to match"; -+ mandatory true; -+ -+ case ipv4-prefix { -+ when "./type = 'ipv4'"; -+ -+ leaf ipv4-prefix { -+ description "Configure IPv4 prefix to match"; -+ type inet:ipv4-prefix; -+ } -+ -+ leaf ipv4-exact-match { -+ description "Exact match of prefix"; -+ type boolean; -+ default false; -+ } -+ } -+ case ipv6-prefix { -+ when "./type = 'ipv6'"; -+ -+ leaf ipv6-prefix { -+ description "Configure IPv6 prefix to match"; -+ type inet:ipv6-prefix; -+ } -+ -+ leaf ipv6-exact-match { -+ description "Exact match of prefix"; -+ type boolean; -+ default false; -+ } -+ } -+ case mac { -+ when "./type = 'mac'"; -+ -+ leaf mac { -+ description "Configure MAC address to match"; -+ type yang:mac-address; -+ } -+ } -+ case any { -+ leaf any { -+ description "Match anything"; -+ type empty; -+ } -+ } -+ } -+ } -+ -+ list prefix-list { -+ description "Prefix list instance"; -+ -+ key "type name sequence"; -+ -+ leaf type { -+ description "Prefix list type"; -+ type enumeration { -+ enum ipv4 { -+ description "Internet Protocol address version 4"; -+ value 0; -+ } -+ enum ipv6 { -+ description "Internet Protocol address version 6"; -+ value 1; -+ } -+ } -+ } -+ -+ leaf name { -+ description "Prefix list name"; -+ type access-list-name; -+ } -+ -+ leaf sequence { -+ description "Access list sequence value"; -+ type access-list-sequence; -+ } -+ -+ leaf action { -+ description "Prefix list action on match"; -+ type access-list-action; -+ mandatory true; -+ } -+ -+ leaf description { -+ description "Prefix list user description"; -+ type string; -+ } -+ -+ choice value { -+ description "Prefix list value to match"; -+ mandatory true; -+ -+ case ipv4-prefix { -+ when "./type = 'ipv4'"; -+ -+ leaf ipv4-prefix { -+ description "Configure IPv4 prefix to match"; -+ type inet:ipv4-prefix; -+ } -+ -+ leaf ipv4-prefix-length-greater-or-equal { -+ description -+ "Specifies if matching prefixes with length greater than -+ or equal to value"; -+ type uint8 { -+ range "0..32"; -+ } -+ } -+ -+ leaf ipv4-prefix-length-lesser-or-equal { -+ description -+ "Specifies if matching prefixes with length lesser than -+ or equal to value"; -+ type uint8 { -+ range "0..32"; -+ } -+ } -+ } -+ case ipv6-prefix { -+ when "./type = 'ipv6'"; -+ -+ leaf ipv6-prefix { -+ description "Configure IPv6 prefix to match"; -+ type inet:ipv6-prefix; -+ } -+ -+ leaf ipv6-prefix-length-greater-or-equal { -+ description -+ "Specifies if matching prefixes with length greater than -+ or equal to value"; -+ type uint8 { -+ range "0..128"; -+ } -+ } -+ -+ leaf ipv6-prefix-length-lesser-or-equal { -+ description -+ "Specifies if matching prefixes with length lesser than -+ or equal to value"; -+ type uint8 { -+ range "0..128"; -+ } -+ } -+ } -+ case any { -+ leaf any { -+ description "Match anything"; -+ type empty; -+ } -+ } -+ } -+ } -+ } -+} diff --git a/net/frr/patches/010-add_yang_routemap.patch b/net/frr/patches/010-add_yang_routemap.patch deleted file mode 100644 index 7026acb6d9..0000000000 --- a/net/frr/patches/010-add_yang_routemap.patch +++ /dev/null @@ -1,390 +0,0 @@ ---- a/dev/null 2020-04-10 18:48:03.582667900 +0300 -+++ b/yang/frr-route-map.yang 2020-05-02 11:43:04.182956847 +0300 -@@ -0,0 +1,387 @@ -+module frr-route-map { -+ yang-version 1.1; -+ namespace "http://frrouting.org/yang/route-map"; -+ prefix frr-route-map; -+ -+ import ietf-inet-types { -+ prefix inet; -+ } -+ import frr-filter { -+ prefix filter; -+ } -+ import frr-interface { -+ prefix frr-interface; -+ } -+ -+ organization "FRRouting"; -+ contact -+ "FRR Users List: -+ FRR Development List: "; -+ description "This module defines route map settings"; -+ -+ revision 2019-07-01 { -+ description "Initial revision"; -+ } -+ -+ /* -+ * Types. -+ */ -+ typedef route-map-sequence { -+ description "Route map valid sequence numbers"; -+ type uint16 { -+ range "1..65535"; -+ } -+ } -+ -+ typedef route-map-name { -+ description "Route map name format"; -+ type string; -+ } -+ -+ /* -+ * Operational data. -+ */ -+ container lib { -+ list route-map { -+ description "Route map instance"; -+ -+ key "name"; -+ -+ leaf name { -+ description "Route map instance name"; -+ type route-map-name; -+ } -+ -+ list entry { -+ description "Route map entry"; -+ -+ key "sequence"; -+ -+ leaf sequence { -+ description -+ "Route map instance priority (low number means higher priority)"; -+ type route-map-sequence; -+ } -+ -+ leaf description { -+ description "Route map description"; -+ type string; -+ } -+ -+ leaf action { -+ description -+ "Route map actions: permit (executes action), deny (quits evaluation)"; -+ mandatory true; -+ type enumeration { -+ enum permit { -+ description -+ "Executes configured action and permits the prefix/route -+ if the conditions matched. An alternative exit action can -+ be configured to continue processing the route map list -+ or jump to process another route map."; -+ value 0; -+ } -+ enum deny { -+ description -+ "If all conditions are met the prefix/route is denied and -+ route map processing stops."; -+ value 1; -+ } -+ } -+ } -+ -+ leaf call { -+ description -+ "Call another route map before calling `exit-policy`. If the -+ called route map returns deny then this route map will also -+ return deny"; -+ type route-map-name; -+ } -+ -+ leaf exit-policy { -+ description "What do to after route map successful match, set and call"; -+ type enumeration { -+ enum permit-or-deny { -+ description "End route map evaluation and return"; -+ value 0; -+ } -+ enum next { -+ description -+ "Proceed evaluating next route map entry per sequence"; -+ value 1; -+ } -+ enum goto { -+ description -+ "Go to route map entry with the provided sequence number"; -+ value 2; -+ } -+ } -+ default "permit-or-deny"; -+ } -+ -+ leaf goto-value { -+ when "../exit-policy = 'goto'"; -+ description -+ "Sequence number to jump (when using `goto` exit policy)"; -+ mandatory true; -+ type route-map-sequence; -+ } -+ -+ list match-condition { -+ description "Route map match conditions"; -+ -+ key "condition"; -+ -+ leaf condition { -+ description "Match condition"; -+ type enumeration { -+ enum interface { -+ description "Match interface"; -+ value 0; -+ } -+ enum ipv4-address-list { -+ description "Match an IPv4 access-list"; -+ value 1; -+ } -+ enum ipv4-prefix-list { -+ description "Match an IPv4 prefix-list"; -+ value 2; -+ } -+ enum ipv4-next-hop-list { -+ description "Match an IPv4 next-hop"; -+ value 3; -+ } -+ enum ipv4-next-hop-prefix-list { -+ description "Match an IPv4 next-hop prefix list"; -+ value 4; -+ } -+ enum ipv4-next-hop-type { -+ description "Match an IPv4 next-hop type"; -+ value 5; -+ } -+ enum ipv6-address-list { -+ description "Match an IPv6 access-list"; -+ value 6; -+ } -+ enum ipv6-prefix-list { -+ description "Match an IPv6 prefix-list"; -+ value 7; -+ } -+ enum ipv6-next-hop-type { -+ description "Match an IPv6 next-hop type"; -+ value 8; -+ } -+ enum metric { -+ description "Match a route metric"; -+ value 9; -+ } -+ enum tag { -+ description "Match a route tag"; -+ value 10; -+ } -+ /* zebra specific conditions. */ -+ enum ipv4-prefix-length { -+ description "Match IPv4 prefix length"; -+ value 100; -+ } -+ enum ipv6-prefix-length { -+ description "Match IPv6 prefix length"; -+ value 101; -+ } -+ enum ipv4-next-hop-prefix-length { -+ description "Match next-hop prefix length"; -+ value 102; -+ } -+ enum source-protocol { -+ description "Match source protocol"; -+ value 103; -+ } -+ enum source-instance { -+ description "Match source protocol instance"; -+ value 104; -+ } -+ } -+ } -+ -+ choice condition-value { -+ description -+ "Value to match (interpretation depends on condition type)"; -+ mandatory true; -+ case interface { -+ when "./condition = 'interface'"; -+ leaf interface { -+ type string; -+ } -+ } -+ case access-list-num { -+ when "./condition = 'ipv4-address-list' or -+ ./condition = 'ipv4-next-hop-list'"; -+ leaf access-list-num { -+ type filter:access-list-standard; -+ } -+ } -+ case access-list-num-extended { -+ when "./condition = 'ipv4-address-list' or -+ ./condition = 'ipv4-next-hop-list'"; -+ leaf access-list-num-extended { -+ type filter:access-list-extended; -+ } -+ } -+ case list-name { -+ when "./condition = 'ipv4-address-list' or -+ ./condition = 'ipv4-prefix-list' or -+ ./condition = 'ipv4-next-hop-list' or -+ ./condition = 'ipv4-next-hop-prefix-list' or -+ ./condition = 'ipv6-address-list' or -+ ./condition = 'ipv6-prefix-list'"; -+ leaf list-name { -+ type filter:access-list-name; -+ } -+ } -+ case ipv4-next-hop-type { -+ when "./condition = 'ipv4-next-hop-type'"; -+ leaf ipv4-next-hop-type { -+ type enumeration { -+ enum blackhole { -+ value 0; -+ } -+ } -+ } -+ } -+ case ipv6-next-hop-type { -+ when "./condition = 'ipv6-next-hop-type'"; -+ leaf ipv6-next-hop-type { -+ type enumeration { -+ enum blackhole { -+ value 0; -+ } -+ } -+ } -+ } -+ case metric { -+ when "./condition = 'metric'"; -+ leaf metric { -+ type uint32 { -+ range "1..4294967295"; -+ } -+ } -+ } -+ case tag { -+ when "./condition = 'tag'"; -+ leaf tag { -+ type uint32 { -+ range "1..4294967295"; -+ } -+ } -+ } -+ } -+ } -+ -+ list set-action { -+ description "Route map set actions"; -+ -+ key "action"; -+ -+ leaf action { -+ description "Action to do when the route map matches"; -+ type enumeration { -+ enum ipv4-next-hop { -+ description "Set IPv4 address of the next hop"; -+ value 0; -+ } -+ enum ipv6-next-hop { -+ description "Set IPv6 address of the next hop"; -+ value 1; -+ } -+ enum metric { -+ description "Set prefix/route metric"; -+ value 2; -+ } -+ enum tag { -+ description "Set tag"; -+ value 3; -+ } -+ /* zebra specific conditions. */ -+ enum source { -+ description "Set source address for route"; -+ value 100; -+ } -+ } -+ } -+ -+ choice action-value { -+ description -+ "Value to set (interpretation depends on action-type)"; -+ case ipv4-address { -+ when "./action = 'ipv4-next-hop'"; -+ leaf ipv4-address { -+ description "IPv4 address"; -+ type inet:ipv4-address; -+ } -+ } -+ case ipv6-address { -+ when "./action = 'ipv6-next-hop'"; -+ leaf ipv6-address { -+ description "IPv6 address"; -+ type inet:ipv6-address; -+ } -+ } -+ case metric { -+ when "./action = 'metric'"; -+ choice metric-value { -+ description "Metric to set or use"; -+ case value { -+ leaf value { -+ description "Use the following metric value"; -+ type uint32 { -+ range "0..4294967295"; -+ } -+ } -+ } -+ case add-metric { -+ leaf add-metric { -+ description "Add unit to metric"; -+ type boolean; -+ } -+ } -+ case subtract-metric { -+ leaf subtract-metric { -+ description "Subtract unit from metric"; -+ type boolean; -+ } -+ } -+ case use-round-trip-time { -+ leaf use-round-trip-time { -+ description "Use the round trip time as metric"; -+ type boolean; -+ } -+ } -+ case add-round-trip-time { -+ leaf add-round-trip-time { -+ description "Add round trip time to metric"; -+ type boolean; -+ } -+ } -+ case subtract-round-trip-time { -+ leaf subtract-round-trip-time { -+ description "Subtract round trip time to metric"; -+ type boolean; -+ } -+ } -+ } -+ } -+ case tag { -+ when "./action = 'tag'"; -+ leaf tag { -+ description "Tag value"; -+ type uint32 { -+ range "0..4294967295"; -+ } -+ } -+ } -+ } -+ } -+ } -+ } -+ } -+} diff --git a/net/frr/patches/011-mod_yang_routemap_model.patch b/net/frr/patches/011-mod_yang_routemap_model.patch deleted file mode 100644 index ac56137054..0000000000 --- a/net/frr/patches/011-mod_yang_routemap_model.patch +++ /dev/null @@ -1,5045 +0,0 @@ -From 0c0e73045b1898610eef9309b9f5927254356710 Mon Sep 17 00:00:00 2001 -From: Rafael Zalamena -Date: Fri, 27 Sep 2019 19:32:10 -0300 -Subject: [PATCH 01/10] yang: update route map model - -Important changes: - - * Rename top container `route-map` to `lib`; - * Rename list `instance` to `route-map`; - * Move route map repeated data to list `entry`; - * Use interface reference instead of typedef'ed string; - * Remove some zebra specific route map conditions; - * Protect `tag` set value with `when "./action = 'tag'"`; - -Signed-off-by: Rafael Zalamena ---- -From a7282663eff6f036a427165b7fa73c75dccd47ff Mon Sep 17 00:00:00 2001 -From: Rafael Zalamena -Date: Mon, 30 Sep 2019 10:17:33 -0300 -Subject: [PATCH 02/10] lib: export route map structures and functions - -These exported items are going to be used by the new northbound CLI. - -Signed-off-by: Rafael Zalamena ---- - lib/routemap.c | 213 ++----------------------------------------------- - lib/routemap.h | 209 ++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 216 insertions(+), 206 deletions(-) - -diff --git a/lib/routemap.c b/lib/routemap.c -index 14fec0283c..a8feebd313 100644 ---- a/lib/routemap.c -+++ b/lib/routemap.c -@@ -50,178 +50,7 @@ static vector route_match_vec; - /* Vector for route set rules. */ - static vector route_set_vec; - --struct route_map_match_set_hooks { -- /* match interface */ -- int (*match_interface)(struct vty *vty, struct route_map_index *index, -- const char *command, const char *arg, -- route_map_event_t type); -- -- /* no match interface */ -- int (*no_match_interface)(struct vty *vty, -- struct route_map_index *index, -- const char *command, const char *arg, -- route_map_event_t type); -- -- /* match ip address */ -- int (*match_ip_address)(struct vty *vty, struct route_map_index *index, -- const char *command, const char *arg, -- route_map_event_t type); -- -- /* no match ip address */ -- int (*no_match_ip_address)(struct vty *vty, -- struct route_map_index *index, -- const char *command, const char *arg, -- route_map_event_t type); -- -- /* match ip address prefix list */ -- int (*match_ip_address_prefix_list)(struct vty *vty, -- struct route_map_index *index, -- const char *command, -- const char *arg, -- route_map_event_t type); -- -- /* no match ip address prefix list */ -- int (*no_match_ip_address_prefix_list)(struct vty *vty, -- struct route_map_index *index, -- const char *command, -- const char *arg, -- route_map_event_t type); -- -- /* match ip next hop */ -- int (*match_ip_next_hop)(struct vty *vty, struct route_map_index *index, -- const char *command, const char *arg, -- route_map_event_t type); -- -- /* no match ip next hop */ -- int (*no_match_ip_next_hop)(struct vty *vty, -- struct route_map_index *index, -- const char *command, const char *arg, -- route_map_event_t type); -- -- /* match ip next hop prefix list */ -- int (*match_ip_next_hop_prefix_list)(struct vty *vty, -- struct route_map_index *index, -- const char *command, -- const char *arg, -- route_map_event_t type); -- -- /* no match ip next hop prefix list */ -- int (*no_match_ip_next_hop_prefix_list)(struct vty *vty, -- struct route_map_index *index, -- const char *command, -- const char *arg, -- route_map_event_t type); -- -- /* match ip next-hop type */ -- int (*match_ip_next_hop_type)(struct vty *vty, -- struct route_map_index *index, -- const char *command, -- const char *arg, -- route_map_event_t type); -- -- /* no match ip next-hop type */ -- int (*no_match_ip_next_hop_type)(struct vty *vty, -- struct route_map_index *index, -- const char *command, -- const char *arg, -- route_map_event_t type); -- -- /* match ipv6 address */ -- int (*match_ipv6_address)(struct vty *vty, -- struct route_map_index *index, -- const char *command, const char *arg, -- route_map_event_t type); -- -- /* no match ipv6 address */ -- int (*no_match_ipv6_address)(struct vty *vty, -- struct route_map_index *index, -- const char *command, const char *arg, -- route_map_event_t type); -- -- -- /* match ipv6 address prefix list */ -- int (*match_ipv6_address_prefix_list)(struct vty *vty, -- struct route_map_index *index, -- const char *command, -- const char *arg, -- route_map_event_t type); -- -- /* no match ipv6 address prefix list */ -- int (*no_match_ipv6_address_prefix_list)(struct vty *vty, -- struct route_map_index *index, -- const char *command, -- const char *arg, -- route_map_event_t type); -- -- /* match ipv6 next-hop type */ -- int (*match_ipv6_next_hop_type)(struct vty *vty, -- struct route_map_index *index, -- const char *command, -- const char *arg, -- route_map_event_t type); -- -- /* no match ipv6 next-hop type */ -- int (*no_match_ipv6_next_hop_type)(struct vty *vty, -- struct route_map_index *index, -- const char *command, const char *arg, -- route_map_event_t type); -- -- /* match metric */ -- int (*match_metric)(struct vty *vty, struct route_map_index *index, -- const char *command, const char *arg, -- route_map_event_t type); -- -- /* no match metric */ -- int (*no_match_metric)(struct vty *vty, struct route_map_index *index, -- const char *command, const char *arg, -- route_map_event_t type); -- -- /* match tag */ -- int (*match_tag)(struct vty *vty, struct route_map_index *index, -- const char *command, const char *arg, -- route_map_event_t type); -- -- /* no match tag */ -- int (*no_match_tag)(struct vty *vty, struct route_map_index *index, -- const char *command, const char *arg, -- route_map_event_t type); -- -- /* set ip nexthop */ -- int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index, -- const char *command, const char *arg); -- -- /* no set ip nexthop */ -- int (*no_set_ip_nexthop)(struct vty *vty, struct route_map_index *index, -- const char *command, const char *arg); -- -- /* set ipv6 nexthop local */ -- int (*set_ipv6_nexthop_local)(struct vty *vty, -- struct route_map_index *index, -- const char *command, const char *arg); -- -- /* no set ipv6 nexthop local */ -- int (*no_set_ipv6_nexthop_local)(struct vty *vty, -- struct route_map_index *index, -- const char *command, const char *arg); -- -- /* set metric */ -- int (*set_metric)(struct vty *vty, struct route_map_index *index, -- const char *command, const char *arg); -- -- /* no set metric */ -- int (*no_set_metric)(struct vty *vty, struct route_map_index *index, -- const char *command, const char *arg); -- -- /* set tag */ -- int (*set_tag)(struct vty *vty, struct route_map_index *index, -- const char *command, const char *arg); -- -- /* no set tag */ -- int (*no_set_tag)(struct vty *vty, struct route_map_index *index, -- const char *command, const char *arg); --}; -- --static struct route_map_match_set_hooks rmap_match_set_hook; -+struct route_map_match_set_hooks rmap_match_set_hook; - - /* match interface */ - void route_map_match_interface_hook(int (*func)( -@@ -595,35 +424,9 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index, - } - - --/* Route map rule. This rule has both `match' rule and `set' rule. */ --struct route_map_rule { -- /* Rule type. */ -- const struct route_map_rule_cmd *cmd; -- -- /* For pretty printing. */ -- char *rule_str; -- -- /* Pre-compiled match rule. */ -- void *value; -- -- /* Linked list. */ -- struct route_map_rule *next; -- struct route_map_rule *prev; --}; -- --/* Making route map list. */ --struct route_map_list { -- struct route_map *head; -- struct route_map *tail; -- -- void (*add_hook)(const char *); -- void (*delete_hook)(const char *); -- void (*event_hook)(const char *); --}; -- - /* Master list of route map. */ --static struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL}; --static struct hash *route_map_master_hash = NULL; -+struct route_map_list route_map_master = {NULL, NULL, NULL, NULL, NULL}; -+struct hash *route_map_master_hash = NULL; - - static unsigned int route_map_hash_key_make(const void *p) - { -@@ -691,8 +494,6 @@ static void route_map_rule_delete(struct route_map_rule_list *, - struct route_map_rule *); - static bool rmap_debug; - --static void route_map_index_delete(struct route_map_index *, int); -- - /* New route map allocation. Please note route map's name must be - specified. */ - static struct route_map *route_map_new(const char *name) -@@ -784,7 +585,7 @@ static void route_map_free_map(struct route_map *map) - } - - /* Route map delete from list. */ --static void route_map_delete(struct route_map *map) -+void route_map_delete(struct route_map *map) - { - struct route_map_index *index; - char *name; -@@ -883,7 +684,7 @@ static int route_map_clear_updated(struct route_map *map) - - /* Lookup route map. If there isn't route map create one and return - it. */ --static struct route_map *route_map_get(const char *name) -+struct route_map *route_map_get(const char *name) - { - struct route_map *map; - -@@ -1097,7 +898,7 @@ static struct route_map_index *route_map_index_new(void) - } - - /* Free route map index. */ --static void route_map_index_delete(struct route_map_index *index, int notify) -+void route_map_index_delete(struct route_map_index *index, int notify) - { - struct route_map_rule *rule; - -@@ -1202,7 +1003,7 @@ route_map_index_add(struct route_map *map, enum route_map_type type, int pref) - } - - /* Get route map index. */ --static struct route_map_index * -+struct route_map_index * - route_map_index_get(struct route_map *map, enum route_map_type type, int pref) - { - struct route_map_index *index; -diff --git a/lib/routemap.h b/lib/routemap.h -index 1ffd0525ae..41959c24e5 100644 ---- a/lib/routemap.h -+++ b/lib/routemap.h -@@ -140,6 +140,22 @@ enum rmap_compile_rets { - - }; - -+/* Route map rule. This rule has both `match' rule and `set' rule. */ -+struct route_map_rule { -+ /* Rule type. */ -+ const struct route_map_rule_cmd *cmd; -+ -+ /* For pretty printing. */ -+ char *rule_str; -+ -+ /* Pre-compiled match rule. */ -+ void *value; -+ -+ /* Linked list. */ -+ struct route_map_rule *next; -+ struct route_map_rule *prev; -+}; -+ - /* Route map rule list. */ - struct route_map_rule_list { - struct route_map_rule *head; -@@ -435,6 +451,199 @@ extern void route_map_counter_increment(struct route_map *map); - /* Decrement the route-map used counter */ - extern void route_map_counter_decrement(struct route_map *map); - -+/* Route map hooks data structure. */ -+struct route_map_match_set_hooks { -+ /* match interface */ -+ int (*match_interface)(struct vty *vty, struct route_map_index *index, -+ const char *command, const char *arg, -+ route_map_event_t type); -+ -+ /* no match interface */ -+ int (*no_match_interface)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, const char *arg, -+ route_map_event_t type); -+ -+ /* match ip address */ -+ int (*match_ip_address)(struct vty *vty, struct route_map_index *index, -+ const char *command, const char *arg, -+ route_map_event_t type); -+ -+ /* no match ip address */ -+ int (*no_match_ip_address)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, const char *arg, -+ route_map_event_t type); -+ -+ /* match ip address prefix list */ -+ int (*match_ip_address_prefix_list)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, -+ const char *arg, -+ route_map_event_t type); -+ -+ /* no match ip address prefix list */ -+ int (*no_match_ip_address_prefix_list)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, -+ const char *arg, -+ route_map_event_t type); -+ -+ /* match ip next hop */ -+ int (*match_ip_next_hop)(struct vty *vty, struct route_map_index *index, -+ const char *command, const char *arg, -+ route_map_event_t type); -+ -+ /* no match ip next hop */ -+ int (*no_match_ip_next_hop)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, const char *arg, -+ route_map_event_t type); -+ -+ /* match ip next hop prefix list */ -+ int (*match_ip_next_hop_prefix_list)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, -+ const char *arg, -+ route_map_event_t type); -+ -+ /* no match ip next hop prefix list */ -+ int (*no_match_ip_next_hop_prefix_list)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, -+ const char *arg, -+ route_map_event_t type); -+ -+ /* match ip next-hop type */ -+ int (*match_ip_next_hop_type)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, -+ const char *arg, -+ route_map_event_t type); -+ -+ /* no match ip next-hop type */ -+ int (*no_match_ip_next_hop_type)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, -+ const char *arg, -+ route_map_event_t type); -+ -+ /* match ipv6 address */ -+ int (*match_ipv6_address)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, const char *arg, -+ route_map_event_t type); -+ -+ /* no match ipv6 address */ -+ int (*no_match_ipv6_address)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, const char *arg, -+ route_map_event_t type); -+ -+ -+ /* match ipv6 address prefix list */ -+ int (*match_ipv6_address_prefix_list)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, -+ const char *arg, -+ route_map_event_t type); -+ -+ /* no match ipv6 address prefix list */ -+ int (*no_match_ipv6_address_prefix_list)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, -+ const char *arg, -+ route_map_event_t type); -+ -+ /* match ipv6 next-hop type */ -+ int (*match_ipv6_next_hop_type)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, -+ const char *arg, -+ route_map_event_t type); -+ -+ /* no match ipv6 next-hop type */ -+ int (*no_match_ipv6_next_hop_type)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, const char *arg, -+ route_map_event_t type); -+ -+ /* match metric */ -+ int (*match_metric)(struct vty *vty, struct route_map_index *index, -+ const char *command, const char *arg, -+ route_map_event_t type); -+ -+ /* no match metric */ -+ int (*no_match_metric)(struct vty *vty, struct route_map_index *index, -+ const char *command, const char *arg, -+ route_map_event_t type); -+ -+ /* match tag */ -+ int (*match_tag)(struct vty *vty, struct route_map_index *index, -+ const char *command, const char *arg, -+ route_map_event_t type); -+ -+ /* no match tag */ -+ int (*no_match_tag)(struct vty *vty, struct route_map_index *index, -+ const char *command, const char *arg, -+ route_map_event_t type); -+ -+ /* set ip nexthop */ -+ int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index, -+ const char *command, const char *arg); -+ -+ /* no set ip nexthop */ -+ int (*no_set_ip_nexthop)(struct vty *vty, struct route_map_index *index, -+ const char *command, const char *arg); -+ -+ /* set ipv6 nexthop local */ -+ int (*set_ipv6_nexthop_local)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, const char *arg); -+ -+ /* no set ipv6 nexthop local */ -+ int (*no_set_ipv6_nexthop_local)(struct vty *vty, -+ struct route_map_index *index, -+ const char *command, const char *arg); -+ -+ /* set metric */ -+ int (*set_metric)(struct vty *vty, struct route_map_index *index, -+ const char *command, const char *arg); -+ -+ /* no set metric */ -+ int (*no_set_metric)(struct vty *vty, struct route_map_index *index, -+ const char *command, const char *arg); -+ -+ /* set tag */ -+ int (*set_tag)(struct vty *vty, struct route_map_index *index, -+ const char *command, const char *arg); -+ -+ /* no set tag */ -+ int (*no_set_tag)(struct vty *vty, struct route_map_index *index, -+ const char *command, const char *arg); -+}; -+ -+extern struct route_map_match_set_hooks rmap_match_set_hook; -+ -+/* Making route map list. */ -+struct route_map_list { -+ struct route_map *head; -+ struct route_map *tail; -+ -+ void (*add_hook)(const char *); -+ void (*delete_hook)(const char *); -+ void (*event_hook)(const char *); -+}; -+ -+extern struct route_map_list route_map_master; -+ -+extern struct route_map *route_map_get(const char *name); -+extern void route_map_delete(struct route_map *map); -+extern struct route_map_index *route_map_index_get(struct route_map *map, -+ enum route_map_type type, -+ int pref); -+extern void route_map_index_delete(struct route_map_index *index, int notify); -+ - #ifdef __cplusplus - } - #endif - -From 686d244f00d87fa0b76c8e4644550d413fc3400b Mon Sep 17 00:00:00 2001 -From: Rafael Zalamena -Date: Mon, 30 Sep 2019 10:34:49 -0300 -Subject: [PATCH 03/10] lib: implement route map northbound - -Based on the route map old CLI, implement the route map handling using -the exported functions. - -Use a curry-like programming pattern avoid code repetition when -destroying match/set entries. This is needed by other daemons that -implement custom route map functions and need to pass to lib their -specific destroy functions. - -Signed-off-by: Rafael Zalamena ---- - lib/routemap.h | 24 + - lib/routemap_northbound.c | 1393 +++++++++++++++++++++++++++++++++++++ - lib/subdir.am | 2 + - yang/subdir.am | 1 + - 4 files changed, 1420 insertions(+) - create mode 100644 lib/routemap_northbound.c - -diff --git a/lib/routemap.h b/lib/routemap.h -index 41959c24e5..d9e7f73f81 100644 ---- a/lib/routemap.h -+++ b/lib/routemap.h -@@ -644,6 +644,30 @@ extern struct route_map_index *route_map_index_get(struct route_map *map, - int pref); - extern void route_map_index_delete(struct route_map_index *index, int notify); - -+/* routemap_northbound.c */ -+typedef int (*routemap_match_hook_fun)(struct vty *vty, -+ struct route_map_index *rmi, -+ const char *command, const char *arg, -+ route_map_event_t event); -+ -+typedef int (*routemap_set_hook_fun)(struct vty *vty, -+ struct route_map_index *rmi, -+ const char *command, const char *arg); -+ -+struct routemap_hook_context { -+ struct route_map_index *rhc_rmi; -+ const char *rhc_rule; -+ route_map_event_t rhc_event; -+ routemap_set_hook_fun rhc_shook; -+ routemap_match_hook_fun rhc_mhook; -+}; -+ -+int lib_route_map_entry_match_destroy(enum nb_event event, -+ const struct lyd_node *dnode); -+int lib_route_map_entry_set_destroy(enum nb_event event, -+ const struct lyd_node *dnode); -+extern const struct frr_yang_module_info frr_route_map_info; -+ - #ifdef __cplusplus - } - #endif -diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c -new file mode 100644 -index 0000000000..02eb756334 ---- /dev/null -+++ b/lib/routemap_northbound.c -@@ -0,0 +1,1393 @@ -+/* -+ * Route map northbound implementation. -+ * -+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF") -+ * Rafael Zalamena -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301 USA. -+ */ -+ -+#include -+ -+#include "lib/command.h" -+#include "lib/log.h" -+#include "lib/northbound.h" -+#include "lib/routemap.h" -+ -+/* -+ * Auxiliary functions to avoid code duplication: -+ * -+ * lib_route_map_entry_set_destroy: unset `set` commands. -+ * lib_route_map_entry_match_destroy: unset `match` commands. -+ */ -+int lib_route_map_entry_match_destroy(enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ struct routemap_hook_context *rhc; -+ int rv; -+ -+ if (event != NB_EV_APPLY) -+ return NB_OK; -+ -+ rhc = nb_running_get_entry(dnode, NULL, true); -+ if (rhc->rhc_mhook == NULL) -+ return NB_OK; -+ -+ rv = rhc->rhc_mhook(NULL, rhc->rhc_rmi, rhc->rhc_rule, NULL, -+ rhc->rhc_event); -+ if (rv != CMD_SUCCESS) -+ return NB_ERR_INCONSISTENCY; -+ -+ return NB_OK; -+} -+ -+int lib_route_map_entry_set_destroy(enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ struct routemap_hook_context *rhc; -+ int rv; -+ -+ if (event != NB_EV_APPLY) -+ return NB_OK; -+ -+ rhc = nb_running_get_entry(dnode, NULL, true); -+ if (rhc->rhc_shook == NULL) -+ return NB_OK; -+ -+ rv = rhc->rhc_shook(NULL, rhc->rhc_rmi, rhc->rhc_rule, NULL); -+ if (rv != CMD_SUCCESS) -+ return NB_ERR_INCONSISTENCY; -+ -+ return NB_OK; -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map -+ */ -+static int lib_route_map_create(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct route_map *rm; -+ const char *rm_name; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ case NB_EV_PREPARE: -+ case NB_EV_ABORT: -+ /* NOTHING */ -+ break; -+ case NB_EV_APPLY: -+ rm_name = yang_dnode_get_string(dnode, "./name"); -+ rm = route_map_get(rm_name); -+ nb_running_set_entry(dnode, rm); -+ break; -+ } -+ -+ return NB_OK; -+} -+ -+static int lib_route_map_destroy(enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ struct route_map *rm; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ case NB_EV_PREPARE: -+ case NB_EV_ABORT: -+ /* NOTHING */ -+ break; -+ case NB_EV_APPLY: -+ rm = nb_running_unset_entry(dnode); -+ route_map_delete(rm); -+ break; -+ } -+ -+ return NB_OK; -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry -+ */ -+static int lib_route_map_entry_create(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct route_map_index *rmi; -+ struct route_map *rm; -+ uint16_t sequence; -+ int action; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ case NB_EV_PREPARE: -+ case NB_EV_ABORT: -+ /* NOTHING */ -+ break; -+ case NB_EV_APPLY: -+ sequence = yang_dnode_get_uint16(dnode, "./sequence"); -+ action = yang_dnode_get_enum(dnode, "./action") == 0 -+ ? RMAP_PERMIT -+ : RMAP_DENY; -+ rm = nb_running_get_entry(dnode, NULL, true); -+ rmi = route_map_index_get(rm, action, sequence); -+ nb_running_set_entry(dnode, rmi); -+ break; -+ } -+ -+ return NB_OK; -+} -+ -+static int lib_route_map_entry_destroy(enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ struct route_map_index *rmi; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ case NB_EV_PREPARE: -+ case NB_EV_ABORT: -+ /* NOTHING */ -+ break; -+ case NB_EV_APPLY: -+ rmi = nb_running_unset_entry(dnode); -+ route_map_index_delete(rmi, 1); -+ break; -+ } -+ -+ return NB_OK; -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/description -+ */ -+static int lib_route_map_entry_description_modify(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct route_map_index *rmi; -+ const char *description; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ /* NOTHING */ -+ break; -+ case NB_EV_PREPARE: -+ description = yang_dnode_get_string(dnode, NULL); -+ resource->ptr = XSTRDUP(MTYPE_TMP, description); -+ if (resource->ptr == NULL) -+ return NB_ERR_RESOURCE; -+ break; -+ case NB_EV_ABORT: -+ XFREE(MTYPE_TMP, resource->ptr); -+ break; -+ case NB_EV_APPLY: -+ rmi = nb_running_get_entry(dnode, NULL, true); -+ if (rmi->description != NULL) -+ XFREE(MTYPE_TMP, rmi->description); -+ rmi->description = resource->ptr; -+ break; -+ } -+ -+ return NB_OK; -+} -+ -+static int lib_route_map_entry_description_destroy(enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ struct route_map_index *rmi; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ case NB_EV_PREPARE: -+ case NB_EV_ABORT: -+ /* NOTHING */ -+ break; -+ case NB_EV_APPLY: -+ rmi = nb_running_get_entry(dnode, NULL, true); -+ if (rmi->description != NULL) -+ XFREE(MTYPE_TMP, rmi->description); -+ rmi->description = NULL; -+ break; -+ } -+ -+ return NB_OK; -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/action -+ */ -+static int lib_route_map_entry_action_modify(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct route_map_index *rmi; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ case NB_EV_PREPARE: -+ case NB_EV_ABORT: -+ /* NOTHING */ -+ break; -+ case NB_EV_APPLY: -+ rmi = nb_running_get_entry(dnode, NULL, true); -+ rmi->type = yang_dnode_get_enum(dnode, NULL); -+ /* TODO: notify? */ -+ break; -+ } -+ -+ return NB_OK; -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/call -+ */ -+static int lib_route_map_entry_call_modify(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct route_map_index *rmi; -+ const char *rm_name, *rmn_name; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ rm_name = yang_dnode_get_string(dnode, "../../name"); -+ rmn_name = yang_dnode_get_string(dnode, NULL); -+ /* Don't allow to jump to the same route map instance. */ -+ if (strcmp(rm_name, rmn_name) == 0) -+ return NB_ERR_VALIDATION; -+ -+ /* TODO: detect circular route map sequences. */ -+ break; -+ case NB_EV_PREPARE: -+ rmn_name = yang_dnode_get_string(dnode, NULL); -+ resource->ptr = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmn_name); -+ break; -+ case NB_EV_ABORT: -+ XFREE(MTYPE_ROUTE_MAP_NAME, resource->ptr); -+ break; -+ case NB_EV_APPLY: -+ rmi = nb_running_get_entry(dnode, NULL, true); -+ if (rmi->nextrm) { -+ route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED, -+ rmi->nextrm, rmi->map->name); -+ XFREE(MTYPE_ROUTE_MAP_NAME, rmi->nextrm); -+ } -+ rmi->nextrm = resource->ptr; -+ route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, rmi->nextrm, -+ rmi->map->name); -+ break; -+ } -+ -+ return NB_OK; -+} -+ -+static int lib_route_map_entry_call_destroy(enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ struct route_map_index *rmi; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ case NB_EV_PREPARE: -+ case NB_EV_ABORT: -+ /* NOTHING */ -+ break; -+ case NB_EV_APPLY: -+ rmi = nb_running_get_entry(dnode, NULL, true); -+ route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED, rmi->nextrm, -+ rmi->map->name); -+ XFREE(MTYPE_ROUTE_MAP_NAME, rmi->nextrm); -+ rmi->nextrm = NULL; -+ break; -+ } -+ -+ return NB_OK; -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/exit-policy -+ */ -+static int lib_route_map_entry_exit_policy_modify(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct route_map_index *rmi; -+ int rm_action; -+ int policy; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ policy = yang_dnode_get_enum(dnode, NULL); -+ switch (policy) { -+ case 0: /* permit-or-deny */ -+ break; -+ case 1: /* next */ -+ /* FALLTHROUGH */ -+ case 2: /* goto */ -+ rm_action = yang_dnode_get_enum(dnode, "../action"); -+ if (rm_action == 1 /* deny */) { -+ /* -+ * On deny it is not possible to 'goto' -+ * anywhere. -+ */ -+ return NB_ERR_VALIDATION; -+ } -+ break; -+ } -+ break; -+ case NB_EV_PREPARE: -+ case NB_EV_ABORT: -+ break; -+ case NB_EV_APPLY: -+ rmi = nb_running_get_entry(dnode, NULL, true); -+ policy = yang_dnode_get_enum(dnode, NULL); -+ -+ switch (policy) { -+ case 0: /* permit-or-deny */ -+ rmi->exitpolicy = RMAP_EXIT; -+ break; -+ case 1: /* next */ -+ rmi->exitpolicy = RMAP_NEXT; -+ break; -+ case 2: /* goto */ -+ rmi->exitpolicy = RMAP_GOTO; -+ break; -+ } -+ break; -+ } -+ -+ return NB_OK; -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/goto-value -+ */ -+static int lib_route_map_entry_goto_value_modify(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct route_map_index *rmi; -+ uint16_t rmi_index; -+ uint16_t rmi_next; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ rmi_index = yang_dnode_get_uint16(dnode, "../sequence"); -+ rmi_next = yang_dnode_get_uint16(dnode, NULL); -+ if (rmi_next <= rmi_index) { -+ /* Can't jump backwards on a route map. */ -+ return NB_ERR_VALIDATION; -+ } -+ break; -+ case NB_EV_PREPARE: -+ case NB_EV_ABORT: -+ /* NOTHING */ -+ break; -+ case NB_EV_APPLY: -+ rmi = nb_running_get_entry(dnode, NULL, true); -+ rmi->nextpref = yang_dnode_get_uint16(dnode, NULL); -+ break; -+ } -+ -+ return NB_OK; -+} -+ -+static int lib_route_map_entry_goto_value_destroy(enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ struct route_map_index *rmi; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ case NB_EV_PREPARE: -+ case NB_EV_ABORT: -+ /* NOTHING */ -+ break; -+ case NB_EV_APPLY: -+ rmi = nb_running_get_entry(dnode, NULL, true); -+ rmi->nextpref = 0; -+ break; -+ } -+ -+ return NB_OK; -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/match-condition -+ */ -+static int -+lib_route_map_entry_match_condition_create(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct routemap_hook_context *rhc; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ /* NOTHING */ -+ break; -+ case NB_EV_PREPARE: -+ resource->ptr = XCALLOC(MTYPE_TMP, sizeof(*rhc)); -+ break; -+ case NB_EV_ABORT: -+ XFREE(MTYPE_TMP, resource->ptr); -+ break; -+ case NB_EV_APPLY: -+ rhc = resource->ptr; -+ rhc->rhc_rmi = nb_running_get_entry(dnode, NULL, true); -+ nb_running_set_entry(dnode, rhc); -+ break; -+ } -+ -+ return NB_OK; -+} -+ -+static int -+lib_route_map_entry_match_condition_destroy(enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ struct routemap_hook_context *rhc; -+ int rv; -+ -+ if (event != NB_EV_APPLY) -+ return NB_OK; -+ -+ rv = lib_route_map_entry_match_destroy(event, dnode); -+ rhc = nb_running_unset_entry(dnode); -+ XFREE(MTYPE_TMP, rhc); -+ -+ return rv; -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/interface -+ */ -+static int lib_route_map_entry_match_condition_interface_modify( -+ enum nb_event event, const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct routemap_hook_context *rhc; -+ const char *ifname; -+ int rv; -+ -+ if (event != NB_EV_APPLY) -+ return NB_OK; -+ -+ /* Check for hook function. */ -+ if (rmap_match_set_hook.match_interface == NULL) -+ return NB_OK; -+ -+ /* Add configuration. */ -+ rhc = nb_running_get_entry(dnode, NULL, true); -+ ifname = yang_dnode_get_string(dnode, NULL); -+ -+ /* Set destroy information. */ -+ rhc->rhc_mhook = rmap_match_set_hook.no_match_interface; -+ rhc->rhc_rule = "interface"; -+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; -+ -+ rv = rmap_match_set_hook.match_interface(NULL, rhc->rhc_rmi, -+ "interface", ifname, -+ RMAP_EVENT_MATCH_ADDED); -+ if (rv != CMD_SUCCESS) { -+ rhc->rhc_mhook = NULL; -+ return NB_ERR_INCONSISTENCY; -+ } -+ -+ return NB_OK; -+} -+ -+static int lib_route_map_entry_match_condition_interface_destroy( -+ enum nb_event event, const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_match_destroy(event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/access-list-num -+ */ -+static int lib_route_map_entry_match_condition_access_list_num_modify( -+ enum nb_event event, const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct routemap_hook_context *rhc; -+ const char *acl; -+ int condition, rv; -+ -+ if (event != NB_EV_APPLY) -+ return NB_OK; -+ -+ /* Check for hook function. */ -+ rv = CMD_SUCCESS; -+ acl = yang_dnode_get_string(dnode, NULL); -+ rhc = nb_running_get_entry(dnode, NULL, true); -+ condition = yang_dnode_get_enum(dnode, "../condition"); -+ switch (condition) { -+ case 1: /* ipv4-address-list */ -+ if (rmap_match_set_hook.match_ip_address == NULL) -+ break; -+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_address; -+ rhc->rhc_rule = "ip address"; -+ rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; -+ rv = rmap_match_set_hook.match_ip_address( -+ NULL, rhc->rhc_rmi, "ip address", acl, -+ RMAP_EVENT_FILTER_ADDED); -+ break; -+ case 3: /* ipv4-next-hop-list */ -+ if (rmap_match_set_hook.match_ip_next_hop == NULL) -+ break; -+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop; -+ rhc->rhc_rule = "ip next-hop"; -+ rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; -+ rv = rmap_match_set_hook.match_ip_next_hop( -+ NULL, rhc->rhc_rmi, "ip next-hop", acl, -+ RMAP_EVENT_FILTER_ADDED); -+ break; -+ } -+ if (rv != CMD_SUCCESS) { -+ rhc->rhc_mhook = NULL; -+ return NB_ERR_INCONSISTENCY; -+ } -+ -+ return NB_OK; -+} -+ -+static int lib_route_map_entry_match_condition_access_list_num_destroy( -+ enum nb_event event, const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_match_destroy(event, dnode); -+} -+ -+/* -+ * XPath: -+ * /frr-route-map:lib/route-map/entry/match-condition/access-list-num-extended -+ */ -+static int lib_route_map_entry_match_condition_access_list_num_extended_modify( -+ enum nb_event event, const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ return lib_route_map_entry_match_condition_access_list_num_modify( -+ event, dnode, resource); -+} -+ -+static int lib_route_map_entry_match_condition_access_list_num_extended_destroy( -+ enum nb_event event, const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_match_condition_access_list_num_destroy( -+ event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/list-name -+ */ -+static int lib_route_map_entry_match_condition_list_name_modify( -+ enum nb_event event, const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct routemap_hook_context *rhc; -+ const char *acl; -+ int condition; -+ int rv; -+ -+ if (event != NB_EV_APPLY) -+ return NB_OK; -+ -+ /* Check for hook installation, otherwise we can just stop. */ -+ acl = yang_dnode_get_string(dnode, NULL); -+ rhc = nb_running_get_entry(dnode, NULL, true); -+ condition = yang_dnode_get_enum(dnode, "../condition"); -+ switch (condition) { -+ case 1: /* ipv4-address-list */ -+ if (rmap_match_set_hook.match_ip_address == NULL) -+ return NB_OK; -+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_address; -+ rhc->rhc_rule = "ip address"; -+ rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; -+ rv = rmap_match_set_hook.match_ip_address( -+ NULL, rhc->rhc_rmi, "ip address", acl, -+ RMAP_EVENT_FILTER_ADDED); -+ break; -+ case 2: /* ipv4-prefix-list */ -+ if (rmap_match_set_hook.match_ip_address_prefix_list == NULL) -+ return NB_OK; -+ rhc->rhc_mhook = -+ rmap_match_set_hook.no_match_ip_address_prefix_list; -+ rhc->rhc_rule = "ip address prefix-list"; -+ rhc->rhc_event = RMAP_EVENT_PLIST_DELETED; -+ rv = rmap_match_set_hook.match_ip_address_prefix_list( -+ NULL, rhc->rhc_rmi, "ip address prefix-list", acl, -+ RMAP_EVENT_PLIST_ADDED); -+ break; -+ case 3: /* ipv4-next-hop-list */ -+ if (rmap_match_set_hook.match_ip_next_hop == NULL) -+ return NB_OK; -+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop; -+ rhc->rhc_rule = "ip next-hop"; -+ rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; -+ rv = rmap_match_set_hook.match_ip_next_hop( -+ NULL, rhc->rhc_rmi, "ip next-hop", acl, -+ RMAP_EVENT_FILTER_ADDED); -+ break; -+ case 4: /* ipv4-next-hop-prefix-list */ -+ if (rmap_match_set_hook.match_ip_next_hop_prefix_list == NULL) -+ return NB_OK; -+ rhc->rhc_mhook = -+ rmap_match_set_hook.no_match_ip_next_hop_prefix_list; -+ rhc->rhc_rule = "ip next-hop prefix-list"; -+ rhc->rhc_event = RMAP_EVENT_PLIST_DELETED; -+ rv = rmap_match_set_hook.match_ip_next_hop_prefix_list( -+ NULL, rhc->rhc_rmi, "ip next-hop prefix-list", acl, -+ RMAP_EVENT_PLIST_ADDED); -+ break; -+ case 6: /* ipv6-address-list */ -+ if (rmap_match_set_hook.match_ipv6_address == NULL) -+ return NB_OK; -+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_address; -+ rhc->rhc_rule = "ipv6 address"; -+ rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; -+ rv = rmap_match_set_hook.match_ipv6_address( -+ NULL, rhc->rhc_rmi, "ipv6 address", acl, -+ RMAP_EVENT_FILTER_ADDED); -+ break; -+ case 7: /* ipv6-prefix-list */ -+ if (rmap_match_set_hook.match_ipv6_address_prefix_list == NULL) -+ return NB_OK; -+ rhc->rhc_mhook = -+ rmap_match_set_hook.no_match_ipv6_address_prefix_list; -+ rhc->rhc_rule = "ipv6 address prefix-list"; -+ rhc->rhc_event = RMAP_EVENT_PLIST_DELETED; -+ rv = rmap_match_set_hook.match_ipv6_address_prefix_list( -+ NULL, rhc->rhc_rmi, "ipv6 address prefix-list", acl, -+ RMAP_EVENT_PLIST_ADDED); -+ break; -+ default: -+ rv = CMD_ERR_NO_MATCH; -+ break; -+ } -+ if (rv != CMD_SUCCESS) { -+ rhc->rhc_mhook = NULL; -+ return NB_ERR_INCONSISTENCY; -+ } -+ -+ return NB_OK; -+} -+ -+static int lib_route_map_entry_match_condition_list_name_destroy( -+ enum nb_event event, const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_match_destroy(event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/ipv4-next-hop-type -+ */ -+static int lib_route_map_entry_match_condition_ipv4_next_hop_type_modify( -+ enum nb_event event, const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct routemap_hook_context *rhc; -+ const char *type; -+ int rv; -+ -+ if (event != NB_EV_APPLY) -+ return NB_OK; -+ -+ /* Check for hook function. */ -+ if (rmap_match_set_hook.match_ip_next_hop_type == NULL) -+ return NB_OK; -+ -+ /* Add configuration. */ -+ rhc = nb_running_get_entry(dnode, NULL, true); -+ type = yang_dnode_get_string(dnode, NULL); -+ -+ /* Set destroy information. */ -+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop_type; -+ rhc->rhc_rule = "ip next-hop type"; -+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; -+ -+ rv = rmap_match_set_hook.match_ip_next_hop_type( -+ NULL, rhc->rhc_rmi, "ip next-hop type", type, -+ RMAP_EVENT_MATCH_ADDED); -+ if (rv != CMD_SUCCESS) { -+ rhc->rhc_mhook = NULL; -+ return NB_ERR_INCONSISTENCY; -+ } -+ -+ return NB_OK; -+} -+ -+static int lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy( -+ enum nb_event event, const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_match_destroy(event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/ipv6-next-hop-type -+ */ -+static int lib_route_map_entry_match_condition_ipv6_next_hop_type_modify( -+ enum nb_event event, const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct routemap_hook_context *rhc; -+ const char *type; -+ int rv; -+ -+ if (event != NB_EV_APPLY) -+ return NB_OK; -+ -+ /* Check for hook function. */ -+ if (rmap_match_set_hook.match_ipv6_next_hop_type == NULL) -+ return NB_OK; -+ -+ /* Add configuration. */ -+ rhc = nb_running_get_entry(dnode, NULL, true); -+ type = yang_dnode_get_string(dnode, NULL); -+ -+ /* Set destroy information. */ -+ rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_next_hop_type; -+ rhc->rhc_rule = "ipv6 next-hop type"; -+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; -+ -+ rv = rmap_match_set_hook.match_ipv6_next_hop_type( -+ NULL, rhc->rhc_rmi, "ipv6 next-hop type", type, -+ RMAP_EVENT_MATCH_ADDED); -+ if (rv != CMD_SUCCESS) { -+ rhc->rhc_mhook = NULL; -+ return NB_ERR_INCONSISTENCY; -+ } -+ -+ return NB_OK; -+} -+ -+static int lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy( -+ enum nb_event event, const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_match_destroy(event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/metric -+ */ -+static int -+lib_route_map_entry_match_condition_metric_modify(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct routemap_hook_context *rhc; -+ const char *type; -+ int rv; -+ -+ if (event != NB_EV_APPLY) -+ return NB_OK; -+ -+ /* Check for hook function. */ -+ if (rmap_match_set_hook.match_metric == NULL) -+ return NB_OK; -+ -+ /* Add configuration. */ -+ rhc = nb_running_get_entry(dnode, NULL, true); -+ type = yang_dnode_get_string(dnode, NULL); -+ -+ /* Set destroy information. */ -+ rhc->rhc_mhook = rmap_match_set_hook.no_match_metric; -+ rhc->rhc_rule = "metric"; -+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; -+ -+ rv = rmap_match_set_hook.match_metric(NULL, rhc->rhc_rmi, "metric", -+ type, RMAP_EVENT_MATCH_ADDED); -+ if (rv != CMD_SUCCESS) { -+ rhc->rhc_mhook = NULL; -+ return NB_ERR_INCONSISTENCY; -+ } -+ -+ return NB_OK; -+} -+ -+static int -+lib_route_map_entry_match_condition_metric_destroy(enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_match_destroy(event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/tag -+ */ -+static int -+lib_route_map_entry_match_condition_tag_modify(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct routemap_hook_context *rhc; -+ const char *tag; -+ int rv; -+ -+ if (event != NB_EV_APPLY) -+ return NB_OK; -+ -+ /* Check for hook function. */ -+ if (rmap_match_set_hook.match_tag == NULL) -+ return NB_OK; -+ -+ /* Add configuration. */ -+ rhc = nb_running_get_entry(dnode, NULL, true); -+ tag = yang_dnode_get_string(dnode, NULL); -+ -+ /* Set destroy information. */ -+ rhc->rhc_mhook = rmap_match_set_hook.no_match_tag; -+ rhc->rhc_rule = "tag"; -+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; -+ -+ rv = rmap_match_set_hook.match_tag(NULL, rhc->rhc_rmi, "tag", tag, -+ RMAP_EVENT_MATCH_ADDED); -+ if (rv != CMD_SUCCESS) { -+ rhc->rhc_mhook = NULL; -+ return NB_ERR_INCONSISTENCY; -+ } -+ -+ return NB_OK; -+} -+ -+static int -+lib_route_map_entry_match_condition_tag_destroy(enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_match_destroy(event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/set-action -+ */ -+static int lib_route_map_entry_set_action_create(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ return lib_route_map_entry_match_condition_create(event, dnode, -+ resource); -+} -+ -+static int lib_route_map_entry_set_action_destroy(enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ struct routemap_hook_context *rhc; -+ int rv; -+ -+ if (event != NB_EV_APPLY) -+ return NB_OK; -+ -+ rv = lib_route_map_entry_set_destroy(event, dnode); -+ rhc = nb_running_unset_entry(dnode); -+ XFREE(MTYPE_TMP, rhc); -+ -+ return rv; -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/set-action/ipv4-address -+ */ -+static int -+lib_route_map_entry_set_action_ipv4_address_modify(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct routemap_hook_context *rhc; -+ const char *address; -+ struct in_addr ia; -+ int rv; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ /* -+ * NOTE: validate if 'action' is 'ipv4-next-hop', -+ * currently it is not necessary because this is the -+ * only implemented action. -+ */ -+ yang_dnode_get_ipv4(&ia, dnode, NULL); -+ if (ia.s_addr == 0 || IPV4_CLASS_DE(ntohl(ia.s_addr))) -+ return NB_ERR_VALIDATION; -+ /* FALLTHROUGH */ -+ case NB_EV_PREPARE: -+ case NB_EV_ABORT: -+ return NB_OK; -+ case NB_EV_APPLY: -+ break; -+ } -+ -+ /* Check for hook function. */ -+ if (rmap_match_set_hook.set_ip_nexthop == NULL) -+ return NB_OK; -+ -+ /* Add configuration. */ -+ rhc = nb_running_get_entry(dnode, NULL, true); -+ address = yang_dnode_get_string(dnode, NULL); -+ -+ /* Set destroy information. */ -+ rhc->rhc_shook = rmap_match_set_hook.no_set_ip_nexthop; -+ rhc->rhc_rule = "ip next-hop"; -+ -+ rv = rmap_match_set_hook.set_ip_nexthop(NULL, rhc->rhc_rmi, -+ "ip next-hop", address); -+ if (rv != CMD_SUCCESS) { -+ rhc->rhc_shook = NULL; -+ return NB_ERR_INCONSISTENCY; -+ } -+ -+ return NB_OK; -+} -+ -+static int lib_route_map_entry_set_action_ipv4_address_destroy( -+ enum nb_event event, const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_set_destroy(event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/set-action/ipv6-address -+ */ -+static int -+lib_route_map_entry_set_action_ipv6_address_modify(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct routemap_hook_context *rhc; -+ const char *address; -+ struct in6_addr i6a; -+ int rv; -+ -+ switch (event) { -+ case NB_EV_VALIDATE: -+ /* -+ * NOTE: validate if 'action' is 'ipv6-next-hop', -+ * currently it is not necessary because this is the -+ * only implemented action. Other actions might have -+ * different validations. -+ */ -+ yang_dnode_get_ipv6(&i6a, dnode, NULL); -+ if (!IN6_IS_ADDR_LINKLOCAL(&i6a)) -+ return NB_ERR_VALIDATION; -+ /* FALLTHROUGH */ -+ case NB_EV_PREPARE: -+ case NB_EV_ABORT: -+ return NB_OK; -+ case NB_EV_APPLY: -+ break; -+ } -+ -+ /* Check for hook function. */ -+ if (rmap_match_set_hook.set_ipv6_nexthop_local == NULL) -+ return NB_OK; -+ -+ /* Add configuration. */ -+ rhc = nb_running_get_entry(dnode, NULL, true); -+ address = yang_dnode_get_string(dnode, NULL); -+ -+ /* Set destroy information. */ -+ rhc->rhc_shook = rmap_match_set_hook.no_set_ipv6_nexthop_local; -+ rhc->rhc_rule = "ipv6 next-hop local"; -+ -+ rv = rmap_match_set_hook.set_ipv6_nexthop_local( -+ NULL, rhc->rhc_rmi, "ipv6 next-hop local", address); -+ if (rv != CMD_SUCCESS) { -+ rhc->rhc_shook = NULL; -+ return NB_ERR_INCONSISTENCY; -+ } -+ -+ return NB_OK; -+} -+ -+static int lib_route_map_entry_set_action_ipv6_address_destroy( -+ enum nb_event event, const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_set_destroy(event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/set-action/value -+ */ -+static int set_action_modify(enum nb_event event, const struct lyd_node *dnode, -+ union nb_resource *resource, const char *value) -+{ -+ struct routemap_hook_context *rhc; -+ int rv; -+ -+ /* -+ * NOTE: validate if 'action' is 'metric', currently it is not -+ * necessary because this is the only implemented action. Other -+ * actions might have different validations. -+ */ -+ if (event != NB_EV_APPLY) -+ return NB_OK; -+ -+ /* Check for hook function. */ -+ if (rmap_match_set_hook.set_metric == NULL) -+ return NB_OK; -+ -+ /* Add configuration. */ -+ rhc = nb_running_get_entry(dnode, NULL, true); -+ -+ /* Set destroy information. */ -+ rhc->rhc_shook = rmap_match_set_hook.no_set_metric; -+ rhc->rhc_rule = "metric"; -+ -+ rv = rmap_match_set_hook.set_metric(NULL, rhc->rhc_rmi, "metric", -+ value); -+ if (rv != CMD_SUCCESS) { -+ rhc->rhc_shook = NULL; -+ return NB_ERR_INCONSISTENCY; -+ } -+ -+ return NB_OK; -+} -+ -+static int -+lib_route_map_entry_set_action_value_modify(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ const char *metric = yang_dnode_get_string(dnode, NULL); -+ -+ return set_action_modify(event, dnode, resource, metric); -+} -+ -+static int -+lib_route_map_entry_set_action_value_destroy(enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_set_destroy(event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/set-action/add-metric -+ */ -+static int -+lib_route_map_entry_set_action_add_metric_modify(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ return set_action_modify(event, dnode, resource, "+metric"); -+} -+ -+static int -+lib_route_map_entry_set_action_add_metric_destroy(enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_set_action_value_destroy(event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/set-action/subtract-metric -+ */ -+static int lib_route_map_entry_set_action_subtract_metric_modify( -+ enum nb_event event, const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ return set_action_modify(event, dnode, resource, "-metric"); -+} -+ -+static int lib_route_map_entry_set_action_subtract_metric_destroy( -+ enum nb_event event, const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_set_action_value_destroy(event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/set-action/use-round-trip-time -+ */ -+static int lib_route_map_entry_set_action_use_round_trip_time_modify( -+ enum nb_event event, const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ return set_action_modify(event, dnode, resource, "rtt"); -+} -+ -+static int lib_route_map_entry_set_action_use_round_trip_time_destroy( -+ enum nb_event event, const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_set_action_value_destroy(event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/set-action/add-round-trip-time -+ */ -+static int lib_route_map_entry_set_action_add_round_trip_time_modify( -+ enum nb_event event, const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ return set_action_modify(event, dnode, resource, "+rtt"); -+} -+ -+static int lib_route_map_entry_set_action_add_round_trip_time_destroy( -+ enum nb_event event, const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_set_action_value_destroy(event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/set-action/subtract-round-trip-time -+ */ -+static int lib_route_map_entry_set_action_subtract_round_trip_time_modify( -+ enum nb_event event, const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ return set_action_modify(event, dnode, resource, "-rtt"); -+} -+ -+static int lib_route_map_entry_set_action_subtract_round_trip_time_destroy( -+ enum nb_event event, const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_set_action_value_destroy(event, dnode); -+} -+ -+/* -+ * XPath: /frr-route-map:lib/route-map/entry/set-action/tag -+ */ -+static int -+lib_route_map_entry_set_action_tag_modify(enum nb_event event, -+ const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ struct routemap_hook_context *rhc; -+ const char *tag; -+ int rv; -+ -+ /* -+ * NOTE: validate if 'action' is 'tag', currently it is not -+ * necessary because this is the only implemented action. Other -+ * actions might have different validations. -+ */ -+ if (event != NB_EV_APPLY) -+ return NB_OK; -+ -+ /* Check for hook function. */ -+ if (rmap_match_set_hook.set_tag == NULL) -+ return NB_OK; -+ -+ /* Add configuration. */ -+ rhc = nb_running_get_entry(dnode, NULL, true); -+ tag = yang_dnode_get_string(dnode, NULL); -+ -+ /* Set destroy information. */ -+ rhc->rhc_shook = rmap_match_set_hook.no_set_tag; -+ rhc->rhc_rule = "tag"; -+ -+ rv = rmap_match_set_hook.set_tag(NULL, rhc->rhc_rmi, "tag", tag); -+ if (rv != CMD_SUCCESS) { -+ rhc->rhc_shook = NULL; -+ return NB_ERR_INCONSISTENCY; -+ } -+ -+ return NB_OK; -+} -+ -+static int -+lib_route_map_entry_set_action_tag_destroy(enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ return lib_route_map_entry_set_destroy(event, dnode); -+} -+ -+/* clang-format off */ -+const struct frr_yang_module_info frr_route_map_info = { -+ .name = "frr-route-map", -+ .nodes = { -+ { -+ .xpath = "/frr-route-map:lib/route-map", -+ .cbs = { -+ .create = lib_route_map_create, -+ .destroy = lib_route_map_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry", -+ .cbs = { -+ .create = lib_route_map_entry_create, -+ .destroy = lib_route_map_entry_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/description", -+ .cbs = { -+ .modify = lib_route_map_entry_description_modify, -+ .destroy = lib_route_map_entry_description_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/action", -+ .cbs = { -+ .modify = lib_route_map_entry_action_modify, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/call", -+ .cbs = { -+ .modify = lib_route_map_entry_call_modify, -+ .destroy = lib_route_map_entry_call_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/exit-policy", -+ .cbs = { -+ .modify = lib_route_map_entry_exit_policy_modify, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/goto-value", -+ .cbs = { -+ .modify = lib_route_map_entry_goto_value_modify, -+ .destroy = lib_route_map_entry_goto_value_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition", -+ .cbs = { -+ .create = lib_route_map_entry_match_condition_create, -+ .destroy = lib_route_map_entry_match_condition_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/interface", -+ .cbs = { -+ .modify = lib_route_map_entry_match_condition_interface_modify, -+ .destroy = lib_route_map_entry_match_condition_interface_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/access-list-num", -+ .cbs = { -+ .modify = lib_route_map_entry_match_condition_access_list_num_modify, -+ .destroy = lib_route_map_entry_match_condition_access_list_num_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/access-list-num-extended", -+ .cbs = { -+ .modify = lib_route_map_entry_match_condition_access_list_num_extended_modify, -+ .destroy = lib_route_map_entry_match_condition_access_list_num_extended_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/list-name", -+ .cbs = { -+ .modify = lib_route_map_entry_match_condition_list_name_modify, -+ .destroy = lib_route_map_entry_match_condition_list_name_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/ipv4-next-hop-type", -+ .cbs = { -+ .modify = lib_route_map_entry_match_condition_ipv4_next_hop_type_modify, -+ .destroy = lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/ipv6-next-hop-type", -+ .cbs = { -+ .modify = lib_route_map_entry_match_condition_ipv6_next_hop_type_modify, -+ .destroy = lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/metric", -+ .cbs = { -+ .modify = lib_route_map_entry_match_condition_metric_modify, -+ .destroy = lib_route_map_entry_match_condition_metric_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/tag", -+ .cbs = { -+ .modify = lib_route_map_entry_match_condition_tag_modify, -+ .destroy = lib_route_map_entry_match_condition_tag_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/set-action", -+ .cbs = { -+ .create = lib_route_map_entry_set_action_create, -+ .destroy = lib_route_map_entry_set_action_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/ipv4-address", -+ .cbs = { -+ .modify = lib_route_map_entry_set_action_ipv4_address_modify, -+ .destroy = lib_route_map_entry_set_action_ipv4_address_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/ipv6-address", -+ .cbs = { -+ .modify = lib_route_map_entry_set_action_ipv6_address_modify, -+ .destroy = lib_route_map_entry_set_action_ipv6_address_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/value", -+ .cbs = { -+ .modify = lib_route_map_entry_set_action_value_modify, -+ .destroy = lib_route_map_entry_set_action_value_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/add-metric", -+ .cbs = { -+ .modify = lib_route_map_entry_set_action_add_metric_modify, -+ .destroy = lib_route_map_entry_set_action_add_metric_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/subtract-metric", -+ .cbs = { -+ .modify = lib_route_map_entry_set_action_subtract_metric_modify, -+ .destroy = lib_route_map_entry_set_action_subtract_metric_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/use-round-trip-time", -+ .cbs = { -+ .modify = lib_route_map_entry_set_action_use_round_trip_time_modify, -+ .destroy = lib_route_map_entry_set_action_use_round_trip_time_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/add-round-trip-time", -+ .cbs = { -+ .modify = lib_route_map_entry_set_action_add_round_trip_time_modify, -+ .destroy = lib_route_map_entry_set_action_add_round_trip_time_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/subtract-round-trip-time", -+ .cbs = { -+ .modify = lib_route_map_entry_set_action_subtract_round_trip_time_modify, -+ .destroy = lib_route_map_entry_set_action_subtract_round_trip_time_destroy, -+ } -+ }, -+ { -+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/tag", -+ .cbs = { -+ .modify = lib_route_map_entry_set_action_tag_modify, -+ .destroy = lib_route_map_entry_set_action_tag_destroy, -+ } -+ }, -+ { -+ .xpath = NULL, -+ }, -+ } -+}; -diff --git a/lib/subdir.am b/lib/subdir.am -index d804d839db..94b3d933ac 100644 ---- a/lib/subdir.am -+++ b/lib/subdir.am -@@ -71,6 +71,7 @@ lib_libfrr_la_SOURCES = \ - lib/qobj.c \ - lib/ringbuf.c \ - lib/routemap.c \ -+ lib/routemap_northbound.c \ - lib/sbuf.c \ - lib/seqlock.c \ - lib/sha256.c \ -@@ -105,6 +106,7 @@ lib_libfrr_la_SOURCES = \ - - nodist_lib_libfrr_la_SOURCES = \ - yang/frr-interface.yang.c \ -+ yang/frr-route-map.yang.c \ - yang/frr-route-types.yang.c \ - yang/ietf/ietf-routing-types.yang.c \ - yang/frr-module-translator.yang.c \ -diff --git a/yang/subdir.am b/yang/subdir.am -index cfaf1a6401..7a15a6a309 100644 ---- a/yang/subdir.am -+++ b/yang/subdir.am -@@ -22,6 +22,7 @@ EXTRA_DIST += yang/embedmodel.py - dist_yangmodels_DATA += yang/frr-module-translator.yang - dist_yangmodels_DATA += yang/frr-test-module.yang - dist_yangmodels_DATA += yang/frr-interface.yang -+dist_yangmodels_DATA += yang/frr-route-map.yang - dist_yangmodels_DATA += yang/frr-route-types.yang - dist_yangmodels_DATA += yang/ietf/ietf-routing-types.yang - - -From 2b3e4807ecf4d2586fe4d651b904967ea8d759c0 Mon Sep 17 00:00:00 2001 -From: Rafael Zalamena -Date: Mon, 30 Sep 2019 15:01:46 -0300 -Subject: [PATCH 04/10] lib: implement new route map CLI - -Use the northbound back-end instead of the old route map CLI. - -Signed-off-by: Rafael Zalamena ---- - lib/routemap.c | 1103 +------------------------------------ - lib/routemap.h | 19 + - lib/routemap_cli.c | 1075 ++++++++++++++++++++++++++++++++++++ - lib/routemap_northbound.c | 7 + - lib/subdir.am | 4 + - vtysh/extract.pl.in | 2 +- - 6 files changed, 1108 insertions(+), 1102 deletions(-) - create mode 100644 lib/routemap_cli.c - -diff --git a/lib/routemap.c b/lib/routemap.c -index a8feebd313..e07ad08123 100644 ---- a/lib/routemap.c -+++ b/lib/routemap.c -@@ -759,14 +759,6 @@ static const char *route_map_result_str(route_map_result_t res) - return "invalid"; - } - --static int route_map_empty(struct route_map *map) --{ -- if (map->head == NULL && map->tail == NULL) -- return 1; -- else -- return 0; --} -- - /* show route-map */ - static void vty_show_route_map_entry(struct vty *vty, struct route_map *map) - { -@@ -2010,871 +2002,6 @@ void route_map_notify_dependencies(const char *affected_name, - - - /* VTY related functions. */ --DEFUN (match_interface, -- match_interface_cmd, -- "match interface WORD", -- MATCH_STR -- "match first hop interface of route\n" -- "Interface name\n") --{ -- int idx_word = 2; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.match_interface) -- return rmap_match_set_hook.match_interface( -- vty, index, "interface", argv[idx_word]->arg, -- RMAP_EVENT_MATCH_ADDED); -- return CMD_SUCCESS; --} -- --DEFUN (no_match_interface, -- no_match_interface_cmd, -- "no match interface [WORD]", -- NO_STR -- MATCH_STR -- "Match first hop interface of route\n" -- "Interface name\n") --{ -- char *iface = (argc == 4) ? argv[3]->arg : NULL; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.no_match_interface) -- return rmap_match_set_hook.no_match_interface( -- vty, index, "interface", iface, -- RMAP_EVENT_MATCH_DELETED); -- return CMD_SUCCESS; --} -- -- --DEFUN (match_ip_address, -- match_ip_address_cmd, -- "match ip address <(1-199)|(1300-2699)|WORD>", -- MATCH_STR -- IP_STR -- "Match address of route\n" -- "IP access-list number\n" -- "IP access-list number (expanded range)\n" -- "IP Access-list name\n") --{ -- int idx_acl = 3; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.match_ip_address) -- return rmap_match_set_hook.match_ip_address( -- vty, index, "ip address", argv[idx_acl]->arg, -- RMAP_EVENT_FILTER_ADDED); -- return CMD_SUCCESS; --} -- -- --DEFUN (no_match_ip_address, -- no_match_ip_address_cmd, -- "no match ip address [<(1-199)|(1300-2699)|WORD>]", -- NO_STR -- MATCH_STR -- IP_STR -- "Match address of route\n" -- "IP access-list number\n" -- "IP access-list number (expanded range)\n" -- "IP Access-list name\n") --{ -- int idx_word = 4; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.no_match_ip_address) { -- if (argc <= idx_word) -- return rmap_match_set_hook.no_match_ip_address( -- vty, index, "ip address", NULL, -- RMAP_EVENT_FILTER_DELETED); -- return rmap_match_set_hook.no_match_ip_address( -- vty, index, "ip address", argv[idx_word]->arg, -- RMAP_EVENT_FILTER_DELETED); -- } -- return CMD_SUCCESS; --} -- -- --DEFUN (match_ip_address_prefix_list, -- match_ip_address_prefix_list_cmd, -- "match ip address prefix-list WORD", -- MATCH_STR -- IP_STR -- "Match address of route\n" -- "Match entries of prefix-lists\n" -- "IP prefix-list name\n") --{ -- int idx_word = 4; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.match_ip_address_prefix_list) -- return rmap_match_set_hook.match_ip_address_prefix_list( -- vty, index, "ip address prefix-list", -- argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED); -- return CMD_SUCCESS; --} -- -- --DEFUN (no_match_ip_address_prefix_list, -- no_match_ip_address_prefix_list_cmd, -- "no match ip address prefix-list [WORD]", -- NO_STR -- MATCH_STR -- IP_STR -- "Match address of route\n" -- "Match entries of prefix-lists\n" -- "IP prefix-list name\n") --{ -- int idx_word = 5; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.no_match_ip_address_prefix_list) { -- if (argc <= idx_word) -- return rmap_match_set_hook -- .no_match_ip_address_prefix_list( -- vty, index, "ip address prefix-list", -- NULL, RMAP_EVENT_PLIST_DELETED); -- return rmap_match_set_hook.no_match_ip_address_prefix_list( -- vty, index, "ip address prefix-list", -- argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED); -- } -- return CMD_SUCCESS; --} -- -- --DEFUN (match_ip_next_hop, -- match_ip_next_hop_cmd, -- "match ip next-hop <(1-199)|(1300-2699)|WORD>", -- MATCH_STR -- IP_STR -- "Match next-hop address of route\n" -- "IP access-list number\n" -- "IP access-list number (expanded range)\n" -- "IP Access-list name\n") --{ -- int idx_acl = 3; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.match_ip_next_hop) -- return rmap_match_set_hook.match_ip_next_hop( -- vty, index, "ip next-hop", argv[idx_acl]->arg, -- RMAP_EVENT_FILTER_ADDED); -- return CMD_SUCCESS; --} -- -- --DEFUN (no_match_ip_next_hop, -- no_match_ip_next_hop_cmd, -- "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]", -- NO_STR -- MATCH_STR -- IP_STR -- "Match next-hop address of route\n" -- "IP access-list number\n" -- "IP access-list number (expanded range)\n" -- "IP Access-list name\n") --{ -- int idx_word = 4; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.no_match_ip_next_hop) { -- if (argc <= idx_word) -- return rmap_match_set_hook.no_match_ip_next_hop( -- vty, index, "ip next-hop", NULL, -- RMAP_EVENT_FILTER_DELETED); -- return rmap_match_set_hook.no_match_ip_next_hop( -- vty, index, "ip next-hop", argv[idx_word]->arg, -- RMAP_EVENT_FILTER_DELETED); -- } -- return CMD_SUCCESS; --} -- -- --DEFUN (match_ip_next_hop_prefix_list, -- match_ip_next_hop_prefix_list_cmd, -- "match ip next-hop prefix-list WORD", -- MATCH_STR -- IP_STR -- "Match next-hop address of route\n" -- "Match entries of prefix-lists\n" -- "IP prefix-list name\n") --{ -- int idx_word = 4; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.match_ip_next_hop_prefix_list) -- return rmap_match_set_hook.match_ip_next_hop_prefix_list( -- vty, index, "ip next-hop prefix-list", -- argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED); -- return CMD_SUCCESS; --} -- --DEFUN (no_match_ip_next_hop_prefix_list, -- no_match_ip_next_hop_prefix_list_cmd, -- "no match ip next-hop prefix-list [WORD]", -- NO_STR -- MATCH_STR -- IP_STR -- "Match next-hop address of route\n" -- "Match entries of prefix-lists\n" -- "IP prefix-list name\n") --{ -- int idx_word = 5; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.no_match_ip_next_hop) { -- if (argc <= idx_word) -- return rmap_match_set_hook.no_match_ip_next_hop( -- vty, index, "ip next-hop prefix-list", NULL, -- RMAP_EVENT_PLIST_DELETED); -- return rmap_match_set_hook.no_match_ip_next_hop( -- vty, index, "ip next-hop prefix-list", -- argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED); -- } -- return CMD_SUCCESS; --} -- --DEFUN(match_ip_next_hop_type, match_ip_next_hop_type_cmd, -- "match ip next-hop type ", -- MATCH_STR IP_STR -- "Match next-hop address of route\n" -- "Match entries by type\n" -- "Blackhole\n") --{ -- int idx_word = 4; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.match_ip_next_hop_type) -- return rmap_match_set_hook.match_ip_next_hop_type( -- vty, index, "ip next-hop type", argv[idx_word]->arg, -- RMAP_EVENT_MATCH_ADDED); -- return CMD_SUCCESS; --} -- --DEFUN(no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd, -- "no match ip next-hop type []", -- NO_STR MATCH_STR IP_STR -- "Match next-hop address of route\n" -- "Match entries by type\n" -- "Blackhole\n") --{ -- int idx_word = 5; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.no_match_ip_next_hop) { -- if (argc <= idx_word) -- return rmap_match_set_hook.no_match_ip_next_hop( -- vty, index, "ip next-hop type", NULL, -- RMAP_EVENT_MATCH_DELETED); -- return rmap_match_set_hook.no_match_ip_next_hop( -- vty, index, "ip next-hop type", argv[idx_word]->arg, -- RMAP_EVENT_MATCH_DELETED); -- } -- return CMD_SUCCESS; --} -- -- --DEFUN (match_ipv6_address, -- match_ipv6_address_cmd, -- "match ipv6 address WORD", -- MATCH_STR -- IPV6_STR -- "Match IPv6 address of route\n" -- "IPv6 access-list name\n") --{ -- int idx_word = 3; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.match_ipv6_address) -- return rmap_match_set_hook.match_ipv6_address( -- vty, index, "ipv6 address", argv[idx_word]->arg, -- RMAP_EVENT_FILTER_ADDED); -- return CMD_SUCCESS; --} -- --DEFUN (no_match_ipv6_address, -- no_match_ipv6_address_cmd, -- "no match ipv6 address WORD", -- NO_STR -- MATCH_STR -- IPV6_STR -- "Match IPv6 address of route\n" -- "IPv6 access-list name\n") --{ -- int idx_word = 4; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.no_match_ipv6_address) -- return rmap_match_set_hook.no_match_ipv6_address( -- vty, index, "ipv6 address", argv[idx_word]->arg, -- RMAP_EVENT_FILTER_DELETED); -- return CMD_SUCCESS; --} -- -- --DEFUN (match_ipv6_address_prefix_list, -- match_ipv6_address_prefix_list_cmd, -- "match ipv6 address prefix-list WORD", -- MATCH_STR -- IPV6_STR -- "Match address of route\n" -- "Match entries of prefix-lists\n" -- "IP prefix-list name\n") --{ -- int idx_word = 4; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.match_ipv6_address_prefix_list) -- return rmap_match_set_hook.match_ipv6_address_prefix_list( -- vty, index, "ipv6 address prefix-list", -- argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED); -- return CMD_SUCCESS; --} -- --DEFUN (no_match_ipv6_address_prefix_list, -- no_match_ipv6_address_prefix_list_cmd, -- "no match ipv6 address prefix-list WORD", -- NO_STR -- MATCH_STR -- IPV6_STR -- "Match address of route\n" -- "Match entries of prefix-lists\n" -- "IP prefix-list name\n") --{ -- int idx_word = 5; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.no_match_ipv6_address_prefix_list) -- return rmap_match_set_hook.no_match_ipv6_address_prefix_list( -- vty, index, "ipv6 address prefix-list", -- argv[idx_word]->arg, RMAP_EVENT_PLIST_DELETED); -- return CMD_SUCCESS; --} -- --DEFUN(match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd, -- "match ipv6 next-hop type ", -- MATCH_STR IPV6_STR -- "Match next-hop address of route\n" -- "Match entries by type\n" -- "Blackhole\n") --{ -- int idx_word = 4; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.match_ipv6_next_hop_type) -- return rmap_match_set_hook.match_ipv6_next_hop_type( -- vty, index, "ipv6 next-hop type", argv[idx_word]->arg, -- RMAP_EVENT_MATCH_ADDED); -- return CMD_SUCCESS; --} -- --DEFUN(no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd, -- "no match ipv6 next-hop type []", -- NO_STR MATCH_STR IPV6_STR -- "Match address of route\n" -- "Match entries by type\n" -- "Blackhole\n") --{ -- int idx_word = 5; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.no_match_ipv6_next_hop_type) -- return rmap_match_set_hook.no_match_ipv6_next_hop_type( -- vty, index, "ipv6 next-hop type", -- (argc <= idx_word) ? NULL : argv[idx_word]->arg, -- RMAP_EVENT_MATCH_DELETED); -- return CMD_SUCCESS; --} -- --DEFUN (match_metric, -- match_metric_cmd, -- "match metric (0-4294967295)", -- MATCH_STR -- "Match metric of route\n" -- "Metric value\n") --{ -- int idx_number = 2; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.match_metric) -- return rmap_match_set_hook.match_metric(vty, index, "metric", -- argv[idx_number]->arg, -- RMAP_EVENT_MATCH_ADDED); -- return CMD_SUCCESS; --} -- -- --DEFUN (no_match_metric, -- no_match_metric_cmd, -- "no match metric [(0-4294967295)]", -- NO_STR -- MATCH_STR -- "Match metric of route\n" -- "Metric value\n") --{ -- int idx_number = 3; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.no_match_metric) { -- if (argc <= idx_number) -- return rmap_match_set_hook.no_match_metric( -- vty, index, "metric", NULL, -- RMAP_EVENT_MATCH_DELETED); -- return rmap_match_set_hook.no_match_metric( -- vty, index, "metric", argv[idx_number]->arg, -- RMAP_EVENT_MATCH_DELETED); -- } -- return CMD_SUCCESS; --} -- -- --DEFUN (match_tag, -- match_tag_cmd, -- "match tag (1-4294967295)", -- MATCH_STR -- "Match tag of route\n" -- "Tag value\n") --{ -- int idx_number = 2; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.match_tag) -- return rmap_match_set_hook.match_tag(vty, index, "tag", -- argv[idx_number]->arg, -- RMAP_EVENT_MATCH_ADDED); -- return CMD_SUCCESS; --} -- -- --DEFUN (no_match_tag, -- no_match_tag_cmd, -- "no match tag [(1-4294967295)]", -- NO_STR -- MATCH_STR -- "Match tag of route\n" -- "Tag value\n") --{ -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- int idx = 0; -- char *arg = argv_find(argv, argc, "(1-4294967295)", &idx) -- ? argv[idx]->arg -- : NULL; -- -- if (rmap_match_set_hook.no_match_tag) -- return rmap_match_set_hook.no_match_tag( -- vty, index, "tag", arg, RMAP_EVENT_MATCH_DELETED); -- return CMD_SUCCESS; --} -- -- --DEFUN (set_ip_nexthop, -- set_ip_nexthop_cmd, -- "set ip next-hop A.B.C.D", -- SET_STR -- IP_STR -- "Next hop address\n" -- "IP address of next hop\n") --{ -- int idx_ipv4 = 3; -- union sockunion su; -- int ret; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- ret = str2sockunion(argv[idx_ipv4]->arg, &su); -- if (ret < 0) { -- vty_out(vty, "%% Malformed nexthop address\n"); -- return CMD_WARNING_CONFIG_FAILED; -- } -- if (su.sin.sin_addr.s_addr == 0 -- || IPV4_CLASS_DE(ntohl(su.sin.sin_addr.s_addr))) { -- vty_out(vty, -- "%% nexthop address cannot be 0.0.0.0, multicast or reserved\n"); -- return CMD_WARNING_CONFIG_FAILED; -- } -- -- if (rmap_match_set_hook.set_ip_nexthop) -- return rmap_match_set_hook.set_ip_nexthop( -- vty, index, "ip next-hop", argv[idx_ipv4]->arg); -- return CMD_SUCCESS; --} -- -- --DEFUN (no_set_ip_nexthop, -- no_set_ip_nexthop_cmd, -- "no set ip next-hop [A.B.C.D]", -- NO_STR -- SET_STR -- IP_STR -- "Next hop address\n" -- "IP address of next hop\n") --{ -- int idx = 0; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- const char *arg = NULL; -- -- if (argv_find(argv, argc, "A.B.C.D", &idx)) -- arg = argv[idx]->arg; -- -- if (rmap_match_set_hook.no_set_ip_nexthop) -- return rmap_match_set_hook.no_set_ip_nexthop( -- vty, index, "ip next-hop", arg); -- -- return CMD_SUCCESS; --} -- -- --DEFUN (set_ipv6_nexthop_local, -- set_ipv6_nexthop_local_cmd, -- "set ipv6 next-hop local X:X::X:X", -- SET_STR -- IPV6_STR -- "IPv6 next-hop address\n" -- "IPv6 local address\n" -- "IPv6 address of next hop\n") --{ -- int idx_ipv6 = 4; -- struct in6_addr addr; -- int ret; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr); -- if (!ret) { -- vty_out(vty, "%% Malformed nexthop address\n"); -- return CMD_WARNING_CONFIG_FAILED; -- } -- if (!IN6_IS_ADDR_LINKLOCAL(&addr)) { -- vty_out(vty, "%% Invalid link-local nexthop address\n"); -- return CMD_WARNING_CONFIG_FAILED; -- } -- -- if (rmap_match_set_hook.set_ipv6_nexthop_local) -- return rmap_match_set_hook.set_ipv6_nexthop_local( -- vty, index, "ipv6 next-hop local", argv[idx_ipv6]->arg); -- return CMD_SUCCESS; --} -- -- --DEFUN (no_set_ipv6_nexthop_local, -- no_set_ipv6_nexthop_local_cmd, -- "no set ipv6 next-hop local [X:X::X:X]", -- NO_STR -- SET_STR -- IPV6_STR -- "IPv6 next-hop address\n" -- "IPv6 local address\n" -- "IPv6 address of next hop\n") --{ -- int idx_ipv6 = 5; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.no_set_ipv6_nexthop_local) { -- if (argc <= idx_ipv6) -- return rmap_match_set_hook.no_set_ipv6_nexthop_local( -- vty, index, "ipv6 next-hop local", NULL); -- return rmap_match_set_hook.no_set_ipv6_nexthop_local( -- vty, index, "ipv6 next-hop local", argv[5]->arg); -- } -- return CMD_SUCCESS; --} -- --DEFUN (set_metric, -- set_metric_cmd, -- "set metric <(0-4294967295)|rtt|+rtt|-rtt|+metric|-metric>", -- SET_STR -- "Metric value for destination routing protocol\n" -- "Metric value\n" -- "Assign round trip time\n" -- "Add round trip time\n" -- "Subtract round trip time\n" -- "Add metric\n" -- "Subtract metric\n") --{ -- int idx_number = 2; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- const char *pass = (argv[idx_number]->type == RANGE_TKN) -- ? argv[idx_number]->arg -- : argv[idx_number]->text; -- -- if (rmap_match_set_hook.set_metric) -- return rmap_match_set_hook.set_metric(vty, index, "metric", -- pass); -- return CMD_SUCCESS; --} -- -- --DEFUN (no_set_metric, -- no_set_metric_cmd, -- "no set metric [(0-4294967295)]", -- NO_STR -- SET_STR -- "Metric value for destination routing protocol\n" -- "Metric value\n") --{ -- int idx_number = 3; -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- if (rmap_match_set_hook.no_set_metric) { -- if (argc <= idx_number) -- return rmap_match_set_hook.no_set_metric( -- vty, index, "metric", NULL); -- return rmap_match_set_hook.no_set_metric(vty, index, "metric", -- argv[idx_number]->arg); -- } -- return CMD_SUCCESS; --} -- -- --DEFUN (set_tag, -- set_tag_cmd, -- "set tag (1-4294967295)", -- SET_STR -- "Tag value for routing protocol\n" -- "Tag value\n") --{ -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- int idx_number = 2; -- if (rmap_match_set_hook.set_tag) -- return rmap_match_set_hook.set_tag(vty, index, "tag", -- argv[idx_number]->arg); -- return CMD_SUCCESS; --} -- -- --DEFUN (no_set_tag, -- no_set_tag_cmd, -- "no set tag [(1-4294967295)]", -- NO_STR -- SET_STR -- "Tag value for routing protocol\n" -- "Tag value\n") --{ -- VTY_DECLVAR_CONTEXT(route_map_index, index); -- -- int idx_number = 3; -- if (rmap_match_set_hook.no_set_tag) { -- if (argc <= idx_number) -- return rmap_match_set_hook.no_set_tag(vty, index, "tag", -- NULL); -- return rmap_match_set_hook.no_set_tag(vty, index, "tag", -- argv[idx_number]->arg); -- } -- return CMD_SUCCESS; --} -- -- --DEFUN_NOSH (route_map, -- route_map_cmd, -- "route-map WORD (1-65535)", -- "Create route-map or enter route-map command mode\n" -- "Route map tag\n" -- "Route map denies set operations\n" -- "Route map permits set operations\n" -- "Sequence to insert to/delete from existing route-map entry\n") --{ -- int idx_word = 1; -- int idx_permit_deny = 2; -- int idx_number = 3; -- struct route_map *map; -- struct route_map_index *index; -- char *endptr = NULL; -- int permit = -- argv[idx_permit_deny]->arg[0] == 'p' ? RMAP_PERMIT : RMAP_DENY; -- unsigned long pref = strtoul(argv[idx_number]->arg, &endptr, 10); -- const char *mapname = argv[idx_word]->arg; -- -- /* Get route map. */ -- map = route_map_get(mapname); -- index = route_map_index_get(map, permit, pref); -- -- VTY_PUSH_CONTEXT(RMAP_NODE, index); -- return CMD_SUCCESS; --} -- --DEFUN (no_route_map_all, -- no_route_map_all_cmd, -- "no route-map WORD", -- NO_STR -- "Create route-map or enter route-map command mode\n" -- "Route map tag\n") --{ -- int idx_word = 2; -- const char *mapname = argv[idx_word]->arg; -- struct route_map *map; -- -- map = route_map_lookup_by_name(mapname); -- if (map == NULL) { -- vty_out(vty, "%% Could not find route-map %s\n", mapname); -- return CMD_WARNING_CONFIG_FAILED; -- } -- -- route_map_delete(map); -- -- return CMD_SUCCESS; --} -- --DEFUN (no_route_map, -- no_route_map_cmd, -- "no route-map WORD (1-65535)", -- NO_STR -- "Create route-map or enter route-map command mode\n" -- "Route map tag\n" -- "Route map denies set operations\n" -- "Route map permits set operations\n" -- "Sequence to insert to/delete from existing route-map entry\n") --{ -- int idx_word = 2; -- int idx_permit_deny = 3; -- int idx_number = 4; -- struct route_map *map; -- struct route_map_index *index; -- char *endptr = NULL; -- int permit = strmatch(argv[idx_permit_deny]->text, "permit") -- ? RMAP_PERMIT -- : RMAP_DENY; -- const char *prefstr = argv[idx_number]->arg; -- const char *mapname = argv[idx_word]->arg; -- unsigned long pref = strtoul(prefstr, &endptr, 10); -- -- /* Existence check. */ -- map = route_map_lookup_by_name(mapname); -- if (map == NULL) { -- vty_out(vty, "%% Could not find route-map %s\n", mapname); -- return CMD_WARNING_CONFIG_FAILED; -- } -- -- /* Lookup route map index. */ -- index = route_map_index_lookup(map, permit, pref); -- if (index == NULL) { -- vty_out(vty, "%% Could not find route-map entry %s %s\n", -- mapname, prefstr); -- return CMD_WARNING_CONFIG_FAILED; -- } -- -- /* Delete index from route map. */ -- route_map_index_delete(index, 1); -- -- /* If this route rule is the last one, delete route map itself. */ -- if (route_map_empty(map)) -- route_map_delete(map); -- -- return CMD_SUCCESS; --} -- --DEFUN (rmap_onmatch_next, -- rmap_onmatch_next_cmd, -- "on-match next", -- "Exit policy on matches\n" -- "Next clause\n") --{ -- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); -- -- if (index) { -- if (index->type == RMAP_DENY) { -- /* Under a deny clause, match means it's finished. No -- * need to set next */ -- vty_out(vty, -- "on-match next not supported under route-map deny\n"); -- return CMD_WARNING_CONFIG_FAILED; -- } -- index->exitpolicy = RMAP_NEXT; -- } -- return CMD_SUCCESS; --} -- --DEFUN (no_rmap_onmatch_next, -- no_rmap_onmatch_next_cmd, -- "no on-match next", -- NO_STR -- "Exit policy on matches\n" -- "Next clause\n") --{ -- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); -- -- if (index) -- index->exitpolicy = RMAP_EXIT; -- -- return CMD_SUCCESS; --} -- --DEFUN (rmap_onmatch_goto, -- rmap_onmatch_goto_cmd, -- "on-match goto (1-65535)", -- "Exit policy on matches\n" -- "Goto Clause number\n" -- "Number\n") --{ -- int idx = 0; -- char *num = argv_find(argv, argc, "(1-65535)", &idx) ? argv[idx]->arg -- : NULL; -- -- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); -- int d = 0; -- -- if (index) { -- if (index->type == RMAP_DENY) { -- /* Under a deny clause, match means it's finished. No -- * need to go anywhere */ -- vty_out(vty, -- "on-match goto not supported under route-map deny\n"); -- return CMD_WARNING_CONFIG_FAILED; -- } -- -- if (num) -- d = strtoul(num, NULL, 10); -- else -- d = index->pref + 1; -- -- if (d <= index->pref) { -- /* Can't allow you to do that, Dave */ -- vty_out(vty, "can't jump backwards in route-maps\n"); -- return CMD_WARNING_CONFIG_FAILED; -- } else { -- index->exitpolicy = RMAP_GOTO; -- index->nextpref = d; -- } -- } -- return CMD_SUCCESS; --} -- --DEFUN (no_rmap_onmatch_goto, -- no_rmap_onmatch_goto_cmd, -- "no on-match goto", -- NO_STR -- "Exit policy on matches\n" -- "Goto Clause number\n") --{ -- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); -- -- if (index) -- index->exitpolicy = RMAP_EXIT; -- -- return CMD_SUCCESS; --} -- --/* Cisco/GNU Zebra compatibility aliases */ --/* ALIAS_FIXME */ --DEFUN (rmap_continue, -- rmap_continue_cmd, -- "continue (1-65535)", -- "Continue on a different entry within the route-map\n" -- "Route-map entry sequence number\n") --{ -- return rmap_onmatch_goto(self, vty, argc, argv); --} -- --/* ALIAS_FIXME */ --DEFUN (no_rmap_continue, -- no_rmap_continue_cmd, -- "no continue [(1-65535)]", -- NO_STR -- "Continue on a different entry within the route-map\n" -- "Route-map entry sequence number\n") --{ -- return no_rmap_onmatch_goto(self, vty, argc, argv); --} -- - static void clear_route_map_helper(struct route_map *map) - { - struct route_map_index *index; -@@ -2937,89 +2064,6 @@ DEFUN (rmap_show_unused, - return vty_show_unused_route_map(vty); - } - --DEFUN (rmap_call, -- rmap_call_cmd, -- "call WORD", -- "Jump to another Route-Map after match+set\n" -- "Target route-map name\n") --{ -- int idx_word = 1; -- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); -- const char *rmap = argv[idx_word]->arg; -- -- assert(index); -- -- /* If "call" is invoked with the same route-map name as -- * the one previously configured then, ignore the duplicate -- * configuration. -- */ -- if (index->nextrm && (strcmp(index->nextrm, rmap) == 0)) -- return CMD_SUCCESS; -- -- if (index->nextrm) { -- route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED, -- index->nextrm, index->map->name); -- XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm); -- } -- index->nextrm = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); -- -- /* Execute event hook. */ -- route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, index->nextrm, -- index->map->name); -- return CMD_SUCCESS; --} -- --DEFUN (no_rmap_call, -- no_rmap_call_cmd, -- "no call", -- NO_STR -- "Jump to another Route-Map after match+set\n") --{ -- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); -- -- if (index->nextrm) { -- route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED, -- index->nextrm, index->map->name); -- XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm); -- index->nextrm = NULL; -- } -- -- return CMD_SUCCESS; --} -- --DEFUN (rmap_description, -- rmap_description_cmd, -- "description LINE...", -- "Route-map comment\n" -- "Comment describing this route-map rule\n") --{ -- int idx_line = 1; -- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); -- -- if (index) { -- if (index->description) -- XFREE(MTYPE_TMP, index->description); -- index->description = argv_concat(argv, argc, idx_line); -- } -- return CMD_SUCCESS; --} -- --DEFUN (no_rmap_description, -- no_rmap_description_cmd, -- "no description", -- NO_STR -- "Route-map comment\n") --{ -- struct route_map_index *index = VTY_GET_CONTEXT(route_map_index); -- -- if (index) { -- if (index->description) -- XFREE(MTYPE_TMP, index->description); -- index->description = NULL; -- } -- return CMD_SUCCESS; --} -- - DEFUN (debug_rmap, - debug_rmap_cmd, - "debug route-map", -@@ -3045,59 +2089,6 @@ DEFUN (no_debug_rmap, - static struct cmd_node rmap_debug_node = {RMAP_DEBUG_NODE, "", 1}; - - /* Configuration write function. */ --static int route_map_config_write(struct vty *vty) --{ -- struct route_map *map; -- struct route_map_index *index; -- struct route_map_rule *rule; -- int first = 1; -- int write = 0; -- struct listnode *ln; -- struct list *maplist = list_new(); -- -- for (map = route_map_master.head; map; map = map->next) -- listnode_add(maplist, map); -- -- list_sort(maplist, sort_route_map); -- -- for (ALL_LIST_ELEMENTS_RO(maplist, ln, map)) -- for (index = map->head; index; index = index->next) { -- if (!first) -- vty_out(vty, "!\n"); -- else -- first = 0; -- -- vty_out(vty, "route-map %s %s %d\n", map->name, -- route_map_type_str(index->type), index->pref); -- -- if (index->description) -- vty_out(vty, " description %s\n", -- index->description); -- -- for (rule = index->match_list.head; rule; -- rule = rule->next) -- vty_out(vty, " match %s %s\n", rule->cmd->str, -- rule->rule_str ? rule->rule_str : ""); -- -- for (rule = index->set_list.head; rule; -- rule = rule->next) -- vty_out(vty, " set %s %s\n", rule->cmd->str, -- rule->rule_str ? rule->rule_str : ""); -- if (index->nextrm) -- vty_out(vty, " call %s\n", index->nextrm); -- if (index->exitpolicy == RMAP_GOTO) -- vty_out(vty, " on-match goto %d\n", -- index->nextpref); -- if (index->exitpolicy == RMAP_NEXT) -- vty_out(vty, " on-match next\n"); -- -- write++; -- } -- -- list_delete(&maplist); -- return write; --} -- - static int rmap_config_write_debug(struct vty *vty) - { - int write = 0; -@@ -3110,9 +2101,6 @@ static int rmap_config_write_debug(struct vty *vty) - return write; - } - --/* Route map node structure. */ --static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1}; -- - /* Common route map rules */ - - void *route_map_rule_tag_compile(const char *arg) -@@ -3171,14 +2159,6 @@ void route_map_finish(void) - route_map_master_hash = NULL; - } - --static void rmap_autocomplete(vector comps, struct cmd_token *token) --{ -- struct route_map *map; -- -- for (map = route_map_master.head; map; map = map->next) -- vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name)); --} -- - /* Increment the use_count counter while attaching the route map */ - void route_map_counter_increment(struct route_map *map) - { -@@ -3196,14 +2176,6 @@ void route_map_counter_decrement(struct route_map *map) - } - } - --static const struct cmd_variable_handler rmap_var_handlers[] = { -- {/* "route-map WORD" */ -- .varname = "route_map", -- .completions = rmap_autocomplete}, -- {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete}, -- {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete}, -- {.completions = NULL}}; -- - /* Initialization of route map vector. */ - void route_map_init(void) - { -@@ -3221,43 +2193,17 @@ void route_map_init(void) - 8, route_map_dep_hash_make_key, route_map_dep_hash_cmp, - "Route Map Dep Hash"); - -- cmd_variable_handler_register(rmap_var_handlers); -- - rmap_debug = false; - -- /* Install route map top node. */ -- install_node(&rmap_node, route_map_config_write); -+ route_map_cli_init(); - -+ /* Install route map top node. */ - install_node(&rmap_debug_node, rmap_config_write_debug); - - /* Install route map commands. */ -- install_default(RMAP_NODE); -- install_element(CONFIG_NODE, &route_map_cmd); -- install_element(CONFIG_NODE, &no_route_map_cmd); -- install_element(CONFIG_NODE, &no_route_map_all_cmd); -- - install_element(CONFIG_NODE, &debug_rmap_cmd); - install_element(CONFIG_NODE, &no_debug_rmap_cmd); - -- /* Install the on-match stuff */ -- install_element(RMAP_NODE, &route_map_cmd); -- install_element(RMAP_NODE, &rmap_onmatch_next_cmd); -- install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd); -- install_element(RMAP_NODE, &rmap_onmatch_goto_cmd); -- install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd); -- install_element(RMAP_NODE, &rmap_continue_cmd); -- install_element(RMAP_NODE, &no_rmap_continue_cmd); -- -- /* Install the continue stuff (ALIAS of on-match). */ -- -- /* Install the call stuff. */ -- install_element(RMAP_NODE, &rmap_call_cmd); -- install_element(RMAP_NODE, &no_rmap_call_cmd); -- -- /* Install description commands. */ -- install_element(RMAP_NODE, &rmap_description_cmd); -- install_element(RMAP_NODE, &no_rmap_description_cmd); -- - /* Install show command */ - install_element(ENABLE_NODE, &rmap_clear_counters_cmd); - -@@ -3266,49 +2212,4 @@ void route_map_init(void) - - install_element(ENABLE_NODE, &debug_rmap_cmd); - install_element(ENABLE_NODE, &no_debug_rmap_cmd); -- -- install_element(RMAP_NODE, &match_interface_cmd); -- install_element(RMAP_NODE, &no_match_interface_cmd); -- -- install_element(RMAP_NODE, &match_ip_address_cmd); -- install_element(RMAP_NODE, &no_match_ip_address_cmd); -- -- install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd); -- install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd); -- -- install_element(RMAP_NODE, &match_ip_next_hop_cmd); -- install_element(RMAP_NODE, &no_match_ip_next_hop_cmd); -- -- install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); -- install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); -- -- install_element(RMAP_NODE, &match_ip_next_hop_type_cmd); -- install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd); -- -- install_element(RMAP_NODE, &match_ipv6_address_cmd); -- install_element(RMAP_NODE, &no_match_ipv6_address_cmd); -- -- install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd); -- install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd); -- -- install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd); -- install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd); -- -- install_element(RMAP_NODE, &match_metric_cmd); -- install_element(RMAP_NODE, &no_match_metric_cmd); -- -- install_element(RMAP_NODE, &match_tag_cmd); -- install_element(RMAP_NODE, &no_match_tag_cmd); -- -- install_element(RMAP_NODE, &set_ip_nexthop_cmd); -- install_element(RMAP_NODE, &no_set_ip_nexthop_cmd); -- -- install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd); -- install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd); -- -- install_element(RMAP_NODE, &set_metric_cmd); -- install_element(RMAP_NODE, &no_set_metric_cmd); -- -- install_element(RMAP_NODE, &set_tag_cmd); -- install_element(RMAP_NODE, &no_set_tag_cmd); - } -diff --git a/lib/routemap.h b/lib/routemap.h -index d9e7f73f81..70e150c981 100644 ---- a/lib/routemap.h -+++ b/lib/routemap.h -@@ -666,8 +666,27 @@ int lib_route_map_entry_match_destroy(enum nb_event event, - const struct lyd_node *dnode); - int lib_route_map_entry_set_destroy(enum nb_event event, - const struct lyd_node *dnode); -+ - extern const struct frr_yang_module_info frr_route_map_info; - -+/* routemap_cli.c */ -+extern void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, -+ bool show_defaults); -+extern void route_map_instance_show_end(struct vty *vty, -+ struct lyd_node *dnode); -+extern void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, -+ bool show_defaults); -+extern void route_map_action_show(struct vty *vty, struct lyd_node *dnode, -+ bool show_defaults); -+extern void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode, -+ bool show_defaults); -+extern void route_map_call_show(struct vty *vty, struct lyd_node *dnode, -+ bool show_defaults); -+extern void route_map_description_show(struct vty *vty, -+ struct lyd_node *dnode, -+ bool show_defaults); -+extern void route_map_cli_init(void); -+ - #ifdef __cplusplus - } - #endif -diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c -new file mode 100644 -index 0000000000..987693c961 ---- /dev/null -+++ b/lib/routemap_cli.c -@@ -0,0 +1,1075 @@ -+/* -+ * Route map northbound CLI implementation. -+ * -+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF") -+ * Rafael Zalamena -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301 USA. -+ */ -+ -+#include -+ -+#include "lib/command.h" -+#include "lib/northbound_cli.h" -+#include "lib/routemap.h" -+ -+#ifndef VTYSH_EXTRACT_PL -+#include "lib/routemap_cli_clippy.c" -+#endif /* VTYSH_EXTRACT_PL */ -+ -+#define ROUTE_MAP_CMD_STR \ -+ "Create route-map or enter route-map command mode\n" \ -+ "Route map tag\n" -+#define ROUTE_MAP_OP_CMD_STR \ -+ "Route map denies set operations\n" \ -+ "Route map permits set operations\n" -+#define ROUTE_MAP_SEQUENCE_CMD_STR \ -+ "Sequence to insert to/delete from existing route-map entry\n" -+ -+DEFPY_NOSH( -+ route_map, route_map_cmd, -+ "route-map WORD$name $action (1-65535)$sequence", -+ ROUTE_MAP_CMD_STR -+ ROUTE_MAP_OP_CMD_STR -+ ROUTE_MAP_SEQUENCE_CMD_STR) -+{ -+ char xpath_action[XPATH_MAXLEN + 64]; -+ char xpath_index[XPATH_MAXLEN + 32]; -+ char xpath[XPATH_MAXLEN]; -+ int rv; -+ -+ snprintf(xpath, sizeof(xpath), -+ "/frr-route-map:lib/route-map[name='%s']", name); -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ -+ snprintf(xpath_index, sizeof(xpath_index), "%s/entry[sequence='%lu']", -+ xpath, sequence); -+ nb_cli_enqueue_change(vty, xpath_index, NB_OP_CREATE, NULL); -+ -+ snprintf(xpath_action, sizeof(xpath_action), "%s/action", xpath_index); -+ nb_cli_enqueue_change(vty, xpath_action, NB_OP_MODIFY, action); -+ -+ rv = nb_cli_apply_changes(vty, NULL); -+ if (rv == CMD_SUCCESS) -+ VTY_PUSH_XPATH(RMAP_NODE, xpath_index); -+ -+ return rv; -+} -+ -+DEFPY( -+ no_route_map_all, no_route_map_all_cmd, -+ "no route-map WORD$name", -+ NO_STR -+ ROUTE_MAP_CMD_STR) -+{ -+ char xpath[XPATH_MAXLEN]; -+ -+ snprintf(xpath, sizeof(xpath), -+ "/frr-route-map:lib/route-map[name='%s']", name); -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_route_map, no_route_map_cmd, -+ "no route-map WORD$name $action (1-65535)$sequence", -+ NO_STR -+ ROUTE_MAP_CMD_STR -+ ROUTE_MAP_OP_CMD_STR -+ ROUTE_MAP_SEQUENCE_CMD_STR) -+{ -+ char xpath[XPATH_MAXLEN]; -+ -+ snprintf(xpath, sizeof(xpath), -+ "/frr-route-map:lib/route-map[name='%s']/entry[sequence='%lu']", -+ name, sequence); -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, -+ bool show_defaults) -+{ -+ const char *name = yang_dnode_get_string(dnode, "../name"); -+ const char *action = yang_dnode_get_string(dnode, "./action"); -+ const char *sequence = yang_dnode_get_string(dnode, "./sequence"); -+ -+ vty_out(vty, "route-map %s %s %s\n", name, action, sequence); -+} -+ -+void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode) -+{ -+ vty_out(vty, "!\n"); -+} -+ -+DEFPY( -+ match_interface, match_interface_cmd, -+ "match interface IFNAME", -+ MATCH_STR -+ "Match first hop interface of route\n" -+ INTERFACE_STR) -+{ -+ const char *xpath = "./match-condition[condition='interface']"; -+ char xpath_value[XPATH_MAXLEN]; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ snprintf(xpath_value, sizeof(xpath_value), "%s/interface", xpath); -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ifname); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_match_interface, no_match_interface_cmd, -+ "no match interface [IFNAME]", -+ NO_STR -+ MATCH_STR -+ "Match first hop interface of route\n" -+ INTERFACE_STR) -+{ -+ const char *xpath = "./match-condition[condition='interface']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ match_ip_address, match_ip_address_cmd, -+ "match ip address <(1-199)$acll|(1300-2699)$aclh|WORD$name>", -+ MATCH_STR -+ IP_STR -+ "Match address of route\n" -+ "IP access-list number\n" -+ "IP access-list number (expanded range)\n" -+ "IP Access-list name\n") -+{ -+ const char *xpath = "./match-condition[condition='ipv4-address-list']"; -+ char xpath_value[XPATH_MAXLEN + 32]; -+ int acln = acll ? acll : aclh; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ if (name) { -+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", -+ xpath); -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); -+ } else /* if (acll || aclh) */ { -+ if ((acln >= 1 && acln <= 99) -+ || (acln >= 1300 && acln <= 1999)) { -+ snprintf(xpath_value, sizeof(xpath_value), -+ "%s/access-list-num", xpath); -+ } else { -+ /* -+ * if ((acln >= 100 && acln <= 199) -+ * || (acln >= 2000 && acln <= 2699)) -+ */ -+ snprintf(xpath_value, sizeof(xpath_value), -+ "%s/access-list-num-extended", xpath); -+ } -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, -+ acll_str ? acll_str : aclh_str); -+ } -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_match_ip_address, no_match_ip_address_cmd, -+ "no match ip address [<(1-199)|(1300-2699)|WORD>]", -+ NO_STR -+ MATCH_STR -+ IP_STR -+ "Match address of route\n" -+ "IP access-list number\n" -+ "IP access-list number (expanded range)\n" -+ "IP Access-list name\n") -+{ -+ const char *xpath = "./match-condition[condition='ipv4-address-list']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ match_ip_address_prefix_list, -+ match_ip_address_prefix_list_cmd, -+ "match ip address prefix-list WORD$name", -+ MATCH_STR -+ IP_STR -+ "Match address of route\n" -+ "Match entries of prefix-lists\n" -+ "IP prefix-list name\n") -+{ -+ const char *xpath = "./match-condition[condition='ipv4-prefix-list']"; -+ char xpath_value[XPATH_MAXLEN]; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd, -+ "no match ip address prefix-list [WORD]", -+ NO_STR -+ MATCH_STR -+ IP_STR -+ "Match address of route\n" -+ "Match entries of prefix-lists\n" -+ "IP prefix-list name\n") -+{ -+ const char *xpath = "./match-condition[condition='ipv4-prefix-list']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ match_ip_next_hop, match_ip_next_hop_cmd, -+ "match ip next-hop <(1-199)$acll|(1300-2699)$aclh|WORD$name>", -+ MATCH_STR -+ IP_STR -+ "Match next-hop address of route\n" -+ "IP access-list number\n" -+ "IP access-list number (expanded range)\n" -+ "IP Access-list name\n") -+{ -+ const char *xpath = "./match-condition[condition='ipv4-next-hop-list']"; -+ char xpath_value[XPATH_MAXLEN + 32]; -+ int acln = acll ? acll : aclh; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ if (name) { -+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", -+ xpath); -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); -+ } else /* if (acll || aclh) */ { -+ if ((acln >= 1 && acln <= 99) -+ || (acln >= 1300 && acln <= 1999)) { -+ snprintf(xpath_value, sizeof(xpath_value), -+ "%s/access-list-num", xpath); -+ } else { -+ /* -+ * if ((acln >= 100 && acln <= 199) -+ * || (acln >= 2000 && acln <= 2699)) -+ */ -+ snprintf(xpath_value, sizeof(xpath_value), -+ "%s/access-list-num-extended", xpath); -+ } -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, -+ acll_str ? acll_str : aclh_str); -+ } -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_match_ip_next_hop, no_match_ip_next_hop_cmd, -+ "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]", -+ NO_STR -+ MATCH_STR -+ IP_STR -+ "Match address of route\n" -+ "IP access-list number\n" -+ "IP access-list number (expanded range)\n" -+ "IP Access-list name\n") -+{ -+ const char *xpath = "./match-condition[condition='ipv4-next-hop-list']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ match_ip_next_hop_prefix_list, -+ match_ip_next_hop_prefix_list_cmd, -+ "match ip next-hop prefix-list WORD$name", -+ MATCH_STR -+ IP_STR -+ "Match next-hop address of route\n" -+ "Match entries of prefix-lists\n" -+ "IP prefix-list name\n") -+{ -+ const char *xpath = -+ "./match-condition[condition='ipv4-next-hop-prefix-list']"; -+ char xpath_value[XPATH_MAXLEN]; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_match_ip_next_hop_prefix_list, -+ no_match_ip_next_hop_prefix_list_cmd, -+ "no match ip next-hop prefix-list [WORD]", -+ NO_STR -+ MATCH_STR -+ IP_STR -+ "Match next-hop address of route\n" -+ "Match entries of prefix-lists\n" -+ "IP prefix-list name\n") -+{ -+ const char *xpath = -+ "./match-condition[condition='ipv4-next-hop-prefix-list']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ match_ip_next_hop_type, match_ip_next_hop_type_cmd, -+ "match ip next-hop type $type", -+ MATCH_STR -+ IP_STR -+ "Match next-hop address of route\n" -+ "Match entries by type\n" -+ "Blackhole\n") -+{ -+ const char *xpath = "./match-condition[condition='ipv4-next-hop-type']"; -+ char xpath_value[XPATH_MAXLEN]; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-next-hop-type", -+ xpath); -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd, -+ "no match ip next-hop type []", -+ NO_STR MATCH_STR IP_STR -+ "Match next-hop address of route\n" -+ "Match entries by type\n" -+ "Blackhole\n") -+{ -+ const char *xpath = "./match-condition[condition='ipv4-next-hop-type']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ match_ipv6_address, match_ipv6_address_cmd, -+ "match ipv6 address WORD$name", -+ MATCH_STR -+ IPV6_STR -+ "Match IPv6 address of route\n" -+ "IPv6 access-list name\n") -+{ -+ const char *xpath = "./match-condition[condition='ipv6-address-list']"; -+ char xpath_value[XPATH_MAXLEN]; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_match_ipv6_address, no_match_ipv6_address_cmd, -+ "no match ipv6 address [WORD]", -+ NO_STR -+ MATCH_STR -+ IPV6_STR -+ "Match IPv6 address of route\n" -+ "IPv6 access-list name\n") -+{ -+ const char *xpath = "./match-condition[condition='ipv6-address-list']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ match_ipv6_address_prefix_list, match_ipv6_address_prefix_list_cmd, -+ "match ipv6 address prefix-list WORD$name", -+ MATCH_STR -+ IPV6_STR -+ "Match address of route\n" -+ "Match entries of prefix-lists\n" -+ "IP prefix-list name\n") -+{ -+ const char *xpath = "./match-condition[condition='ipv6-prefix-list']"; -+ char xpath_value[XPATH_MAXLEN]; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_match_ipv6_address_prefix_list, -+ no_match_ipv6_address_prefix_list_cmd, -+ "no match ipv6 address prefix-list [WORD]", -+ NO_STR -+ MATCH_STR -+ IPV6_STR -+ "Match address of route\n" -+ "Match entries of prefix-lists\n" -+ "IP prefix-list name\n") -+{ -+ const char *xpath = "./match-condition[condition='ipv6-prefix-list']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd, -+ "match ipv6 next-hop type $type", -+ MATCH_STR IPV6_STR -+ "Match next-hop address of route\n" -+ "Match entries by type\n" -+ "Blackhole\n") -+{ -+ const char *xpath = "./match-condition[condition='ipv6-next-hop-type']"; -+ char xpath_value[XPATH_MAXLEN]; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-next-hop-type", -+ xpath); -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd, -+ "no match ipv6 next-hop type []", -+ NO_STR MATCH_STR IPV6_STR -+ "Match address of route\n" -+ "Match entries by type\n" -+ "Blackhole\n") -+{ -+ const char *xpath = "./match-condition[condition='ipv6-next-hop-type']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ match_metric, match_metric_cmd, -+ "match metric (0-4294967295)$metric", -+ MATCH_STR -+ "Match metric of route\n" -+ "Metric value\n") -+{ -+ const char *xpath = "./match-condition[condition='metric']"; -+ char xpath_value[XPATH_MAXLEN]; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ snprintf(xpath_value, sizeof(xpath_value), "%s/metric", xpath); -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, metric_str); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_match_metric, no_match_metric_cmd, -+ "no match metric [(0-4294967295)]", -+ NO_STR -+ MATCH_STR -+ "Match metric of route\n" -+ "Metric value\n") -+{ -+ const char *xpath = "./match-condition[condition='metric']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ match_tag, match_tag_cmd, -+ "match tag (1-4294967295)$tag", -+ MATCH_STR -+ "Match tag of route\n" -+ "Tag value\n") -+{ -+ const char *xpath = "./match-condition[condition='tag']"; -+ char xpath_value[XPATH_MAXLEN]; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath); -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_match_tag, no_match_tag_cmd, -+ "no match tag [(1-4294967295)]", -+ NO_STR -+ MATCH_STR -+ "Match tag of route\n" -+ "Tag value\n") -+{ -+ const char *xpath = "./match-condition[condition='tag']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, -+ bool show_defaults) -+{ -+ int condition = yang_dnode_get_enum(dnode, "./condition"); -+ struct lyd_node *ln; -+ const char *acl; -+ -+ switch (condition) { -+ case 0: /* interface */ -+ vty_out(vty, " match interface %s\n", -+ yang_dnode_get_string(dnode, "./interface")); -+ break; -+ case 1: /* ipv4-address-list */ -+ case 3: /* ipv4-next-hop-list */ -+ acl = NULL; -+ if ((ln = yang_dnode_get(dnode, "./list-name")) != NULL) -+ acl = yang_dnode_get_string(ln, NULL); -+ else if ((ln = yang_dnode_get(dnode, "./access-list-num")) -+ != NULL) -+ acl = yang_dnode_get_string(ln, NULL); -+ else if ((ln = yang_dnode_get(dnode, -+ "./access-list-num-extended")) -+ != NULL) -+ acl = yang_dnode_get_string(ln, NULL); -+ -+ assert(acl); -+ -+ switch (condition) { -+ case 1: -+ vty_out(vty, " match ip address %s\n", acl); -+ break; -+ case 3: -+ vty_out(vty, " match ip next-hop %s\n", acl); -+ break; -+ } -+ break; -+ case 2: /* ipv4-prefix-list */ -+ vty_out(vty, " match ip address prefix-list %s\n", -+ yang_dnode_get_string(dnode, "./list-name")); -+ break; -+ case 4: /* ipv4-next-hop-prefix-list */ -+ vty_out(vty, " match ip next-hop prefix-list %s\n", -+ yang_dnode_get_string(dnode, "./list-name")); -+ break; -+ case 5: /* ipv4-next-hop-type */ -+ vty_out(vty, " match ip next-hop type %s\n", -+ yang_dnode_get_string(dnode, "./ipv4-next-hop-type")); -+ break; -+ case 6: /* ipv6-address-list */ -+ vty_out(vty, " match ipv6 address %s\n", -+ yang_dnode_get_string(dnode, "./list-name")); -+ break; -+ case 7: /* ipv6-prefix-list */ -+ vty_out(vty, " match ipv6 address prefix-list %s\n", -+ yang_dnode_get_string(dnode, "./list-name")); -+ break; -+ case 8: /* ipv6-next-hop-type */ -+ vty_out(vty, " match ipv6 next-hop type %s\n", -+ yang_dnode_get_string(dnode, "./ipv6-next-hop-type")); -+ break; -+ case 9: /* metric */ -+ vty_out(vty, " match metric %s\n", -+ yang_dnode_get_string(dnode, "./metric")); -+ break; -+ case 10: /* tag */ -+ vty_out(vty, " match tag %s\n", -+ yang_dnode_get_string(dnode, "./tag")); -+ break; -+ case 100: -+ /* NOTHING: custom field, should be handled by daemon. */ -+ break; -+ } -+} -+ -+DEFPY( -+ set_ip_nexthop, set_ip_nexthop_cmd, -+ "set ip next-hop A.B.C.D$addr", -+ SET_STR -+ IP_STR -+ "Next hop address\n" -+ "IP address of next hop\n") -+{ -+ const char *xpath = "./set-action[action='ipv4-next-hop']"; -+ char xpath_value[XPATH_MAXLEN]; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-address", xpath); -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_set_ip_nexthop, no_set_ip_nexthop_cmd, -+ "no set ip next-hop [A.B.C.D]", -+ NO_STR -+ SET_STR -+ IP_STR -+ "Next hop address\n" -+ "IP address of next hop\n") -+{ -+ const char *xpath = "./set-action[action='ipv4-next-hop']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ set_ipv6_nexthop_local, set_ipv6_nexthop_local_cmd, -+ "set ipv6 next-hop local X:X::X:X$addr", -+ SET_STR -+ IPV6_STR -+ "IPv6 next-hop address\n" -+ "IPv6 local address\n" -+ "IPv6 address of next hop\n") -+{ -+ const char *xpath = "./set-action[action='ipv6-next-hop']"; -+ char xpath_value[XPATH_MAXLEN]; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-address", xpath); -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_cmd, -+ "no set ipv6 next-hop local [X:X::X:X]", -+ NO_STR -+ SET_STR -+ IPV6_STR -+ "IPv6 next-hop address\n" -+ "IPv6 local address\n" -+ "IPv6 address of next hop\n") -+{ -+ const char *xpath = "./set-action[action='ipv6-next-hop']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ set_metric, set_metric_cmd, -+ "set metric <(0-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt|+metric$ametric|-metric$smetric>", -+ SET_STR -+ "Metric value for destination routing protocol\n" -+ "Metric value\n" -+ "Assign round trip time\n" -+ "Add round trip time\n" -+ "Subtract round trip time\n" -+ "Add metric\n" -+ "Subtract metric\n") -+{ -+ const char *xpath = "./set-action[action='metric']"; -+ char xpath_value[XPATH_MAXLEN]; -+ char value[64]; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ if (rtt) { -+ snprintf(xpath_value, sizeof(xpath_value), -+ "%s/use-round-trip-time", xpath); -+ snprintf(value, sizeof(value), "true"); -+ } else if (artt) { -+ snprintf(xpath_value, sizeof(xpath_value), -+ "%s/add-round-trip-time", xpath); -+ snprintf(value, sizeof(value), "true"); -+ } else if (srtt) { -+ snprintf(xpath_value, sizeof(xpath_value), -+ "%s/subtract-round-trip-time", xpath); -+ snprintf(value, sizeof(value), "true"); -+ } else if (ametric) { -+ snprintf(xpath_value, sizeof(xpath_value), "%s/add-metric", -+ xpath); -+ snprintf(value, sizeof(value), "true"); -+ } else if (smetric) { -+ snprintf(xpath_value, sizeof(xpath_value), "%s/subtract-metric", -+ xpath); -+ snprintf(value, sizeof(value), "true"); -+ } else { -+ snprintf(xpath_value, sizeof(xpath_value), "%s/value", xpath); -+ snprintf(value, sizeof(value), "%lu", metric); -+ } -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, value); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_set_metric, no_set_metric_cmd, -+ "no set metric [(0-4294967295)]", -+ NO_STR -+ SET_STR -+ "Metric value for destination routing protocol\n" -+ "Metric value\n") -+{ -+ const char *xpath = "./set-action[action='metric']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ set_tag, set_tag_cmd, -+ "set tag (1-4294967295)$tag", -+ SET_STR -+ "Tag value for routing protocol\n" -+ "Tag value\n") -+{ -+ const char *xpath = "./set-action[action='tag']"; -+ char xpath_value[XPATH_MAXLEN]; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); -+ snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath); -+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_set_tag, no_set_tag_cmd, -+ "no set tag [(1-4294967295)]", -+ NO_STR -+ SET_STR -+ "Tag value for routing protocol\n" -+ "Tag value\n") -+{ -+ const char *xpath = "./set-action[action='tag']"; -+ -+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+void route_map_action_show(struct vty *vty, struct lyd_node *dnode, -+ bool show_defaults) -+{ -+ int action = yang_dnode_get_enum(dnode, "./action"); -+ -+ switch (action) { -+ case 0: /* ipv4-next-hop */ -+ vty_out(vty, " set ip next-hop %s\n", -+ yang_dnode_get_string(dnode, "./ipv4-address")); -+ break; -+ case 1: /* ipv6-next-hop */ -+ vty_out(vty, " set ipv6 next-hop local %s\n", -+ yang_dnode_get_string(dnode, "./ipv6-address")); -+ break; -+ case 2: /* metric */ -+ if (yang_dnode_get(dnode, "./use-round-trip-time")) { -+ vty_out(vty, " set metric rtt\n"); -+ } else if (yang_dnode_get(dnode, "./add-round-trip-time")) { -+ vty_out(vty, " set metric +rtt\n"); -+ } else if (yang_dnode_get(dnode, "./subtract-round-trip-time")) { -+ vty_out(vty, " set metric -rtt\n"); -+ } else if (yang_dnode_get(dnode, "./add-metric")) { -+ vty_out(vty, " set metric +metric\n"); -+ } else if (yang_dnode_get(dnode, "./subtract-metric")) { -+ vty_out(vty, " set metric -metric\n"); -+ } else { -+ vty_out(vty, " set metric %s\n", -+ yang_dnode_get_string(dnode, "./value")); -+ } -+ break; -+ case 3: /* tag */ -+ vty_out(vty, " set tag %s\n", -+ yang_dnode_get_string(dnode, "./tag")); -+ break; -+ case 100: -+ /* NOTHING: custom field, should be handled by daemon. */ -+ break; -+ } -+} -+ -+DEFPY( -+ rmap_onmatch_next, rmap_onmatch_next_cmd, -+ "on-match next", -+ "Exit policy on matches\n" -+ "Next clause\n") -+{ -+ nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_MODIFY, "next"); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_rmap_onmatch_next, -+ no_rmap_onmatch_next_cmd, -+ "no on-match next", -+ NO_STR -+ "Exit policy on matches\n" -+ "Next clause\n") -+{ -+ nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ rmap_onmatch_goto, rmap_onmatch_goto_cmd, -+ "on-match goto (1-65535)$rm_num", -+ "Exit policy on matches\n" -+ "Goto Clause number\n" -+ "Number\n") -+{ -+ nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_MODIFY, "goto"); -+ nb_cli_enqueue_change(vty, "./goto-value", NB_OP_MODIFY, rm_num_str); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_rmap_onmatch_goto, no_rmap_onmatch_goto_cmd, -+ "no on-match goto", -+ NO_STR -+ "Exit policy on matches\n" -+ "Goto Clause number\n") -+{ -+ nb_cli_enqueue_change(vty, "./exit-policy", NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+/* Cisco/GNU Zebra compatibility aliases */ -+ALIAS( -+ rmap_onmatch_goto, rmap_continue_cmd, -+ "continue (1-65535)$rm_num", -+ "Continue on a different entry within the route-map\n" -+ "Route-map entry sequence number\n") -+ -+ALIAS( -+ no_rmap_onmatch_goto, no_rmap_continue_cmd, -+ "no continue [(1-65535)]", -+ NO_STR -+ "Continue on a different entry within the route-map\n" -+ "Route-map entry sequence number\n") -+ -+void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode, -+ bool show_defaults) -+{ -+ int exit_policy = yang_dnode_get_enum(dnode, NULL); -+ -+ switch (exit_policy) { -+ case 0: /* permit-or-deny */ -+ /* NOTHING: default option. */ -+ break; -+ case 1: /* next */ -+ vty_out(vty, " on-match next\n"); -+ break; -+ case 2: /* goto */ -+ vty_out(vty, " on-match goto %s\n", -+ yang_dnode_get_string(dnode, "../goto-value")); -+ break; -+ } -+} -+ -+DEFPY( -+ rmap_call, rmap_call_cmd, -+ "call WORD$name", -+ "Jump to another Route-Map after match+set\n" -+ "Target route-map name\n") -+{ -+ nb_cli_enqueue_change(vty, "./call", NB_OP_MODIFY, name); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+DEFPY( -+ no_rmap_call, no_rmap_call_cmd, -+ "no call", -+ NO_STR -+ "Jump to another Route-Map after match+set\n") -+{ -+ nb_cli_enqueue_change(vty, "./call", NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+void route_map_call_show(struct vty *vty, struct lyd_node *dnode, -+ bool show_defaults) -+{ -+ vty_out(vty, " call %s\n", yang_dnode_get_string(dnode, NULL)); -+} -+ -+DEFPY( -+ rmap_description, rmap_description_cmd, -+ "description LINE...", -+ "Route-map comment\n" -+ "Comment describing this route-map rule\n") -+{ -+ char *desc; -+ int rv; -+ -+ desc = argv_concat(argv, argc, 1); -+ nb_cli_enqueue_change(vty, "./description", NB_OP_MODIFY, desc); -+ rv = nb_cli_apply_changes(vty, NULL); -+ XFREE(MTYPE_TMP, desc); -+ -+ return rv; -+} -+ -+DEFUN (no_rmap_description, -+ no_rmap_description_cmd, -+ "no description", -+ NO_STR -+ "Route-map comment\n") -+{ -+ nb_cli_enqueue_change(vty, "./description", NB_OP_DESTROY, NULL); -+ -+ return nb_cli_apply_changes(vty, NULL); -+} -+ -+void route_map_description_show(struct vty *vty, struct lyd_node *dnode, -+ bool show_defaults) -+{ -+ vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL)); -+} -+ -+static int route_map_config_write(struct vty *vty) -+{ -+ struct lyd_node *dnode; -+ int written = 0; -+ -+ dnode = yang_dnode_get(running_config->dnode, -+ "/frr-route-map:lib"); -+ if (dnode) { -+ nb_cli_show_dnode_cmds(vty, dnode, false); -+ written = 1; -+ } -+ -+ return written; -+} -+ -+/* Route map node structure. */ -+static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# ", 1}; -+ -+static void rmap_autocomplete(vector comps, struct cmd_token *token) -+{ -+ struct route_map *map; -+ -+ for (map = route_map_master.head; map; map = map->next) -+ vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name)); -+} -+ -+static const struct cmd_variable_handler rmap_var_handlers[] = { -+ {.varname = "route_map", .completions = rmap_autocomplete}, -+ {.tokenname = "ROUTEMAP_NAME", .completions = rmap_autocomplete}, -+ {.tokenname = "RMAP_NAME", .completions = rmap_autocomplete}, -+ {.completions = NULL} -+}; -+ -+void route_map_cli_init(void) -+{ -+ /* Auto complete handler. */ -+ cmd_variable_handler_register(rmap_var_handlers); -+ -+ /* CLI commands. */ -+ install_node(&rmap_node, route_map_config_write); -+ install_default(RMAP_NODE); -+ install_element(CONFIG_NODE, &route_map_cmd); -+ install_element(CONFIG_NODE, &no_route_map_cmd); -+ install_element(CONFIG_NODE, &no_route_map_all_cmd); -+ -+ /* Install the on-match stuff */ -+ install_element(RMAP_NODE, &route_map_cmd); -+ install_element(RMAP_NODE, &rmap_onmatch_next_cmd); -+ install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd); -+ install_element(RMAP_NODE, &rmap_onmatch_goto_cmd); -+ install_element(RMAP_NODE, &no_rmap_onmatch_goto_cmd); -+ install_element(RMAP_NODE, &rmap_continue_cmd); -+ install_element(RMAP_NODE, &no_rmap_continue_cmd); -+ -+ /* Install the call stuff. */ -+ install_element(RMAP_NODE, &rmap_call_cmd); -+ install_element(RMAP_NODE, &no_rmap_call_cmd); -+ -+ /* Install description commands. */ -+ install_element(RMAP_NODE, &rmap_description_cmd); -+ install_element(RMAP_NODE, &no_rmap_description_cmd); -+ -+ /* Install 'match' commands. */ -+ install_element(RMAP_NODE, &match_interface_cmd); -+ install_element(RMAP_NODE, &no_match_interface_cmd); -+ -+ install_element(RMAP_NODE, &match_ip_address_cmd); -+ install_element(RMAP_NODE, &no_match_ip_address_cmd); -+ -+ install_element(RMAP_NODE, &match_ip_address_prefix_list_cmd); -+ install_element(RMAP_NODE, &no_match_ip_address_prefix_list_cmd); -+ -+ install_element(RMAP_NODE, &match_ip_next_hop_cmd); -+ install_element(RMAP_NODE, &no_match_ip_next_hop_cmd); -+ -+ install_element(RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); -+ install_element(RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); -+ -+ install_element(RMAP_NODE, &match_ip_next_hop_type_cmd); -+ install_element(RMAP_NODE, &no_match_ip_next_hop_type_cmd); -+ -+ install_element(RMAP_NODE, &match_ipv6_address_cmd); -+ install_element(RMAP_NODE, &no_match_ipv6_address_cmd); -+ -+ install_element(RMAP_NODE, &match_ipv6_address_prefix_list_cmd); -+ install_element(RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd); -+ -+ install_element(RMAP_NODE, &match_ipv6_next_hop_type_cmd); -+ install_element(RMAP_NODE, &no_match_ipv6_next_hop_type_cmd); -+ -+ install_element(RMAP_NODE, &match_metric_cmd); -+ install_element(RMAP_NODE, &no_match_metric_cmd); -+ -+ install_element(RMAP_NODE, &match_tag_cmd); -+ install_element(RMAP_NODE, &no_match_tag_cmd); -+ -+ /* Install 'set' commands. */ -+ install_element(RMAP_NODE, &set_ip_nexthop_cmd); -+ install_element(RMAP_NODE, &no_set_ip_nexthop_cmd); -+ -+ install_element(RMAP_NODE, &set_ipv6_nexthop_local_cmd); -+ install_element(RMAP_NODE, &no_set_ipv6_nexthop_local_cmd); -+ -+ install_element(RMAP_NODE, &set_metric_cmd); -+ install_element(RMAP_NODE, &no_set_metric_cmd); -+ -+ install_element(RMAP_NODE, &set_tag_cmd); -+ install_element(RMAP_NODE, &no_set_tag_cmd); -+} -diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c -index 02eb756334..b9ac01e865 100644 ---- a/lib/routemap_northbound.c -+++ b/lib/routemap_northbound.c -@@ -1218,6 +1218,8 @@ const struct frr_yang_module_info frr_route_map_info = { - .cbs = { - .create = lib_route_map_entry_create, - .destroy = lib_route_map_entry_destroy, -+ .cli_show = route_map_instance_show, -+ .cli_show_end = route_map_instance_show_end, - } - }, - { -@@ -1225,6 +1227,7 @@ const struct frr_yang_module_info frr_route_map_info = { - .cbs = { - .modify = lib_route_map_entry_description_modify, - .destroy = lib_route_map_entry_description_destroy, -+ .cli_show = route_map_description_show, - } - }, - { -@@ -1238,12 +1241,14 @@ const struct frr_yang_module_info frr_route_map_info = { - .cbs = { - .modify = lib_route_map_entry_call_modify, - .destroy = lib_route_map_entry_call_destroy, -+ .cli_show = route_map_call_show, - } - }, - { - .xpath = "/frr-route-map:lib/route-map/entry/exit-policy", - .cbs = { - .modify = lib_route_map_entry_exit_policy_modify, -+ .cli_show = route_map_exit_policy_show, - } - }, - { -@@ -1258,6 +1263,7 @@ const struct frr_yang_module_info frr_route_map_info = { - .cbs = { - .create = lib_route_map_entry_match_condition_create, - .destroy = lib_route_map_entry_match_condition_destroy, -+ .cli_show = route_map_condition_show, - } - }, - { -@@ -1321,6 +1327,7 @@ const struct frr_yang_module_info frr_route_map_info = { - .cbs = { - .create = lib_route_map_entry_set_action_create, - .destroy = lib_route_map_entry_set_action_destroy, -+ .cli_show = route_map_action_show, - } - }, - { -diff --git a/lib/subdir.am b/lib/subdir.am -index 94b3d933ac..ffac721256 100644 ---- a/lib/subdir.am -+++ b/lib/subdir.am -@@ -71,6 +71,7 @@ lib_libfrr_la_SOURCES = \ - lib/qobj.c \ - lib/ringbuf.c \ - lib/routemap.c \ -+ lib/routemap_cli.c \ - lib/routemap_northbound.c \ - lib/sbuf.c \ - lib/seqlock.c \ -@@ -122,6 +123,7 @@ vtysh_scan += \ - $(top_srcdir)/lib/nexthop_group.c \ - $(top_srcdir)/lib/plist.c \ - $(top_srcdir)/lib/routemap.c \ -+ $(top_srcdir)/lib/routemap_cli.c \ - $(top_srcdir)/lib/vrf.c \ - $(top_srcdir)/lib/vty.c \ - # end -@@ -141,6 +143,8 @@ lib/nexthop_group_clippy.c: $(CLIPPY_DEPS) - lib/nexthop_group.lo: lib/nexthop_group_clippy.c - lib/northbound_cli_clippy.c: $(CLIPPY_DEPS) - lib/northbound_cli.lo: lib/northbound_cli_clippy.c -+lib/routemap_cli_clippy.c: $(CLIPPY_DEPS) -+lib/routemap_cli.lo: lib/routemap_cli_clippy.c - lib/vty_clippy.c: $(CLIPPY_DEPS) - lib/vty.lo: lib/vty_clippy.c - lib/log_vty_clippy.c: $(CLIPPY_DEPS) -diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in -index 13413888bf..b7ac0abe02 100755 ---- a/vtysh/extract.pl.in -+++ b/vtysh/extract.pl.in -@@ -87,7 +87,7 @@ sub scan_file { - if ($file =~ /lib\/keychain\.c$/) { - $protocol = "VTYSH_RIPD|VTYSH_EIGRPD"; - } -- elsif ($file =~ /lib\/routemap\.c$/) { -+ elsif ($file =~ /lib\/routemap\.c$/ || $file =~ /lib\/routemap_cli\.c$/) { - $protocol = "VTYSH_RMAP"; - } - elsif ($file =~ /lib\/vrf\.c$/) { - -From a513824c343971e51603471948c958430b602371 Mon Sep 17 00:00:00 2001 -From: Rafael Zalamena -Date: Tue, 1 Oct 2019 17:56:16 -0300 -Subject: [PATCH 05/10] yang/lib: add filter model to code - -This fixes a warning on daemons that use route map about filter yang -model not being included in the binary. - -Signed-off-by: Rafael Zalamena ---- - lib/subdir.am | 1 + - yang/subdir.am | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/lib/subdir.am b/lib/subdir.am -index ffac721256..4f62eb2264 100644 ---- a/lib/subdir.am -+++ b/lib/subdir.am -@@ -106,6 +106,7 @@ lib_libfrr_la_SOURCES = \ - # end - - nodist_lib_libfrr_la_SOURCES = \ -+ yang/frr-filter.yang.c \ - yang/frr-interface.yang.c \ - yang/frr-route-map.yang.c \ - yang/frr-route-types.yang.c \ -diff --git a/yang/subdir.am b/yang/subdir.am -index 7a15a6a309..c1297dafd5 100644 ---- a/yang/subdir.am -+++ b/yang/subdir.am -@@ -19,6 +19,7 @@ EXTRA_DIST += yang/embedmodel.py - # global symbols :(. Just put it in the daemon. Dynamic libraries.so work - # without problems, as seen in libfrr. - -+dist_yangmodels_DATA += yang/frr-filter.yang - dist_yangmodels_DATA += yang/frr-module-translator.yang - dist_yangmodels_DATA += yang/frr-test-module.yang - dist_yangmodels_DATA += yang/frr-interface.yang - -From a162869ef0798ef98d756238c6b89108a69f5a5d Mon Sep 17 00:00:00 2001 -From: Rafael Zalamena -Date: Mon, 30 Sep 2019 15:02:15 -0300 -Subject: [PATCH 06/10] lib: fix route map generic error output - -Two fixes here: - -* Don't attempt to use `vty` pointer in vty; -* When `vty` is unavailable output to log; - -Signed-off-by: Rafael Zalamena ---- - lib/routemap.c | 68 ++++++++++++++++++++++++++++++++++---------------- - 1 file changed, 46 insertions(+), 22 deletions(-) - -diff --git a/lib/routemap.c b/lib/routemap.c -index e07ad08123..5369fa771f 100644 ---- a/lib/routemap.c -+++ b/lib/routemap.c -@@ -308,15 +308,21 @@ int generic_match_add(struct vty *vty, struct route_map_index *index, - ret = route_map_add_match(index, command, arg, type); - switch (ret) { - case RMAP_RULE_MISSING: -- vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); -+ if (vty) -+ vty_out(vty, "%% [%s] Can't find rule.\n", -+ frr_protonameinst); -+ else -+ zlog_warn("Can't find rule: %s", command); - return CMD_WARNING_CONFIG_FAILED; -- break; - case RMAP_COMPILE_ERROR: -- vty_out(vty, -- "%% [%s] Argument form is unsupported or malformed.\n", -- frr_protonameinst); -+ if (vty) -+ vty_out(vty, -+ "%% [%s] Argument form is unsupported or malformed.\n", -+ frr_protonameinst); -+ else -+ zlog_warn("Argument form is unsupported or malformed: " -+ "%s %s", command, arg); - return CMD_WARNING_CONFIG_FAILED; -- break; - case RMAP_COMPILE_SUCCESS: - /* - * Nothing to do here move along -@@ -353,13 +359,21 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index, - ret = route_map_delete_match(index, command, dep_name, type); - switch (ret) { - case RMAP_RULE_MISSING: -- vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); -+ if (vty) -+ vty_out(vty, "%% [%s] Can't find rule.\n", -+ frr_protonameinst); -+ else -+ zlog_warn("Can't find rule: %s", command); - retval = CMD_WARNING_CONFIG_FAILED; - break; - case RMAP_COMPILE_ERROR: -- vty_out(vty, -- "%% [%s] Argument form is unsupported or malformed.\n", -- frr_protonameinst); -+ if (vty) -+ vty_out(vty, -+ "%% [%s] Argument form is unsupported or malformed.\n", -+ frr_protonameinst); -+ else -+ zlog_warn("Argument form is unsupported or malformed: " -+ "%s %s", command, arg); - retval = CMD_WARNING_CONFIG_FAILED; - break; - case RMAP_COMPILE_SUCCESS: -@@ -383,15 +397,20 @@ int generic_set_add(struct vty *vty, struct route_map_index *index, - ret = route_map_add_set(index, command, arg); - switch (ret) { - case RMAP_RULE_MISSING: -- vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); -+ if (vty) -+ vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); -+ else -+ zlog_warn("Can't find rule: %s", command); - return CMD_WARNING_CONFIG_FAILED; -- break; - case RMAP_COMPILE_ERROR: -- vty_out(vty, -- "%% [%s] Argument form is unsupported or malformed.\n", -- frr_protonameinst); -+ if (vty) -+ vty_out(vty, -+ "%% [%s] Argument form is unsupported or malformed.\n", -+ frr_protonameinst); -+ else -+ zlog_warn("Argument form is unsupported or malformed: " -+ "%s %s", command, arg); - return CMD_WARNING_CONFIG_FAILED; -- break; - case RMAP_COMPILE_SUCCESS: - break; - } -@@ -407,15 +426,20 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index, - ret = route_map_delete_set(index, command, arg); - switch (ret) { - case RMAP_RULE_MISSING: -- vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); -+ if (vty) -+ vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); -+ else -+ zlog_warn("Can't find rule: %s", command); - return CMD_WARNING_CONFIG_FAILED; -- break; - case RMAP_COMPILE_ERROR: -- vty_out(vty, -- "%% [%s] Argument form is unsupported or malformed.\n", -- frr_protonameinst); -+ if (vty) -+ vty_out(vty, -+ "%% [%s] Argument form is unsupported or malformed.\n", -+ frr_protonameinst); -+ else -+ zlog_warn("Argument form is unsupported or malformed: " -+ "%s %s", command, arg); - return CMD_WARNING_CONFIG_FAILED; -- break; - case RMAP_COMPILE_SUCCESS: - break; - } - -From e324ef433ca611ddf8274015c0b36c8de1fb3075 Mon Sep 17 00:00:00 2001 -From: Rafael Zalamena -Date: Tue, 1 Oct 2019 15:52:51 -0300 -Subject: [PATCH 07/10] lib: add backward compatibility for route map - -Allow old CLI users to still print their configuration without migrating -to northbound. - -Signed-off-by: Rafael Zalamena ---- - lib/routemap_cli.c | 56 +++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 55 insertions(+), 1 deletion(-) - -diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c -index 987693c961..7023710564 100644 ---- a/lib/routemap_cli.c -+++ b/lib/routemap_cli.c -@@ -46,6 +46,9 @@ DEFPY_NOSH( - ROUTE_MAP_OP_CMD_STR - ROUTE_MAP_SEQUENCE_CMD_STR) - { -+ struct route_map_index *rmi; -+ struct route_map *rm; -+ int action_type; - char xpath_action[XPATH_MAXLEN + 64]; - char xpath_index[XPATH_MAXLEN + 32]; - char xpath[XPATH_MAXLEN]; -@@ -63,9 +66,16 @@ DEFPY_NOSH( - nb_cli_enqueue_change(vty, xpath_action, NB_OP_MODIFY, action); - - rv = nb_cli_apply_changes(vty, NULL); -- if (rv == CMD_SUCCESS) -+ if (rv == CMD_SUCCESS) { - VTY_PUSH_XPATH(RMAP_NODE, xpath_index); - -+ /* Add support for non-migrated route map users. */ -+ rm = route_map_get(name); -+ action_type = (action[0] == 'p') ? RMAP_PERMIT : RMAP_DENY; -+ rmi = route_map_index_get(rm, action_type, sequence); -+ VTY_PUSH_CONTEXT(RMAP_NODE, rmi); -+ } -+ - return rv; - } - -@@ -105,11 +115,55 @@ DEFPY( - void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, - bool show_defaults) - { -+ const struct route_map_rule *rmr; -+ const struct route_map_index *rmi; - const char *name = yang_dnode_get_string(dnode, "../name"); - const char *action = yang_dnode_get_string(dnode, "./action"); - const char *sequence = yang_dnode_get_string(dnode, "./sequence"); - - vty_out(vty, "route-map %s %s %s\n", name, action, sequence); -+ -+ rmi = nb_running_get_entry(dnode, NULL, false); -+ if (rmi == NULL) { -+ /* -+ * We can't have outdated rules if route map hasn't -+ * been created yet. -+ */ -+ return; -+ } -+ -+#define SKIP_RULE(name) if (strcmp((name), rmr->cmd->str) == 0) continue -+ -+ /* Print route map `match` for old CLI users. */ -+ for (rmr = rmi->match_list.head; rmr; rmr = rmr->next) { -+ /* Skip all matches implemented by northbound. */ -+ SKIP_RULE("interface"); -+ SKIP_RULE("ip address"); -+ SKIP_RULE("ip address prefix-list"); -+ SKIP_RULE("ip next-hop"); -+ SKIP_RULE("ip next-hop prefix-list"); -+ SKIP_RULE("ip next-hop type"); -+ SKIP_RULE("ipv6 address"); -+ SKIP_RULE("ipv6 address prefix-list"); -+ SKIP_RULE("ipv6 next-hop type"); -+ SKIP_RULE("metric"); -+ SKIP_RULE("tag"); -+ -+ vty_out(vty, " match %s %s\n", rmr->cmd->str, -+ rmr->rule_str ? rmr->rule_str : ""); -+ } -+ -+ /* Print route map `set` for old CLI users. */ -+ for (rmr = rmi->set_list.head; rmr; rmr = rmr->next) { -+ /* Skip all sets implemented by northbound. */ -+ SKIP_RULE("metric"); -+ SKIP_RULE("tag"); -+ -+ vty_out(vty, " set %s %s\n", rmr->cmd->str, -+ rmr->rule_str ? rmr->rule_str : ""); -+ } -+ -+#undef SKIP_RULE - } - - void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode) - -From 91835f1fd2a8dd05a5ba03c8961b699aaabed7e7 Mon Sep 17 00:00:00 2001 -From: Rafael Zalamena -Date: Tue, 1 Oct 2019 17:56:41 -0300 -Subject: [PATCH 08/10] *: fix route map integration - -Add the appropriated code to bootstrap route map northbound for all -daemons. - -Signed-off-by: Rafael Zalamena ---- - bgpd/bgp_main.c | 2 ++ - eigrpd/eigrp_main.c | 1 + - isisd/isis_main.c | 2 ++ - ospf6d/ospf6_main.c | 1 + - ospfd/ospf_main.c | 2 ++ - ripd/rip_main.c | 2 ++ - ripngd/ripng_main.c | 2 ++ - zebra/main.c | 1 + - 8 files changed, 13 insertions(+) - -diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c -index fab2a584c0..0b33f7e9d9 100644 ---- a/bgpd/bgp_main.c -+++ b/bgpd/bgp_main.c -@@ -360,6 +360,8 @@ static void bgp_vrf_terminate(void) - } - - static const struct frr_yang_module_info *const bgpd_yang_modules[] = { -+ &frr_interface_info, -+ &frr_route_map_info, - }; - - FRR_DAEMON_INFO(bgpd, BGP, .vty_port = BGP_VTY_PORT, -diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c -index 0746b04edb..922c0fe3e7 100644 ---- a/eigrpd/eigrp_main.c -+++ b/eigrpd/eigrp_main.c -@@ -140,6 +140,7 @@ struct quagga_signal_t eigrp_signals[] = { - static const struct frr_yang_module_info *const eigrpd_yang_modules[] = { - &frr_eigrpd_info, - &frr_interface_info, -+ &frr_route_map_info, - }; - - FRR_DAEMON_INFO(eigrpd, EIGRP, .vty_port = EIGRP_VTY_PORT, -diff --git a/isisd/isis_main.c b/isisd/isis_main.c -index 364441f79d..f7fe089b99 100644 ---- a/isisd/isis_main.c -+++ b/isisd/isis_main.c -@@ -39,6 +39,7 @@ - #include "vrf.h" - #include "qobj.h" - #include "libfrr.h" -+#include "routemap.h" - - #include "isisd/isis_constants.h" - #include "isisd/isis_common.h" -@@ -166,6 +167,7 @@ static const struct frr_yang_module_info *const isisd_yang_modules[] = { - #ifndef FABRICD - &frr_isisd_info, - #endif /* ifndef FABRICD */ -+ &frr_route_map_info, - }; - - #ifdef FABRICD -diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c -index 0aaefeb3c2..e4bed7a79d 100644 ---- a/ospf6d/ospf6_main.c -+++ b/ospf6d/ospf6_main.c -@@ -167,6 +167,7 @@ struct quagga_signal_t ospf6_signals[] = { - - static const struct frr_yang_module_info *const ospf6d_yang_modules[] = { - &frr_interface_info, -+ &frr_route_map_info, - }; - - FRR_DAEMON_INFO(ospf6d, OSPF6, .vty_port = OSPF6_VTY_PORT, -diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c -index d02ffe0448..7caa79d207 100644 ---- a/ospfd/ospf_main.c -+++ b/ospfd/ospf_main.c -@@ -40,6 +40,7 @@ - #include "zclient.h" - #include "vrf.h" - #include "libfrr.h" -+#include "routemap.h" - - #include "ospfd/ospfd.h" - #include "ospfd/ospf_interface.h" -@@ -126,6 +127,7 @@ struct quagga_signal_t ospf_signals[] = { - - static const struct frr_yang_module_info *const ospfd_yang_modules[] = { - &frr_interface_info, -+ &frr_route_map_info, - }; - - FRR_DAEMON_INFO(ospfd, OSPF, .vty_port = OSPF_VTY_PORT, -diff --git a/ripd/rip_main.c b/ripd/rip_main.c -index 060bb76585..ca41afaea6 100644 ---- a/ripd/rip_main.c -+++ b/ripd/rip_main.c -@@ -35,6 +35,7 @@ - #include "vrf.h" - #include "if_rmap.h" - #include "libfrr.h" -+#include "routemap.h" - - #include "ripd/ripd.h" - #include "ripd/rip_nb.h" -@@ -115,6 +116,7 @@ static struct quagga_signal_t ripd_signals[] = { - static const struct frr_yang_module_info *const ripd_yang_modules[] = { - &frr_interface_info, - &frr_ripd_info, -+ &frr_route_map_info, - }; - - FRR_DAEMON_INFO(ripd, RIP, .vty_port = RIP_VTY_PORT, -diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c -index 9daeeb9580..99adb2cba7 100644 ---- a/ripngd/ripng_main.c -+++ b/ripngd/ripng_main.c -@@ -36,6 +36,7 @@ - #include "vrf.h" - #include "if_rmap.h" - #include "libfrr.h" -+#include "routemap.h" - - #include "ripngd/ripngd.h" - #include "ripngd/ripng_nb.h" -@@ -115,6 +116,7 @@ struct quagga_signal_t ripng_signals[] = { - static const struct frr_yang_module_info *const ripngd_yang_modules[] = { - &frr_interface_info, - &frr_ripngd_info, -+ &frr_route_map_info, - }; - - FRR_DAEMON_INFO(ripngd, RIPNG, .vty_port = RIPNG_VTY_PORT, -diff --git a/zebra/main.c b/zebra/main.c -index f23702d878..5951c7e280 100644 ---- a/zebra/main.c -+++ b/zebra/main.c -@@ -237,6 +237,7 @@ struct quagga_signal_t zebra_signals[] = { - - static const struct frr_yang_module_info *const zebra_yang_modules[] = { - &frr_interface_info, -+ &frr_route_map_info, - }; - - FRR_DAEMON_INFO( - -From 54a35ff48b600cd59b715b6e5aea4e69de1b995f Mon Sep 17 00:00:00 2001 -From: Rafael Zalamena -Date: Mon, 14 Oct 2019 23:29:19 -0300 -Subject: [PATCH 09/10] lib: fix route map northbound memory leak - -Keep a list of hook contexts used by northbound so we don't lose the -pointer when free()ing the route map index entry data. - -Signed-off-by: Rafael Zalamena ---- - lib/routemap.c | 5 +++++ - lib/routemap.h | 11 +++++++++++ - lib/routemap_northbound.c | 39 ++++++++++++++++++++++++++++++--------- - 3 files changed, 46 insertions(+), 9 deletions(-) - -diff --git a/lib/routemap.c b/lib/routemap.c -index 5369fa771f..912cf28202 100644 ---- a/lib/routemap.c -+++ b/lib/routemap.c -@@ -909,6 +909,7 @@ static struct route_map_index *route_map_index_new(void) - - new = XCALLOC(MTYPE_ROUTE_MAP_INDEX, sizeof(struct route_map_index)); - new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */ -+ TAILQ_INIT(&new->rhclist); - QOBJ_REG(new, route_map_index); - return new; - } -@@ -924,6 +925,10 @@ void route_map_index_delete(struct route_map_index *index, int notify) - zlog_debug("Deleting route-map %s sequence %d", - index->map->name, index->pref); - -+ /* Free route map northbound hook contexts. */ -+ while (!TAILQ_EMPTY(&index->rhclist)) -+ routemap_hook_context_free(TAILQ_FIRST(&index->rhclist)); -+ - /* Free route match. */ - while ((rule = index->match_list.head) != NULL) - route_map_rule_delete(&index->match_list, rule); -diff --git a/lib/routemap.h b/lib/routemap.h -index 70e150c981..05c958967c 100644 ---- a/lib/routemap.h -+++ b/lib/routemap.h -@@ -162,6 +162,9 @@ struct route_map_rule_list { - struct route_map_rule *tail; - }; - -+/* Forward struct declaration: the complete can be found later this file. */ -+struct routemap_hook_context; -+ - /* Route map index structure. */ - struct route_map_index { - struct route_map *map; -@@ -194,6 +197,9 @@ struct route_map_index { - uint64_t applied; - uint64_t applied_clear; - -+ /* List of match/sets contexts. */ -+ TAILQ_HEAD(, routemap_hook_context) rhclist; -+ - QOBJ_FIELDS - }; - DECLARE_QOBJ_TYPE(route_map_index) -@@ -660,6 +666,7 @@ struct routemap_hook_context { - route_map_event_t rhc_event; - routemap_set_hook_fun rhc_shook; - routemap_match_hook_fun rhc_mhook; -+ TAILQ_ENTRY(routemap_hook_context) rhc_entry; - }; - - int lib_route_map_entry_match_destroy(enum nb_event event, -@@ -667,6 +674,10 @@ int lib_route_map_entry_match_destroy(enum nb_event event, - int lib_route_map_entry_set_destroy(enum nb_event event, - const struct lyd_node *dnode); - -+struct routemap_hook_context * -+routemap_hook_context_insert(struct route_map_index *rmi); -+void routemap_hook_context_free(struct routemap_hook_context *rhc); -+ - extern const struct frr_yang_module_info frr_route_map_info; - - /* routemap_cli.c */ -diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c -index b9ac01e865..3173a708e4 100644 ---- a/lib/routemap_northbound.c -+++ b/lib/routemap_northbound.c -@@ -74,6 +74,30 @@ int lib_route_map_entry_set_destroy(enum nb_event event, - return NB_OK; - } - -+/* -+ * Auxiliary hook context list manipulation functions. -+ */ -+struct routemap_hook_context * -+routemap_hook_context_insert(struct route_map_index *rmi) -+{ -+ struct routemap_hook_context *rhc; -+ -+ rhc = XCALLOC(MTYPE_TMP, sizeof(*rhc)); -+ rhc->rhc_rmi = rmi; -+ TAILQ_INSERT_TAIL(&rmi->rhclist, rhc, rhc_entry); -+ -+ return rhc; -+} -+ -+void -+routemap_hook_context_free(struct routemap_hook_context *rhc) -+{ -+ struct route_map_index *rmi = rhc->rhc_rmi; -+ -+ TAILQ_REMOVE(&rmi->rhclist, rhc, rhc_entry); -+ XFREE(MTYPE_TMP, rhc); -+} -+ - /* - * XPath: /frr-route-map:lib/route-map - */ -@@ -436,20 +460,17 @@ lib_route_map_entry_match_condition_create(enum nb_event event, - union nb_resource *resource) - { - struct routemap_hook_context *rhc; -+ struct route_map_index *rmi; - - switch (event) { - case NB_EV_VALIDATE: -- /* NOTHING */ -- break; - case NB_EV_PREPARE: -- resource->ptr = XCALLOC(MTYPE_TMP, sizeof(*rhc)); -- break; - case NB_EV_ABORT: -- XFREE(MTYPE_TMP, resource->ptr); -+ /* NOTHING */ - break; - case NB_EV_APPLY: -- rhc = resource->ptr; -- rhc->rhc_rmi = nb_running_get_entry(dnode, NULL, true); -+ rmi = nb_running_get_entry(dnode, NULL, true); -+ rhc = routemap_hook_context_insert(rmi); - nb_running_set_entry(dnode, rhc); - break; - } -@@ -469,7 +490,7 @@ lib_route_map_entry_match_condition_destroy(enum nb_event event, - - rv = lib_route_map_entry_match_destroy(event, dnode); - rhc = nb_running_unset_entry(dnode); -- XFREE(MTYPE_TMP, rhc); -+ routemap_hook_context_free(rhc); - - return rv; - } -@@ -893,7 +914,7 @@ static int lib_route_map_entry_set_action_destroy(enum nb_event event, - - rv = lib_route_map_entry_set_destroy(event, dnode); - rhc = nb_running_unset_entry(dnode); -- XFREE(MTYPE_TMP, rhc); -+ routemap_hook_context_free(rhc); - - return rv; - } - -From 79661106763d4f6d9c200a4f4d25439f1cfecf3a Mon Sep 17 00:00:00 2001 -From: Rafael Zalamena -Date: Wed, 5 Feb 2020 11:09:31 -0300 -Subject: [PATCH 10/10] lib: fix route-map YANG module on old gcc versions - -Copy the fix made in 'lib/if.c' to 'lib/routemap_northbound.c' so we can -have a working YANG model when compiled with GCC version less than 5. - -Signed-off-by: Rafael Zalamena ---- - lib/routemap_northbound.c | 25 +++++++++++++++++++++++++ - 1 file changed, 25 insertions(+) - -diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c -index 3173a708e4..78f2a5a018 100644 ---- a/lib/routemap_northbound.c -+++ b/lib/routemap_northbound.c -@@ -1224,7 +1224,32 @@ lib_route_map_entry_set_action_tag_destroy(enum nb_event event, - } - - /* clang-format off */ -+#if defined(__GNUC__) && ((__GNUC__ - 0) < 5) && !defined(__clang__) -+/* -+ * gcc versions before 5.x miscalculate the size for structs with variable -+ * length arrays (they just count it as size 0) -+ */ -+struct frr_yang_module_info_sizen { -+ /* YANG module name. */ -+ const char *name; -+ -+ /* Northbound callbacks. */ -+ const struct { -+ /* Data path of this YANG node. */ -+ const char *xpath; -+ -+ /* Callbacks implemented for this node. */ -+ struct nb_callbacks cbs; -+ -+ /* Priority - lower priorities are processed first. */ -+ uint32_t priority; -+ } nodes[28]; -+}; -+ -+const struct frr_yang_module_info_sizen frr_route_map_info_sizen asm("frr_route_map_info") = { -+#else - const struct frr_yang_module_info frr_route_map_info = { -+#endif - .name = "frr-route-map", - .nodes = { - { diff --git a/net/frr/patches/012-add_yang_filter.patch b/net/frr/patches/012-add_yang_filter.patch deleted file mode 100644 index e3c4ebaf38..0000000000 --- a/net/frr/patches/012-add_yang_filter.patch +++ /dev/null @@ -1,83 +0,0 @@ -From bec0aa85b1f404ac9800c7524070fcf8582e82bc Mon Sep 17 00:00:00 2001 -From: Rafael Zalamena -Date: Thu, 1 Aug 2019 19:56:46 -0300 -Subject: [PATCH] yang: simplify filter choice by removing cases - -Based on @rwestphal feedback, lets remove `case`s where we don't expect -to add more items or items with more than one `leaf`. - -Signed-off-by: Rafael Zalamena ---- - yang/frr-filter.yang | 48 +++++++++++++++++--------------------------- - 1 file changed, 18 insertions(+), 30 deletions(-) - -diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang -index 92af6aebfd..e79ede87b7 100644 ---- a/yang/frr-filter.yang -+++ b/yang/frr-filter.yang -@@ -107,23 +107,17 @@ module frr-filter { - Extended access list: source value to match."; - mandatory true; - -- case host { -- leaf host { -- description "Host to match"; -- type inet:ipv4-address; -- } -+ leaf host { -+ description "Host to match"; -+ type inet:ipv4-address; - } -- case network { -- leaf network { -- description "Network to match"; -- type inet:ipv4-prefix; -- } -+ leaf network { -+ description "Network to match"; -+ type inet:ipv4-prefix; - } -- case any { -- leaf any { -- description "Match any"; -- type empty; -- } -+ leaf any { -+ description "Match any"; -+ type empty; - } - } - -@@ -132,23 +126,17 @@ module frr-filter { - ./sequence >= 2000 and ./sequence <= 2699"; - description "Destination value to match"; - -- case destination-host { -- leaf destination-host { -- description "Host to match"; -- type inet:ipv4-address; -- } -+ leaf destination-host { -+ description "Host to match"; -+ type inet:ipv4-address; - } -- case destination-network { -- leaf destination-network { -- description "Network to match"; -- type inet:ipv4-prefix; -- } -+ leaf destination-network { -+ description "Network to match"; -+ type inet:ipv4-prefix; - } -- case destination-any { -- leaf destination-any { -- description "Match any"; -- type empty; -- } -+ leaf destination-any { -+ description "Match any"; -+ type empty; - } - } - } diff --git a/net/frr/patches/013-backport_northbound.patch b/net/frr/patches/013-backport_northbound.patch deleted file mode 100644 index dacb4562e7..0000000000 --- a/net/frr/patches/013-backport_northbound.patch +++ /dev/null @@ -1,147 +0,0 @@ -From dc397e4c0adc13982fc5d83a1afc42178708f4a5 Mon Sep 17 00:00:00 2001 -From: Renato Westphal -Date: Fri, 3 Apr 2020 20:10:04 -0300 -Subject: [PATCH] lib: consolidate flexible array hack in a single place - -Old gcc versions (< 5.x) have a bug that prevents C99 flexible -arrays from working properly on shared libraries. - -We already have a hack in place to work around this problem, but it -needs to be replicated in every declaration of a frr_yang_module_info -variable within libfrr. This clearly isn't a good solution if we -consider that many more libfrr YANG modules are about to come in -the future. - -This commit introduces a different workaround that operates within -the northbound layer itself, such that implementers of libfrr YANG -modules won't need to worry about this problem anymore. - -Signed-off-by: Renato Westphal ---- - lib/if.c | 24 ------------------------ - lib/northbound.c | 7 +++++++ - lib/northbound.h | 11 +++++++++++ - lib/routemap_northbound.c | 25 ------------------------- - 4 files changed, 18 insertions(+), 49 deletions(-) - -diff --git a/lib/if.c b/lib/if.c -index dabf66799d..24b103b3ff 100644 ---- a/lib/if.c -+++ b/lib/if.c -@@ -1657,31 +1657,7 @@ static int lib_interface_description_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_size3 { -- /* 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[3]; --}; -- --const struct frr_yang_module_info_size3 frr_interface_info_size3 asm("frr_interface_info") = { --#else - const struct frr_yang_module_info frr_interface_info = { --#endif - .name = "frr-interface", - .nodes = { - { -diff --git a/lib/northbound.c b/lib/northbound.c -index cebedcff09..85e723d7cf 100644 ---- a/lib/northbound.c -+++ b/lib/northbound.c -@@ -1866,6 +1866,13 @@ static void nb_load_callbacks(const struct frr_yang_module_info *module) - struct nb_node *nb_node; - uint32_t priority; - -+ if (i > YANG_MODULE_MAX_NODES) { -+ zlog_err( -+ "%s: %s.yang has more than %u nodes. Please increase YANG_MODULE_MAX_NODES to fix this problem.", -+ __func__, module->name, YANG_MODULE_MAX_NODES); -+ exit(1); -+ } -+ - nb_node = nb_node_find(module->nodes[i].xpath); - if (!nb_node) { - flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, -diff --git a/lib/northbound.h b/lib/northbound.h -index 76a11e518c..19a2ba0865 100644 ---- a/lib/northbound.h -+++ b/lib/northbound.h -@@ -403,6 +403,13 @@ struct nb_node { - /* The YANG list doesn't contain key leafs. */ - #define F_NB_NODE_KEYLESS_LIST 0x02 - -+/* -+ * HACK: old gcc versions (< 5.x) have a bug that prevents C99 flexible arrays -+ * from working properly on shared libraries. For those compilers, use a fixed -+ * size array to work around the problem. -+ */ -+#define YANG_MODULE_MAX_NODES 1024 -+ - struct frr_yang_module_info { - /* YANG module name. */ - const char *name; -@@ -417,7 +424,11 @@ struct frr_yang_module_info { - - /* Priority - lower priorities are processed first. */ - uint32_t priority; -+#if defined(__GNUC__) && ((__GNUC__ - 0) < 5) && !defined(__clang__) -+ } nodes[YANG_MODULE_MAX_NODES + 1]; -+#else - } nodes[]; -+#endif - }; - - /* Northbound error codes. */ -diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c -index 69cebbd2a1..dd4cbd7d99 100644 ---- a/lib/routemap_northbound.c -+++ b/lib/routemap_northbound.c -@@ -1221,32 +1221,7 @@ 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 = { - { diff --git a/net/frr/patches/014-backport_northbound.patch b/net/frr/patches/014-backport_northbound.patch deleted file mode 100644 index 879c380e84..0000000000 --- a/net/frr/patches/014-backport_northbound.patch +++ /dev/null @@ -1,330 +0,0 @@ -From 97cd849362b45ecbcb20194b5771c5ce777de6bc Mon Sep 17 00:00:00 2001 -From: Renato Westphal -Date: Tue, 21 Apr 2020 21:27:47 -0300 -Subject: [PATCH] lib: create a wrapper function for all northbound callbacks - -The intention here is to keep the code more organized. These wrappers -should be used by the northbound clients only, and never directly -by any YANG backend code. - -Signed-off-by: Renato Westphal ---- - lib/northbound.c | 222 +++++++++++++++++++++++----------------- - lib/northbound_grpc.cpp | 3 +- - 2 files changed, 131 insertions(+), 94 deletions(-) - -diff --git a/lib/northbound.c b/lib/northbound.c -index 85e723d7cf..d10e4713f5 100644 ---- a/lib/northbound.c -+++ b/lib/northbound.c -@@ -62,11 +62,10 @@ static struct { - */ - static bool transaction_in_progress; - -+static int nb_callback_pre_validate(const struct nb_node *nb_node, -+ const struct lyd_node *dnode); - static int nb_callback_configuration(const enum nb_event event, - struct nb_config_change *change); --static void nb_log_callback(const enum nb_event event, -- enum nb_operation operation, const char *xpath, -- const char *value); - static struct nb_transaction *nb_transaction_new(struct nb_config *config, - struct nb_config_cbs *changes, - enum nb_client client, -@@ -609,18 +608,7 @@ static int nb_candidate_validate_code(struct nb_config *candidate, - if (!nb_node->cbs.pre_validate) - goto next; - -- if (DEBUG_MODE_CHECK(&nb_dbg_cbs_config, -- DEBUG_MODE_ALL)) { -- char xpath[XPATH_MAXLEN]; -- -- yang_dnode_get_path(child, xpath, -- sizeof(xpath)); -- nb_log_callback(NB_EV_VALIDATE, -- NB_OP_PRE_VALIDATE, xpath, -- NULL); -- } -- -- ret = (*nb_node->cbs.pre_validate)(child); -+ ret = nb_callback_pre_validate(nb_node, child); - if (ret != NB_OK) - return NB_ERR_VALIDATION; - -@@ -791,14 +779,128 @@ int nb_running_lock_check(enum nb_client client, const void *user) - return ret; - } - --static void nb_log_callback(const enum nb_event event, -- enum nb_operation operation, const char *xpath, -- const char *value) -+static void nb_log_config_callback(const enum nb_event event, -+ enum nb_operation operation, -+ const struct lyd_node *dnode) - { -+ const char *value; -+ char xpath[XPATH_MAXLEN]; -+ -+ if (!DEBUG_MODE_CHECK(&nb_dbg_cbs_config, DEBUG_MODE_ALL)) -+ return; -+ -+ yang_dnode_get_path(dnode, xpath, sizeof(xpath)); -+ if (yang_snode_is_typeless_data(dnode->schema)) -+ value = "(none)"; -+ else -+ value = yang_dnode_get_string(dnode, NULL); -+ - zlog_debug( - "northbound callback: event [%s] op [%s] xpath [%s] value [%s]", - nb_event_name(event), nb_operation_name(operation), xpath, -- value ? value : "(NULL)"); -+ value); -+} -+ -+static int nb_callback_create(const struct nb_node *nb_node, -+ enum nb_event event, const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ nb_log_config_callback(event, NB_OP_CREATE, dnode); -+ -+ return nb_node->cbs.create(event, dnode, resource); -+} -+ -+static int nb_callback_modify(const struct nb_node *nb_node, -+ enum nb_event event, const struct lyd_node *dnode, -+ union nb_resource *resource) -+{ -+ nb_log_config_callback(event, NB_OP_MODIFY, dnode); -+ -+ return nb_node->cbs.modify(event, dnode, resource); -+} -+ -+static int nb_callback_destroy(const struct nb_node *nb_node, -+ enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ nb_log_config_callback(event, NB_OP_DESTROY, dnode); -+ -+ return nb_node->cbs.destroy(event, dnode); -+} -+ -+static int nb_callback_move(const struct nb_node *nb_node, enum nb_event event, -+ const struct lyd_node *dnode) -+{ -+ nb_log_config_callback(event, NB_OP_MOVE, dnode); -+ -+ return nb_node->cbs.move(event, dnode); -+} -+ -+static int nb_callback_pre_validate(const struct nb_node *nb_node, -+ const struct lyd_node *dnode) -+{ -+ nb_log_config_callback(NB_EV_VALIDATE, NB_OP_PRE_VALIDATE, dnode); -+ -+ return nb_node->cbs.pre_validate(dnode); -+} -+ -+static void nb_callback_apply_finish(const struct nb_node *nb_node, -+ const struct lyd_node *dnode) -+{ -+ nb_log_config_callback(NB_EV_APPLY, NB_OP_APPLY_FINISH, dnode); -+ -+ nb_node->cbs.apply_finish(dnode); -+} -+ -+struct yang_data *nb_callback_get_elem(const struct nb_node *nb_node, -+ const char *xpath, -+ const void *list_entry) -+{ -+ DEBUGD(&nb_dbg_cbs_state, -+ "northbound callback (get_elem): xpath [%s] list_entry [%p]", -+ xpath, list_entry); -+ -+ return nb_node->cbs.get_elem(xpath, list_entry); -+} -+ -+const void *nb_callback_get_next(const struct nb_node *nb_node, -+ const void *parent_list_entry, -+ const void *list_entry) -+{ -+ DEBUGD(&nb_dbg_cbs_state, -+ "northbound callback (get_next): node [%s] parent_list_entry [%p] list_entry [%p]", -+ nb_node->xpath, parent_list_entry, list_entry); -+ -+ return nb_node->cbs.get_next(parent_list_entry, list_entry); -+} -+ -+int nb_callback_get_keys(const struct nb_node *nb_node, const void *list_entry, -+ struct yang_list_keys *keys) -+{ -+ DEBUGD(&nb_dbg_cbs_state, -+ "northbound callback (get_keys): node [%s] list_entry [%p]", -+ nb_node->xpath, list_entry); -+ -+ return nb_node->cbs.get_keys(list_entry, keys); -+} -+ -+const void *nb_callback_lookup_entry(const struct nb_node *nb_node, -+ const void *parent_list_entry, -+ const struct yang_list_keys *keys) -+{ -+ DEBUGD(&nb_dbg_cbs_state, -+ "northbound callback (lookup_entry): node [%s] parent_list_entry [%p]", -+ nb_node->xpath, parent_list_entry); -+ -+ return nb_node->cbs.lookup_entry(parent_list_entry, keys); -+} -+ -+int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath, -+ const struct list *input, struct list *output) -+{ -+ DEBUGD(&nb_dbg_cbs_rpc, "northbound RPC: %s", xpath); -+ -+ return nb_node->cbs.rpc(xpath, input, output); - } - - /* -@@ -815,15 +917,6 @@ static int nb_callback_configuration(const enum nb_event event, - union nb_resource *resource; - int ret = NB_ERR; - -- if (DEBUG_MODE_CHECK(&nb_dbg_cbs_config, DEBUG_MODE_ALL)) { -- const char *value = "(none)"; -- -- if (dnode && !yang_snode_is_typeless_data(dnode->schema)) -- value = yang_dnode_get_string(dnode, NULL); -- -- yang_dnode_get_path(dnode, xpath, sizeof(xpath)); -- nb_log_callback(event, operation, xpath, value); -- } - - if (event == NB_EV_VALIDATE) - resource = NULL; -@@ -832,16 +925,16 @@ static int nb_callback_configuration(const enum nb_event event, - - switch (operation) { - case NB_OP_CREATE: -- ret = (*nb_node->cbs.create)(event, dnode, resource); -+ ret = nb_callback_create(nb_node, event, dnode, resource); - break; - case NB_OP_MODIFY: -- ret = (*nb_node->cbs.modify)(event, dnode, resource); -+ ret = nb_callback_modify(nb_node, event, dnode, resource); - break; - case NB_OP_DESTROY: -- ret = (*nb_node->cbs.destroy)(event, dnode); -+ ret = nb_callback_destroy(nb_node, event, dnode); - break; - case NB_OP_MOVE: -- ret = (*nb_node->cbs.move)(event, dnode); -+ ret = nb_callback_move(nb_node, event, dnode); - break; - default: - yang_dnode_get_path(dnode, xpath, sizeof(xpath)); -@@ -890,57 +983,6 @@ static int nb_callback_configuration(const enum nb_event event, - return ret; - } - --struct yang_data *nb_callback_get_elem(const struct nb_node *nb_node, -- const char *xpath, -- const void *list_entry) --{ -- DEBUGD(&nb_dbg_cbs_state, -- "northbound callback (get_elem): xpath [%s] list_entry [%p]", -- xpath, list_entry); -- -- return nb_node->cbs.get_elem(xpath, list_entry); --} -- --const void *nb_callback_get_next(const struct nb_node *nb_node, -- const void *parent_list_entry, -- const void *list_entry) --{ -- DEBUGD(&nb_dbg_cbs_state, -- "northbound callback (get_next): node [%s] parent_list_entry [%p] list_entry [%p]", -- nb_node->xpath, parent_list_entry, list_entry); -- -- return nb_node->cbs.get_next(parent_list_entry, list_entry); --} -- --int nb_callback_get_keys(const struct nb_node *nb_node, const void *list_entry, -- struct yang_list_keys *keys) --{ -- DEBUGD(&nb_dbg_cbs_state, -- "northbound callback (get_keys): node [%s] list_entry [%p]", -- nb_node->xpath, list_entry); -- -- return nb_node->cbs.get_keys(list_entry, keys); --} -- --const void *nb_callback_lookup_entry(const struct nb_node *nb_node, -- const void *parent_list_entry, -- const struct yang_list_keys *keys) --{ -- DEBUGD(&nb_dbg_cbs_state, -- "northbound callback (lookup_entry): node [%s] parent_list_entry [%p]", -- nb_node->xpath, parent_list_entry); -- -- return nb_node->cbs.lookup_entry(parent_list_entry, keys); --} -- --int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath, -- const struct list *input, struct list *output) --{ -- DEBUGD(&nb_dbg_cbs_rpc, "northbound RPC: %s", xpath); -- -- return nb_node->cbs.rpc(xpath, input, output); --} -- - static struct nb_transaction * - nb_transaction_new(struct nb_config *config, struct nb_config_cbs *changes, - enum nb_client client, const void *user, const char *comment) -@@ -1058,7 +1100,6 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction) - { - struct nb_config_cbs cbs; - struct nb_config_cb *cb; -- char xpath[XPATH_MAXLEN]; - - /* Initialize tree of 'apply_finish' callbacks. */ - RB_INIT(nb_config_cbs, &cbs); -@@ -1075,6 +1116,8 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction) - * be called though). - */ - if (change->cb.operation == NB_OP_DESTROY) { -+ char xpath[XPATH_MAXLEN]; -+ - dnode = dnode->parent; - if (!dnode) - break; -@@ -1111,15 +1154,8 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction) - } - - /* Call the 'apply_finish' callbacks, sorted by their priorities. */ -- RB_FOREACH (cb, nb_config_cbs, &cbs) { -- if (DEBUG_MODE_CHECK(&nb_dbg_cbs_config, DEBUG_MODE_ALL)) { -- yang_dnode_get_path(cb->dnode, xpath, sizeof(xpath)); -- nb_log_callback(NB_EV_APPLY, NB_OP_APPLY_FINISH, xpath, -- NULL); -- } -- -- (*cb->nb_node->cbs.apply_finish)(cb->dnode); -- } -+ RB_FOREACH (cb, nb_config_cbs, &cbs) -+ nb_callback_apply_finish(cb->nb_node, cb->dnode); - - /* Release memory. */ - while (!RB_EMPTY(nb_config_cbs, &cbs)) { -diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp -index b195f1aeca..66bf05c1ab 100644 ---- a/lib/northbound_grpc.cpp -+++ b/lib/northbound_grpc.cpp -@@ -545,7 +545,8 @@ class NorthboundImpl final : public frr::Northbound::Service - } - - // Execute callback registered for this XPath. -- if (nb_node->cbs.rpc(xpath, input_list, output_list) != NB_OK) { -+ if (nb_callback_rpc(nb_node, xpath, input_list, output_list) -+ != NB_OK) { - flog_warn(EC_LIB_NB_CB_RPC, - "%s: rpc callback failed: %s", __func__, - xpath); diff --git a/net/frr/patches/098-fix_mips_libyang.patch b/net/frr/patches/098-fix_mips_libyang.patch deleted file mode 100644 index 3785cfef3e..0000000000 --- a/net/frr/patches/098-fix_mips_libyang.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- a/lib/northbound.h -+++ b/lib/northbound.h -@@ -504,11 +504,7 @@ struct frr_yang_module_info { - - /* Priority - lower priorities are processed first. */ - uint32_t priority; --#if defined(__GNUC__) && ((__GNUC__ - 0) < 5) && !defined(__clang__) - } nodes[YANG_MODULE_MAX_NODES + 1]; --#else -- } nodes[]; --#endif - }; - - /* Northbound error codes. */ -- 2.30.2