diff options
175 files changed, 4946 insertions, 1474 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index ce22e8404d..c25d0e269a 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -3395,7 +3395,8 @@ void bgp_attr_extcom_tunnel_type(struct attr *attr, bgp_encap_types *tunnel_type) { struct ecommunity *ecom; - int i; + uint32_t i; + if (!attr) return; @@ -4021,7 +4022,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, uint8_t *pnt; int tbit; int ecom_tr_size = 0; - int i; + uint32_t i; for (i = 0; i < attr->ecommunity->size; i++) { pnt = attr->ecommunity->val + (i * 8); diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 7cc9ecd79e..1df646c346 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -89,7 +89,7 @@ char *ecom_mac2str(char *ecom_mac) /* Fetch router-mac from extended community */ bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac) { - int i = 0; + uint32_t i = 0; struct ecommunity *ecom; ecom = attr->ecommunity; @@ -122,7 +122,7 @@ bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac) uint8_t bgp_attr_default_gw(struct attr *attr) { struct ecommunity *ecom; - int i; + uint32_t i; ecom = attr->ecommunity; if (!ecom || !ecom->size) @@ -153,7 +153,7 @@ uint8_t bgp_attr_default_gw(struct attr *attr) uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg) { struct ecommunity *ecom; - int i; + uint32_t i; uint16_t df_pref = 0; *alg = EVPN_MH_DF_ALG_SERVICE_CARVING; @@ -190,7 +190,7 @@ uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg) uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) { struct ecommunity *ecom; - int i; + uint32_t i; uint8_t flags = 0; ecom = attr->ecommunity; @@ -237,7 +237,7 @@ void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag, bool *proxy) { struct ecommunity *ecom; - int i; + uint32_t i; uint8_t val; ecom = attr->ecommunity; diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 43bfb3e2bc..c358d4203e 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -95,7 +95,7 @@ static bool ecommunity_add_val_internal(struct ecommunity *ecom, bool unique, bool overwrite, uint8_t ecom_size) { - int c, ins_idx; + uint32_t c, ins_idx; const struct ecommunity_val *eval4 = (struct ecommunity_val *)eval; const struct ecommunity_val_ipv6 *eval6 = (struct ecommunity_val_ipv6 *)eval; @@ -113,7 +113,7 @@ static bool ecommunity_add_val_internal(struct ecommunity *ecom, /* check also if the extended community itself exists. */ c = 0; - ins_idx = -1; + ins_idx = UINT32_MAX; for (uint8_t *p = ecom->val; c < ecom->size; p += ecom_size, c++) { if (unique) { @@ -145,12 +145,12 @@ static bool ecommunity_add_val_internal(struct ecommunity *ecom, if (ret > 0) { if (!unique) break; - if (ins_idx == -1) + if (ins_idx == UINT32_MAX) ins_idx = c; } } - if (ins_idx == -1) + if (ins_idx == UINT32_MAX) ins_idx = c; /* Add the value to the structure with numerical sorting. */ @@ -193,7 +193,7 @@ static struct ecommunity * ecommunity_uniq_sort_internal(struct ecommunity *ecom, unsigned short ecom_size) { - int i; + uint32_t i; struct ecommunity *new; const void *eval; @@ -895,7 +895,7 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt) */ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) { - int i; + uint32_t i; uint8_t *pnt; uint8_t type = 0; uint8_t sub_type = 0; @@ -1176,8 +1176,8 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) bool ecommunity_match(const struct ecommunity *ecom1, const struct ecommunity *ecom2) { - int i = 0; - int j = 0; + uint32_t i = 0; + uint32_t j = 0; if (ecom1 == NULL && ecom2 == NULL) return true; @@ -1209,7 +1209,7 @@ extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *ecom, uint8_t type, uint8_t subtype) { uint8_t *p; - int c; + uint32_t c; /* If the value already exists in the structure return 0. */ c = 0; @@ -1230,7 +1230,7 @@ bool ecommunity_strip(struct ecommunity *ecom, uint8_t type, uint8_t subtype) { uint8_t *p, *q, *new; - int c, found = 0; + uint32_t c, found = 0; /* When this is fist value, just add it. */ if (ecom == NULL || ecom->val == NULL) return false; @@ -1278,7 +1278,7 @@ bool ecommunity_strip(struct ecommunity *ecom, uint8_t type, bool ecommunity_del_val(struct ecommunity *ecom, struct ecommunity_val *eval) { uint8_t *p; - int c, found = 0; + uint32_t c, found = 0; /* Make sure specified value exists. */ if (ecom == NULL || ecom->val == NULL) @@ -1512,7 +1512,7 @@ void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate *aggregate, const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw) { const uint8_t *eval; - int i; + uint32_t i; if (bw) *bw = 0; diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 6318e7edb1..6d0275a0c3 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -114,7 +114,7 @@ struct ecommunity { uint8_t unit_size; /* Size of Extended Communities attribute. */ - int size; + uint32_t size; /* Extended Communities value. */ uint8_t *val; diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 96f4b0aa78..88747b14b1 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -870,7 +870,7 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr) struct ecommunity ecom_tmp; struct ecommunity_val eval; uint8_t *ecom_val_ptr; - int i; + uint32_t i; uint8_t *pnt; int type = 0; int sub_type = 0; @@ -2710,7 +2710,7 @@ static int is_route_matching_for_vrf(struct bgp *bgp_vrf, { struct attr *attr = pi->attr; struct ecommunity *ecom; - int i; + uint32_t i; assert(attr); /* Route should have valid RT to be even considered. */ @@ -2777,7 +2777,7 @@ static int is_route_matching_for_vni(struct bgp *bgp, struct bgpevpn *vpn, { struct attr *attr = pi->attr; struct ecommunity *ecom; - int i; + uint32_t i; assert(attr); /* Route should have valid RT to be even considered. */ @@ -3260,7 +3260,7 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi, struct prefix_evpn *evp = (struct prefix_evpn *)p; struct attr *attr = pi->attr; struct ecommunity *ecom; - int i; + uint32_t i; struct prefix_evpn ad_evp; assert(attr); @@ -4906,7 +4906,7 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, */ void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf) { - int i = 0; + uint32_t i = 0; struct ecommunity_val *eval = NULL; struct listnode *node = NULL, *nnode = NULL; struct ecommunity *ecom = NULL; @@ -4926,7 +4926,7 @@ void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf) */ void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *bgp_vrf) { - int i; + uint32_t i; struct ecommunity_val *eval; struct listnode *node, *nnode; struct ecommunity *ecom; @@ -4963,7 +4963,7 @@ void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *bgp_vrf) */ void bgp_evpn_map_vni_to_its_rts(struct bgp *bgp, struct bgpevpn *vpn) { - int i; + uint32_t i; struct ecommunity_val *eval; struct listnode *node, *nnode; struct ecommunity *ecom; @@ -4983,7 +4983,7 @@ void bgp_evpn_map_vni_to_its_rts(struct bgp *bgp, struct bgpevpn *vpn) */ void bgp_evpn_unmap_vni_from_its_rts(struct bgp *bgp, struct bgpevpn *vpn) { - int i; + uint32_t i; struct ecommunity_val *eval; struct listnode *node, *nnode; struct ecommunity *ecom; diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 287555b1fc..3cb3d06217 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -60,6 +60,7 @@ #include "bgpd/bgp_keepalives.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_errors.h" +#include "bgpd/bgp_script.h" #include "lib/routing_nb.h" #include "bgpd/bgp_nb.h" #include "bgpd/bgp_evpn_mh.h" @@ -510,6 +511,10 @@ int main(int argc, char **argv) /* Initializations. */ bgp_vrf_init(); +#ifdef HAVE_SCRIPTING + bgp_script_init(); +#endif + hook_register(routing_conf_event, routing_control_plane_protocols_name_validate); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 3bc4c03233..1d66d75288 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -419,8 +419,7 @@ int vpn_leak_label_callback( static bool ecom_intersect(struct ecommunity *e1, struct ecommunity *e2) { - int i; - int j; + uint32_t i, j; if (!e1 || !e2) return false; diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index a3f1eb8401..4f22f5bcfe 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -754,7 +754,7 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p, struct bgp_pbr_entry_main *api) { int ret; - int i, action_count = 0; + uint32_t i, action_count = 0; struct ecommunity *ecom; struct ecommunity_val *ecom_eval; struct bgp_pbr_entry_action *api_action; diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 0f4f26e3ee..ceaf8c0963 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -65,6 +65,7 @@ #include "bgpd/bgp_flowspec_util.h" #include "bgpd/bgp_encap_types.h" #include "bgpd/bgp_mpath.h" +#include "bgpd/bgp_script.h" #ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/bgp_rfapi_cfg.h" @@ -337,99 +338,138 @@ static const struct route_map_rule_cmd route_match_peer_cmd = { route_match_peer_free }; -#if defined(HAVE_LUA) -static enum route_map_cmd_result_t -route_match_command(void *rule, const struct prefix *prefix, void *object) -{ - int status = RMAP_NOMATCH; - u_int32_t locpref = 0; - u_int32_t newlocpref = 0; - enum lua_rm_status lrm_status; - struct bgp_path_info *path = (struct bgp_path_info *)object; - lua_State *L = lua_initialize("/etc/frr/lua.scr"); - - if (L == NULL) - return status; +#ifdef HAVE_SCRIPTING +enum frrlua_rm_status { /* - * Setup the prefix information to pass in + * Script function run failure. This will translate into a deny */ - lua_setup_prefix_table(L, prefix); - - zlog_debug("Set up prefix table"); + LUA_RM_FAILURE = 0, /* - * Setup the bgp_path_info information + * No Match was found for the route map function */ - lua_newtable(L); - lua_pushinteger(L, path->attr->med); - lua_setfield(L, -2, "metric"); - lua_pushinteger(L, path->attr->nh_ifindex); - lua_setfield(L, -2, "ifindex"); - lua_pushstring(L, path->attr->aspath->str); - lua_setfield(L, -2, "aspath"); - lua_pushinteger(L, path->attr->local_pref); - lua_setfield(L, -2, "localpref"); - zlog_debug("%s %d", path->attr->aspath->str, path->attr->nh_ifindex); - lua_setglobal(L, "nexthop"); - - zlog_debug("Set up nexthop information"); + LUA_RM_NOMATCH, /* - * Run the rule + * Match was found but no changes were made to the incoming data. */ - lrm_status = lua_run_rm_rule(L, rule); - switch (lrm_status) { + LUA_RM_MATCH, + /* + * Match was found and data was modified, so figure out what changed + */ + LUA_RM_MATCH_AND_CHANGE, +}; + +static enum route_map_cmd_result_t +route_match_script(void *rule, const struct prefix *prefix, void *object) +{ + const char *scriptname = rule; + struct bgp_path_info *path = (struct bgp_path_info *)object; + + struct frrscript *fs = frrscript_load(scriptname, NULL); + + if (!fs) { + zlog_err("Issue loading script rule; defaulting to no match"); + return RMAP_NOMATCH; + } + + enum frrlua_rm_status status_failure = LUA_RM_FAILURE, + status_nomatch = LUA_RM_NOMATCH, + status_match = LUA_RM_MATCH, + status_match_and_change = LUA_RM_MATCH_AND_CHANGE; + + /* Make result values available */ + struct frrscript_env env[] = { + {"integer", "RM_FAILURE", &status_failure}, + {"integer", "RM_NOMATCH", &status_nomatch}, + {"integer", "RM_MATCH", &status_match}, + {"integer", "RM_MATCH_AND_CHANGE", &status_match_and_change}, + {"integer", "action", &status_failure}, + {"prefix", "prefix", prefix}, + {"attr", "attributes", path->attr}, + {"peer", "peer", path->peer}, + {}}; + + struct frrscript_env results[] = { + {"integer", "action"}, + {"attr", "attributes"}, + {}, + }; + + int result = frrscript_call(fs, env); + + if (result) { + zlog_err("Issue running script rule; defaulting to no match"); + return RMAP_NOMATCH; + } + + enum frrlua_rm_status *lrm_status = + frrscript_get_result(fs, &results[0]); + + int status = RMAP_NOMATCH; + + switch (*lrm_status) { case LUA_RM_FAILURE: - zlog_debug("RM_FAILURE"); + zlog_err( + "Executing route-map match script '%s' failed; defaulting to no match", + scriptname); + status = RMAP_NOMATCH; break; case LUA_RM_NOMATCH: - zlog_debug("RM_NOMATCH"); + status = RMAP_NOMATCH; break; case LUA_RM_MATCH_AND_CHANGE: - zlog_debug("MATCH AND CHANGE"); - lua_getglobal(L, "nexthop"); - path->attr->med = get_integer(L, "metric"); - /* - * This needs to be abstraced with the set function - */ + status = RMAP_MATCH; + zlog_debug("Updating attribute based on script's values"); + + uint32_t locpref = 0; + struct attr *newattr = frrscript_get_result(fs, &results[1]); + + path->attr->med = newattr->med; + if (path->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) locpref = path->attr->local_pref; - newlocpref = get_integer(L, "localpref"); - if (newlocpref != locpref) { - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); - path->attr->local_pref = newlocpref; + if (locpref != newattr->local_pref) { + SET_FLAG(path->attr->flag, + ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)); + path->attr->local_pref = newattr->local_pref; } - status = RMAP_MATCH; + + aspath_free(newattr->aspath); + XFREE(MTYPE_TMP, newattr); break; case LUA_RM_MATCH: - zlog_debug("MATCH ONLY"); status = RMAP_MATCH; break; } - lua_close(L); + + XFREE(MTYPE_TMP, lrm_status); + frrscript_unload(fs); + return status; } -static void *route_match_command_compile(const char *arg) +static void *route_match_script_compile(const char *arg) { - char *command; + char *scriptname; + + scriptname = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); - command = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); - return command; + return scriptname; } -static void -route_match_command_free(void *rule) +static void route_match_script_free(void *rule) { XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static const struct route_map_rule_cmd route_match_command_cmd = { - "command", - route_match_command, - route_match_command_compile, - route_match_command_free +static const struct route_map_rule_cmd route_match_script_cmd = { + "script", + route_match_script, + route_match_script_compile, + route_match_script_free }; -#endif + +#endif /* HAVE_SCRIPTING */ /* `match ip address IP_ACCESS_LIST' */ @@ -4096,30 +4136,29 @@ DEFUN (no_match_peer, RMAP_EVENT_MATCH_DELETED); } -#if defined(HAVE_LUA) -DEFUN (match_command, - match_command_cmd, - "match command WORD", - MATCH_STR - "Run a command to match\n" - "The command to run\n") -{ - return bgp_route_match_add(vty, "command", argv[2]->arg, - RMAP_EVENT_FILTER_ADDED); -} - -DEFUN (no_match_command, - no_match_command_cmd, - "no match command WORD", +#ifdef HAVE_SCRIPTING +DEFUN (match_script, + match_script_cmd, + "[no] match script WORD", NO_STR MATCH_STR - "Run a command to match\n" - "The command to run\n") + "Execute script to determine match\n" + "The script name to run, without .lua; e.g. 'myroutemap' to run myroutemap.lua\n") { - return bgp_route_match_delete(vty, "command", argv[3]->arg, - RMAP_EVENT_FILTER_DELETED); + bool no = strmatch(argv[0]->text, "no"); + int i = 0; + argv_find(argv, argc, "WORD", &i); + const char *script = argv[i]->arg; + + if (no) { + return bgp_route_match_delete(vty, "script", script, + RMAP_EVENT_FILTER_DELETED); + } else { + return bgp_route_match_add(vty, "script", script, + RMAP_EVENT_FILTER_ADDED); + } } -#endif +#endif /* HAVE_SCRIPTING */ /* match probability */ DEFUN (match_probability, @@ -5633,8 +5672,8 @@ void bgp_route_map_init(void) route_map_install_match(&route_match_peer_cmd); route_map_install_match(&route_match_local_pref_cmd); -#if defined(HAVE_LUA) - route_map_install_match(&route_match_command_cmd); +#ifdef HAVE_SCRIPTING + route_map_install_match(&route_match_script_cmd); #endif route_map_install_match(&route_match_ip_address_cmd); route_map_install_match(&route_match_ip_next_hop_cmd); @@ -5798,9 +5837,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &no_set_ipv6_nexthop_prefer_global_cmd); install_element(RMAP_NODE, &set_ipv6_nexthop_peer_cmd); install_element(RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd); -#if defined(HAVE_LUA) - install_element(RMAP_NODE, &match_command_cmd); - install_element(RMAP_NODE, &no_match_command_cmd); +#ifdef HAVE_SCRIPTING + install_element(RMAP_NODE, &match_script_cmd); #endif } diff --git a/bgpd/bgp_script.c b/bgpd/bgp_script.c new file mode 100644 index 0000000000..0cda1927f8 --- /dev/null +++ b/bgpd/bgp_script.c @@ -0,0 +1,192 @@ +/* BGP scripting foo + * Copyright (C) 2020 NVIDIA Corporation + * Quentin Young + * + * 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; see the file COPYING; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <zebra.h> + +#ifdef HAVE_SCRIPTING + +#include "bgpd.h" +#include "bgp_script.h" +#include "bgp_debug.h" +#include "bgp_aspath.h" +#include "frratomic.h" +#include "frrscript.h" +#include "frrlua.h" + +static void lua_pushpeer(lua_State *L, const struct peer *peer) +{ + lua_newtable(L); + lua_pushinteger(L, peer->as); + lua_setfield(L, -2, "remote_as"); + lua_pushinteger(L, peer->local_as); + lua_setfield(L, -2, "local_as"); + lua_pushinaddr(L, &peer->remote_id); + lua_setfield(L, -2, "remote_id"); + lua_pushinaddr(L, &peer->local_id); + lua_setfield(L, -2, "local_id"); + lua_pushstring(L, lookup_msg(bgp_status_msg, peer->status, NULL)); + lua_setfield(L, -2, "state"); + lua_pushstring(L, peer->desc ? peer->desc : ""); + lua_setfield(L, -2, "description"); + lua_pushtimet(L, &peer->uptime); + lua_setfield(L, -2, "uptime"); + lua_pushtimet(L, &peer->readtime); + lua_setfield(L, -2, "last_readtime"); + lua_pushtimet(L, &peer->resettime); + lua_setfield(L, -2, "last_resettime"); + lua_pushsockunion(L, peer->su_local); + lua_setfield(L, -2, "local_address"); + lua_pushsockunion(L, peer->su_remote); + lua_setfield(L, -2, "remote_address"); + lua_pushinteger(L, peer->cap); + lua_setfield(L, -2, "capabilities"); + lua_pushinteger(L, peer->flags); + lua_setfield(L, -2, "flags"); + lua_pushstring(L, peer->password ? peer->password : ""); + lua_setfield(L, -2, "password"); + + /* Nested tables here */ + lua_newtable(L); + { + lua_newtable(L); + { + lua_pushinteger(L, peer->holdtime); + lua_setfield(L, -2, "hold"); + lua_pushinteger(L, peer->keepalive); + lua_setfield(L, -2, "keepalive"); + lua_pushinteger(L, peer->connect); + lua_setfield(L, -2, "connect"); + lua_pushinteger(L, peer->routeadv); + lua_setfield(L, -2, "route_advertisement"); + } + lua_setfield(L, -2, "configured"); + + lua_newtable(L); + { + lua_pushinteger(L, peer->v_holdtime); + lua_setfield(L, -2, "hold"); + lua_pushinteger(L, peer->v_keepalive); + lua_setfield(L, -2, "keepalive"); + lua_pushinteger(L, peer->v_connect); + lua_setfield(L, -2, "connect"); + lua_pushinteger(L, peer->v_routeadv); + lua_setfield(L, -2, "route_advertisement"); + } + lua_setfield(L, -2, "negotiated"); + } + lua_setfield(L, -2, "timers"); + + lua_newtable(L); + { + lua_pushinteger(L, atomic_load_explicit(&peer->open_in, + memory_order_relaxed)); + lua_setfield(L, -2, "open_in"); + lua_pushinteger(L, atomic_load_explicit(&peer->open_out, + memory_order_relaxed)); + lua_setfield(L, -2, "open_out"); + lua_pushinteger(L, atomic_load_explicit(&peer->update_in, + memory_order_relaxed)); + lua_setfield(L, -2, "update_in"); + lua_pushinteger(L, atomic_load_explicit(&peer->update_out, + memory_order_relaxed)); + lua_setfield(L, -2, "update_out"); + lua_pushinteger(L, atomic_load_explicit(&peer->update_time, + memory_order_relaxed)); + lua_setfield(L, -2, "update_time"); + lua_pushinteger(L, atomic_load_explicit(&peer->keepalive_in, + memory_order_relaxed)); + lua_setfield(L, -2, "keepalive_in"); + lua_pushinteger(L, atomic_load_explicit(&peer->keepalive_out, + memory_order_relaxed)); + lua_setfield(L, -2, "keepalive_out"); + lua_pushinteger(L, atomic_load_explicit(&peer->notify_in, + memory_order_relaxed)); + lua_setfield(L, -2, "notify_in"); + lua_pushinteger(L, atomic_load_explicit(&peer->notify_out, + memory_order_relaxed)); + lua_setfield(L, -2, "notify_out"); + lua_pushinteger(L, atomic_load_explicit(&peer->refresh_in, + memory_order_relaxed)); + lua_setfield(L, -2, "refresh_in"); + lua_pushinteger(L, atomic_load_explicit(&peer->refresh_out, + memory_order_relaxed)); + lua_setfield(L, -2, "refresh_out"); + lua_pushinteger(L, atomic_load_explicit(&peer->dynamic_cap_in, + memory_order_relaxed)); + lua_setfield(L, -2, "dynamic_cap_in"); + lua_pushinteger(L, atomic_load_explicit(&peer->dynamic_cap_out, + memory_order_relaxed)); + lua_setfield(L, -2, "dynamic_cap_out"); + lua_pushinteger(L, peer->established); + lua_setfield(L, -2, "times_established"); + lua_pushinteger(L, peer->dropped); + lua_setfield(L, -2, "times_dropped"); + } + lua_setfield(L, -2, "stats"); +} + +static void lua_pushattr(lua_State *L, const struct attr *attr) +{ + lua_newtable(L); + lua_pushinteger(L, attr->med); + lua_setfield(L, -2, "metric"); + lua_pushinteger(L, attr->nh_ifindex); + lua_setfield(L, -2, "ifindex"); + lua_pushstring(L, attr->aspath->str); + lua_setfield(L, -2, "aspath"); + lua_pushinteger(L, attr->local_pref); + lua_setfield(L, -2, "localpref"); +} + +static void *lua_toattr(lua_State *L, int idx) +{ + struct attr *attr = XCALLOC(MTYPE_TMP, sizeof(struct attr)); + + lua_getfield(L, -1, "metric"); + attr->med = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, -1, "ifindex"); + attr->nh_ifindex = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, -1, "aspath"); + attr->aspath = aspath_str2aspath(lua_tostring(L, -1)); + lua_pop(L, 1); + lua_getfield(L, -1, "localpref"); + attr->local_pref = lua_tointeger(L, -1); + lua_pop(L, 1); + + return attr; +} + +struct frrscript_codec frrscript_codecs_bgpd[] = { + {.typename = "peer", + .encoder = (encoder_func)lua_pushpeer, + .decoder = NULL}, + {.typename = "attr", + .encoder = (encoder_func)lua_pushattr, + .decoder = lua_toattr}, + {}}; + +void bgp_script_init(void) +{ + frrscript_register_type_codecs(frrscript_codecs_bgpd); +} + +#endif /* HAVE_SCRIPTING */ diff --git a/bgpd/bgp_script.h b/bgpd/bgp_script.h new file mode 100644 index 0000000000..6682c2eebd --- /dev/null +++ b/bgpd/bgp_script.h @@ -0,0 +1,34 @@ +/* BGP scripting foo + * Copyright (C) 2020 NVIDIA Corporation + * Quentin Young + * + * 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; see the file COPYING; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +#ifndef __BGP_SCRIPT__ +#define __BGP_SCRIPT__ + +#include <zebra.h> + +#ifdef HAVE_SCRIPTING + +/* + * Initialize scripting stuff. + */ +void bgp_script_init(void); + +#endif /* HAVE_SCRIPTING */ + +#endif /* __BGP_SCRIPT__ */ diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index b1ff9ac251..30babb7b76 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -518,10 +518,7 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest, /* bgp_path_info adj_out reference */ adv->pathi = bgp_path_info_lock(path); - if (attr) - adv->baa = bgp_advertise_intern(subgrp->hash, attr); - else - adv->baa = baa_new(); + adv->baa = bgp_advertise_intern(subgrp->hash, attr); adv->adj = adj; adj->attr_hash = attr_hash; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 114a00cc36..e5f1b78b66 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -4952,27 +4952,63 @@ ALIAS_HIDDEN(no_neighbor_activate, no_neighbor_activate_hidden_cmd, NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Enable the Address Family for this Neighbor\n") -DEFUN_YANG (neighbor_set_peer_group, - neighbor_set_peer_group_cmd, - "neighbor <A.B.C.D|X:X::X:X|WORD> peer-group PGNAME", - NEIGHBOR_STR - NEIGHBOR_ADDR_STR2 - "Member of the peer-group\n" - "Peer-group name\n") +DEFUN (neighbor_set_peer_group, + neighbor_set_peer_group_cmd, + "neighbor <A.B.C.D|X:X::X:X|WORD> peer-group PGNAME", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Member of the peer-group\n" + "Peer-group name\n") { + VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_peer = 1; int idx_word = 3; - char base_xpath[XPATH_MAXLEN]; + int ret; + as_t as; + union sockunion su; + struct peer *peer; + struct peer_group *group; - if (peer_and_group_lookup_nb(vty, argv[idx_peer]->arg, base_xpath, - sizeof(base_xpath), NULL) - < 0) + ret = str2sockunion(argv[idx_peer]->arg, &su); + if (ret < 0) { + peer = peer_lookup_by_conf_if(bgp, argv[idx_peer]->arg); + if (!peer) { + vty_out(vty, "%% Malformed address or name: %s\n", + argv[idx_peer]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + } else { + if (peer_address_self_check(bgp, &su)) { + vty_out(vty, + "%% Can not configure the local system as neighbor\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Disallow for dynamic neighbor. */ + peer = peer_lookup(bgp, &su); + if (peer && peer_dynamic_neighbor(peer)) { + vty_out(vty, + "%% Operation not allowed on a dynamic neighbor\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + + group = peer_group_lookup(bgp, argv[idx_word]->arg); + if (!group) { + vty_out(vty, "%% Configure the peer-group first\n"); return CMD_WARNING_CONFIG_FAILED; + } - nb_cli_enqueue_change(vty, "./peer-group", NB_OP_MODIFY, - argv[idx_word]->arg); + ret = peer_group_bind(bgp, &su, peer, group, &as); - return nb_cli_apply_changes(vty, base_xpath); + if (ret == BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT) { + vty_out(vty, + "%% Peer with AS %u cannot be in this peer-group, members must be all internal or all external\n", + as); + return CMD_WARNING_CONFIG_FAILED; + } + + return bgp_vty_return(vty, ret); } ALIAS_HIDDEN(neighbor_set_peer_group, neighbor_set_peer_group_hidden_cmd, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 9a2693fd56..368397d7aa 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -6974,6 +6974,22 @@ int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi, return 0; } +static bool peer_maximum_prefix_clear_overflow(struct peer *peer) +{ + if (!CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) + return false; + + UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); + if (peer->t_pmax_restart) { + BGP_TIMER_OFF(peer->t_pmax_restart); + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Maximum-prefix restart timer cancelled", + peer->host); + } + BGP_EVENT_ADD(peer, BGP_Start); + return true; +} + int peer_maximum_prefix_set(struct peer *peer, afi_t afi, safi_t safi, uint32_t max, uint8_t threshold, int warning, uint16_t restart, bool force) @@ -7095,7 +7111,11 @@ int peer_maximum_prefix_unset(struct peer *peer, afi_t afi, safi_t safi) member->pmax[afi][safi] = 0; member->pmax_threshold[afi][safi] = 0; member->pmax_restart[afi][safi] = 0; + + peer_maximum_prefix_clear_overflow(member); } + } else { + peer_maximum_prefix_clear_overflow(peer); } return 0; @@ -7130,6 +7150,7 @@ int is_ebgp_multihop_configured(struct peer *peer) int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops) { struct peer_group *group; + struct peer *gpeer; struct listnode *node, *nnode; int ret; @@ -7166,9 +7187,10 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops) return ret; } else { group = peer->group; + group->conf->gtsm_hops = gtsm_hops; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, - peer)) { - peer->gtsm_hops = group->conf->gtsm_hops; + gpeer)) { + gpeer->gtsm_hops = group->conf->gtsm_hops; /* Calling ebgp multihop also resets the * session. @@ -7178,7 +7200,7 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops) * value is * irrelevant. */ - peer_ebgp_multihop_set(peer, MAXTTL); + peer_ebgp_multihop_set(gpeer, MAXTTL); } } } else { @@ -7199,9 +7221,10 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops) MAXTTL + 1 - gtsm_hops); } else { group = peer->group; + group->conf->gtsm_hops = gtsm_hops; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, - peer)) { - peer->gtsm_hops = group->conf->gtsm_hops; + gpeer)) { + gpeer->gtsm_hops = group->conf->gtsm_hops; /* Change setting of existing peer * established then change value (may break @@ -7211,17 +7234,18 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops) * no session then do nothing (will get * handled by next connection) */ - if (peer->fd >= 0 - && peer->gtsm_hops + if (gpeer->fd >= 0 + && gpeer->gtsm_hops != BGP_GTSM_HOPS_DISABLED) sockopt_minttl( - peer->su.sa.sa_family, peer->fd, - MAXTTL + 1 - peer->gtsm_hops); - if ((peer->status < Established) - && peer->doppelganger - && (peer->doppelganger->fd >= 0)) - sockopt_minttl(peer->su.sa.sa_family, - peer->doppelganger->fd, + gpeer->su.sa.sa_family, + gpeer->fd, + MAXTTL + 1 - gpeer->gtsm_hops); + if ((gpeer->status < Established) + && gpeer->doppelganger + && (gpeer->doppelganger->fd >= 0)) + sockopt_minttl(gpeer->su.sa.sa_family, + gpeer->doppelganger->fd, MAXTTL + 1 - gtsm_hops); } } @@ -7298,18 +7322,8 @@ int peer_clear(struct peer *peer, struct listnode **nnode) { if (!CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN) || !CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SHUTDOWN)) { - if (CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) { - UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); - if (peer->t_pmax_restart) { - BGP_TIMER_OFF(peer->t_pmax_restart); - if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s Maximum-prefix restart timer canceled", - peer->host); - } - BGP_EVENT_ADD(peer, BGP_Start); + if (peer_maximum_prefix_clear_overflow(peer)) return 0; - } peer->v_start = BGP_INIT_START_TIMER; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 3d87b63542..b2732a40b4 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -984,7 +984,7 @@ static int rfapiEcommunitiesMatchBeec(struct ecommunity *ecom, int rfapiEcommunitiesIntersect(struct ecommunity *e1, struct ecommunity *e2) { - int i, j; + uint32_t i, j; if (!e1 || !e2) return 0; @@ -1014,7 +1014,8 @@ int rfapiEcommunitiesIntersect(struct ecommunity *e1, struct ecommunity *e2) int rfapiEcommunityGetLNI(struct ecommunity *ecom, uint32_t *lni) { if (ecom) { - int i; + uint32_t i; + for (i = 0; i < ecom->size; ++i) { uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE); @@ -1034,7 +1035,8 @@ int rfapiEcommunityGetEthernetTag(struct ecommunity *ecom, uint16_t *tag_id) struct bgp *bgp = bgp_get_default(); *tag_id = 0; /* default to untagged */ if (ecom) { - int i; + uint32_t i; + for (i = 0; i < ecom->size; ++i) { as_t as = 0; int encode = 0; diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c index 762cd2596f..bc29f05aeb 100644 --- a/bgpd/rfapi/vnc_export_bgp.c +++ b/bgpd/rfapi/vnc_export_bgp.c @@ -134,7 +134,7 @@ static void encap_attr_export_ce(struct attr *new, struct attr *orig, static int getce(struct bgp *bgp, struct attr *attr, struct prefix *pfx_ce) { uint8_t *ecp; - int i; + uint32_t i; uint16_t localadmin = bgp->rfapi_cfg->resolve_nve_roo_local_admin; for (ecp = attr->ecommunity->val, i = 0; i < attr->ecommunity->size; diff --git a/bgpd/subdir.am b/bgpd/subdir.am index ac84f4b9e4..df1555c32a 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -96,6 +96,7 @@ bgpd_libbgp_a_SOURCES = \ bgpd/bgp_regex.c \ bgpd/bgp_route.c \ bgpd/bgp_routemap.c \ + bgpd/bgp_script.c \ bgpd/bgp_table.c \ bgpd/bgp_updgrp.c \ bgpd/bgp_updgrp_adv.c \ @@ -175,6 +176,7 @@ noinst_HEADERS += \ bgpd/bgp_rd.h \ bgpd/bgp_regex.h \ bgpd/bgp_route.h \ + bgpd/bgp_script.h \ bgpd/bgp_table.h \ bgpd/bgp_updgrp.h \ bgpd/bgp_vpn.h \ diff --git a/configure.ac b/configure.ac index 0cbf4d22e6..8f9517763d 100755 --- a/configure.ac +++ b/configure.ac @@ -138,6 +138,12 @@ AC_ARG_WITH([moduledir], [AS_HELP_STRING([--with-moduledir=DIR], [module directo ]) AC_SUBST([moduledir], [$moduledir]) +AC_ARG_WITH([scriptdir], [AS_HELP_STRING([--with-scriptdir=DIR], [script directory (${sysconfdir}/scripts)])], [ + scriptdir="$withval" +], [ + scriptdir="\${sysconfdir}/scripts" +]) +AC_SUBST([scriptdir], [$scriptdir]) AC_ARG_WITH([yangmodelsdir], [AS_HELP_STRING([--with-yangmodelsdir=DIR], [yang models directory (${datarootdir}/yang)])], [ yangmodelsdir="$withval" @@ -274,24 +280,22 @@ if test "$enable_clang_coverage" = "yes"; then ]) fi +if test "$enable_scripting" = "yes"; then + AX_PROG_LUA([5.3]) + AX_LUA_HEADERS + AX_LUA_LIBS([ + AC_DEFINE([HAVE_SCRIPTING], [1], [Have support for scripting]) + LIBS="$LIBS $LUA_LIB" + ]) +fi + if test "$enable_dev_build" = "yes"; then AC_DEFINE([DEV_BUILD], [1], [Build for development]) if test "$orig_cflags" = ""; then AC_C_FLAG([-g3]) AC_C_FLAG([-O0]) fi - if test "$enable_lua" = "yes"; then - AX_PROG_LUA([5.3]) - AX_LUA_HEADERS - AX_LUA_LIBS([ - AC_DEFINE([HAVE_LUA], [1], [Have support for Lua interpreter]) - LIBS="$LIBS $LUA_LIB" - ]) - fi else - if test "$enable_lua" = "yes"; then - AC_MSG_ERROR([Lua is not meant to be built/used outside of development at this time]) - fi if test "$orig_cflags" = ""; then AC_C_FLAG([-g]) AC_C_FLAG([-O2]) @@ -697,8 +701,8 @@ fi AC_ARG_ENABLE([dev_build], AS_HELP_STRING([--enable-dev-build], [build for development])) -AC_ARG_ENABLE([lua], - AS_HELP_STRING([--enable-lua], [Build Lua scripting])) +AC_ARG_ENABLE([scripting], + AS_HELP_STRING([--enable-scripting], [Build with scripting support])) AC_ARG_ENABLE([netlink-debug], AS_HELP_STRING([--disable-netlink-debug], [pretty print netlink debug messages])) @@ -1862,7 +1866,7 @@ dnl --------------- dnl sysrepo dnl --------------- if test "$enable_sysrepo" = "yes"; then - PKG_CHECK_MODULES([SYSREPO], [libsysrepo], + PKG_CHECK_MODULES([SYSREPO], [sysrepo], [AC_DEFINE([HAVE_SYSREPO], [1], [Enable sysrepo integration]) SYSREPO=true], [SYSREPO=false @@ -2446,19 +2450,23 @@ CFG_SBIN="$sbindir" CFG_STATE="$frr_statedir" CFG_MODULE="$moduledir" CFG_YANGMODELS="$yangmodelsdir" +CFG_SCRIPT="$scriptdir" for I in 1 2 3 4 5 6 7 8 9 10; do eval CFG_SYSCONF="\"$CFG_SYSCONF\"" eval CFG_SBIN="\"$CFG_SBIN\"" eval CFG_STATE="\"$CFG_STATE\"" eval CFG_MODULE="\"$CFG_MODULE\"" eval CFG_YANGMODELS="\"$CFG_YANGMODELS\"" + eval CFG_SCRIPT="\"$CFG_SCRIPT\"" done AC_SUBST([CFG_SYSCONF]) AC_SUBST([CFG_SBIN]) AC_SUBST([CFG_STATE]) AC_SUBST([CFG_MODULE]) +AC_SUBST([CFG_SCRIPT]) AC_SUBST([CFG_YANGMODELS]) AC_DEFINE_UNQUOTED([MODULE_PATH], ["$CFG_MODULE"], [path to modules]) +AC_DEFINE_UNQUOTED([SCRIPT_PATH], ["$CFG_SCRIPT"], [path to scripts]) AC_DEFINE_UNQUOTED([YANG_MODELS_PATH], ["$CFG_YANGMODELS"], [path to YANG data models]) AC_DEFINE_UNQUOTED([WATCHFRR_SH_PATH], ["${CFG_SBIN%/}/watchfrr.sh"], [path to watchfrr.sh]) @@ -2582,6 +2590,7 @@ state file directory : ${frr_statedir} config file directory : `eval echo \`echo ${sysconfdir}\`` example directory : `eval echo \`echo ${exampledir}\`` module directory : ${CFG_MODULE} +script directory : ${CFG_SCRIPT} user to run as : ${enable_user} group to run as : ${enable_group} group for vty sockets : ${enable_vty_group} diff --git a/debian/control b/debian/control index 4aaa9f21bf..b9e96b55d0 100644 --- a/debian/control +++ b/debian/control @@ -29,7 +29,8 @@ Build-Depends: bison, python3-dev, python3-pytest <!nocheck>, python3-sphinx, - texinfo (>= 4.7) + texinfo (>= 4.7), + liblua5.3-dev <pkg.frr.lua> Standards-Version: 4.5.0.3 Homepage: https://www.frrouting.org/ Vcs-Browser: https://github.com/FRRouting/frr/tree/debian/master diff --git a/debian/rules b/debian/rules index 6cc03c378a..25ae04261d 100755 --- a/debian/rules +++ b/debian/rules @@ -29,6 +29,12 @@ else CONF_SYSTEMD=--enable-systemd=no endif +ifeq ($(filter pkg.frr.lua,$(DEB_BUILD_PROFILES)),) + CONF_LUA=--disable-scripting +else + CONF_LUA=--enable-scripting +endif + export PYTHON=python3 %: @@ -49,6 +55,7 @@ override_dh_auto_configure: \ $(CONF_SYSTEMD) \ $(CONF_RPKI) \ + $(CONF_LUA) \ --with-libpam \ --enable-doc \ --enable-doc-html \ diff --git a/doc/developer/library.rst b/doc/developer/library.rst index 3d5c6a2a15..1bfe5df2f0 100644 --- a/doc/developer/library.rst +++ b/doc/developer/library.rst @@ -15,6 +15,6 @@ Library Facilities (libfrr) hooks cli modules - lua + scripting diff --git a/doc/developer/lua.rst b/doc/developer/lua.rst deleted file mode 100644 index 3315c31ad7..0000000000 --- a/doc/developer/lua.rst +++ /dev/null @@ -1,65 +0,0 @@ -.. _lua: - -Lua -=== - -Lua is currently experimental within FRR and has very limited -support. If you would like to compile FRR with Lua you must -follow these steps: - -1. Installation of Relevant Libraries - - .. code-block:: shell - - apt-get install lua5.3 liblua5-3 liblua5.3-dev - - These are the Debian libraries that are needed. There should - be equivalent RPM's that can be found - -2. Compilation - - Configure needs these options - - .. code-block:: shell - - ./configure --enable-dev-build --enable-lua <all other interesting options> - - Typically you just include the two new enable lines to build with it. - -3. Using Lua - - * Copy tools/lua.scr into /etc/frr - - * Create a route-map match command - - .. code-block:: console - - ! - router bgp 55 - neighbor 10.50.11.116 remote-as external - address-family ipv4 unicast - neighbor 10.50.11.116 route-map TEST in - exit-address-family - ! - route-map TEST permit 10 - match command mooey - ! - - * In the lua.scr file make sure that you have a function named 'mooey' - - .. code-block:: console - - function mooey () - zlog_debug(string.format("afi: %d: %s %d ifdx: %d aspath: %s localpref: %d", - prefix.family, prefix.route, nexthop.metric, - nexthop.ifindex, nexthop.aspath, nexthop.localpref)) - - nexthop.metric = 33 - nexthop.localpref = 13 - return 3 - end - -4. General Comments - - Please be aware that this is extremely experimental and needs a ton of work - to get this up into a state that is usable. diff --git a/doc/developer/scripting.rst b/doc/developer/scripting.rst new file mode 100644 index 0000000000..b0413619ab --- /dev/null +++ b/doc/developer/scripting.rst @@ -0,0 +1,433 @@ +.. _scripting: + +Scripting +========= + +.. seealso:: User docs for scripting + +Overview +-------- + +FRR has the ability to call Lua scripts to perform calculations, make +decisions, or otherwise extend builtin behavior with arbitrary user code. This +is implemented using the standard Lua C bindings. The supported version of Lua +is 5.3. + +C objects may be passed into Lua and Lua objects may be retrieved by C code via +a marshalling system. In this way, arbitrary data from FRR may be passed to +scripts. It is possible to pass C functions as well. + +The Lua environment is isolated from the C environment; user scripts cannot +access FRR's address space unless explicitly allowed by FRR. + +For general information on how Lua is used to extend C, refer to Part IV of +"Programming in Lua". + +https://www.lua.org/pil/contents.html#24 + + +Design +------ + +Why Lua +^^^^^^^ + +Lua is designed to be embedded in C applications. It is very small; the +standard library is 220K. It is relatively fast. It has a simple, minimal +syntax that is relatively easy to learn and can be understood by someone with +little to no programming experience. Moreover it is widely used to add +scripting capabilities to applications. In short it is designed for this task. + +Reasons against supporting multiple scripting languages: + +- Each language would require different FFI methods, and specifically + different object encoders; a lot of code +- Languages have different capabilities that would have to be brought to + parity with each other; a lot of work +- Languages have vastly different performance characteristics; this would + create alot of basically unfixable issues, and result in a single de facto + standard scripting language (the fastest) +- Each language would need a dedicated maintainer for the above reasons; + this is pragmatically difficult +- Supporting multiple languages fractures the community and limits the audience + with which a given script can be shared + +General +^^^^^^^ + +FRR's concept of a script is somewhat abstracted away from the fact that it is +Lua underneath. A script in has two things: + +- name +- state + +In code: + +.. code-block:: c + + struct frrscript { + /* Script name */ + char *name; + + /* Lua state */ + struct lua_State *L; + }; + + +``name`` is simply a string. Everything else is in ``state``, which is itself a +Lua library object (``lua_State``). This is an opaque struct that is +manipulated using ``lua_*`` functions. The basic ones are imported from +``lua.h`` and the rest are implemented within FRR to fill our use cases. The +thing to remember is that all operations beyond the initial loading the script +take place on this opaque state object. + +There are four basic actions that can be done on a script: + +- load +- execute +- query state +- unload + +They are typically done in this order. + + +Loading +^^^^^^^ + +A snippet of Lua code is referred to as a "chunk". These are simply text. FRR +presently assumes chunks are located in individual files specific to one task. +These files are stored in the scripts directory and must end in ``.lua``. + +A script object is created by loading a script. This is done with +``frrscript_load()``. This function takes the name of the script and an +optional callback function. The string ".lua" is appended to the script name, +and the resultant filename is looked for in the scripts directory. + +For example, to load ``/etc/frr/scripts/bingus.lua``: + +.. code-block:: c + + struct frrscript *fs = frrscript_load("bingus", NULL); + +During loading the script is validated for syntax and its initial environment +is setup. By default this does not include the Lua standard library; there are +security issues to consider, though for practical purposes untrusted users +should not be able to write the scripts directory anyway. If desired the Lua +standard library may be added to the script environment using +``luaL_openlibs(fs->L)`` after loading the script. Further information on +setting up the script environment is in the Lua manual. + + +Executing +^^^^^^^^^ + +After loading, scripts may be executed. A script may take input in the form of +variable bindings set in its environment prior to being run, and may provide +results by setting the value of variables. Arbitrary C values may be +transferred into the script environment, including functions. + +A typical execution call looks something like this: + +.. code-block:: c + + struct frrscript *fs = frrscript_load(...); + + int status_ok = 0, status_fail = 1; + struct prefix p = ...; + + struct frrscript_env env[] = { + {"integer", "STATUS_FAIL", &status_fail}, + {"integer", "STATUS_OK", &status_ok}, + {"prefix", "myprefix", &p}, + {}}; + + int result = frrscript_call(fs, env); + + +To execute a loaded script, we need to define the inputs. These inputs are +passed by binding values to variable names that will be accessible within the +Lua environment. Basically, all communication with the script takes place via +global variables within the script, and to provide inputs we predefine globals +before the script runs. This is done by passing ``frrscript_call()`` an array +of ``struct frrscript_env``. Each struct has three fields. The first identifies +the type of the value being passed; more on this later. The second defines the +name of the global variable within the script environment to bind the third +argument (the value) to. + +The script is then executed and returns a general status code. In the success +case this will be 0, otherwise it will be nonzero. The script itself does not +determine this code, it is provided by the Lua interpreter. + + +Querying State +^^^^^^^^^^^^^^ + +When a chunk is executed, its state at exit is preserved and can be inspected. + +After running a script, results may be retrieved by querying the script's +state. Again this is done by retrieving the values of global variables, which +are known to the script author to be "output" variables. + +A result is retrieved like so: + +.. code-block:: c + + struct frrscript_env myresult = {"string", "myresult"}; + + char *myresult = frrscript_get_result(fs, &myresult); + + ... do something ... + + XFREE(MTYPE_TMP, myresult); + + +As with arguments, results are retrieved by providing a ``struct +frrscript_env`` specifying a type and a global name. No value is necessary, nor +is it modified by ``frrscript_get_result()``. That function simply extracts the +requested value from the script state and returns it. + +In most cases the returned value will be allocated with ``MTYPE_TMP`` and will +need to be freed after use. + + +Unloading +^^^^^^^^^ + +To destroy a script and its associated state: + +.. code-block:: c + + frrscript_unload(fs); + +Values returned by ``frrscript_get_result`` are still valid after the script +they were retrieved from is unloaded. + +Note that you must unload and then load the script if you want to reset its +state, for example to run it again with different inputs. Otherwise the state +from the previous run carries over into subsequent runs. + + +.. _marshalling: + +Marshalling +^^^^^^^^^^^ + +Earlier sections glossed over the meaning of the type name field in ``struct +frrscript_env`` and how data is passed between C and Lua. Lua, as a dynamically +typed, garbage collected language, cannot directly use C values without some +kind of marshalling / unmarshalling system to translate types between the two +runtimes. + +Lua communicates with C code using a stack. C code wishing to provide data to +Lua scripts must provide a function that marshalls the C data into a Lua +representation and pushes it on the stack. C code wishing to retrieve data from +Lua must provide a corresponding unmarshalling function that retrieves a Lua +value from the stack and converts it to the corresponding C type. These two +functions, together with a chosen name of the type they operate on, are +referred to as ``codecs`` in FRR. + +A codec is defined as: + +.. code-block:: c + + typedef void (*encoder_func)(lua_State *, const void *); + typedef void *(*decoder_func)(lua_State *, int); + + struct frrscript_codec { + const char *typename; + encoder_func encoder; + decoder_func decoder; + }; + +A typename string and two function pointers. + +``typename`` can be anything you want. For example, for the combined types of +``struct prefix`` and its equivalent in Lua I have chosen the name ``prefix``. +There is no restriction on naming here, it is just a human name used as a key +and specified when passing and retrieving values. + +``encoder`` is a function that takes a ``lua_State *`` and a C type and pushes +onto the Lua stack a value representing the C type. For C structs, the usual +case, this will typically be a Lua table (tables are the only datastructure Lua +has). For example, here is the encoder function for ``struct prefix``: + + +.. code-block:: c + + void lua_pushprefix(lua_State *L, const struct prefix *prefix) + { + char buffer[PREFIX_STRLEN]; + + zlog_debug("frrlua: pushing prefix table"); + + lua_newtable(L); + lua_pushstring(L, prefix2str(prefix, buffer, PREFIX_STRLEN)); + lua_setfield(L, -2, "network"); + lua_pushinteger(L, prefix->prefixlen); + lua_setfield(L, -2, "length"); + lua_pushinteger(L, prefix->family); + lua_setfield(L, -2, "family"); + } + +This function pushes a single value onto the Lua stack. It is a table whose equivalent in Lua is: + +.. code-block:: + + { ["network"] = "1.2.3.4/24", ["prefixlen"] = 24, ["family"] = 2 } + + +``decoder`` does the reverse; it takes a ``lua_State *`` and an index into the +stack, and unmarshalls a Lua value there into the corresponding C type. Again +for ``struct prefix``: + + +.. code-block:: c + + void *lua_toprefix(lua_State *L, int idx) + { + struct prefix *p = XCALLOC(MTYPE_TMP, sizeof(struct prefix)); + + lua_getfield(L, idx, "network"); + str2prefix(lua_tostring(L, -1), p); + lua_pop(L, 1); + + return p; + } + +By convention these functions should be called ``lua_to*``, as this is the +naming convention used by the Lua C library for the basic types e.g. +``lua_tointeger`` and ``lua_tostring``. + +The returned data must always be copied off the stack and the copy must be +allocated with ``MTYPE_TMP``. This way it is possible to unload the script +(destroy the state) without invalidating any references to values stored in it. + +To register a new type with its corresponding encoding functions: + +.. code-block:: c + + struct frrscript_codec frrscript_codecs_lib[] = { + {.typename = "prefix", + .encoder = (encoder_func)lua_pushprefix, + .decoder = lua_toprefix}, + {.typename = "sockunion", + .encoder = (encoder_func)lua_pushsockunion, + .decoder = lua_tosockunion}, + ... + {}}; + + frrscript_register_type_codecs(frrscript_codecs_lib); + +From this point on the type names are available to be used when calling any +script and getting its results. + +.. note:: + + Marshalled types are not restricted to simple values like integers, strings + and tables. It is possible to marshall a type such that the resultant object + in Lua is an actual object-oriented object, complete with methods that call + back into defined C functions. See the Lua manual for how to do this; for a + code example, look at how zlog is exported into the script environment. + + +Script Environment +------------------ + +Logging +^^^^^^^ + +For convenience, script environments are populated by default with a ``log`` +object which contains methods corresponding to each of the ``zlog`` levels: + +.. code-block:: lua + + log.info("info") + log.warn("warn") + log.error("error") + log.notice("notice") + log.debug("debug") + +The log messages will show up in the daemon's log output. + + +Examples +-------- + +For a complete code example involving passing custom types, retrieving results, +and doing complex calculations in Lua, look at the implementation of the +``match script SCRIPT`` command for BGP routemaps. This example calls into a +script with a route prefix and attributes received from a peer and expects the +script to return a match / no match / match and update result. + +An example script to use with this follows. This script matches, does not match +or updates a route depending on how many BGP UPDATE messages the peer has +received when the script is called, simply as a demonstration of what can be +accomplished with scripting. + +.. code-block:: lua + + + -- Example route map matching + -- author: qlyoung + -- + -- The following variables are available to us: + -- log + -- logging library, with the usual functions + -- prefix + -- the route under consideration + -- attributes + -- the route's attributes + -- peer + -- the peer which received this route + -- RM_FAILURE + -- status code in case of failure + -- RM_NOMATCH + -- status code for no match + -- RM_MATCH + -- status code for match + -- RM_MATCH_AND_CHANGE + -- status code for match-and-set + -- + -- We need to set the following out values: + -- action + -- Set to the appropriate status code to indicate what we did + -- attributes + -- Setting fields on here will propagate them back up to the caller if + -- 'action' is set to RM_MATCH_AND_CHANGE. + + + log.info("Evaluating route " .. prefix.network .. " from peer " .. peer.remote_id.string) + + function on_match (prefix, attrs) + log.info("Match") + action = RM_MATCH + end + + function on_nomatch (prefix, attrs) + log.info("No match") + action = RM_NOMATCH + end + + function on_match_and_change (prefix, attrs) + action = RM_MATCH_AND_CHANGE + log.info("Match and change") + attrs["metric"] = attrs["metric"] + 7 + end + + special_routes = { + ["172.16.10.4/24"] = on_match, + ["172.16.13.1/8"] = on_nomatch, + ["192.168.0.24/8"] = on_match_and_change, + } + + + if special_routes[prefix.network] then + special_routes[prefix.network](prefix, attributes) + elseif peer.stats.update_in % 3 == 0 then + on_match(prefix, attributes) + elseif peer.stats.update_in % 2 == 0 then + on_nomatch(prefix, attributes) + else + on_match_and_change(prefix, attributes) + end + diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index 0129be6bf1..07a25886d0 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -37,7 +37,6 @@ dev_RSTFILES = \ doc/developer/lists.rst \ doc/developer/locking.rst \ doc/developer/logging.rst \ - doc/developer/lua.rst \ doc/developer/memtypes.rst \ doc/developer/modules.rst \ doc/developer/next-hop-tracking.rst \ @@ -52,6 +51,7 @@ dev_RSTFILES = \ doc/developer/path-internals.rst \ doc/developer/path.rst \ doc/developer/rcu.rst \ + doc/developer/scripting.rst \ doc/developer/static-linking.rst \ doc/developer/tracing.rst \ doc/developer/testing.rst \ diff --git a/doc/user/index.rst b/doc/user/index.rst index 993acf3b4c..7b9464668b 100644 --- a/doc/user/index.rst +++ b/doc/user/index.rst @@ -29,6 +29,7 @@ Basics ipv6 kernel snmp + scripting .. modules ######### diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 382d71b71f..a13e6ce43b 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -362,6 +362,10 @@ options from the list below. Set hardcoded rpaths in the executable [default=yes]. +.. option:: --enable-scripting + + Enable Lua scripting [default=no]. + You may specify any combination of the above options to the configure script. By default, the executables are placed in :file:`/usr/local/sbin` and the configuration files in :file:`/usr/local/etc`. The :file:`/usr/local/` @@ -382,6 +386,10 @@ options to the configuration script. Configure zebra to use `dir` for local state files, such as pid files and unix sockets. +.. option:: --with-scriptdir <dir> + + Look for Lua scripts in ``dir`` [``prefix``/etc/frr/scripts]. + .. option:: --with-yangmodelsdir <dir> Look for YANG modules in `dir` [`prefix`/share/yang]. Note that the FRR diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index cbde0fd46f..7184a0e197 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -322,6 +322,23 @@ To start OSPF process you have to specify the OSPF router. This feature is enabled by default. +.. index:: clear ip ospf [(1-65535)] process +.. clicmd:: clear ip ospf [(1-65535)] process + + This command can be used to clear the ospf process data structures. This + will clear the ospf neighborship as well and it will get re-established. + This will clear the LSDB too. This will be helpful when there is a change + in router-id and if user wants the router-id change to take effect, user can + use this cli instead of restarting the ospfd daemon. + +.. index:: clear ip ospf [(1-65535)] neighbor +.. clicmd:: clear ip ospf [(1-65535)] neighbor + + This command can be used to clear the ospf neighbor data structures. This + will clear the ospf neighborship and it will get re-established. This + command can be used when the neighbor state get stuck at some state and + this can be used to recover it from that state. + .. _ospf-area: Areas diff --git a/doc/user/scripting.rst b/doc/user/scripting.rst new file mode 100644 index 0000000000..b0295e5706 --- /dev/null +++ b/doc/user/scripting.rst @@ -0,0 +1,28 @@ +.. _scripting: + +********* +Scripting +********* + +The behavior of FRR may be extended or customized using its built-in scripting +capabilities. + +Some configuration commands accept the name of a Lua script to call to perform +some task or make some decision. These scripts have their environments +populated with some set of inputs, and are expected to populate some set of +output variables, which are read by FRR after the script completes. The names +and expected contents of these scripts are documented alongside the commands +that support them. + +These scripts live in :file:`/etc/frr/scripts/` by default. This is +configurable at compile time via ``--with-scriptdir``. It may be +overriden at runtime with the ``--scriptdir`` daemon option. + +In order to use scripting, FRR must be built with ``--enable-scripting``. + +.. note:: + + Scripts are typically loaded just-in-time. This means you can change the + contents of a script that is in use without restarting FRR. Not all + scripting locations may behave this way; refer to the documentation for the + particular location. diff --git a/doc/user/subdir.am b/doc/user/subdir.am index a78d261863..3585245e85 100644 --- a/doc/user/subdir.am +++ b/doc/user/subdir.am @@ -35,6 +35,7 @@ user_RSTFILES = \ doc/user/routemap.rst \ doc/user/routeserver.rst \ doc/user/rpki.rst \ + doc/user/scripting.rst \ doc/user/setup.rst \ doc/user/sharp.rst \ doc/user/snmp.rst \ diff --git a/eigrpd/eigrp_cli.c b/eigrpd/eigrp_cli.c index 3610b3a869..00d8ea8867 100644 --- a/eigrpd/eigrp_cli.c +++ b/eigrpd/eigrp_cli.c @@ -29,6 +29,7 @@ #include "eigrp_structs.h" #include "eigrpd.h" #include "eigrp_zebra.h" +#include "eigrp_cli.h" #ifndef VTYSH_EXTRACT_PL #include "eigrpd/eigrp_cli_clippy.c" diff --git a/eigrpd/eigrp_cli.h b/eigrpd/eigrp_cli.h new file mode 100644 index 0000000000..c5f2fd8009 --- /dev/null +++ b/eigrpd/eigrp_cli.h @@ -0,0 +1,70 @@ +/* + * EIGRP CLI Functions. + * Copyright (C) 2019 + * Authors: + * Donnie Savage + * + * This file is part of FRR. + * + * FRR 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, or (at your option) any + * later version. + * + * FRR 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; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _EIGRP_CLI_H_ +#define _EIGRP_CLI_H_ + +/*Prototypes*/ +extern void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode); +extern void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_passive_interface(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_maximum_paths(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_redistribute(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_hello_interval(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_summarize_address(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_authentication(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void eigrp_cli_init(void); + +#endif /*EIGRP_CLI_H_ */ diff --git a/eigrpd/eigrp_const.h b/eigrpd/eigrp_const.h index d3d9bca82a..149cf00efc 100644 --- a/eigrpd/eigrp_const.h +++ b/eigrpd/eigrp_const.h @@ -122,10 +122,10 @@ enum metric_change { METRIC_DECREASE, METRIC_SAME, METRIC_INCREASE }; #define EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL 2 // Remote external network /*EIGRP TT entry flags*/ -#define EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG (1 << 0) -#define EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG (1 << 1) -#define EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG (1 << 2) -#define EIGRP_NEXTHOP_ENTRY_EXTERNAL_FLAG (1 << 3) +#define EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG (1 << 0) +#define EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG (1 << 1) +#define EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG (1 << 2) +#define EIGRP_ROUTE_DESCRIPTOR_EXTERNAL_FLAG (1 << 3) /*EIGRP FSM state count, event count*/ #define EIGRP_FSM_STATE_MAX 5 diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c index dfce2acad4..e1ad51a9db 100644 --- a/eigrpd/eigrp_dump.c +++ b/eigrpd/eigrp_dump.c @@ -236,7 +236,8 @@ void show_ip_eigrp_topology_header(struct vty *vty, struct eigrp *eigrp) "Codes: P - Passive, A - Active, U - Update, Q - Query, R - Reply\n r - reply Status, s - sia Status\n\n"); } -void show_ip_eigrp_prefix_entry(struct vty *vty, struct eigrp_prefix_entry *tn) +void show_ip_eigrp_prefix_descriptor(struct vty *vty, + struct eigrp_prefix_descriptor *tn) { struct list *successors = eigrp_topology_get_successor(tn); @@ -251,14 +252,15 @@ void show_ip_eigrp_prefix_entry(struct vty *vty, struct eigrp_prefix_entry *tn) list_delete(&successors); } -void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp, - struct eigrp_nexthop_entry *te, bool *first) +void show_ip_eigrp_route_descriptor(struct vty *vty, struct eigrp *eigrp, + struct eigrp_route_descriptor *te, + bool *first) { if (te->reported_distance == EIGRP_MAX_METRIC) return; if (*first) { - show_ip_eigrp_prefix_entry(vty, te->prefix); + show_ip_eigrp_prefix_descriptor(vty, te->prefix); *first = false; } diff --git a/eigrpd/eigrp_dump.h b/eigrpd/eigrp_dump.h index 348356bb3c..0d512fc63f 100644 --- a/eigrpd/eigrp_dump.h +++ b/eigrpd/eigrp_dump.h @@ -151,11 +151,11 @@ extern void show_ip_eigrp_interface_sub(struct vty *, struct eigrp *, struct eigrp_interface *); extern void show_ip_eigrp_neighbor_sub(struct vty *, struct eigrp_neighbor *, int); -extern void show_ip_eigrp_prefix_entry(struct vty *, - struct eigrp_prefix_entry *); -extern void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp, - struct eigrp_nexthop_entry *ne, - bool *first); +extern void show_ip_eigrp_prefix_descriptor(struct vty *vty, + struct eigrp_prefix_descriptor *tn); +extern void show_ip_eigrp_route_descriptor(struct vty *vty, struct eigrp *eigrp, + struct eigrp_route_descriptor *ne, + bool *first); extern void eigrp_debug_init(void); diff --git a/eigrpd/eigrp_fsm.c b/eigrpd/eigrp_fsm.c index a69a3eec0a..d2d435bf2d 100644 --- a/eigrpd/eigrp_fsm.c +++ b/eigrpd/eigrp_fsm.c @@ -77,6 +77,7 @@ #include "linklist.h" #include "vty.h" +#include "eigrpd/eigrp_types.h" #include "eigrpd/eigrp_structs.h" #include "eigrpd/eigrpd.h" #include "eigrpd/eigrp_interface.h" @@ -88,6 +89,7 @@ #include "eigrpd/eigrp_dump.h" #include "eigrpd/eigrp_topology.h" #include "eigrpd/eigrp_fsm.h" +#include "eigrpd/eigrp_metric.h" /* * Prototypes @@ -262,13 +264,13 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) { // Loading base information from message // struct eigrp *eigrp = msg->eigrp; - struct eigrp_prefix_entry *prefix = msg->prefix; - struct eigrp_nexthop_entry *entry = msg->entry; + struct eigrp_prefix_descriptor *prefix = msg->prefix; + struct eigrp_route_descriptor *entry = msg->entry; uint8_t actual_state = prefix->state; enum metric_change change; if (entry == NULL) { - entry = eigrp_nexthop_entry_new(); + entry = eigrp_route_descriptor_new(); entry->adv_router = msg->adv_router; entry->ei = msg->adv_router->ei; entry->prefix = prefix; @@ -286,7 +288,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) switch (actual_state) { case EIGRP_FSM_STATE_PASSIVE: { - struct eigrp_nexthop_entry *head = + struct eigrp_route_descriptor *head = listnode_head(prefix->entries); if (head->reported_distance < prefix->fdistance) { @@ -307,7 +309,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) } case EIGRP_FSM_STATE_ACTIVE_0: { if (msg->packet_type == EIGRP_OPC_REPLY) { - struct eigrp_nexthop_entry *head = + struct eigrp_route_descriptor *head = listnode_head(prefix->entries); listnode_delete(prefix->rij, entry->adv_router); @@ -322,7 +324,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) return EIGRP_FSM_EVENT_LR_FCN; } else if (msg->packet_type == EIGRP_OPC_QUERY && (entry->flags - & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { + & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) { return EIGRP_FSM_EVENT_QACT; } @@ -332,14 +334,14 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) } case EIGRP_FSM_STATE_ACTIVE_1: { if (msg->packet_type == EIGRP_OPC_QUERY - && (entry->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { + && (entry->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) { return EIGRP_FSM_EVENT_QACT; } else if (msg->packet_type == EIGRP_OPC_REPLY) { listnode_delete(prefix->rij, entry->adv_router); if (change == METRIC_INCREASE && (entry->flags - & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { + & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) { return EIGRP_FSM_EVENT_DINC; } else if (prefix->rij->count) { return EIGRP_FSM_KEEP_STATE; @@ -350,7 +352,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) } else if (msg->packet_type == EIGRP_OPC_UPDATE && change == METRIC_INCREASE && (entry->flags - & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { + & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) { return EIGRP_FSM_EVENT_DINC; } return EIGRP_FSM_KEEP_STATE; @@ -359,7 +361,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) } case EIGRP_FSM_STATE_ACTIVE_2: { if (msg->packet_type == EIGRP_OPC_REPLY) { - struct eigrp_nexthop_entry *head = + struct eigrp_route_descriptor *head = listnode_head(prefix->entries); listnode_delete(prefix->rij, entry->adv_router); @@ -385,7 +387,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) if (change == METRIC_INCREASE && (entry->flags - & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { + & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) { return EIGRP_FSM_EVENT_DINC; } else if (prefix->rij->count) { return EIGRP_FSM_KEEP_STATE; @@ -396,7 +398,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) } else if (msg->packet_type == EIGRP_OPC_UPDATE && change == METRIC_INCREASE && (entry->flags - & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { + & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) { return EIGRP_FSM_EVENT_DINC; } return EIGRP_FSM_KEEP_STATE; @@ -434,9 +436,9 @@ int eigrp_fsm_event(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg) { struct eigrp *eigrp = msg->eigrp; - struct eigrp_prefix_entry *prefix = msg->prefix; + struct eigrp_prefix_descriptor *prefix = msg->prefix; struct list *successors = eigrp_topology_get_successor(prefix); - struct eigrp_nexthop_entry *ne; + struct eigrp_route_descriptor *ne; assert(successors); // If this is NULL we have shit the bed, fun huh? @@ -461,9 +463,9 @@ int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg) { struct eigrp *eigrp = msg->eigrp; - struct eigrp_prefix_entry *prefix = msg->prefix; + struct eigrp_prefix_descriptor *prefix = msg->prefix; struct list *successors = eigrp_topology_get_successor(prefix); - struct eigrp_nexthop_entry *ne; + struct eigrp_route_descriptor *ne; assert(successors); // If this is NULL somebody poked us in the eye. @@ -487,8 +489,8 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg) { struct eigrp *eigrp = msg->eigrp; - struct eigrp_prefix_entry *prefix = msg->prefix; - struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries); + struct eigrp_prefix_descriptor *prefix = msg->prefix; + struct eigrp_route_descriptor *ne = listnode_head(prefix->entries); if (prefix->state == EIGRP_FSM_STATE_PASSIVE) { if (!eigrp_metrics_is_same(prefix->reported_metric, @@ -515,8 +517,8 @@ int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg) { struct eigrp *eigrp = msg->eigrp; - struct eigrp_prefix_entry *prefix = msg->prefix; - struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries); + struct eigrp_prefix_descriptor *prefix = msg->prefix; + struct eigrp_route_descriptor *ne = listnode_head(prefix->entries); prefix->fdistance = prefix->distance = prefix->rdistance = ne->distance; prefix->reported_metric = ne->total_metric; @@ -545,7 +547,7 @@ int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg) { struct list *successors = eigrp_topology_get_successor(msg->prefix); - struct eigrp_nexthop_entry *ne; + struct eigrp_route_descriptor *ne; assert(successors); // Trump and his big hands @@ -566,8 +568,8 @@ int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg) { struct eigrp *eigrp = msg->eigrp; - struct eigrp_prefix_entry *prefix = msg->prefix; - struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries); + struct eigrp_prefix_descriptor *prefix = msg->prefix; + struct eigrp_route_descriptor *ne = listnode_head(prefix->entries); prefix->state = EIGRP_FSM_STATE_PASSIVE; prefix->distance = prefix->rdistance = ne->distance; @@ -598,8 +600,8 @@ int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg) { struct eigrp *eigrp = msg->eigrp; - struct eigrp_prefix_entry *prefix = msg->prefix; - struct eigrp_nexthop_entry *best_successor; + struct eigrp_prefix_descriptor *prefix = msg->prefix; + struct eigrp_route_descriptor *best_successor; struct list *successors = eigrp_topology_get_successor(prefix); assert(successors); // Routing without a stack @@ -628,7 +630,7 @@ int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg) { struct list *successors = eigrp_topology_get_successor(msg->prefix); - struct eigrp_nexthop_entry *ne; + struct eigrp_route_descriptor *ne; assert(successors); // Cats and no Dogs diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c index dd43dd0478..74eff958da 100644 --- a/eigrpd/eigrp_interface.c +++ b/eigrpd/eigrp_interface.c @@ -55,6 +55,8 @@ #include "eigrpd/eigrp_memory.h" #include "eigrpd/eigrp_fsm.h" #include "eigrpd/eigrp_dump.h" +#include "eigrpd/eigrp_types.h" +#include "eigrpd/eigrp_metric.h" struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp, struct prefix *p) @@ -229,8 +231,8 @@ void eigrp_del_if_params(struct eigrp_if_params *eip) int eigrp_if_up(struct eigrp_interface *ei) { - struct eigrp_prefix_entry *pe; - struct eigrp_nexthop_entry *ne; + struct eigrp_prefix_descriptor *pe; + struct eigrp_route_descriptor *ne; struct eigrp_metrics metric; struct eigrp_interface *ei2; struct listnode *node, *nnode; @@ -263,14 +265,14 @@ int eigrp_if_up(struct eigrp_interface *ei) /*Add connected entry to topology table*/ - ne = eigrp_nexthop_entry_new(); + ne = eigrp_route_descriptor_new(); ne->ei = ei; ne->reported_metric = metric; ne->total_metric = metric; ne->distance = eigrp_calculate_metrics(eigrp, metric); ne->reported_distance = 0; ne->adv_router = eigrp->neighbor_self; - ne->flags = EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG; + ne->flags = EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG; struct prefix dest_addr; @@ -280,7 +282,7 @@ int eigrp_if_up(struct eigrp_interface *ei) &dest_addr); if (pe == NULL) { - pe = eigrp_prefix_entry_new(); + pe = eigrp_prefix_descriptor_new(); pe->serno = eigrp->serno; pe->destination = (struct prefix *)prefix_ipv4_new(); prefix_copy(pe->destination, &dest_addr); @@ -292,10 +294,10 @@ int eigrp_if_up(struct eigrp_interface *ei) pe->state = EIGRP_FSM_STATE_PASSIVE; pe->fdistance = eigrp_calculate_metrics(eigrp, metric); pe->req_action |= EIGRP_FSM_NEED_UPDATE; - eigrp_prefix_entry_add(eigrp->topology_table, pe); + eigrp_prefix_descriptor_add(eigrp->topology_table, pe); listnode_add(eigrp->topology_changes_internalIPV4, pe); - eigrp_nexthop_entry_add(eigrp, pe, ne); + eigrp_route_descriptor_add(eigrp, pe, ne); for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei2)) { eigrp_update_send(ei2); @@ -307,7 +309,7 @@ int eigrp_if_up(struct eigrp_interface *ei) struct eigrp_fsm_action_message msg; ne->prefix = pe; - eigrp_nexthop_entry_add(eigrp, pe, ne); + eigrp_route_descriptor_add(eigrp, pe, ne); msg.packet_type = EIGRP_OPC_UPDATE; msg.eigrp = eigrp; @@ -416,7 +418,7 @@ uint8_t eigrp_default_iftype(struct interface *ifp) void eigrp_if_free(struct eigrp_interface *ei, int source) { struct prefix dest_addr; - struct eigrp_prefix_entry *pe; + struct eigrp_prefix_descriptor *pe; struct eigrp *eigrp = ei->eigrp; if (source == INTERFACE_DOWN_BY_VTY) { @@ -429,7 +431,8 @@ void eigrp_if_free(struct eigrp_interface *ei, int source) pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table, &dest_addr); if (pe) - eigrp_prefix_entry_delete(eigrp, eigrp->topology_table, pe); + eigrp_prefix_descriptor_delete(eigrp, eigrp->topology_table, + pe); eigrp_if_down(ei); @@ -494,33 +497,3 @@ struct eigrp_interface *eigrp_if_lookup_by_name(struct eigrp *eigrp, return NULL; } - -uint32_t eigrp_bandwidth_to_scaled(uint32_t bandwidth) -{ - uint64_t temp_bandwidth = (256ull * 10000000) / bandwidth; - - temp_bandwidth = temp_bandwidth < EIGRP_MAX_METRIC ? temp_bandwidth - : EIGRP_MAX_METRIC; - - return (uint32_t)temp_bandwidth; -} - -uint32_t eigrp_scaled_to_bandwidth(uint32_t scaled) -{ - uint64_t temp_scaled = scaled * (256ull * 10000000); - - temp_scaled = - temp_scaled < EIGRP_MAX_METRIC ? temp_scaled : EIGRP_MAX_METRIC; - - return (uint32_t)temp_scaled; -} - -uint32_t eigrp_delay_to_scaled(uint32_t delay) -{ - return delay * 256; -} - -uint32_t eigrp_scaled_to_delay(uint32_t scaled) -{ - return scaled / 256; -} diff --git a/eigrpd/eigrp_interface.h b/eigrpd/eigrp_interface.h index 1e66dafde2..68ab5125e3 100644 --- a/eigrpd/eigrp_interface.h +++ b/eigrpd/eigrp_interface.h @@ -58,9 +58,4 @@ extern struct eigrp_interface *eigrp_if_lookup_by_name(struct eigrp *, /* Simulate down/up on the interface. */ extern void eigrp_if_reset(struct interface *); -extern uint32_t eigrp_bandwidth_to_scaled(uint32_t); -extern uint32_t eigrp_scaled_to_bandwidth(uint32_t); -extern uint32_t eigrp_delay_to_scaled(uint32_t); -extern uint32_t eigrp_scaled_to_delay(uint32_t); - #endif /* ZEBRA_EIGRP_INTERFACE_H_ */ diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c index 6c44ce361c..b1a6498cbc 100644 --- a/eigrpd/eigrp_main.c +++ b/eigrpd/eigrp_main.c @@ -66,6 +66,8 @@ #include "eigrpd/eigrp_filter.h" #include "eigrpd/eigrp_errors.h" #include "eigrpd/eigrp_vrf.h" +#include "eigrpd/eigrp_cli.h" +#include "eigrpd/eigrp_yang.h" //#include "eigrpd/eigrp_routemap.h" /* eigprd privileges */ diff --git a/eigrpd/eigrp_memory.c b/eigrpd/eigrp_memory.c index 85b14c28ce..57ca785340 100644 --- a/eigrpd/eigrp_memory.c +++ b/eigrpd/eigrp_memory.c @@ -37,6 +37,6 @@ DEFINE_MTYPE(EIGRPD, EIGRP_IPV4_INT_TLV, "EIGRP IPv4 TLV") DEFINE_MTYPE(EIGRPD, EIGRP_SEQ_TLV, "EIGRP SEQ TLV") DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_TLV, "EIGRP AUTH TLV") DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_SHA256_TLV, "EIGRP SHA TLV") -DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_ENTRY, "EIGRP Prefix") -DEFINE_MTYPE(EIGRPD, EIGRP_NEXTHOP_ENTRY, "EIGRP Nexthop Entry") +DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_DESCRIPTOR, "EIGRP Prefix") +DEFINE_MTYPE(EIGRPD, EIGRP_ROUTE_DESCRIPTOR, "EIGRP Nexthop Entry") DEFINE_MTYPE(EIGRPD, EIGRP_FSM_MSG, "EIGRP FSM Message") diff --git a/eigrpd/eigrp_memory.h b/eigrpd/eigrp_memory.h index e4d02c09d4..21ecba2aae 100644 --- a/eigrpd/eigrp_memory.h +++ b/eigrpd/eigrp_memory.h @@ -36,8 +36,8 @@ DECLARE_MTYPE(EIGRP_IPV4_INT_TLV) DECLARE_MTYPE(EIGRP_SEQ_TLV) DECLARE_MTYPE(EIGRP_AUTH_TLV) DECLARE_MTYPE(EIGRP_AUTH_SHA256_TLV) -DECLARE_MTYPE(EIGRP_PREFIX_ENTRY) -DECLARE_MTYPE(EIGRP_NEXTHOP_ENTRY) +DECLARE_MTYPE(EIGRP_PREFIX_DESCRIPTOR) +DECLARE_MTYPE(EIGRP_ROUTE_DESCRIPTOR) DECLARE_MTYPE(EIGRP_FSM_MSG) #endif /* _FRR_EIGRP_MEMORY_H */ diff --git a/eigrpd/eigrp_metric.c b/eigrpd/eigrp_metric.c new file mode 100644 index 0000000000..2b05db71d5 --- /dev/null +++ b/eigrpd/eigrp_metric.c @@ -0,0 +1,146 @@ +/* + * EIGRP Metric Math Functions. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "eigrpd/eigrp_structs.h" +#include "eigrpd/eigrpd.h" +#include "eigrpd/eigrp_types.h" +#include "eigrpd/eigrp_metric.h" + +eigrp_scaled_t eigrp_bandwidth_to_scaled(eigrp_bandwidth_t bandwidth) +{ + eigrp_bandwidth_t scaled = EIGRP_BANDWIDTH_MAX; + + if (bandwidth != EIGRP_BANDWIDTH_MAX) { + scaled = (EIGRP_CLASSIC_SCALER * EIGRP_BANDWIDTH_SCALER); + scaled = scaled / bandwidth; + + scaled = scaled ? scaled : EIGRP_BANDWIDTH_MIN; + } + + scaled = (scaled < EIGRP_METRIC_MAX) ? scaled : EIGRP_METRIC_MAX; + return (eigrp_scaled_t)scaled; +} + +eigrp_bandwidth_t eigrp_scaled_to_bandwidth(eigrp_scaled_t scaled) +{ + eigrp_bandwidth_t bandwidth = EIGRP_BANDWIDTH_MAX; + + if (scaled != EIGRP_CLASSIC_MAX) { + bandwidth = (EIGRP_CLASSIC_SCALER * EIGRP_BANDWIDTH_SCALER); + bandwidth = scaled * bandwidth; + bandwidth = (bandwidth < EIGRP_METRIC_MAX) + ? bandwidth + : EIGRP_BANDWIDTH_MAX; + } + + return bandwidth; +} + +eigrp_scaled_t eigrp_delay_to_scaled(eigrp_delay_t delay) +{ + delay = delay ? delay : EIGRP_DELAY_MIN; + return delay * EIGRP_CLASSIC_SCALER; +} + +eigrp_delay_t eigrp_scaled_to_delay(eigrp_scaled_t scaled) +{ + scaled = scaled / EIGRP_CLASSIC_SCALER; + scaled = scaled ? scaled : EIGRP_DELAY_MIN; + + return scaled; +} + +eigrp_metric_t eigrp_calculate_metrics(struct eigrp *eigrp, + struct eigrp_metrics metric) +{ + eigrp_metric_t composite = 0; + + if (metric.delay == EIGRP_MAX_METRIC) + return EIGRP_METRIC_MAX; + + /* + * EIGRP Composite = + * {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)} + */ + + if (eigrp->k_values[0]) + composite += (eigrp->k_values[0] * metric.bandwidth); + if (eigrp->k_values[1]) + composite += ((eigrp->k_values[1] * metric.bandwidth) + / (256 - metric.load)); + if (eigrp->k_values[2]) + composite += (eigrp->k_values[2] * metric.delay); + if (eigrp->k_values[3] && !eigrp->k_values[4]) + composite *= eigrp->k_values[3]; + if (!eigrp->k_values[3] && eigrp->k_values[4]) + composite *= (eigrp->k_values[4] / metric.reliability); + if (eigrp->k_values[3] && eigrp->k_values[4]) + composite *= ((eigrp->k_values[4] / metric.reliability) + + eigrp->k_values[3]); + + composite = + (composite <= EIGRP_METRIC_MAX) ? composite : EIGRP_METRIC_MAX; + + return composite; +} + +eigrp_metric_t +eigrp_calculate_total_metrics(struct eigrp *eigrp, + struct eigrp_route_descriptor *entry) +{ + struct eigrp_interface *ei = entry->ei; + eigrp_delay_t temp_delay; + eigrp_bandwidth_t bw; + + entry->total_metric = entry->reported_metric; + temp_delay = entry->total_metric.delay + + eigrp_delay_to_scaled(ei->params.delay); + + entry->total_metric.delay = temp_delay > EIGRP_METRIC_MAX_CLASSIC + ? EIGRP_METRIC_MAX_CLASSIC + : temp_delay; + + bw = eigrp_bandwidth_to_scaled(ei->params.bandwidth); + entry->total_metric.bandwidth = entry->total_metric.bandwidth > bw + ? bw + : entry->total_metric.bandwidth; + + return eigrp_calculate_metrics(eigrp, entry->total_metric); +} + +bool eigrp_metrics_is_same(struct eigrp_metrics metric1, + struct eigrp_metrics metric2) +{ + if ((metric1.bandwidth == metric2.bandwidth) + && (metric1.delay == metric2.delay) + && (metric1.hop_count == metric2.hop_count) + && (metric1.load == metric2.load) + && (metric1.reliability == metric2.reliability) + && (metric1.mtu[0] == metric2.mtu[0]) + && (metric1.mtu[1] == metric2.mtu[1]) + && (metric1.mtu[2] == metric2.mtu[2])) { + return true; + } + + return false; /* if different */ +} diff --git a/eigrpd/eigrp_metric.h b/eigrpd/eigrp_metric.h new file mode 100644 index 0000000000..8e9cd66747 --- /dev/null +++ b/eigrpd/eigrp_metric.h @@ -0,0 +1,63 @@ +/* + * EIGRP Metric Math Functions. + * Copyright (C) 2013-2016 + * Authors: + * Donnie Savage + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ZEBRA_EIGRP_METRIC_H_ +#define _ZEBRA_EIGRP_METRIC_H_ + +/* Constants */ +#define EIGRP_BANDWIDTH_MIN 0x1ull /* 1 */ +#define EIGRP_BANDWIDTH_SCALER 10000000ull /* Inversion value */ +#define EIGRP_BANDWIDTH_MAX 0xffffffffffffffffull /* 1.84467441x10^19 */ + +#define EIGRP_DELAY_MIN 0x1ull /* 1 */ +#define EIGRP_DELAY_PICO 1000000ull +#define EIGRP_DELAY_MAX 0xffffffffffffffffull /* 1.84467441x10^19 */ + +#define EIGRP_MAX_LOAD 256 +#define EIGRP_MAX_HOPS 100 + +#define EIGRP_INACCESSIBLE 0xFFFFFFFFFFFFFFFFull + +#define EIGRP_METRIC_MAX 0xffffffffffffffffull /* 1.84467441x10^19 */ +#define EIGRP_METRIC_MAX_CLASSIC 0xffffffff +#define EIGRP_METRIC_SCALER 65536 /* CLASSIC to WIDE conversion */ + +#define EIGRP_CLASSIC_MAX 0xffffffff /* 4294967295 */ +#define EIGRP_CLASSIC_SCALER 256 /* IGRP to EIGRP conversion */ + + +/* Prototypes */ +extern eigrp_scaled_t eigrp_bandwidth_to_scaled(eigrp_bandwidth_t bw); +extern eigrp_bandwidth_t eigrp_scaled_to_bandwidth(eigrp_scaled_t scale); +extern eigrp_scaled_t eigrp_delay_to_scaled(eigrp_delay_t delay); +extern eigrp_delay_t eigrp_scaled_to_delay(eigrp_scaled_t scale); + +extern eigrp_metric_t eigrp_calculate_metrics(struct eigrp *eigrp, + struct eigrp_metrics metric); +extern eigrp_metric_t +eigrp_calculate_total_metrics(struct eigrp *eigrp, + struct eigrp_route_descriptor *rd); +extern bool eigrp_metrics_is_same(struct eigrp_metrics m1, + struct eigrp_metrics m2); + +#endif /* _ZEBRA_EIGRP_METRIC_H_ */ diff --git a/eigrpd/eigrp_neighbor.c b/eigrpd/eigrp_neighbor.c index 2d5bb0a7d1..1da2f7a108 100644 --- a/eigrpd/eigrp_neighbor.c +++ b/eigrpd/eigrp_neighbor.c @@ -343,7 +343,7 @@ void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty) eigrp_nbr_delete(nbr); } -int eigrp_nbr_split_horizon_check(struct eigrp_nexthop_entry *ne, +int eigrp_nbr_split_horizon_check(struct eigrp_route_descriptor *ne, struct eigrp_interface *ei) { if (ne->distance == EIGRP_MAX_METRIC) diff --git a/eigrpd/eigrp_neighbor.h b/eigrpd/eigrp_neighbor.h index 1c308fa981..80ab1eded5 100644 --- a/eigrpd/eigrp_neighbor.h +++ b/eigrpd/eigrp_neighbor.h @@ -54,6 +54,6 @@ extern struct eigrp_neighbor * eigrp_nbr_lookup_by_addr_process(struct eigrp *eigrp, struct in_addr addr); extern void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty); -extern int eigrp_nbr_split_horizon_check(struct eigrp_nexthop_entry *ne, +extern int eigrp_nbr_split_horizon_check(struct eigrp_route_descriptor *ne, struct eigrp_interface *ei); #endif /* _ZEBRA_EIGRP_NEIGHBOR_H */ diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c index 51b4998959..69dcc20253 100644 --- a/eigrpd/eigrp_network.c +++ b/eigrpd/eigrp_network.c @@ -346,76 +346,6 @@ int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p) return 1; } -uint32_t eigrp_calculate_metrics(struct eigrp *eigrp, - struct eigrp_metrics metric) -{ - uint64_t temp_metric; - temp_metric = 0; - - if (metric.delay == EIGRP_MAX_METRIC) - return EIGRP_MAX_METRIC; - - // EIGRP Metric = - // {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)} - - if (eigrp->k_values[0]) - temp_metric += (eigrp->k_values[0] * metric.bandwidth); - if (eigrp->k_values[1]) - temp_metric += ((eigrp->k_values[1] * metric.bandwidth) - / (256 - metric.load)); - if (eigrp->k_values[2]) - temp_metric += (eigrp->k_values[2] * metric.delay); - if (eigrp->k_values[3] && !eigrp->k_values[4]) - temp_metric *= eigrp->k_values[3]; - if (!eigrp->k_values[3] && eigrp->k_values[4]) - temp_metric *= (eigrp->k_values[4] / metric.reliability); - if (eigrp->k_values[3] && eigrp->k_values[4]) - temp_metric *= ((eigrp->k_values[4] / metric.reliability) - + eigrp->k_values[3]); - - if (temp_metric <= EIGRP_MAX_METRIC) - return (uint32_t)temp_metric; - else - return EIGRP_MAX_METRIC; -} - -uint32_t eigrp_calculate_total_metrics(struct eigrp *eigrp, - struct eigrp_nexthop_entry *entry) -{ - struct eigrp_interface *ei = entry->ei; - - entry->total_metric = entry->reported_metric; - uint64_t temp_delay = - (uint64_t)entry->total_metric.delay - + (uint64_t)eigrp_delay_to_scaled(ei->params.delay); - entry->total_metric.delay = temp_delay > EIGRP_MAX_METRIC - ? EIGRP_MAX_METRIC - : (uint32_t)temp_delay; - - uint32_t bw = eigrp_bandwidth_to_scaled(ei->params.bandwidth); - entry->total_metric.bandwidth = entry->total_metric.bandwidth > bw - ? bw - : entry->total_metric.bandwidth; - - return eigrp_calculate_metrics(eigrp, entry->total_metric); -} - -uint8_t eigrp_metrics_is_same(struct eigrp_metrics metric1, - struct eigrp_metrics metric2) -{ - if ((metric1.bandwidth == metric2.bandwidth) - && (metric1.delay == metric2.delay) - && (metric1.hop_count == metric2.hop_count) - && (metric1.load == metric2.load) - && (metric1.reliability == metric2.reliability) - && (metric1.mtu[0] == metric2.mtu[0]) - && (metric1.mtu[1] == metric2.mtu[1]) - && (metric1.mtu[2] == metric2.mtu[2])) - return 1; - - return 0; // if different -} - void eigrp_external_routes_refresh(struct eigrp *eigrp, int type) { } diff --git a/eigrpd/eigrp_network.h b/eigrpd/eigrp_network.h index 7839fc946b..eeb32ba356 100644 --- a/eigrpd/eigrp_network.h +++ b/eigrpd/eigrp_network.h @@ -43,11 +43,6 @@ extern int eigrp_if_drop_allspfrouters(struct eigrp *top, struct prefix *p, unsigned int ifindex); extern void eigrp_adjust_sndbuflen(struct eigrp *, unsigned int); -extern uint32_t eigrp_calculate_metrics(struct eigrp *, struct eigrp_metrics); -extern uint32_t eigrp_calculate_total_metrics(struct eigrp *, - struct eigrp_nexthop_entry *); -extern uint8_t eigrp_metrics_is_same(struct eigrp_metrics, - struct eigrp_metrics); extern void eigrp_external_routes_refresh(struct eigrp *, int); #endif /* EIGRP_NETWORK_H_ */ diff --git a/eigrpd/eigrp_northbound.c b/eigrpd/eigrp_northbound.c index 5b87f72640..482667f633 100644 --- a/eigrpd/eigrp_northbound.c +++ b/eigrpd/eigrp_northbound.c @@ -34,6 +34,7 @@ #include "eigrp_interface.h" #include "eigrp_network.h" #include "eigrp_zebra.h" +#include "eigrp_cli.h" /* Helper functions. */ static void redistribute_get_metrics(const struct lyd_node *dnode, diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c index f5f6ab5dff..252cd647a2 100644 --- a/eigrpd/eigrp_packet.c +++ b/eigrpd/eigrp_packet.c @@ -1144,7 +1144,7 @@ struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *s) } uint16_t eigrp_add_internalTLV_to_stream(struct stream *s, - struct eigrp_prefix_entry *pe) + struct eigrp_prefix_descriptor *pe) { uint16_t length; diff --git a/eigrpd/eigrp_packet.h b/eigrpd/eigrp_packet.h index f354615fdb..cb69bc26b2 100644 --- a/eigrpd/eigrp_packet.h +++ b/eigrpd/eigrp_packet.h @@ -36,48 +36,51 @@ extern int eigrp_read(struct thread *); extern int eigrp_write(struct thread *); -extern struct eigrp_packet *eigrp_packet_new(size_t, struct eigrp_neighbor *); -extern struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *, - struct eigrp_neighbor *); -extern void eigrp_packet_free(struct eigrp_packet *); -extern void eigrp_packet_delete(struct eigrp_interface *); -extern void eigrp_packet_header_init(int, struct eigrp *, struct stream *, - uint32_t, uint32_t, uint32_t); -extern void eigrp_packet_checksum(struct eigrp_interface *, struct stream *, - uint16_t); +extern struct eigrp_packet *eigrp_packet_new(size_t size, + struct eigrp_neighbor *nbr); +extern struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *old, + struct eigrp_neighbor *nbr); +extern void eigrp_packet_free(struct eigrp_packet *ep); +extern void eigrp_packet_delete(struct eigrp_interface *ei); +extern void eigrp_packet_header_init(int type, struct eigrp *eigrp, + struct stream *s, uint32_t flags, + uint32_t sequence, uint32_t ack); +extern void eigrp_packet_checksum(struct eigrp_interface *ei, struct stream *s, + uint16_t length); extern struct eigrp_fifo *eigrp_fifo_new(void); -extern struct eigrp_packet *eigrp_fifo_next(struct eigrp_fifo *); -extern struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *); -extern void eigrp_fifo_push(struct eigrp_fifo *, struct eigrp_packet *); -extern void eigrp_fifo_free(struct eigrp_fifo *); -extern void eigrp_fifo_reset(struct eigrp_fifo *); - -extern void eigrp_send_packet_reliably(struct eigrp_neighbor *); - -extern struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *); -extern uint16_t eigrp_add_internalTLV_to_stream(struct stream *, - struct eigrp_prefix_entry *); -extern uint16_t eigrp_add_authTLV_MD5_to_stream(struct stream *, - struct eigrp_interface *); -extern uint16_t eigrp_add_authTLV_SHA256_to_stream(struct stream *, - struct eigrp_interface *); - -extern int eigrp_unack_packet_retrans(struct thread *); -extern int eigrp_unack_multicast_packet_retrans(struct thread *); +extern struct eigrp_packet *eigrp_fifo_next(struct eigrp_fifo *fifo); +extern struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *fifo); +extern void eigrp_fifo_push(struct eigrp_fifo *fifo, struct eigrp_packet *ep); +extern void eigrp_fifo_free(struct eigrp_fifo *fifo); +extern void eigrp_fifo_reset(struct eigrp_fifo *fifo); + +extern void eigrp_send_packet_reliably(struct eigrp_neighbor *nbr); + +extern struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *s); +extern uint16_t +eigrp_add_internalTLV_to_stream(struct stream *s, + struct eigrp_prefix_descriptor *pe); +extern uint16_t eigrp_add_authTLV_MD5_to_stream(struct stream *s, + struct eigrp_interface *ei); +extern uint16_t eigrp_add_authTLV_SHA256_to_stream(struct stream *s, + struct eigrp_interface *ei); + +extern int eigrp_unack_packet_retrans(struct thread *thread); +extern int eigrp_unack_multicast_packet_retrans(struct thread *thread); /* * untill there is reason to have their own header, these externs are found in * eigrp_hello.c */ extern void eigrp_sw_version_initialize(void); -extern void eigrp_hello_send(struct eigrp_interface *, uint8_t, - struct in_addr *); -extern void eigrp_hello_send_ack(struct eigrp_neighbor *); -extern void eigrp_hello_receive(struct eigrp *, struct ip *, - struct eigrp_header *, struct stream *, - struct eigrp_interface *, int); -extern int eigrp_hello_timer(struct thread *); +extern void eigrp_hello_send(struct eigrp_interface *ei, uint8_t flags, + struct in_addr *nbr_addr); +extern void eigrp_hello_send_ack(struct eigrp_neighbor *nbr); +extern void eigrp_hello_receive(struct eigrp *eigrp, struct ip *iph, + struct eigrp_header *eigrph, struct stream *s, + struct eigrp_interface *ei, int size); +extern int eigrp_hello_timer(struct thread *thread); /* * These externs are found in eigrp_update.c @@ -85,76 +88,83 @@ extern int eigrp_hello_timer(struct thread *); extern bool eigrp_update_prefix_apply(struct eigrp *eigrp, struct eigrp_interface *ei, int in, struct prefix *prefix); -extern void eigrp_update_send(struct eigrp_interface *); -extern void eigrp_update_receive(struct eigrp *, struct ip *, - struct eigrp_header *, struct stream *, - struct eigrp_interface *, int); -extern void eigrp_update_send_all(struct eigrp *, struct eigrp_interface *); -extern void eigrp_update_send_init(struct eigrp_neighbor *); -extern void eigrp_update_send_EOT(struct eigrp_neighbor *); -extern int eigrp_update_send_GR_thread(struct thread *); -extern void eigrp_update_send_GR(struct eigrp_neighbor *, enum GR_type, - struct vty *); -extern void eigrp_update_send_interface_GR(struct eigrp_interface *, - enum GR_type, struct vty *); -extern void eigrp_update_send_process_GR(struct eigrp *, enum GR_type, - struct vty *); +extern void eigrp_update_send(struct eigrp_interface *ei); +extern void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, + struct eigrp_header *eigrph, struct stream *s, + struct eigrp_interface *ei, int size); +extern void eigrp_update_send_all(struct eigrp *eigrp, + struct eigrp_interface *exception); +extern void eigrp_update_send_init(struct eigrp_neighbor *nbr); +extern void eigrp_update_send_EOT(struct eigrp_neighbor *nbr); +extern int eigrp_update_send_GR_thread(struct thread *thread); +extern void eigrp_update_send_GR(struct eigrp_neighbor *nbr, + enum GR_type gr_type, struct vty *vty); +extern void eigrp_update_send_interface_GR(struct eigrp_interface *ei, + enum GR_type gr_type, + struct vty *vty); +extern void eigrp_update_send_process_GR(struct eigrp *eigrp, + enum GR_type gr_type, struct vty *vty); /* * These externs are found in eigrp_query.c */ -extern void eigrp_send_query(struct eigrp_interface *); -extern void eigrp_query_receive(struct eigrp *, struct ip *, - struct eigrp_header *, struct stream *, - struct eigrp_interface *, int); -extern uint32_t eigrp_query_send_all(struct eigrp *); +extern void eigrp_send_query(struct eigrp_interface *ei); +extern void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph, + struct eigrp_header *eigrph, struct stream *s, + struct eigrp_interface *ei, int size); +extern uint32_t eigrp_query_send_all(struct eigrp *eigrp); /* * These externs are found in eigrp_reply.c */ -extern void eigrp_send_reply(struct eigrp_neighbor *, - struct eigrp_prefix_entry *); -extern void eigrp_reply_receive(struct eigrp *, struct ip *, - struct eigrp_header *, struct stream *, - struct eigrp_interface *, int); +extern void eigrp_send_reply(struct eigrp_neighbor *nbr, + struct eigrp_prefix_descriptor *pe); +extern void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph, + struct eigrp_header *eigrph, struct stream *s, + struct eigrp_interface *ei, int size); /* * These externs are found in eigrp_siaquery.c */ -extern void eigrp_send_siaquery(struct eigrp_neighbor *, - struct eigrp_prefix_entry *); -extern void eigrp_siaquery_receive(struct eigrp *, struct ip *, - struct eigrp_header *, struct stream *, - struct eigrp_interface *, int); +extern void eigrp_send_siaquery(struct eigrp_neighbor *nbr, + struct eigrp_prefix_descriptor *pe); +extern void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph, + struct eigrp_header *eigrph, + struct stream *s, struct eigrp_interface *ei, + int size); /* * These externs are found in eigrp_siareply.c */ -extern void eigrp_send_siareply(struct eigrp_neighbor *, - struct eigrp_prefix_entry *); -extern void eigrp_siareply_receive(struct eigrp *, struct ip *, - struct eigrp_header *, struct stream *, - struct eigrp_interface *, int); +extern void eigrp_send_siareply(struct eigrp_neighbor *nbr, + struct eigrp_prefix_descriptor *pe); +extern void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph, + struct eigrp_header *eigrph, + struct stream *s, struct eigrp_interface *ei, + int size); extern struct TLV_MD5_Authentication_Type *eigrp_authTLV_MD5_new(void); -extern void eigrp_authTLV_MD5_free(struct TLV_MD5_Authentication_Type *); +extern void eigrp_authTLV_MD5_free(struct TLV_MD5_Authentication_Type *authTLV); extern struct TLV_SHA256_Authentication_Type *eigrp_authTLV_SHA256_new(void); -extern void eigrp_authTLV_SHA256_free(struct TLV_SHA256_Authentication_Type *); - -extern int eigrp_make_md5_digest(struct eigrp_interface *, struct stream *, - uint8_t); -extern int eigrp_check_md5_digest(struct stream *, - struct TLV_MD5_Authentication_Type *, - struct eigrp_neighbor *, uint8_t); -extern int eigrp_make_sha256_digest(struct eigrp_interface *, struct stream *, - uint8_t); -extern int eigrp_check_sha256_digest(struct stream *, - struct TLV_SHA256_Authentication_Type *, - struct eigrp_neighbor *, uint8_t); - - -extern void eigrp_IPv4_InternalTLV_free(struct TLV_IPv4_Internal_type *); +extern void +eigrp_authTLV_SHA256_free(struct TLV_SHA256_Authentication_Type *authTLV); + +extern int eigrp_make_md5_digest(struct eigrp_interface *ei, struct stream *s, + uint8_t flags); +extern int eigrp_check_md5_digest(struct stream *s, + struct TLV_MD5_Authentication_Type *authTLV, + struct eigrp_neighbor *nbr, uint8_t flags); +extern int eigrp_make_sha256_digest(struct eigrp_interface *ei, + struct stream *s, uint8_t flags); +extern int +eigrp_check_sha256_digest(struct stream *s, + struct TLV_SHA256_Authentication_Type *authTLV, + struct eigrp_neighbor *nbr, uint8_t flags); + + +extern void +eigrp_IPv4_InternalTLV_free(struct TLV_IPv4_Internal_type *IPv4_InternalTLV); extern struct TLV_Sequence_Type *eigrp_SequenceTLV_new(void); diff --git a/eigrpd/eigrp_query.c b/eigrpd/eigrp_query.c index 84dcf5e2d5..0ab7b59dbb 100644 --- a/eigrpd/eigrp_query.c +++ b/eigrpd/eigrp_query.c @@ -58,7 +58,7 @@ uint32_t eigrp_query_send_all(struct eigrp *eigrp) { struct eigrp_interface *iface; struct listnode *node, *node2, *nnode2; - struct eigrp_prefix_entry *pe; + struct eigrp_prefix_descriptor *pe; uint32_t counter; if (eigrp == NULL) { @@ -118,7 +118,7 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph, dest_addr.family = AF_INET; dest_addr.u.prefix4 = tlv->destination; dest_addr.prefixlen = tlv->prefix_length; - struct eigrp_prefix_entry *dest = + struct eigrp_prefix_descriptor *dest = eigrp_topology_table_lookup_ipv4( eigrp->topology_table, &dest_addr); @@ -126,9 +126,9 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph, * know)*/ if (dest != NULL) { struct eigrp_fsm_action_message msg; - struct eigrp_nexthop_entry *entry = - eigrp_prefix_entry_lookup(dest->entries, - nbr); + struct eigrp_route_descriptor *entry = + eigrp_route_descriptor_lookup( + dest->entries, nbr); msg.packet_type = EIGRP_OPC_QUERY; msg.eigrp = eigrp; msg.data_type = EIGRP_INT; @@ -164,7 +164,7 @@ void eigrp_send_query(struct eigrp_interface *ei) uint16_t length = EIGRP_HEADER_LEN; struct listnode *node, *nnode, *node2, *nnode2; struct eigrp_neighbor *nbr; - struct eigrp_prefix_entry *pe; + struct eigrp_prefix_descriptor *pe; bool has_tlv = false; bool new_packet = true; uint16_t eigrp_mtu = EIGRP_PACKET_MTU(ei->ifp->mtu); diff --git a/eigrpd/eigrp_reply.c b/eigrpd/eigrp_reply.c index 26bb27d7ac..d16482173c 100644 --- a/eigrpd/eigrp_reply.c +++ b/eigrpd/eigrp_reply.c @@ -61,20 +61,21 @@ #include "eigrpd/eigrp_memory.h" #include "eigrpd/eigrp_errors.h" -void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe) +void eigrp_send_reply(struct eigrp_neighbor *nbr, + struct eigrp_prefix_descriptor *pe) { struct eigrp_packet *ep; uint16_t length = EIGRP_HEADER_LEN; struct eigrp_interface *ei = nbr->ei; struct eigrp *eigrp = ei->eigrp; - struct eigrp_prefix_entry *pe2; + struct eigrp_prefix_descriptor *pe2; // TODO: Work in progress /* Filtering */ /* get list from eigrp process */ - pe2 = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY, - sizeof(struct eigrp_prefix_entry)); - memcpy(pe2, pe, sizeof(struct eigrp_prefix_entry)); + pe2 = XCALLOC(MTYPE_EIGRP_PREFIX_DESCRIPTOR, + sizeof(struct eigrp_prefix_descriptor)); + memcpy(pe2, pe, sizeof(struct eigrp_prefix_descriptor)); if (eigrp_update_prefix_apply(eigrp, ei, EIGRP_FILTER_OUT, pe2->destination)) { @@ -122,7 +123,7 @@ void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe) eigrp_send_packet_reliably(nbr); } - XFREE(MTYPE_EIGRP_PREFIX_ENTRY, pe2); + XFREE(MTYPE_EIGRP_PREFIX_DESCRIPTOR, pe2); } /*EIGRP REPLY read function*/ @@ -161,7 +162,7 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph, dest_addr.family = AF_INET; dest_addr.u.prefix4 = tlv->destination; dest_addr.prefixlen = tlv->prefix_length; - struct eigrp_prefix_entry *dest = + struct eigrp_prefix_descriptor *dest = eigrp_topology_table_lookup_ipv4(eigrp->topology_table, &dest_addr); /* @@ -177,8 +178,8 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph, } struct eigrp_fsm_action_message msg; - struct eigrp_nexthop_entry *entry = - eigrp_prefix_entry_lookup(dest->entries, nbr); + struct eigrp_route_descriptor *entry = + eigrp_route_descriptor_lookup(dest->entries, nbr); if (eigrp_update_prefix_apply(eigrp, ei, EIGRP_FILTER_IN, &dest_addr)) { diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c index e15f777954..5183e645e5 100644 --- a/eigrpd/eigrp_routemap.c +++ b/eigrpd/eigrp_routemap.c @@ -265,8 +265,8 @@ route_match_metric(void *rule, struct prefix *prefix, route_map_object_t type, // uint32_t *metric; // uint32_t check; // struct rip_info *rinfo; - // struct eigrp_nexthop_entry *te; - // struct eigrp_prefix_entry *pe; + // struct eigrp_route_descriptor *te; + // struct eigrp_prefix_descriptor *pe; // struct listnode *node, *node2, *nnode, *nnode2; // struct eigrp *e; // diff --git a/eigrpd/eigrp_siaquery.c b/eigrpd/eigrp_siaquery.c index ff38325465..027700fe11 100644 --- a/eigrpd/eigrp_siaquery.c +++ b/eigrpd/eigrp_siaquery.c @@ -87,7 +87,7 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph, dest_addr.family = AFI_IP; dest_addr.u.prefix4 = tlv->destination; dest_addr.prefixlen = tlv->prefix_length; - struct eigrp_prefix_entry *dest = + struct eigrp_prefix_descriptor *dest = eigrp_topology_table_lookup_ipv4( eigrp->topology_table, &dest_addr); @@ -95,9 +95,9 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph, * know)*/ if (dest != NULL) { struct eigrp_fsm_action_message msg; - struct eigrp_nexthop_entry *entry = - eigrp_prefix_entry_lookup(dest->entries, - nbr); + struct eigrp_route_descriptor *entry = + eigrp_route_descriptor_lookup( + dest->entries, nbr); msg.packet_type = EIGRP_OPC_SIAQUERY; msg.eigrp = eigrp; msg.data_type = EIGRP_INT; @@ -114,7 +114,7 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph, } void eigrp_send_siaquery(struct eigrp_neighbor *nbr, - struct eigrp_prefix_entry *pe) + struct eigrp_prefix_descriptor *pe) { struct eigrp_packet *ep; uint16_t length = EIGRP_HEADER_LEN; diff --git a/eigrpd/eigrp_siareply.c b/eigrpd/eigrp_siareply.c index d3dd123f90..590b224d68 100644 --- a/eigrpd/eigrp_siareply.c +++ b/eigrpd/eigrp_siareply.c @@ -86,7 +86,7 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph, dest_addr.family = AFI_IP; dest_addr.u.prefix4 = tlv->destination; dest_addr.prefixlen = tlv->prefix_length; - struct eigrp_prefix_entry *dest = + struct eigrp_prefix_descriptor *dest = eigrp_topology_table_lookup_ipv4( eigrp->topology_table, &dest_addr); @@ -94,9 +94,9 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph, * know)*/ if (dest != NULL) { struct eigrp_fsm_action_message msg; - struct eigrp_nexthop_entry *entry = - eigrp_prefix_entry_lookup(dest->entries, - nbr); + struct eigrp_route_descriptor *entry = + eigrp_route_descriptor_lookup( + dest->entries, nbr); msg.packet_type = EIGRP_OPC_SIAQUERY; msg.eigrp = eigrp; msg.data_type = EIGRP_INT; @@ -113,7 +113,7 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph, } void eigrp_send_siareply(struct eigrp_neighbor *nbr, - struct eigrp_prefix_entry *pe) + struct eigrp_prefix_descriptor *pe) { struct eigrp_packet *ep; uint16_t length = EIGRP_HEADER_LEN; diff --git a/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h index 82bddaaae3..cddab57dd5 100644 --- a/eigrpd/eigrp_structs.h +++ b/eigrpd/eigrp_structs.h @@ -37,26 +37,6 @@ #include "eigrpd/eigrp_const.h" #include "eigrpd/eigrp_macros.h" -/* EIGRP master for system wide configuration and variables. */ -struct eigrp_master { - /* EIGRP instance. */ - struct list *eigrp; - - /* EIGRP thread master. */ - struct thread_master *master; - - /* Zebra interface list. */ - struct list *iflist; - - /* EIGRP start time. */ - time_t start_time; - - /* Various EIGRP global configuration. */ - uint8_t options; - -#define EIGRP_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */ -}; - struct eigrp_metrics { uint32_t delay; uint32_t bandwidth; @@ -68,6 +48,16 @@ struct eigrp_metrics { uint8_t flags; }; +struct eigrp_extdata { + uint32_t orig; + uint32_t as; + uint32_t tag; + uint32_t metric; + uint16_t reserved; + uint8_t protocol; + uint8_t flags; +}; + struct eigrp { vrf_id_t vrf_id; @@ -450,7 +440,7 @@ enum GR_type { EIGRP_GR_MANUAL, EIGRP_GR_FILTER }; //--------------------------------------------------------------------------------------------------------------------------------------------- /* EIGRP Topology table node structure */ -struct eigrp_prefix_entry { +struct eigrp_prefix_descriptor { struct list *entries, *rij; uint32_t fdistance; // FD uint32_t rdistance; // RD @@ -473,8 +463,14 @@ struct eigrp_prefix_entry { }; /* EIGRP Topology table record structure */ -struct eigrp_nexthop_entry { - struct eigrp_prefix_entry *prefix; +struct eigrp_route_descriptor { + uint16_t type; + uint16_t afi; + + struct eigrp_prefix_descriptor *prefix; + struct eigrp_neighbor *adv_router; + struct in_addr nexthop; + uint32_t reported_distance; // distance reported by neighbor uint32_t distance; // sum of reported distance and link cost to // advertised neighbor @@ -482,7 +478,9 @@ struct eigrp_nexthop_entry { struct eigrp_metrics reported_metric; struct eigrp_metrics total_metric; - struct eigrp_neighbor *adv_router; // ip address of advertising neighbor + struct eigrp_metrics metric; + struct eigrp_extdata extdata; + uint8_t flags; // used for marking successor and FS struct eigrp_interface *ei; // pointer for case of connected entry @@ -501,8 +499,8 @@ struct eigrp_fsm_action_message { uint8_t packet_type; // UPDATE, QUERY, SIAQUERY, SIAREPLY struct eigrp *eigrp; // which thread sent mesg struct eigrp_neighbor *adv_router; // advertising neighbor - struct eigrp_nexthop_entry *entry; - struct eigrp_prefix_entry *prefix; + struct eigrp_route_descriptor *entry; + struct eigrp_prefix_descriptor *prefix; msg_data_t data_type; // internal or external tlv type struct eigrp_metrics metrics; enum metric_change change; diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c index 2dbee16694..1b7e9fc15b 100644 --- a/eigrpd/eigrp_topology.c +++ b/eigrpd/eigrp_topology.c @@ -39,6 +39,7 @@ #include "vty.h" #include "lib_errors.h" +#include "eigrpd/eigrp_types.h" #include "eigrpd/eigrp_structs.h" #include "eigrpd/eigrpd.h" #include "eigrpd/eigrp_interface.h" @@ -51,9 +52,10 @@ #include "eigrpd/eigrp_topology.h" #include "eigrpd/eigrp_fsm.h" #include "eigrpd/eigrp_memory.h" +#include "eigrpd/eigrp_metric.h" -static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *, - struct eigrp_nexthop_entry *); +static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor *rd1, + struct eigrp_route_descriptor *rd2); /* * Returns linkedlist used as topology table @@ -70,14 +72,14 @@ struct route_table *eigrp_topology_new(void) * Returns new created toplogy node * cmp - assigned function for comparing topology entry */ -struct eigrp_prefix_entry *eigrp_prefix_entry_new(void) +struct eigrp_prefix_descriptor *eigrp_prefix_descriptor_new(void) { - struct eigrp_prefix_entry *new; - new = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY, - sizeof(struct eigrp_prefix_entry)); + struct eigrp_prefix_descriptor *new; + new = XCALLOC(MTYPE_EIGRP_PREFIX_DESCRIPTOR, + sizeof(struct eigrp_prefix_descriptor)); new->entries = list_new(); new->rij = list_new(); - new->entries->cmp = (int (*)(void *, void *))eigrp_nexthop_entry_cmp; + new->entries->cmp = (int (*)(void *, void *))eigrp_route_descriptor_cmp; new->distance = new->fdistance = new->rdistance = EIGRP_MAX_METRIC; new->destination = NULL; @@ -87,8 +89,8 @@ struct eigrp_prefix_entry *eigrp_prefix_entry_new(void) /* * Topology entry comparison */ -static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *entry1, - struct eigrp_nexthop_entry *entry2) +static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor *entry1, + struct eigrp_route_descriptor *entry2) { if (entry1->distance < entry2->distance) return -1; @@ -102,12 +104,12 @@ static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *entry1, * Returns new topology entry */ -struct eigrp_nexthop_entry *eigrp_nexthop_entry_new(void) +struct eigrp_route_descriptor *eigrp_route_descriptor_new(void) { - struct eigrp_nexthop_entry *new; + struct eigrp_route_descriptor *new; - new = XCALLOC(MTYPE_EIGRP_NEXTHOP_ENTRY, - sizeof(struct eigrp_nexthop_entry)); + new = XCALLOC(MTYPE_EIGRP_ROUTE_DESCRIPTOR, + sizeof(struct eigrp_route_descriptor)); new->reported_distance = EIGRP_MAX_METRIC; new->distance = EIGRP_MAX_METRIC; @@ -126,8 +128,8 @@ void eigrp_topology_free(struct eigrp *eigrp, struct route_table *table) /* * Adding topology node to topology table */ -void eigrp_prefix_entry_add(struct route_table *topology, - struct eigrp_prefix_entry *pe) +void eigrp_prefix_descriptor_add(struct route_table *topology, + struct eigrp_prefix_descriptor *pe) { struct route_node *rn; @@ -146,9 +148,9 @@ void eigrp_prefix_entry_add(struct route_table *topology, /* * Adding topology entry to topology node */ -void eigrp_nexthop_entry_add(struct eigrp *eigrp, - struct eigrp_prefix_entry *node, - struct eigrp_nexthop_entry *entry) +void eigrp_route_descriptor_add(struct eigrp *eigrp, + struct eigrp_prefix_descriptor *node, + struct eigrp_route_descriptor *entry) { struct list *l = list_new(); @@ -168,10 +170,11 @@ void eigrp_nexthop_entry_add(struct eigrp *eigrp, /* * Deleting topology node from topology table */ -void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table, - struct eigrp_prefix_entry *pe) +void eigrp_prefix_descriptor_delete(struct eigrp *eigrp, + struct route_table *table, + struct eigrp_prefix_descriptor *pe) { - struct eigrp_nexthop_entry *ne; + struct eigrp_route_descriptor *ne; struct listnode *node, *nnode; struct route_node *rn; @@ -189,7 +192,7 @@ void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table, listnode_delete(eigrp->topology_changes_internalIPV4, pe); for (ALL_LIST_ELEMENTS(pe->entries, node, nnode, ne)) - eigrp_nexthop_entry_delete(eigrp, pe, ne); + eigrp_route_descriptor_delete(eigrp, pe, ne); list_delete(&pe->entries); list_delete(&pe->rij); eigrp_zebra_route_delete(eigrp, pe->destination); @@ -198,20 +201,20 @@ void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table, rn->info = NULL; route_unlock_node(rn); // Lookup above route_unlock_node(rn); // Initial creation - XFREE(MTYPE_EIGRP_PREFIX_ENTRY, pe); + XFREE(MTYPE_EIGRP_PREFIX_DESCRIPTOR, pe); } /* * Deleting topology entry from topology node */ -void eigrp_nexthop_entry_delete(struct eigrp *eigrp, - struct eigrp_prefix_entry *node, - struct eigrp_nexthop_entry *entry) +void eigrp_route_descriptor_delete(struct eigrp *eigrp, + struct eigrp_prefix_descriptor *node, + struct eigrp_route_descriptor *entry) { if (listnode_lookup(node->entries, entry) != NULL) { listnode_delete(node->entries, entry); eigrp_zebra_route_delete(eigrp, node->destination); - XFREE(MTYPE_EIGRP_NEXTHOP_ENTRY, entry); + XFREE(MTYPE_EIGRP_ROUTE_DESCRIPTOR, entry); } } @@ -222,7 +225,7 @@ void eigrp_topology_delete_all(struct eigrp *eigrp, struct route_table *topology) { struct route_node *rn; - struct eigrp_prefix_entry *pe; + struct eigrp_prefix_descriptor *pe; for (rn = route_top(topology); rn; rn = route_next(rn)) { pe = rn->info; @@ -230,15 +233,15 @@ void eigrp_topology_delete_all(struct eigrp *eigrp, if (!pe) continue; - eigrp_prefix_entry_delete(eigrp, topology, pe); + eigrp_prefix_descriptor_delete(eigrp, topology, pe); } } -struct eigrp_prefix_entry * +struct eigrp_prefix_descriptor * eigrp_topology_table_lookup_ipv4(struct route_table *table, struct prefix *address) { - struct eigrp_prefix_entry *pe; + struct eigrp_prefix_descriptor *pe; struct route_node *rn; rn = route_node_lookup(table, address); @@ -259,14 +262,15 @@ eigrp_topology_table_lookup_ipv4(struct route_table *table, * That way we can clean up all the list_new and list_delete's * that we are doing. DBS */ -struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node) +struct list * +eigrp_topology_get_successor(struct eigrp_prefix_descriptor *table_node) { struct list *successors = list_new(); - struct eigrp_nexthop_entry *data; + struct eigrp_route_descriptor *data; struct listnode *node1, *node2; for (ALL_LIST_ELEMENTS(table_node->entries, node1, node2, data)) { - if (data->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) { + if (data->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG) { listnode_add(successors, data); } } @@ -283,7 +287,7 @@ struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node) } struct list * -eigrp_topology_get_successor_max(struct eigrp_prefix_entry *table_node, +eigrp_topology_get_successor_max(struct eigrp_prefix_descriptor *table_node, unsigned int maxpaths) { struct list *successors = eigrp_topology_get_successor(table_node); @@ -300,10 +304,10 @@ eigrp_topology_get_successor_max(struct eigrp_prefix_entry *table_node, return successors; } -struct eigrp_nexthop_entry * -eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *nbr) +struct eigrp_route_descriptor * +eigrp_route_descriptor_lookup(struct list *entries, struct eigrp_neighbor *nbr) { - struct eigrp_nexthop_entry *data; + struct eigrp_route_descriptor *data; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS(entries, node, nnode, data)) { if (data->adv_router == nbr) { @@ -319,8 +323,8 @@ struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp, struct eigrp_neighbor *nbr) { struct listnode *node2, *node22; - struct eigrp_nexthop_entry *entry; - struct eigrp_prefix_entry *pe; + struct eigrp_route_descriptor *entry; + struct eigrp_prefix_descriptor *pe; struct route_node *rn; /* create new empty list for prefixes storage */ @@ -348,8 +352,8 @@ enum metric_change eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg) { struct eigrp *eigrp = msg->eigrp; - struct eigrp_prefix_entry *prefix = msg->prefix; - struct eigrp_nexthop_entry *entry = msg->entry; + struct eigrp_prefix_descriptor *prefix = msg->prefix; + struct eigrp_route_descriptor *entry = msg->entry; enum metric_change change = METRIC_SAME; uint32_t new_reported_distance; @@ -413,7 +417,7 @@ distance_done: void eigrp_topology_update_all_node_flags(struct eigrp *eigrp) { - struct eigrp_prefix_entry *pe; + struct eigrp_prefix_descriptor *pe; struct route_node *rn; if (!eigrp) @@ -430,10 +434,10 @@ void eigrp_topology_update_all_node_flags(struct eigrp *eigrp) } void eigrp_topology_update_node_flags(struct eigrp *eigrp, - struct eigrp_prefix_entry *dest) + struct eigrp_prefix_descriptor *dest) { struct listnode *node; - struct eigrp_nexthop_entry *entry; + struct eigrp_route_descriptor *entry; for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) { if (entry->reported_distance < dest->fdistance) { @@ -444,29 +448,29 @@ void eigrp_topology_update_node_flags(struct eigrp *eigrp, && entry->distance != EIGRP_MAX_METRIC) { // is successor entry->flags |= - EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG; + EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG; entry->flags &= - ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG; + ~EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG; } else { // is feasible successor only entry->flags |= - EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG; + EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG; entry->flags &= - ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG; + ~EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG; } } else { - entry->flags &= ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG; - entry->flags &= ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG; + entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG; + entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG; } } } void eigrp_update_routing_table(struct eigrp *eigrp, - struct eigrp_prefix_entry *prefix) + struct eigrp_prefix_descriptor *prefix) { struct list *successors; struct listnode *node; - struct eigrp_nexthop_entry *entry; + struct eigrp_route_descriptor *entry; successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths); @@ -474,13 +478,13 @@ void eigrp_update_routing_table(struct eigrp *eigrp, eigrp_zebra_route_add(eigrp, prefix->destination, successors, prefix->fdistance); for (ALL_LIST_ELEMENTS_RO(successors, node, entry)) - entry->flags |= EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG; + entry->flags |= EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG; list_delete(&successors); } else { eigrp_zebra_route_delete(eigrp, prefix->destination); for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry)) - entry->flags &= ~EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG; + entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG; } } @@ -488,8 +492,8 @@ void eigrp_topology_neighbor_down(struct eigrp *eigrp, struct eigrp_neighbor *nbr) { struct listnode *node2, *node22; - struct eigrp_prefix_entry *pe; - struct eigrp_nexthop_entry *entry; + struct eigrp_prefix_descriptor *pe; + struct eigrp_route_descriptor *entry; struct route_node *rn; for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) { @@ -521,18 +525,18 @@ void eigrp_topology_neighbor_down(struct eigrp *eigrp, void eigrp_update_topology_table_prefix(struct eigrp *eigrp, struct route_table *table, - struct eigrp_prefix_entry *prefix) + struct eigrp_prefix_descriptor *prefix) { struct listnode *node1, *node2; - struct eigrp_nexthop_entry *entry; + struct eigrp_route_descriptor *entry; for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry)) { if (entry->distance == EIGRP_MAX_METRIC) { - eigrp_nexthop_entry_delete(eigrp, prefix, entry); + eigrp_route_descriptor_delete(eigrp, prefix, entry); } } if (prefix->distance == EIGRP_MAX_METRIC && prefix->nt != EIGRP_TOPOLOGY_TYPE_CONNECTED) { - eigrp_prefix_entry_delete(eigrp, table, prefix); + eigrp_prefix_descriptor_delete(eigrp, table, prefix); } } diff --git a/eigrpd/eigrp_topology.h b/eigrpd/eigrp_topology.h index 718cece403..26fa1a11b0 100644 --- a/eigrpd/eigrp_topology.h +++ b/eigrpd/eigrp_topology.h @@ -35,43 +35,47 @@ /* EIGRP Topology table related functions. */ extern struct route_table *eigrp_topology_new(void); extern void eigrp_topology_init(struct route_table *table); -extern struct eigrp_prefix_entry *eigrp_prefix_entry_new(void); -extern struct eigrp_nexthop_entry *eigrp_nexthop_entry_new(void); +extern struct eigrp_prefix_descriptor *eigrp_prefix_descriptor_new(void); +extern struct eigrp_route_descriptor *eigrp_route_descriptor_new(void); extern void eigrp_topology_free(struct eigrp *eigrp, struct route_table *table); -extern void eigrp_prefix_entry_add(struct route_table *table, - struct eigrp_prefix_entry *pe); -extern void eigrp_nexthop_entry_add(struct eigrp *eigrp, - struct eigrp_prefix_entry *pe, - struct eigrp_nexthop_entry *ne); -extern void eigrp_prefix_entry_delete(struct eigrp *eigrp, - struct route_table *table, - struct eigrp_prefix_entry *pe); -extern void eigrp_nexthop_entry_delete(struct eigrp *eigrp, - struct eigrp_prefix_entry *pe, - struct eigrp_nexthop_entry *ne); +extern void eigrp_prefix_descriptor_add(struct route_table *table, + struct eigrp_prefix_descriptor *pe); +extern void eigrp_route_descriptor_add(struct eigrp *eigrp, + struct eigrp_prefix_descriptor *pe, + struct eigrp_route_descriptor *ne); +extern void eigrp_prefix_descriptor_delete(struct eigrp *eigrp, + struct route_table *table, + struct eigrp_prefix_descriptor *pe); +extern void eigrp_route_descriptor_delete(struct eigrp *eigrp, + struct eigrp_prefix_descriptor *pe, + struct eigrp_route_descriptor *ne); extern void eigrp_topology_delete_all(struct eigrp *eigrp, struct route_table *table); -extern struct eigrp_prefix_entry * +extern struct eigrp_prefix_descriptor * eigrp_topology_table_lookup_ipv4(struct route_table *table, struct prefix *p); -extern struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *pe); extern struct list * -eigrp_topology_get_successor_max(struct eigrp_prefix_entry *pe, +eigrp_topology_get_successor(struct eigrp_prefix_descriptor *pe); +extern struct list * +eigrp_topology_get_successor_max(struct eigrp_prefix_descriptor *pe, unsigned int maxpaths); -extern struct eigrp_nexthop_entry * -eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *neigh); +extern struct eigrp_route_descriptor * +eigrp_route_descriptor_lookup(struct list *entries, + struct eigrp_neighbor *neigh); extern struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp, struct eigrp_neighbor *n); extern void eigrp_topology_update_all_node_flags(struct eigrp *eigrp); -extern void eigrp_topology_update_node_flags(struct eigrp *eigrp, - struct eigrp_prefix_entry *pe); +extern void +eigrp_topology_update_node_flags(struct eigrp *eigrp, + struct eigrp_prefix_descriptor *pe); extern enum metric_change eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg); extern void eigrp_update_routing_table(struct eigrp *eigrp, - struct eigrp_prefix_entry *pe); + struct eigrp_prefix_descriptor *pe); extern void eigrp_topology_neighbor_down(struct eigrp *eigrp, struct eigrp_neighbor *neigh); -extern void eigrp_update_topology_table_prefix(struct eigrp *eigrp, - struct route_table *table, - struct eigrp_prefix_entry *pe); +extern void +eigrp_update_topology_table_prefix(struct eigrp *eigrp, + struct route_table *table, + struct eigrp_prefix_descriptor *pe); #endif diff --git a/eigrpd/eigrp_types.h b/eigrpd/eigrp_types.h new file mode 100644 index 0000000000..bd6510733b --- /dev/null +++ b/eigrpd/eigrp_types.h @@ -0,0 +1,36 @@ +/* + * EIGRP Definition of Data Types + * Copyright (C) 2018 + * Authors: + * Donnie Savage + * + * This file is part of FRR. + * + * FRR 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, or (at your option) any + * later version. + * + * FRR 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; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ZEBRA_EIGRP_TYPES_H_ +#define _ZEBRA_EIGRP_TYPES_H_ + +typedef uint64_t eigrp_bandwidth_t; +typedef uint64_t eigrp_delay_t; +typedef uint64_t eigrp_metric_t; +typedef uint32_t eigrp_scaled_t; + +typedef uint32_t eigrp_system_metric_t; +typedef uint32_t eigrp_system_delay_t; +typedef uint32_t eigrp_system_bandwidth_t; + +#endif /* _ZEBRA_EIGRP_TYPES_H_ */ diff --git a/eigrpd/eigrp_update.c b/eigrpd/eigrp_update.c index cd30eb5ab5..91f3b3218b 100644 --- a/eigrpd/eigrp_update.c +++ b/eigrpd/eigrp_update.c @@ -49,6 +49,7 @@ #include "routemap.h" #include "vty.h" +#include "eigrpd/eigrp_types.h" #include "eigrpd/eigrp_structs.h" #include "eigrpd/eigrpd.h" #include "eigrpd/eigrp_interface.h" @@ -62,6 +63,7 @@ #include "eigrpd/eigrp_fsm.h" #include "eigrpd/eigrp_network.h" #include "eigrpd/eigrp_memory.h" +#include "eigrpd/eigrp_metric.h" bool eigrp_update_prefix_apply(struct eigrp *eigrp, struct eigrp_interface *ei, int in, struct prefix *prefix) @@ -101,11 +103,12 @@ bool eigrp_update_prefix_apply(struct eigrp *eigrp, struct eigrp_interface *ei, * Function is used for removing received prefix * from list of neighbor prefixes */ -static void remove_received_prefix_gr(struct list *nbr_prefixes, - struct eigrp_prefix_entry *recv_prefix) +static void +remove_received_prefix_gr(struct list *nbr_prefixes, + struct eigrp_prefix_descriptor *recv_prefix) { struct listnode *node1, *node11; - struct eigrp_prefix_entry *prefix = NULL; + struct eigrp_prefix_descriptor *prefix = NULL; /* iterate over all prefixes in list */ for (ALL_LIST_ELEMENTS(nbr_prefixes, node1, node11, prefix)) { @@ -136,7 +139,7 @@ static void eigrp_update_receive_GR_ask(struct eigrp *eigrp, struct list *nbr_prefixes) { struct listnode *node1; - struct eigrp_prefix_entry *prefix; + struct eigrp_prefix_descriptor *prefix; struct eigrp_fsm_action_message fsm_msg; /* iterate over all prefixes which weren't advertised by neighbor */ @@ -148,8 +151,8 @@ static void eigrp_update_receive_GR_ask(struct eigrp *eigrp, /* set delay to MAX */ fsm_msg.metrics.delay = EIGRP_MAX_METRIC; - struct eigrp_nexthop_entry *entry = - eigrp_prefix_entry_lookup(prefix->entries, nbr); + struct eigrp_route_descriptor *entry = + eigrp_route_descriptor_lookup(prefix->entries, nbr); fsm_msg.packet_type = EIGRP_OPC_UPDATE; fsm_msg.eigrp = eigrp; @@ -172,8 +175,8 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, { struct eigrp_neighbor *nbr; struct TLV_IPv4_Internal_type *tlv; - struct eigrp_prefix_entry *pe; - struct eigrp_nexthop_entry *ne; + struct eigrp_prefix_descriptor *pe; + struct eigrp_route_descriptor *ne; uint32_t flags; uint16_t type; uint16_t length; @@ -304,7 +307,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, dest_addr.family = AF_INET; dest_addr.u.prefix4 = tlv->destination; dest_addr.prefixlen = tlv->prefix_length; - struct eigrp_prefix_entry *dest = + struct eigrp_prefix_descriptor *dest = eigrp_topology_table_lookup_ipv4( eigrp->topology_table, &dest_addr); @@ -317,9 +320,9 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, dest); struct eigrp_fsm_action_message msg; - struct eigrp_nexthop_entry *entry = - eigrp_prefix_entry_lookup(dest->entries, - nbr); + struct eigrp_route_descriptor *entry = + eigrp_route_descriptor_lookup( + dest->entries, nbr); msg.packet_type = EIGRP_OPC_UPDATE; msg.eigrp = eigrp; @@ -331,7 +334,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, eigrp_fsm_event(&msg); } else { /*Here comes topology information save*/ - pe = eigrp_prefix_entry_new(); + pe = eigrp_prefix_descriptor_new(); pe->serno = eigrp->serno; pe->destination = (struct prefix *)prefix_ipv4_new(); @@ -340,7 +343,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, pe->state = EIGRP_FSM_STATE_PASSIVE; pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE; - ne = eigrp_nexthop_entry_new(); + ne = eigrp_route_descriptor_new(); ne->ei = ei; ne->adv_router = nbr; ne->reported_metric = tlv->metric; @@ -361,11 +364,12 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, pe->fdistance = pe->distance = pe->rdistance = ne->distance; ne->prefix = pe; - ne->flags = EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG; + ne->flags = + EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG; - eigrp_prefix_entry_add(eigrp->topology_table, - pe); - eigrp_nexthop_entry_add(eigrp, pe, ne); + eigrp_prefix_descriptor_add( + eigrp->topology_table, pe); + eigrp_route_descriptor_add(eigrp, pe, ne); pe->distance = pe->fdistance = pe->rdistance = ne->distance; pe->reported_metric = ne->total_metric; @@ -527,8 +531,8 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr) { struct eigrp_packet *ep; uint16_t length = EIGRP_HEADER_LEN; - struct eigrp_nexthop_entry *te; - struct eigrp_prefix_entry *pe; + struct eigrp_route_descriptor *te; + struct eigrp_prefix_descriptor *pe; struct listnode *node2, *nnode2; struct eigrp_interface *ei = nbr->ei; struct eigrp *eigrp = ei->eigrp; @@ -600,7 +604,7 @@ void eigrp_update_send(struct eigrp_interface *ei) { struct eigrp_packet *ep; struct listnode *node, *nnode; - struct eigrp_prefix_entry *pe; + struct eigrp_prefix_descriptor *pe; uint8_t has_tlv; struct eigrp *eigrp = ei->eigrp; struct prefix *dest_addr; @@ -626,7 +630,7 @@ void eigrp_update_send(struct eigrp_interface *ei) has_tlv = 0; for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node, nnode, pe)) { - struct eigrp_nexthop_entry *ne; + struct eigrp_route_descriptor *ne; if (!(pe->req_action & EIGRP_FSM_NEED_UPDATE)) continue; @@ -707,7 +711,7 @@ void eigrp_update_send_all(struct eigrp *eigrp, { struct eigrp_interface *iface; struct listnode *node, *node2, *nnode2; - struct eigrp_prefix_entry *pe; + struct eigrp_prefix_descriptor *pe; for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface)) { if (iface != exception) { @@ -745,7 +749,7 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) { struct eigrp_packet *ep; uint16_t length = EIGRP_HEADER_LEN; - struct eigrp_prefix_entry *pe; + struct eigrp_prefix_descriptor *pe; struct prefix *dest_addr; struct eigrp_interface *ei = nbr->ei; struct eigrp *eigrp = ei->eigrp; @@ -837,8 +841,8 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) /* prepare message for FSM */ struct eigrp_fsm_action_message fsm_msg; - struct eigrp_nexthop_entry *entry = - eigrp_prefix_entry_lookup(pe->entries, nbr); + struct eigrp_route_descriptor *entry = + eigrp_route_descriptor_lookup(pe->entries, nbr); fsm_msg.packet_type = EIGRP_OPC_UPDATE; fsm_msg.eigrp = eigrp; @@ -956,7 +960,7 @@ int eigrp_update_send_GR_thread(struct thread *thread) void eigrp_update_send_GR(struct eigrp_neighbor *nbr, enum GR_type gr_type, struct vty *vty) { - struct eigrp_prefix_entry *pe2; + struct eigrp_prefix_descriptor *pe2; struct list *prefixes; struct route_node *rn; struct eigrp_interface *ei = nbr->ei; diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c index 66dfbaa538..0809ac2cf0 100644 --- a/eigrpd/eigrp_vty.c +++ b/eigrpd/eigrp_vty.c @@ -59,25 +59,21 @@ #include "eigrpd/eigrp_vty_clippy.c" #endif -static void eigrp_vty_display_prefix_entry(struct vty *vty, - struct eigrp *eigrp, - struct eigrp_prefix_entry *pe, +static void eigrp_vty_display_prefix_entry(struct vty *vty, struct eigrp *eigrp, + struct eigrp_prefix_descriptor *pe, bool all) { bool first = true; - struct eigrp_nexthop_entry *te; + struct eigrp_route_descriptor *te; struct listnode *node; for (ALL_LIST_ELEMENTS_RO(pe->entries, node, te)) { if (all - || (((te->flags - & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) - == EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) - || ((te->flags - & EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG) - == EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG))) { - show_ip_eigrp_nexthop_entry(vty, eigrp, te, - &first); + || (((te->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG) + == EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG) + || ((te->flags & EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG) + == EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG))) { + show_ip_eigrp_route_descriptor(vty, eigrp, te, &first); first = false; } } @@ -104,7 +100,7 @@ static struct eigrp *eigrp_vty_get_eigrp(struct vty *vty, const char *vrf_name) static void eigrp_topology_helper(struct vty *vty, struct eigrp *eigrp, const char *all) { - struct eigrp_prefix_entry *tn; + struct eigrp_prefix_descriptor *tn; struct route_node *rn; show_ip_eigrp_topology_header(vty, eigrp); @@ -168,7 +164,7 @@ DEFPY (show_ip_eigrp_topology, "For a specific prefix\n") { struct eigrp *eigrp; - struct eigrp_prefix_entry *tn; + struct eigrp_prefix_descriptor *tn; struct route_node *rn; struct prefix cmp; diff --git a/eigrpd/eigrp_yang.h b/eigrpd/eigrp_yang.h new file mode 100644 index 0000000000..a95e5310fb --- /dev/null +++ b/eigrpd/eigrp_yang.h @@ -0,0 +1,32 @@ +/* + * EIGRP YANG Functions. + * Copyright (C) 2019 + * Authors: + * Donnie Savage + * + * This file is part of FRR. + * + * FRR 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, or (at your option) any + * later version. + * + * FRR 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; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _EIGRP_YANG_H_ +#define _EIGRP_YANG_H_ + +/*Prototypes*/ + +/* eigrp_northbound.c */ +extern const struct frr_yang_module_info frr_eigrpd_info; + +#endif /*EIGRP_YANG_H_ */ diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c index 0795fbd6df..e79123e6b4 100644 --- a/eigrpd/eigrp_zebra.c +++ b/eigrpd/eigrp_zebra.c @@ -41,6 +41,7 @@ #include "log.h" #include "nexthop.h" +#include "eigrpd/eigrp_types.h" #include "eigrpd/eigrp_structs.h" #include "eigrpd/eigrpd.h" #include "eigrpd/eigrp_interface.h" @@ -52,6 +53,7 @@ #include "eigrpd/eigrp_network.h" #include "eigrpd/eigrp_topology.h" #include "eigrpd/eigrp_fsm.h" +#include "eigrpd/eigrp_metric.h" static int eigrp_interface_address_add(ZAPI_CALLBACK_ARGS); static int eigrp_interface_address_delete(ZAPI_CALLBACK_ARGS); @@ -194,7 +196,7 @@ void eigrp_zebra_route_add(struct eigrp *eigrp, struct prefix *p, { struct zapi_route api; struct zapi_nexthop *api_nh; - struct eigrp_nexthop_entry *te; + struct eigrp_route_descriptor *te; struct listnode *node; int count = 0; diff --git a/eigrpd/eigrpd.h b/eigrpd/eigrpd.h index 6b4d45d1fc..01173768ba 100644 --- a/eigrpd/eigrpd.h +++ b/eigrpd/eigrpd.h @@ -37,6 +37,30 @@ #define EIGRP_MAJOR_VERSION 1 #define EIGRP_MINOR_VERSION 2 +#define EIGRP_TLV_32B_VERSION 1 /* Original 32bit scaled metrics */ +#define EIGRP_TLV_64B_VERSION 2 /* Current 64bit 'wide' metrics */ +#define EIGRP_TLV_MTR_VERSION 3 /* MTR TLVs with 32bit metric *Not Supported */ +#define EIGRP_TLV_SAF_VERSION 4 /* SAF TLVs with 64bit metric *Not Supported */ + +struct eigrp_master { + /* EIGRP instance. */ + struct list *eigrp; + + /* EIGRP thread master. */ + struct thread_master *master; + + /* Zebra interface list. */ + struct list *iflist; + + /* EIGRP start time. */ + time_t start_time; + + /* Various EIGRP global configuration. */ + uint8_t options; + +#define EIGRP_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */ +}; + /* Extern variables. */ extern struct zclient *zclient; extern struct thread_master *master; @@ -46,57 +70,10 @@ extern struct zebra_privs_t eigrpd_privs; /* Prototypes */ extern void eigrp_master_init(void); extern void eigrp_terminate(void); -extern void eigrp_finish_final(struct eigrp *); -extern void eigrp_finish(struct eigrp *); +extern void eigrp_finish_final(struct eigrp *eigrp); +extern void eigrp_finish(struct eigrp *eigrp); extern struct eigrp *eigrp_get(uint16_t as, vrf_id_t vrf_id); extern struct eigrp *eigrp_lookup(vrf_id_t vrf_id); -extern void eigrp_router_id_update(struct eigrp *); - -/* eigrp_cli.c */ -extern void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode); -extern void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_passive_interface(struct vty *vty, - struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_maximum_paths(struct vty *vty, - struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_redistribute(struct vty *vty, - struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_hello_interval(struct vty *vty, - struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_summarize_address(struct vty *vty, - struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_authentication(struct vty *vty, - struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); -extern void eigrp_cli_init(void); - -/* eigrp_northbound.c */ -extern const struct frr_yang_module_info frr_eigrpd_info; +extern void eigrp_router_id_update(struct eigrp *eigrp); #endif /* _ZEBRA_EIGRPD_H */ diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am index 98f39440c3..13c9f7f8ae 100644 --- a/eigrpd/subdir.am +++ b/eigrpd/subdir.am @@ -25,6 +25,7 @@ eigrpd_libeigrp_a_SOURCES = \ eigrpd/eigrp_hello.c \ eigrpd/eigrp_interface.c \ eigrpd/eigrp_memory.c \ + eigrpd/eigrp_metric.c \ eigrpd/eigrp_neighbor.c \ eigrpd/eigrp_network.c \ eigrpd/eigrp_northbound.c \ @@ -55,6 +56,7 @@ clippy_scan += \ # end noinst_HEADERS += \ + eigrpd/eigrp_cli.h \ eigrpd/eigrp_const.h \ eigrpd/eigrp_errors.h \ eigrpd/eigrp_filter.h \ @@ -62,13 +64,16 @@ noinst_HEADERS += \ eigrpd/eigrp_interface.h \ eigrpd/eigrp_macros.h \ eigrpd/eigrp_memory.h \ + eigrpd/eigrp_metric.h \ eigrpd/eigrp_neighbor.h \ eigrpd/eigrp_network.h \ eigrpd/eigrp_packet.h \ eigrpd/eigrp_snmp.h \ eigrpd/eigrp_structs.h \ + eigrpd/eigrp_types.h \ eigrpd/eigrp_vrf.h \ eigrpd/eigrp_vty.h \ + eigrpd/eigrp_yang.h \ eigrpd/eigrp_zebra.h \ # end diff --git a/ldpd/lde.h b/ldpd/lde.h index 28468931ec..e09be01ece 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -129,9 +129,7 @@ struct fec_node { uint32_t pw_remote_status; void *data; /* fec specific data */ - uint8_t flags; }; -#define F_FEC_NHS_CHANGED 0x01 #define CHUNK_SIZE 64 struct label_chunk { diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 68b721e213..0f91f49920 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -340,8 +340,6 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance); if (fnh == NULL) { - fn->flags |= F_FEC_NHS_CHANGED; - fnh = fec_nh_add(fn, af, nexthop, ifindex, route_type, route_instance); /* @@ -418,17 +416,11 @@ lde_kernel_update(struct fec *fec) } else fnh->flags |= F_FEC_NH_NO_LDP; } else { - fn->flags |= F_FEC_NHS_CHANGED; lde_send_delete_klabel(fn, fnh); fec_nh_del(fnh); } } - if (!(fn->flags & F_FEC_NHS_CHANGED)) - /* return earlier if nothing has changed */ - return; - fn->flags &= ~F_FEC_NHS_CHANGED; - if (LIST_EMPTY(&fn->nexthops)) { RB_FOREACH(ln, nbr_tree, &lde_nbrs) lde_send_labelwithdraw(ln, fn, NULL, NULL); diff --git a/lib/command.c b/lib/command.c index f40fe6e2c5..b9d607a101 100644 --- a/lib/command.c +++ b/lib/command.c @@ -49,6 +49,8 @@ #include "northbound_cli.h" #include "network.h" +#include "frrscript.h" + DEFINE_MTYPE_STATIC(LIB, HOST, "Host config") DEFINE_MTYPE(LIB, COMPLETION, "Completion item") @@ -2303,6 +2305,30 @@ done: return CMD_SUCCESS; } +#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING) +DEFUN(script, + script_cmd, + "script SCRIPT", + "Test command - execute a script\n" + "Script name (same as filename in /etc/frr/scripts/\n") +{ + struct prefix p; + str2prefix("1.2.3.4/24", &p); + + struct frrscript *fs = frrscript_load(argv[1]->arg, NULL); + + if (fs == NULL) { + vty_out(vty, "Script '/etc/frr/scripts/%s.lua' not found\n", + argv[1]->arg); + } else { + int ret = frrscript_call(fs, NULL); + vty_out(vty, "Script result: %d\n", ret); + } + + return CMD_SUCCESS; +} +#endif + /* Set config filename. Called from vty.c */ void host_config_set(const char *filename) { @@ -2397,6 +2423,10 @@ void cmd_init(int terminal) install_element(VIEW_NODE, &echo_cmd); install_element(VIEW_NODE, &autocomplete_cmd); install_element(VIEW_NODE, &find_cmd); +#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING) + install_element(VIEW_NODE, &script_cmd); +#endif + install_element(ENABLE_NODE, &config_end_cmd); install_element(ENABLE_NODE, &config_disable_cmd); diff --git a/lib/compiler.h b/lib/compiler.h index 217a60d888..70ef8e9bc8 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -279,6 +279,29 @@ extern "C" { #define array_size(ar) (sizeof(ar) / sizeof(ar[0])) +/* Some insane macros to count number of varargs to a functionlike macro */ +#define PP_ARG_N( \ + _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ + _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ + _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ + _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ + _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ + _61, _62, _63, N, ...) N + +#define PP_RSEQ_N() \ + 62, 61, 60, \ + 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \ + 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ + 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \ + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \ + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + +#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__) +#define PP_NARG(...) PP_NARG_(_, ##__VA_ARGS__, PP_RSEQ_N()) + + /* sigh. this is so ugly, it overflows and wraps to being nice again. * * printfrr() supports "%Ld" for <int64_t>, whatever that is typedef'd to. diff --git a/lib/frrlua.c b/lib/frrlua.c index 9f9cf8c1f6..3c270b2340 100644 --- a/lib/frrlua.c +++ b/lib/frrlua.c @@ -2,128 +2,365 @@ * This file defines the lua interface into * FRRouting. * - * Copyright (C) 2016 Cumulus Networks, Inc. - * Donald Sharp + * Copyright (C) 2016-2019 Cumulus Networks, Inc. + * Donald Sharp, Quentin Young * - * This file is part of FRRouting (FRR). + * 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. * - * FRR 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, or (at your option) any later version. - * - * FRR 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. + * 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 FRR; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <zebra.h> -#if defined(HAVE_LUA) +#ifdef HAVE_SCRIPTING + #include "prefix.h" #include "frrlua.h" #include "log.h" +#include "buffer.h" + +/* Lua stuff */ -static int lua_zlog_debug(lua_State *L) +/* + * FRR convenience functions. + * + * This section has convenience functions used to make interacting with the Lua + * stack easier. + */ + +int frrlua_table_get_integer(lua_State *L, const char *key) { - int debug_lua = 1; - const char *string = lua_tostring(L, 1); + int result; - if (debug_lua) - zlog_debug("%s", string); + lua_pushstring(L, key); + lua_gettable(L, -2); - return 0; + result = lua_tointeger(L, -1); + lua_pop(L, 1); + + return result; } -const char *get_string(lua_State *L, const char *key) +/* + * Encoders. + * + * This section has functions that convert internal FRR datatypes into Lua + * datatypes. + */ + +void lua_pushprefix(lua_State *L, const struct prefix *prefix) { - const char *str; + char buffer[PREFIX_STRLEN]; - lua_pushstring(L, key); - lua_gettable(L, -2); + lua_newtable(L); + lua_pushstring(L, prefix2str(prefix, buffer, PREFIX_STRLEN)); + lua_setfield(L, -2, "network"); + lua_pushinteger(L, prefix->prefixlen); + lua_setfield(L, -2, "length"); + lua_pushinteger(L, prefix->family); + lua_setfield(L, -2, "family"); +} - str = (const char *)lua_tostring(L, -1); +void *lua_toprefix(lua_State *L, int idx) +{ + struct prefix *p = XCALLOC(MTYPE_TMP, sizeof(struct prefix)); + + lua_getfield(L, idx, "network"); + str2prefix(lua_tostring(L, -1), p); lua_pop(L, 1); - return str; + return p; } -int get_integer(lua_State *L, const char *key) +void lua_pushinterface(lua_State *L, const struct interface *ifp) { - int result; + lua_newtable(L); + lua_pushstring(L, ifp->name); + lua_setfield(L, -2, "name"); + lua_pushinteger(L, ifp->ifindex); + lua_setfield(L, -2, "ifindex"); + lua_pushinteger(L, ifp->status); + lua_setfield(L, -2, "status"); + lua_pushinteger(L, ifp->flags); + lua_setfield(L, -2, "flags"); + lua_pushinteger(L, ifp->metric); + lua_setfield(L, -2, "metric"); + lua_pushinteger(L, ifp->speed); + lua_setfield(L, -2, "speed"); + lua_pushinteger(L, ifp->mtu); + lua_setfield(L, -2, "mtu"); + lua_pushinteger(L, ifp->mtu6); + lua_setfield(L, -2, "mtu6"); + lua_pushinteger(L, ifp->bandwidth); + lua_setfield(L, -2, "bandwidth"); + lua_pushinteger(L, ifp->link_ifindex); + lua_setfield(L, -2, "link_ifindex"); + lua_pushinteger(L, ifp->ll_type); + lua_setfield(L, -2, "linklayer_type"); +} - lua_pushstring(L, key); - lua_gettable(L, -2); +void *lua_tointerface(lua_State *L, int idx) +{ + struct interface *ifp = XCALLOC(MTYPE_TMP, sizeof(struct interface)); - result = lua_tointeger(L, -1); + lua_getfield(L, idx, "name"); + strlcpy(ifp->name, lua_tostring(L, -1), sizeof(ifp->name)); + lua_pop(L, 1); + lua_getfield(L, idx, "ifindex"); + ifp->ifindex = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, idx, "status"); + ifp->status = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, idx, "flags"); + ifp->flags = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, idx, "metric"); + ifp->metric = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, idx, "speed"); + ifp->speed = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, idx, "mtu"); + ifp->mtu = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, idx, "mtu6"); + ifp->mtu6 = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, idx, "bandwidth"); + ifp->bandwidth = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, idx, "link_ifindex"); + ifp->link_ifindex = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_getfield(L, idx, "linklayer_type"); + ifp->ll_type = lua_tointeger(L, -1); lua_pop(L, 1); - return result; + return ifp; } -static void *lua_alloc(void *ud, void *ptr, size_t osize, - size_t nsize) +void lua_pushinaddr(lua_State *L, const struct in_addr *addr) { - (void)ud; (void)osize; /* not used */ - if (nsize == 0) { - free(ptr); - return NULL; - } else - return realloc(ptr, nsize); + char buf[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, addr, buf, sizeof(buf)); + + lua_newtable(L); + lua_pushinteger(L, addr->s_addr); + lua_setfield(L, -2, "value"); + lua_pushstring(L, buf); + lua_setfield(L, -2, "string"); } -lua_State *lua_initialize(const char *file) +void *lua_toinaddr(lua_State *L, int idx) { - int status; - lua_State *L = lua_newstate(lua_alloc, NULL); + struct in_addr *inaddr = XCALLOC(MTYPE_TMP, sizeof(struct in_addr)); - zlog_debug("Newstate: %p", L); - luaL_openlibs(L); - zlog_debug("Opened lib"); - status = luaL_loadfile(L, file); - if (status) { - zlog_debug("Failure to open %s %d", file, status); - lua_close(L); - return NULL; - } + lua_getfield(L, idx, "value"); + inaddr->s_addr = lua_tointeger(L, -1); + lua_pop(L, 1); - lua_pcall(L, 0, LUA_MULTRET, 0); - zlog_debug("Setting global function"); - lua_pushcfunction(L, lua_zlog_debug); - lua_setglobal(L, "zlog_debug"); + return inaddr; +} + + +void lua_pushin6addr(lua_State *L, const struct in6_addr *addr) +{ + char buf[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, addr, buf, sizeof(buf)); + + lua_newtable(L); + lua_pushlstring(L, (const char *)addr->s6_addr, 16); + lua_setfield(L, -2, "value"); + lua_pushstring(L, buf); + lua_setfield(L, -2, "string"); +} + +void *lua_toin6addr(lua_State *L, int idx) +{ + struct in6_addr *in6addr = XCALLOC(MTYPE_TMP, sizeof(struct in6_addr)); + + lua_getfield(L, idx, "string"); + inet_pton(AF_INET6, lua_tostring(L, -1), in6addr); + lua_pop(L, 1); - return L; + return in6addr; } -void lua_setup_prefix_table(lua_State *L, const struct prefix *prefix) +void lua_pushsockunion(lua_State *L, const union sockunion *su) { - char buffer[100]; + char buf[SU_ADDRSTRLEN]; + sockunion2str(su, buf, sizeof(buf)); lua_newtable(L); - lua_pushstring(L, prefix2str(prefix, buffer, 100)); - lua_setfield(L, -2, "route"); - lua_pushinteger(L, prefix->family); - lua_setfield(L, -2, "family"); - lua_setglobal(L, "prefix"); + lua_pushlstring(L, (const char *)sockunion_get_addr(su), + sockunion_get_addrlen(su)); + lua_setfield(L, -2, "value"); + lua_pushstring(L, buf); + lua_setfield(L, -2, "string"); } -enum lua_rm_status lua_run_rm_rule(lua_State *L, const char *rule) +void *lua_tosockunion(lua_State *L, int idx) { - int status; + union sockunion *su = XCALLOC(MTYPE_TMP, sizeof(union sockunion)); + + lua_getfield(L, idx, "string"); + str2sockunion(lua_tostring(L, -1), su); + + return su; +} - lua_getglobal(L, rule); - status = lua_pcall(L, 0, 1, 0); - if (status) { - zlog_debug("Executing Failure with function: %s: %d", - rule, status); - return LUA_RM_FAILURE; +void lua_pushtimet(lua_State *L, const time_t *time) +{ + lua_pushinteger(L, *time); +} + +void *lua_totimet(lua_State *L, int idx) +{ + time_t *t = XCALLOC(MTYPE_TMP, sizeof(time_t)); + + *t = lua_tointeger(L, idx); + + return t; +} + +void lua_pushintegerp(lua_State *L, const long long *num) +{ + lua_pushinteger(L, *num); +} + +void *lua_tointegerp(lua_State *L, int idx) +{ + int isnum; + long long *num = XCALLOC(MTYPE_TMP, sizeof(long long)); + + *num = lua_tonumberx(L, idx, &isnum); + assert(isnum); + + return num; +} + +void *lua_tostringp(lua_State *L, int idx) +{ + char *string = XSTRDUP(MTYPE_TMP, lua_tostring(L, idx)); + + return string; +} + +/* + * Logging. + * + * Lua-compatible wrappers for FRR logging functions. + */ +static const char *frrlua_log_thunk(lua_State *L) +{ + int nargs; + + nargs = lua_gettop(L); + assert(nargs == 1); + + return lua_tostring(L, 1); +} + +static int frrlua_log_debug(lua_State *L) +{ + zlog_debug("%s", frrlua_log_thunk(L)); + return 0; +} + +static int frrlua_log_info(lua_State *L) +{ + zlog_info("%s", frrlua_log_thunk(L)); + return 0; +} + +static int frrlua_log_notice(lua_State *L) +{ + zlog_notice("%s", frrlua_log_thunk(L)); + return 0; +} + +static int frrlua_log_warn(lua_State *L) +{ + zlog_warn("%s", frrlua_log_thunk(L)); + return 0; +} + +static int frrlua_log_error(lua_State *L) +{ + zlog_err("%s", frrlua_log_thunk(L)); + return 0; +} + +static const luaL_Reg log_funcs[] = { + {"debug", frrlua_log_debug}, + {"info", frrlua_log_info}, + {"notice", frrlua_log_notice}, + {"warn", frrlua_log_warn}, + {"error", frrlua_log_error}, + {}, +}; + +void frrlua_export_logging(lua_State *L) +{ + lua_newtable(L); + luaL_setfuncs(L, log_funcs, 0); + lua_setglobal(L, "log"); +} + +/* + * Debugging. + */ + +char *frrlua_stackdump(lua_State *L) +{ + int top = lua_gettop(L); + + char tmpbuf[64]; + struct buffer *buf = buffer_new(4098); + + for (int i = 1; i <= top; i++) { + int t = lua_type(L, i); + + switch (t) { + case LUA_TSTRING: /* strings */ + snprintf(tmpbuf, sizeof(tmpbuf), "\"%s\"\n", + lua_tostring(L, i)); + buffer_putstr(buf, tmpbuf); + break; + case LUA_TBOOLEAN: /* booleans */ + snprintf(tmpbuf, sizeof(tmpbuf), "%s\n", + lua_toboolean(L, i) ? "true" : "false"); + buffer_putstr(buf, tmpbuf); + break; + case LUA_TNUMBER: /* numbers */ + snprintf(tmpbuf, sizeof(tmpbuf), "%g\n", + lua_tonumber(L, i)); + buffer_putstr(buf, tmpbuf); + break; + default: /* other values */ + snprintf(tmpbuf, sizeof(tmpbuf), "%s\n", + lua_typename(L, t)); + buffer_putstr(buf, tmpbuf); + break; + } } - status = lua_tonumber(L, -1); - return status; + char *result = XSTRDUP(MTYPE_TMP, buffer_getstr(buf)); + + buffer_free(buf); + + return result; } -#endif + +#endif /* HAVE_SCRIPTING */ diff --git a/lib/frrlua.h b/lib/frrlua.h index 40c7a67b89..8e52931e50 100644 --- a/lib/frrlua.h +++ b/lib/frrlua.h @@ -1,88 +1,173 @@ /* - * This file defines the lua interface into - * FRRouting. + * Copyright (C) 2016-2019 Cumulus Networks, Inc. + * Donald Sharp, Quentin Young * - * Copyright (C) 2016 Cumulus Networks, Inc. - * Donald Sharp + * 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 file is part of FRRouting (FRR). - * - * FRR 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, or (at your option) any later version. - * - * FRR 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. + * 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 FRR; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __LUA_H__ -#define __LUA_H__ +#ifndef __FRRLUA_H__ +#define __FRRLUA_H__ + +#include <zebra.h> + +#ifdef HAVE_SCRIPTING -#if defined(HAVE_LUA) +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> -#include "lua.h" -#include "lualib.h" -#include "lauxlib.h" +#include "prefix.h" +#include "frrscript.h" #ifdef __cplusplus extern "C" { #endif /* - * These functions are helper functions that - * try to glom some of the lua_XXX functionality - * into what we actually need, instead of having - * to make multiple calls to set up what - * we want + * Converts a prefix to a Lua value and pushes it on the stack. + */ +void lua_pushprefix(lua_State *L, const struct prefix *prefix); + +/* + * Converts the Lua value at idx to a prefix. + * + * Returns: + * struct prefix allocated with MTYPE_TMP + */ +void *lua_toprefix(lua_State *L, int idx); + +/* + * Converts an interface to a Lua value and pushes it on the stack. + */ +void lua_pushinterface(lua_State *L, const struct interface *ifp); + +/* + * Converts the Lua value at idx to an interface. + * + * Returns: + * struct interface allocated with MTYPE_TMP. This interface is not hooked + * to anything, nor is it inserted in the global interface tree. + */ +void *lua_tointerface(lua_State *L, int idx); + +/* + * Converts an in_addr to a Lua value and pushes it on the stack. + */ +void lua_pushinaddr(lua_State *L, const struct in_addr *addr); + +/* + * Converts the Lua value at idx to an in_addr. + * + * Returns: + * struct in_addr allocated with MTYPE_TMP. + */ +void *lua_toinaddr(lua_State *L, int idx); + +/* + * Converts an in6_addr to a Lua value and pushes it on the stack. */ -enum lua_rm_status { - /* - * Script function run failure. This will translate into a - * deny - */ - LUA_RM_FAILURE = 0, - /* - * No Match was found for the route map function - */ - LUA_RM_NOMATCH, - /* - * Match was found but no changes were made to the - * incoming data. - */ - LUA_RM_MATCH, - /* - * Match was found and data was modified, so - * figure out what changed - */ - LUA_RM_MATCH_AND_CHANGE, -}; +void lua_pushin6addr(lua_State *L, const struct in6_addr *addr); /* - * Open up the lua.scr file and parse - * initial global values, if any. + * Converts the Lua value at idx to an in6_addr. + * + * Returns: + * struct in6_addr allocated with MTYPE_TMP. */ -lua_State *lua_initialize(const char *file); +void *lua_toin6addr(lua_State *L, int idx); -void lua_setup_prefix_table(lua_State *L, const struct prefix *prefix); +/* + * Converts a time_t to a Lua value and pushes it on the stack. + */ +void lua_pushtimet(lua_State *L, const time_t *time); -enum lua_rm_status lua_run_rm_rule(lua_State *L, const char *rule); +/* + * Converts the Lua value at idx to a time_t. + * + * Returns: + * time_t allocated with MTYPE_TMP. + */ +void *lua_totimet(lua_State *L, int idx); /* - * Get particular string/integer information - * from a table. It is *assumed* that - * the table has already been selected + * Converts a sockunion to a Lua value and pushes it on the stack. */ -const char *get_string(lua_State *L, const char *key); -int get_integer(lua_State *L, const char *key); +void lua_pushsockunion(lua_State *L, const union sockunion *su); + +/* + * Converts the Lua value at idx to a sockunion. + * + * Returns: + * sockunion allocated with MTYPE_TMP. + */ +void *lua_tosockunion(lua_State *L, int idx); + +/* + * Converts an int to a Lua value and pushes it on the stack. + */ +void lua_pushintegerp(lua_State *L, const long long *num); + +/* + * Converts the Lua value at idx to an int. + * + * Returns: + * int allocated with MTYPE_TMP. + */ +void *lua_tointegerp(lua_State *L, int idx); + +/* + * Pop string. + * + * Sets *string to a copy of the string at the top of the stack. The copy is + * allocated with MTYPE_TMP and the caller is responsible for freeing it. + */ +void *lua_tostringp(lua_State *L, int idx); + +/* + * Retrieve an integer from table on the top of the stack. + * + * key + * Key of string value in table + */ +int frrlua_table_get_integer(lua_State *L, const char *key); + +/* + * Exports a new table containing bindings to FRR zlog functions into the + * global namespace. + * + * From Lua, these functions may be accessed as: + * + * - log.debug() + * - log.info() + * - log.warn() + * - log.error() + * + * They take a single string argument. + */ +void frrlua_export_logging(lua_State *L); + +/* + * Dump Lua stack to a string. + * + * Return value must be freed with XFREE(MTYPE_TMP, ...); + */ +char *frrlua_stackdump(lua_State *L); #ifdef __cplusplus } #endif -#endif -#endif +#endif /* HAVE_SCRIPTING */ + +#endif /* __FRRLUA_H__ */ diff --git a/lib/frrscript.c b/lib/frrscript.c new file mode 100644 index 0000000000..a3de474a4e --- /dev/null +++ b/lib/frrscript.c @@ -0,0 +1,272 @@ +/* Scripting foo + * Copyright (C) 2020 NVIDIA Corporation + * Quentin Young + * + * 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; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <zebra.h> + +#ifdef HAVE_SCRIPTING + +#include <stdarg.h> +#include <lua.h> + +#include "frrscript.h" +#include "frrlua.h" +#include "memory.h" +#include "hash.h" +#include "log.h" + + +DEFINE_MTYPE_STATIC(LIB, SCRIPT, "Scripting"); + +/* Codecs */ + +struct frrscript_codec frrscript_codecs_lib[] = { + {.typename = "integer", + .encoder = (encoder_func)lua_pushintegerp, + .decoder = lua_tointegerp}, + {.typename = "string", + .encoder = (encoder_func)lua_pushstring, + .decoder = lua_tostringp}, + {.typename = "prefix", + .encoder = (encoder_func)lua_pushprefix, + .decoder = lua_toprefix}, + {.typename = "interface", + .encoder = (encoder_func)lua_pushinterface, + .decoder = lua_tointerface}, + {.typename = "in_addr", + .encoder = (encoder_func)lua_pushinaddr, + .decoder = lua_toinaddr}, + {.typename = "in6_addr", + .encoder = (encoder_func)lua_pushin6addr, + .decoder = lua_toin6addr}, + {.typename = "sockunion", + .encoder = (encoder_func)lua_pushsockunion, + .decoder = lua_tosockunion}, + {.typename = "time_t", + .encoder = (encoder_func)lua_pushtimet, + .decoder = lua_totimet}, + {}}; + +/* Type codecs */ + +struct hash *codec_hash; +char scriptdir[MAXPATHLEN]; + +static unsigned int codec_hash_key(const void *data) +{ + const struct frrscript_codec *c = data; + + return string_hash_make(c->typename); +} + +static bool codec_hash_cmp(const void *d1, const void *d2) +{ + const struct frrscript_codec *e1 = d1; + const struct frrscript_codec *e2 = d2; + + return strmatch(e1->typename, e2->typename); +} + +static void *codec_alloc(void *arg) +{ + struct frrscript_codec *tmp = arg; + + struct frrscript_codec *e = + XCALLOC(MTYPE_SCRIPT, sizeof(struct frrscript_codec)); + e->typename = XSTRDUP(MTYPE_SCRIPT, tmp->typename); + e->encoder = tmp->encoder; + e->decoder = tmp->decoder; + + return e; +} + +#if 0 +static void codec_free(struct codec *c) +{ + XFREE(MTYPE_TMP, c->typename); + XFREE(MTYPE_TMP, c); +} +#endif + +/* Generic script APIs */ + +int frrscript_call(struct frrscript *fs, struct frrscript_env *env) +{ + struct frrscript_codec c = {}; + const void *arg; + const char *bindname; + + /* Encode script arguments */ + for (int i = 0; env && env[i].val != NULL; i++) { + bindname = env[i].name; + c.typename = env[i].typename; + arg = env[i].val; + + struct frrscript_codec *codec = hash_lookup(codec_hash, &c); + assert(codec && "No encoder for type"); + codec->encoder(fs->L, arg); + + lua_setglobal(fs->L, bindname); + } + + int ret = lua_pcall(fs->L, 0, 0, 0); + + switch (ret) { + case LUA_OK: + break; + case LUA_ERRRUN: + zlog_err("Script '%s' runtime error: %s", fs->name, + lua_tostring(fs->L, -1)); + break; + case LUA_ERRMEM: + zlog_err("Script '%s' memory error: %s", fs->name, + lua_tostring(fs->L, -1)); + break; + case LUA_ERRERR: + zlog_err("Script '%s' error handler error: %s", fs->name, + lua_tostring(fs->L, -1)); + break; + case LUA_ERRGCMM: + zlog_err("Script '%s' garbage collector error: %s", fs->name, + lua_tostring(fs->L, -1)); + break; + default: + zlog_err("Script '%s' unknown error: %s", fs->name, + lua_tostring(fs->L, -1)); + break; + } + + if (ret != LUA_OK) { + lua_pop(fs->L, 1); + goto done; + } + +done: + /* LUA_OK is 0, so we can just return lua_pcall's result directly */ + return ret; +} + +void *frrscript_get_result(struct frrscript *fs, + const struct frrscript_env *result) +{ + void *r; + struct frrscript_codec c = {.typename = result->typename}; + + struct frrscript_codec *codec = hash_lookup(codec_hash, &c); + assert(codec && "No encoder for type"); + + if (!codec->decoder) { + zlog_err("No script decoder for type '%s'", result->typename); + return NULL; + } + + lua_getglobal(fs->L, result->name); + r = codec->decoder(fs->L, -1); + lua_pop(fs->L, 1); + + return r; +} + +void frrscript_register_type_codec(struct frrscript_codec *codec) +{ + struct frrscript_codec c = *codec; + + if (hash_lookup(codec_hash, &c)) { + zlog_backtrace(LOG_ERR); + assert(!"Type codec double-registered."); + } + + assert(hash_get(codec_hash, &c, codec_alloc)); +} + +void frrscript_register_type_codecs(struct frrscript_codec *codecs) +{ + for (int i = 0; codecs[i].typename != NULL; i++) + frrscript_register_type_codec(&codecs[i]); +} + +struct frrscript *frrscript_load(const char *name, + int (*load_cb)(struct frrscript *)) +{ + struct frrscript *fs = XCALLOC(MTYPE_SCRIPT, sizeof(struct frrscript)); + + fs->name = XSTRDUP(MTYPE_SCRIPT, name); + fs->L = luaL_newstate(); + frrlua_export_logging(fs->L); + + char fname[MAXPATHLEN]; + snprintf(fname, sizeof(fname), "%s/%s.lua", scriptdir, fs->name); + + int ret = luaL_loadfile(fs->L, fname); + + switch (ret) { + case LUA_OK: + break; + case LUA_ERRSYNTAX: + zlog_err("Failed loading script '%s': syntax error: %s", fname, + lua_tostring(fs->L, -1)); + break; + case LUA_ERRMEM: + zlog_err("Failed loading script '%s': out-of-memory error: %s", + fname, lua_tostring(fs->L, -1)); + break; + case LUA_ERRGCMM: + zlog_err( + "Failed loading script '%s': garbage collector error: %s", + fname, lua_tostring(fs->L, -1)); + break; + case LUA_ERRFILE: + zlog_err("Failed loading script '%s': file read error: %s", + fname, lua_tostring(fs->L, -1)); + break; + default: + zlog_err("Failed loading script '%s': unknown error: %s", fname, + lua_tostring(fs->L, -1)); + break; + } + + if (ret != LUA_OK) + goto fail; + + if (load_cb && (*load_cb)(fs) != 0) + goto fail; + + return fs; +fail: + frrscript_unload(fs); + return NULL; +} + +void frrscript_unload(struct frrscript *fs) +{ + lua_close(fs->L); + XFREE(MTYPE_SCRIPT, fs->name); + XFREE(MTYPE_SCRIPT, fs); +} + +void frrscript_init(const char *sd) +{ + codec_hash = hash_create(codec_hash_key, codec_hash_cmp, + "Lua type encoders"); + + strlcpy(scriptdir, sd, sizeof(scriptdir)); + + /* Register core library types */ + frrscript_register_type_codecs(frrscript_codecs_lib); +} + +#endif /* HAVE_SCRIPTING */ diff --git a/lib/frrscript.h b/lib/frrscript.h new file mode 100644 index 0000000000..f4057f531b --- /dev/null +++ b/lib/frrscript.h @@ -0,0 +1,138 @@ +/* Scripting foo + * Copyright (C) 2020 NVIDIA Corporation + * Quentin Young + * + * 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; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __FRRSCRIPT_H__ +#define __FRRSCRIPT_H__ + +#include <zebra.h> + +#ifdef HAVE_SCRIPTING + +#include <lua.h> +#include "frrlua.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*encoder_func)(lua_State *, const void *); +typedef void *(*decoder_func)(lua_State *, int); + +struct frrscript_codec { + const char *typename; + encoder_func encoder; + decoder_func decoder; +}; + +struct frrscript { + /* Script name */ + char *name; + + /* Lua state */ + struct lua_State *L; +}; + +struct frrscript_env { + /* Value type */ + const char *typename; + + /* Binding name */ + const char *name; + + /* Value */ + const void *val; +}; + +/* + * Create new FRR script. + */ +struct frrscript *frrscript_load(const char *name, + int (*load_cb)(struct frrscript *)); + +/* + * Destroy FRR script. + */ +void frrscript_unload(struct frrscript *fs); + +/* + * Register a Lua codec for a type. + * + * tname + * Name of type; e.g., "peer", "ospf_interface", etc. Chosen at will. + * + * codec(s) + * Function pointer to codec struct. Encoder function should push a Lua + * table representing the passed argument - which will have the C type + * associated with the chosen 'tname' to the provided stack. The decoder + * function should pop a value from the top of the stack and return a heap + * chunk containing that value. Allocations should be made with MTYPE_TMP. + * + * If using the plural function variant, pass a NULL-terminated array. + * + */ +void frrscript_register_type_codec(struct frrscript_codec *codec); +void frrscript_register_type_codecs(struct frrscript_codec *codecs); + +/* + * Initialize scripting subsystem. Call this before anything else. + * + * scriptdir + * Directory in which to look for scripts + */ +void frrscript_init(const char *scriptdir); + + +/* + * Call script. + * + * fs + * The script to call; this is obtained from frrscript_load(). + * + * env + * The script's environment. Specify this as an array of frrscript_env. + * + * Returns: + * 0 if the script ran successfully, nonzero otherwise. + */ +int frrscript_call(struct frrscript *fs, struct frrscript_env *env); + + +/* + * Get result from finished script. + * + * fs + * The script. This script must have been run already. + * + * result + * The result to extract from the script. + * This reuses the frrscript_env type, but only the typename and name fields + * need to be set. The value is returned directly. + * + * Returns: + * The script result of the specified name and type, or NULL. + */ +void *frrscript_get_result(struct frrscript *fs, + const struct frrscript_env *result); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* HAVE_SCRIPTING */ + +#endif /* __FRRSCRIPT_H__ */ diff --git a/lib/libfrr.c b/lib/libfrr.c index 8e7777a1a9..b83883779c 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -43,6 +43,7 @@ #include "frrcu.h" #include "frr_pthread.h" #include "defaults.h" +#include "frrscript.h" DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm)) DEFINE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm)) @@ -55,6 +56,7 @@ char frr_vtydir[256]; const char frr_dbdir[] = DAEMON_DB_DIR; #endif const char frr_moduledir[] = MODULE_PATH; +const char frr_scriptdir[] = SCRIPT_PATH; char frr_protoname[256] = "NONE"; char frr_protonameinst[256] = "NONE"; @@ -100,6 +102,7 @@ static void opt_extend(const struct optspec *os) #define OPTION_DB_FILE 1006 #define OPTION_LOGGING 1007 #define OPTION_LIMIT_FDS 1008 +#define OPTION_SCRIPTDIR 1009 static const struct option lo_always[] = { {"help", no_argument, NULL, 'h'}, @@ -110,6 +113,7 @@ static const struct option lo_always[] = { {"pathspace", required_argument, NULL, 'N'}, {"vty_socket", required_argument, NULL, OPTION_VTYSOCK}, {"moduledir", required_argument, NULL, OPTION_MODULEDIR}, + {"scriptdir", required_argument, NULL, OPTION_SCRIPTDIR}, {"log", required_argument, NULL, OPTION_LOG}, {"log-level", required_argument, NULL, OPTION_LOGLEVEL}, {"tcli", no_argument, NULL, OPTION_TCLI}, @@ -126,6 +130,7 @@ static const struct optspec os_always = { " -N, --pathspace Insert prefix into config & socket paths\n" " --vty_socket Override vty socket path\n" " --moduledir Override modules directory\n" + " --scriptdir Override scripts directory\n" " --log Set Logging to stdout, syslog, or file:<name>\n" " --log-level Set Logging Level to use, debug, info, warn, etc\n" " --tcli Use transaction-based CLI\n" @@ -533,6 +538,14 @@ static int frr_opt(int opt) } di->module_path = optarg; break; + case OPTION_SCRIPTDIR: + if (di->script_path) { + fprintf(stderr, "--scriptdir option specified more than once!\n"); + errors++; + break; + } + di->script_path = optarg; + break; case OPTION_TCLI: di->cli_mode = FRR_CLI_TRANSACTIONAL; break; @@ -717,6 +730,9 @@ struct thread_master *frr_init(void) lib_cmd_init(); frr_pthread_init(); +#ifdef HAVE_SCRIPTING + frrscript_init(di->script_path ? di->script_path : frr_scriptdir); +#endif log_ref_init(); log_ref_vty_init(); diff --git a/lib/libfrr.h b/lib/libfrr.h index 2e4dcbe093..c446931468 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -81,6 +81,7 @@ struct frr_daemon_info { #endif const char *vty_path; const char *module_path; + const char *script_path; const char *pathspace; bool zpathspace; @@ -162,6 +163,7 @@ extern char frr_zclientpath[256]; extern const char frr_sysconfdir[]; extern char frr_vtydir[256]; extern const char frr_moduledir[]; +extern const char frr_scriptdir[]; extern char frr_protoname[]; extern char frr_protonameinst[]; diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index 7048df99fb..853f643472 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -693,6 +693,12 @@ static int nb_write_config(struct nb_config *config, enum nb_cfg_format format, __func__, safe_strerror(errno)); return -1; } + if (fchmod(fd, CONFIGFILE_MASK) != 0) { + flog_warn(EC_LIB_SYSTEM_CALL, + "%s: fchmod() failed: %s(%d):", __func__, + safe_strerror(errno), errno); + return -1; + } /* Make vty for configuration file. */ file_vty = vty_new(); diff --git a/lib/subdir.am b/lib/subdir.am index ee9e827ee8..570e0c3d28 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -26,6 +26,7 @@ lib_libfrr_la_SOURCES = \ lib/filter_nb.c \ lib/frrcu.c \ lib/frrlua.c \ + lib/frrscript.c \ lib/frr_pthread.c \ lib/frrstr.c \ lib/getopt.c \ @@ -185,6 +186,7 @@ pkginclude_HEADERS += \ lib/filter.h \ lib/freebsd-queue.h \ lib/frrlua.h \ + lib/frrscript.h \ lib/frr_pthread.h \ lib/frratomic.h \ lib/frrcu.h \ diff --git a/lib/zclient.c b/lib/zclient.c index cb4555650d..f16c94369b 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -40,6 +40,7 @@ #include "nexthop_group.h" #include "lib_errors.h" #include "srte.h" +#include "printfrr.h" DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient") DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs") @@ -4121,3 +4122,51 @@ uint32_t zclient_get_nhg_start(uint32_t proto) return ZEBRA_NHG_PROTO_SPACING * proto; } + +char *zclient_dump_route_flags(uint32_t flags, char *buf, size_t len) +{ + if (flags == 0) { + snprintfrr(buf, len, "None "); + return buf; + } + + snprintfrr( + buf, len, "%s%s%s%s%s%s%s%s%s%s", + CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION) ? "Recursion " + : "", + CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE) ? "Self " : "", + CHECK_FLAG(flags, ZEBRA_FLAG_IBGP) ? "iBGP " : "", + CHECK_FLAG(flags, ZEBRA_FLAG_SELECTED) ? "Selected " : "", + CHECK_FLAG(flags, ZEBRA_FLAG_FIB_OVERRIDE) ? "Override " : "", + CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE) ? "Evpn " : "", + CHECK_FLAG(flags, ZEBRA_FLAG_RR_USE_DISTANCE) ? "RR Distance " + : "", + CHECK_FLAG(flags, ZEBRA_FLAG_TRAPPED) ? "Trapped " : "", + CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOADED) ? "Offloaded " : "", + CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOAD_FAILED) ? "Offload Failed " + : ""); + return buf; +} + +char *zclient_evpn_dump_macip_flags(uint8_t flags, char *buf, size_t len) +{ + if (flags == 0) { + snprintfrr(buf, len, "None "); + return buf; + } + + snprintfrr( + buf, len, "%s%s%s%s%s%s%s", + CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? "Sticky MAC " : "", + CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? "Gateway MAC " : "", + CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? "Router " + : "", + CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_OVERRIDE_FLAG) ? "Override " + : "", + CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP) ? "SVI MAC " : "", + CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT) ? "Proxy " + : "", + CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SYNC_PATH) ? "Sync " : ""); + + return buf; +} diff --git a/lib/zclient.h b/lib/zclient.h index 910a4dbae5..57bad7c2e6 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -479,6 +479,7 @@ struct zapi_route { uint8_t type; unsigned short instance; + /* If you add flags, update zclient_dump_route_flags */ uint32_t flags; /* * Cause Zebra to consider this routes nexthops recursively @@ -580,6 +581,8 @@ struct zapi_route { } opaque; }; +extern char *zclient_dump_route_flags(uint32_t flags, char *buf, size_t len); + struct zapi_labels { uint8_t message; #define ZAPI_LABELS_FTN 0x01 @@ -768,8 +771,11 @@ zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note) #define ZEBRA_MACIP_TYPE_PROXY_ADVERT 0x20 /* Not locally active */ #define ZEBRA_MACIP_TYPE_SYNC_PATH 0x40 /* sync path */ /* XXX - flags is an u8; that needs to be changed to u32 if you need - * to allocate past 0x80 + * to allocate past 0x80. Additionally touch zclient_evpn_dump_macip_flags */ +#define MACIP_BUF_SIZE 128 +extern char *zclient_evpn_dump_macip_flags(uint8_t flags, char *buf, + size_t len); /* Zebra ES VTEP flags (ZEBRA_REMOTE_ES_VTEP_ADD) */ /* ESR has been rxed from the VTEP. Only VTEPs that have advertised the diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index e99653f918..e18d8ddb31 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -748,8 +748,13 @@ void ospf_ase_unregister_external_lsa(struct ospf_lsa *lsa, struct ospf *top) if (rn) { lst = rn->info; - listnode_delete(lst, lsa); - ospf_lsa_unlock(&lsa); /* external_lsas list */ + struct listnode *node = listnode_lookup(lst, lsa); + /* Unlock lsa only if node is present in the list */ + if (node) { + listnode_delete(lst, lsa); + ospf_lsa_unlock(&lsa); /* external_lsas list */ + } + route_unlock_node(rn); } } diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index d5eba74fd4..4c9db16c6b 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2789,7 +2789,7 @@ int ospf_check_nbr_status(struct ospf *ospf) static int ospf_maxage_lsa_remover(struct thread *thread) { struct ospf *ospf = THREAD_ARG(thread); - struct ospf_lsa *lsa; + struct ospf_lsa *lsa, *old; struct route_node *rn; int reschedule = 0; @@ -2851,6 +2851,17 @@ static int ospf_maxage_lsa_remover(struct thread *thread) /* Remove from lsdb. */ if (lsa->lsdb) { + old = ospf_lsdb_lookup(lsa->lsdb, lsa); + /* The max age LSA here must be the same + * as the LSA in LSDB + */ + if (old != lsa) { + flog_err(EC_OSPF_LSA_MISSING, + "%s: LSA[Type%d:%s]: LSA not in LSDB", + __func__, lsa->data->type, + inet_ntoa(lsa->data->id)); + continue; + } ospf_discard_from_db(ospf, lsa->lsdb, lsa); ospf_lsdb_delete(lsa->lsdb, lsa); } else { diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index c58073c521..68ad62cda4 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -280,7 +280,7 @@ DEFPY (ospf_router_id, for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) if (area->full_nbrs) { vty_out(vty, - "For this router-id change to take effect, save config and restart ospfd\n"); + "For this router-id change to take effect, use “clear ip ospf process” command\n"); return CMD_SUCCESS; } @@ -313,7 +313,7 @@ DEFUN_HIDDEN (ospf_router_id_old, for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) if (area->full_nbrs) { vty_out(vty, - "For this router-id change to take effect, save config and restart ospfd\n"); + "For this router-id change to take effect, use “clear ip ospf process” command\n"); return CMD_SUCCESS; } @@ -346,7 +346,7 @@ DEFPY (no_ospf_router_id, for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) if (area->full_nbrs) { vty_out(vty, - "For this router-id change to take effect, save config and restart ospfd\n"); + "For this router-id change to take effect, use “clear ip ospf process” command\n"); return CMD_SUCCESS; } @@ -11227,6 +11227,70 @@ DEFUN (show_ip_ospf_vrfs, return CMD_SUCCESS; } +DEFPY (clear_ip_ospf_neighbor, + clear_ip_ospf_neighbor_cmd, + "clear ip ospf [(1-65535)]$instance neighbor [A.B.C.D$nbr_id]", + CLEAR_STR + IP_STR + "OSPF information\n" + "Instance ID\n" + "Reset OSPF Neighbor\n" + "Neighbor ID\n") +{ + struct listnode *node; + struct ospf *ospf = NULL; + + /* If user does not specify the arguments, + * instance = 0 and nbr_id = 0.0.0.0 + */ + if (instance != 0) { + /* This means clear only the particular ospf process */ + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; + } + + /* Clear all the ospf processes */ + for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) { + if (!ospf->oi_running) + continue; + + ospf_neighbor_reset(ospf, nbr_id, nbr_id_str); + } + + return CMD_SUCCESS; +} + +DEFPY (clear_ip_ospf_process, + clear_ip_ospf_process_cmd, + "clear ip ospf [(1-65535)]$instance process", + CLEAR_STR + IP_STR + "OSPF information\n" + "Instance ID\n" + "Reset OSPF Process\n") +{ + struct listnode *node; + struct ospf *ospf = NULL; + + /* Check if instance is not passed as an argument */ + if (instance != 0) { + /* This means clear only the particular ospf process */ + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; + } + + /* Clear all the ospf processes */ + for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) { + if (!ospf->oi_running) + continue; + + ospf_process_reset(ospf); + } + + return CMD_SUCCESS; +} static const char *const ospf_abr_type_str[] = { "unknown", "standard", "ibm", "cisco", "shortcut" @@ -12623,6 +12687,8 @@ DEFUN (clear_ip_ospf_interface, void ospf_vty_clear_init(void) { install_element(ENABLE_NODE, &clear_ip_ospf_interface_cmd); + install_element(ENABLE_NODE, &clear_ip_ospf_process_cmd); + install_element(ENABLE_NODE, &clear_ip_ospf_neighbor_cmd); } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 0adf8a7b41..bab75995b7 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -87,13 +87,15 @@ static void ospf_finish_final(struct ospf *); #define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1 -void ospf_router_id_update(struct ospf *ospf) +void ospf_process_refresh_data(struct ospf *ospf, bool reset) { struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id); struct in_addr router_id, router_id_old; struct ospf_interface *oi; struct interface *ifp; - struct listnode *node; + struct listnode *node, *nnode; + struct ospf_area *area; + bool rid_change = false; if (!ospf->oi_running) { if (IS_DEBUG_OSPF_EVENT) @@ -126,8 +128,8 @@ void ospf_router_id_update(struct ospf *ospf) zlog_debug("Router-ID[OLD:%pI4]: Update to %pI4", &ospf->router_id, &router_id); - if (!IPV4_ADDR_SAME(&router_id_old, &router_id)) { - + rid_change = !(IPV4_ADDR_SAME(&router_id_old, &router_id)); + if (rid_change || (reset)) { for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { /* Some nbrs are identified by router_id, these needs * to be rebuilt. Possible optimization would be to do @@ -149,16 +151,8 @@ void ospf_router_id_update(struct ospf *ospf) ospf_if_up(oi); } - /* Flush (inline) all external LSAs based on the OSPF_LSA_SELF - * flag */ - if (ospf->lsdb) { - struct route_node *rn; - struct ospf_lsa *lsa; - - LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa) - if (IS_LSA_SELF(lsa)) - ospf_lsa_flush_schedule(ospf, lsa); - } + /* Flush (inline) all the self originated LSAs */ + ospf_flush_self_originated_lsas_now(ospf); ospf->router_id = router_id; if (IS_DEBUG_OSPF_EVENT) @@ -183,24 +177,81 @@ void ospf_router_id_update(struct ospf *ospf) LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa) { /* AdvRouter and Router ID is the same. */ if (IPV4_ADDR_SAME(&lsa->data->adv_router, - &ospf->router_id)) { + &ospf->router_id) && rid_change) { SET_FLAG(lsa->flags, OSPF_LSA_SELF_CHECKED); SET_FLAG(lsa->flags, OSPF_LSA_SELF); ospf_lsa_flush_schedule(ospf, lsa); } + /* The above flush will send immediately + * So discard the LSA to originate new + */ + ospf_discard_from_db(ospf, ospf->lsdb, lsa); } + + LSDB_LOOP (OPAQUE_AS_LSDB(ospf), rn, lsa) + ospf_discard_from_db(ospf, ospf->lsdb, lsa); + + ospf_lsdb_delete_all(ospf->lsdb); } + /* Delete the LSDB */ + for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) + ospf_area_lsdb_discard_delete(area); + /* update router-lsa's for each area */ ospf_router_lsa_update(ospf); /* update ospf_interface's */ - FOR_ALL_INTERFACES (vrf, ifp) - ospf_if_update(ospf, ifp); + FOR_ALL_INTERFACES (vrf, ifp) { + if (reset) + ospf_if_reset(ifp); + else + ospf_if_update(ospf, ifp); + } ospf_external_lsa_rid_change(ospf); } + + ospf->inst_shutdown = 0; +} + +void ospf_router_id_update(struct ospf *ospf) +{ + ospf_process_refresh_data(ospf, false); +} + +void ospf_process_reset(struct ospf *ospf) +{ + ospf_process_refresh_data(ospf, true); +} + +void ospf_neighbor_reset(struct ospf *ospf, struct in_addr nbr_id, + const char *nbr_str) +{ + struct route_node *rn; + struct ospf_neighbor *nbr; + struct ospf_interface *oi; + struct listnode *node; + + /* Clear only a particular nbr with nbr router id as nbr_id */ + if (nbr_str != NULL) { + for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { + nbr = ospf_nbr_lookup_by_routerid(oi->nbrs, &nbr_id); + if (nbr) + OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr); + } + return; + } + + /* send Neighbor event KillNbr to all associated neighbors. */ + for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + nbr = rn->info; + if (nbr && (nbr != oi->nbr_self)) + OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr); + } + } } /* For OSPF area sort by area id. */ @@ -870,14 +921,11 @@ static struct ospf_area *ospf_area_new(struct ospf *ospf, return new; } -static void ospf_area_free(struct ospf_area *area) +void ospf_area_lsdb_discard_delete(struct ospf_area *area) { struct route_node *rn; struct ospf_lsa *lsa; - ospf_opaque_type10_lsa_term(area); - - /* Free LSDBs. */ LSDB_LOOP (ROUTER_LSDB(area), rn, lsa) ospf_discard_from_db(area->ospf, area->lsdb, lsa); LSDB_LOOP (NETWORK_LSDB(area), rn, lsa) @@ -895,6 +943,15 @@ static void ospf_area_free(struct ospf_area *area) ospf_discard_from_db(area->ospf, area->lsdb, lsa); ospf_lsdb_delete_all(area->lsdb); +} + +static void ospf_area_free(struct ospf_area *area) +{ + ospf_opaque_type10_lsa_term(area); + + /* Free LSDBs. */ + ospf_area_lsdb_discard_delete(area); + ospf_lsdb_free(area->lsdb); ospf_lsa_unlock(&area->router_lsa_self); diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 3087b735ae..6960d151c2 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -571,7 +571,11 @@ extern struct ospf *ospf_lookup_by_inst_name(unsigned short instance, const char *name); extern struct ospf *ospf_lookup_by_vrf_id(vrf_id_t vrf_id); extern void ospf_finish(struct ospf *); +extern void ospf_process_refresh_data(struct ospf *ospf, bool reset); extern void ospf_router_id_update(struct ospf *ospf); +extern void ospf_process_reset(struct ospf *ospf); +extern void ospf_neighbor_reset(struct ospf *ospf, struct in_addr nbr_id, + const char *nbr_str); extern int ospf_network_set(struct ospf *, struct prefix_ipv4 *, struct in_addr, int); extern int ospf_network_unset(struct ospf *, struct prefix_ipv4 *, @@ -596,6 +600,7 @@ extern int ospf_area_shortcut_set(struct ospf *, struct ospf_area *, int); extern int ospf_area_shortcut_unset(struct ospf *, struct ospf_area *); extern int ospf_timers_refresh_set(struct ospf *, int); extern int ospf_timers_refresh_unset(struct ospf *); +void ospf_area_lsdb_discard_delete(struct ospf_area *area); extern int ospf_nbr_nbma_set(struct ospf *, struct in_addr); extern int ospf_nbr_nbma_unset(struct ospf *, struct in_addr); extern int ospf_nbr_nbma_priority_set(struct ospf *, struct in_addr, uint8_t); diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index dbe5de724c..f99971ab7b 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -770,18 +770,20 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc, goto done; } - switch (pnhi->nhr->prefix.family) { - case AF_INET: - if (pnhc->nexthop.gate.ipv4.s_addr - != pnhi->nhr->prefix.u.prefix4.s_addr) - goto done; /* Unrelated change */ - break; - case AF_INET6: - if (memcmp(&pnhc->nexthop.gate.ipv6, - &pnhi->nhr->prefix.u.prefix6, 16) - != 0) - goto done; /* Unrelated change */ - break; + if (pnhi->nhr) { + switch (pnhi->nhr->prefix.family) { + case AF_INET: + if (pnhc->nexthop.gate.ipv4.s_addr + != pnhi->nhr->prefix.u.prefix4.s_addr) + goto done; /* Unrelated change */ + break; + case AF_INET6: + if (memcmp(&pnhc->nexthop.gate.ipv6, + &pnhi->nhr->prefix.u.prefix6, 16) + != 0) + goto done; /* Unrelated change */ + break; + } } pnhi->nhr_matched = true; diff --git a/staticd/static_nb.c b/staticd/static_nb.c index 2010020367..a2a14751cf 100644 --- a/staticd/static_nb.c +++ b/staticd/static_nb.c @@ -47,12 +47,6 @@ const struct frr_yang_module_info frr_staticd_info = { } }, { - .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/table-id", - .cbs = { - .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_table_id_modify, - } - }, - { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop", .cbs = { .apply_finish = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_apply_finish, @@ -131,12 +125,6 @@ const struct frr_yang_module_info frr_staticd_info = { } }, { - .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/table-id", - .cbs = { - .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_table_id_modify, - } - }, - { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop", .cbs = { .apply_finish = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_apply_finish, diff --git a/staticd/static_nb.h b/staticd/static_nb.h index 0a846ab6fb..e85e1d0e9f 100644 --- a/staticd/static_nb.h +++ b/staticd/static_nb.h @@ -31,8 +31,6 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_tag_modify( struct nb_cb_modify_args *args); -int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_table_id_modify( - struct nb_cb_modify_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_create( struct nb_cb_create_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_destroy( @@ -73,8 +71,6 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_tag_modify( struct nb_cb_modify_args *args); -int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_table_id_modify( - struct nb_cb_modify_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_create( struct nb_cb_create_args *args); int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_destroy( @@ -130,13 +126,11 @@ int routing_control_plane_protocols_name_validate( "/frr-routing:routing/control-plane-protocols/" \ "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ "frr-staticd:staticd/route-list[prefix='%s'][afi-safi='%s']/" \ - "path-list[distance='%u']" + "path-list[table-id='%u'][distance='%u']" #define FRR_STATIC_ROUTE_PATH_TAG_XPATH "/tag" -#define FRR_STATIC_ROUTE_PATH_TABLEID_XPATH "/table-id" - /* route-list/frr-nexthops */ #define FRR_STATIC_ROUTE_NH_KEY_XPATH \ "/frr-nexthops/" \ @@ -157,7 +151,7 @@ int routing_control_plane_protocols_name_validate( "/frr-routing:routing/control-plane-protocols/" \ "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ "frr-staticd:staticd/route-list[prefix='%s'][afi-safi='%s']/" \ - "src-list[src-prefix='%s']/path-list[distance='%u']" + "src-list[src-prefix='%s']/path-list[table-id='%u'][distance='%u']" /* route-list/frr-nexthops */ #define FRR_DEL_S_ROUTE_NH_KEY_XPATH \ diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c index 1360660bce..bf669957bf 100644 --- a/staticd/static_nb_config.c +++ b/staticd/static_nb_config.c @@ -35,17 +35,40 @@ static int static_path_list_create(struct nb_cb_create_args *args) { struct route_node *rn; struct static_path *pn; + const struct lyd_node *vrf_dnode; + const char *vrf; uint8_t distance; + uint32_t table_id; switch (args->event) { case NB_EV_VALIDATE: + vrf_dnode = yang_dnode_get_parent(args->dnode, + "control-plane-protocol"); + vrf = yang_dnode_get_string(vrf_dnode, "./vrf"); + table_id = yang_dnode_get_uint32(args->dnode, "./table-id"); + + /* + * TableId is not applicable for VRF. Consider the case of + * l3mdev, there is one uint32_t space to work with. + * A l3mdev device points at a specific table that it + * relates to and a set of interfaces it belongs to. + */ + if (table_id && (strcmp(vrf, vrf_get_default_name()) != 0) + && !vrf_is_backend_netns()) { + snprintf( + args->errmsg, args->errmsg_len, + "%% table param only available when running on netns-based vrfs"); + return NB_ERR_VALIDATION; + } + break; case NB_EV_ABORT: case NB_EV_PREPARE: break; case NB_EV_APPLY: rn = nb_running_get_entry(args->dnode, NULL, true); distance = yang_dnode_get_uint8(args->dnode, "./distance"); - pn = static_add_path(rn, distance); + table_id = yang_dnode_get_uint32(args->dnode, "./table-id"); + pn = static_add_path(rn, table_id, distance); nb_running_set_entry(args->dnode, pn); } @@ -80,44 +103,6 @@ static void static_path_list_tag_modify(struct nb_cb_modify_args *args, static_install_path(rn, pn, info->safi, info->svrf); } -static int static_path_list_tableid_modify(struct nb_cb_modify_args *args, - const struct lyd_node *rn_dnode, - struct stable_info *info) -{ - struct static_path *pn; - struct route_node *rn; - uint32_t table_id; - const struct lyd_node *vrf_dnode; - const char *vrf; - - switch (args->event) { - case NB_EV_VALIDATE: - vrf_dnode = yang_dnode_get_parent(args->dnode, - "control-plane-protocol"); - vrf = yang_dnode_get_string(vrf_dnode, "./vrf"); - table_id = yang_dnode_get_uint32(args->dnode, NULL); - if (table_id && (strcmp(vrf, vrf_get_default_name()) != 0) - && !vrf_is_backend_netns()) { - snprintf(args->errmsg, args->errmsg_len, - "%% table param only available when running on netns-based vrfs"); - return NB_ERR_VALIDATION; - } - break; - case NB_EV_PREPARE: - case NB_EV_ABORT: - break; - case NB_EV_APPLY: - table_id = yang_dnode_get_uint32(args->dnode, NULL); - pn = nb_running_get_entry(args->dnode, NULL, true); - pn->table_id = table_id; - rn = nb_running_get_entry(rn_dnode, NULL, true); - static_install_path(rn, pn, info->safi, info->svrf); - break; - } - - return NB_OK; -} - static bool static_nexthop_create(struct nb_cb_create_args *args, const struct lyd_node *rn_dnode, struct stable_info *info) @@ -614,38 +599,6 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa /* * XPath: - * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/table-id - */ -int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_table_id_modify( - struct nb_cb_modify_args *args) -{ - struct route_node *rn; - const struct lyd_node *rn_dnode; - struct stable_info *info; - - switch (args->event) { - case NB_EV_VALIDATE: - if (static_path_list_tableid_modify(args, NULL, NULL) != NB_OK) - return NB_ERR_VALIDATION; - break; - case NB_EV_PREPARE: - case NB_EV_ABORT: - break; - case NB_EV_APPLY: - rn_dnode = yang_dnode_get_parent(args->dnode, "route-list"); - rn = nb_running_get_entry(rn_dnode, NULL, true); - info = route_table_get_info(rn->table); - - if (static_path_list_tableid_modify(args, rn_dnode, info) - != NB_OK) - return NB_ERR_VALIDATION; - break; - } - return NB_OK; -} - -/* - * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop */ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_create( @@ -1021,41 +974,6 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr /* * XPath: - * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/table-id - */ -int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_table_id_modify( - struct nb_cb_modify_args *args) -{ - struct route_node *rn; - const struct lyd_node *rn_dnode; - const struct lyd_node *src_dnode; - struct stable_info *info; - - switch (args->event) { - case NB_EV_VALIDATE: - if (static_path_list_tableid_modify(args, NULL, NULL) != NB_OK) - return NB_ERR_VALIDATION; - break; - case NB_EV_PREPARE: - case NB_EV_ABORT: - break; - case NB_EV_APPLY: - src_dnode = yang_dnode_get_parent(args->dnode, "src-list"); - rn_dnode = yang_dnode_get_parent(src_dnode, "route-list"); - rn = nb_running_get_entry(rn_dnode, NULL, true); - info = route_table_get_info(rn->table); - - if (static_path_list_tableid_modify(args, src_dnode, info) - != NB_OK) - return NB_ERR_VALIDATION; - - break; - } - return NB_OK; -} - -/* - * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop */ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_create( diff --git a/staticd/static_routes.c b/staticd/static_routes.c index 05355c48fe..1c436a66b0 100644 --- a/staticd/static_routes.c +++ b/staticd/static_routes.c @@ -161,7 +161,8 @@ bool static_add_nexthop_validate(struct static_vrf *svrf, static_types type, return true; } -struct static_path *static_add_path(struct route_node *rn, uint8_t distance) +struct static_path *static_add_path(struct route_node *rn, uint32_t table_id, + uint8_t distance) { struct static_path *pn; struct static_route_info *si; @@ -172,6 +173,7 @@ struct static_path *static_add_path(struct route_node *rn, uint8_t distance) pn = XCALLOC(MTYPE_STATIC_PATH, sizeof(struct static_path)); pn->distance = distance; + pn->table_id = table_id; static_nexthop_list_init(&(pn->nexthop_list)); si = rn->info; diff --git a/staticd/static_routes.h b/staticd/static_routes.h index bd2cd78fd9..470afb605d 100644 --- a/staticd/static_routes.h +++ b/staticd/static_routes.h @@ -187,7 +187,7 @@ extern void static_del_route(struct route_node *rn, safi_t safi, struct static_vrf *svrf); extern struct static_path *static_add_path(struct route_node *rn, - uint8_t distance); + uint32_t table_id, uint8_t distance); extern void static_del_path(struct route_node *rn, struct static_path *pn, safi_t safi, struct static_vrf *svrf); diff --git a/staticd/static_vty.c b/staticd/static_vty.c index c3c453f42d..1488cc1775 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -68,7 +68,6 @@ static int static_route_leak(struct vty *vty, const char *svrf, char buf_src_prefix[PREFIX_STRLEN]; char buf_nh_type[PREFIX_STRLEN]; char buf_tag[PREFIX_STRLEN]; - char buf_tableid[PREFIX_STRLEN]; uint8_t label_stack_id = 0; const char *buf_gate_str; uint8_t distance = ZEBRA_STATIC_DISTANCE_DEFAULT; @@ -162,14 +161,14 @@ static int static_route_leak(struct vty *vty, const char *svrf, "frr-staticd:staticd", "staticd", svrf, buf_prefix, yang_afi_safi_value2identity(afi, safi), - buf_src_prefix, distance); + buf_src_prefix, table_id, distance); else snprintf(xpath_prefix, sizeof(xpath_prefix), FRR_STATIC_ROUTE_INFO_KEY_XPATH, "frr-staticd:staticd", "staticd", svrf, buf_prefix, yang_afi_safi_value2identity(afi, safi), - distance); + table_id, distance); nb_cli_enqueue_change(vty, xpath_prefix, NB_OP_CREATE, NULL); @@ -180,12 +179,6 @@ static int static_route_leak(struct vty *vty, const char *svrf, sizeof(ab_xpath)); nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY, buf_tag); - /* Table-Id processing */ - snprintf(buf_tableid, sizeof(buf_tableid), "%u", table_id); - strlcpy(ab_xpath, xpath_prefix, sizeof(ab_xpath)); - strlcat(ab_xpath, FRR_STATIC_ROUTE_PATH_TABLEID_XPATH, - sizeof(ab_xpath)); - nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY, buf_tableid); /* nexthop processing */ snprintf(ab_xpath, sizeof(ab_xpath), @@ -289,16 +282,16 @@ static int static_route_leak(struct vty *vty, const char *svrf, "frr-staticd:staticd", "staticd", svrf, buf_prefix, yang_afi_safi_value2identity(afi, safi), - buf_src_prefix, distance, buf_nh_type, nh_svrf, - buf_gate_str, ifname); + buf_src_prefix, table_id, distance, + buf_nh_type, nh_svrf, buf_gate_str, ifname); else snprintf(ab_xpath, sizeof(ab_xpath), FRR_DEL_S_ROUTE_NH_KEY_XPATH, "frr-staticd:staticd", "staticd", svrf, buf_prefix, yang_afi_safi_value2identity(afi, safi), - distance, buf_nh_type, nh_svrf, buf_gate_str, - ifname); + table_id, distance, buf_nh_type, nh_svrf, + buf_gate_str, ifname); dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath); if (!dnode) diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index ab9358408e..24bef07ec2 100644 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -82,7 +82,9 @@ class NetworkTopo(Topo): ## ##################################################### - +@pytest.mark.isis +@pytest.mark.ospf +@pytest.mark.rip def setup_module(module): global topo, net global fatal_error diff --git a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py index 98a5033f53..cc1c1e3a0c 100644 --- a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py +++ b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py @@ -64,7 +64,7 @@ class BFDTopo(Topo): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r3"]) - +@pytest.mark.bfd def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(BFDTopo, mod.__name__) diff --git a/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py b/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py index 1adfec76d8..23da7ed850 100644 --- a/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py +++ b/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py @@ -127,7 +127,8 @@ class TemplateTopo(Topo): switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5") switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4") - +@pytest.mark.bfd +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) diff --git a/tests/topotests/bfd-ospf-topo1/__init__.py b/tests/topotests/bfd-ospf-topo1/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/__init__.py diff --git a/tests/topotests/bfd-ospf-topo1/rt1/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt1/bfdd.conf new file mode 100644 index 0000000000..610a20f88a --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/bfdd.conf @@ -0,0 +1,9 @@ +log file bfdd.log +log timestamp precision 3 +! +debug bfd network +debug bfd peer +debug bfd zebra +! +bfd +! diff --git a/tests/topotests/bfd-ospf-topo1/rt1/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt1/ospf6d.conf new file mode 100644 index 0000000000..18def599b4 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/ospf6d.conf @@ -0,0 +1,21 @@ +log file ospf6d.log +log timestamp precision 3 +! +hostname rt1 +! +password 1 +! +interface eth-rt2 + ipv6 ospf6 network broadcast + ipv6 ospf6 bfd +! +interface eth-rt3 + ipv6 ospf6 network broadcast + ipv6 ospf6 bfd +! +router ospf6 + ospf6 router-id 1.1.1.1 + interface eth-rt2 area 0.0.0.0 + interface eth-rt3 area 0.0.0.0 + redistribute connected +! diff --git a/tests/topotests/bfd-ospf-topo1/rt1/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt1/ospfd.conf new file mode 100644 index 0000000000..07b42f9885 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/ospfd.conf @@ -0,0 +1,26 @@ +log file ospfd.log +log timestamp precision 3 +! +hostname rt1 +! +password 1 +! +debug ospf event +debug ospf zebra +! +interface lo + ip ospf area 0.0.0.0 +! +interface eth-rt2 + ip ospf area 0.0.0.0 + ip ospf bfd +! +interface eth-rt3 + ip ospf area 0.0.0.0 + ip ospf bfd +! +router ospf + ospf router-id 1.1.1.1 + passive interface lo + router-info area 0.0.0.0 +! diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ip_route.ref b/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ip_route.ref new file mode 100644 index 0000000000..f354eff697 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ip_route.ref @@ -0,0 +1,74 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ipv6_route.ref b/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ipv6_route.ref new file mode 100644 index 0000000000..6465efb8b5 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ipv6_route.ref @@ -0,0 +1,70 @@ +{ + "::ffff:202:202\/128":[ + { + "prefix":"::ffff:202:202\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ], + "::ffff:303:303\/128":[ + { + "prefix":"::ffff:303:303\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "::ffff:404:404\/128":[ + { + "prefix":"::ffff:404:404\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "::ffff:505:505\/128":[ + { + "prefix":"::ffff:505:505\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step2/show_bfd_peers.ref b/tests/topotests/bfd-ospf-topo1/rt1/step2/show_bfd_peers.ref new file mode 100644 index 0000000000..63f0d50784 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step2/show_bfd_peers.ref @@ -0,0 +1,26 @@ +[ + { + "interface": "eth-rt3", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt2", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt3", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt2", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + } +] diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_healthy.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_healthy.ref new file mode 100644 index 0000000000..42051f9582 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_healthy.ref @@ -0,0 +1,28 @@ +[ + { + "peer": "10.0.2.2", + "interface": "eth-rt3", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "peer": "10.0.1.2", + "interface": "eth-rt2", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt3", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt2", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + } +] diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt2_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt2_down.ref new file mode 100644 index 0000000000..d844ee6813 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt2_down.ref @@ -0,0 +1,15 @@ +[ + { + "peer": "10.0.2.2", + "interface": "eth-rt3", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt3", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + } +] diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt3_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt3_down.ref new file mode 100644 index 0000000000..32799084fb --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt3_down.ref @@ -0,0 +1,15 @@ +[ + { + "peer": "10.0.1.2", + "interface": "eth-rt2", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt2", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + } +] diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_healthy.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_healthy.ref new file mode 100644 index 0000000000..f354eff697 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_healthy.ref @@ -0,0 +1,74 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt2_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt2_down.ref new file mode 100644 index 0000000000..43eecd0b7a --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt2_down.ref @@ -0,0 +1,74 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt3_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt3_down.ref new file mode 100644 index 0000000000..409af6308b --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt3_down.ref @@ -0,0 +1,74 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"ospf", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_healthy.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_healthy.ref new file mode 100644 index 0000000000..6465efb8b5 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_healthy.ref @@ -0,0 +1,70 @@ +{ + "::ffff:202:202\/128":[ + { + "prefix":"::ffff:202:202\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ], + "::ffff:303:303\/128":[ + { + "prefix":"::ffff:303:303\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "::ffff:404:404\/128":[ + { + "prefix":"::ffff:404:404\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "::ffff:505:505\/128":[ + { + "prefix":"::ffff:505:505\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt2_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt2_down.ref new file mode 100644 index 0000000000..cfb1ef1bb6 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt2_down.ref @@ -0,0 +1,70 @@ +{ + "::ffff:202:202\/128":[ + { + "prefix":"::ffff:202:202\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "::ffff:303:303\/128":[ + { + "prefix":"::ffff:303:303\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "::ffff:404:404\/128":[ + { + "prefix":"::ffff:404:404\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ], + "::ffff:505:505\/128":[ + { + "prefix":"::ffff:505:505\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt3_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt3_down.ref new file mode 100644 index 0000000000..58b44da5c2 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt3_down.ref @@ -0,0 +1,70 @@ +{ + "::ffff:202:202\/128":[ + { + "prefix":"::ffff:202:202\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ], + "::ffff:303:303\/128":[ + { + "prefix":"::ffff:303:303\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ], + "::ffff:404:404\/128":[ + { + "prefix":"::ffff:404:404\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ], + "::ffff:505:505\/128":[ + { + "prefix":"::ffff:505:505\/128", + "protocol":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-ospf-topo1/rt1/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt1/zebra.conf new file mode 100644 index 0000000000..6003125b6b --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/zebra.conf @@ -0,0 +1,25 @@ +log file zebra.log +log timestamp precision 3 +! +hostname rt1 +! +debug zebra kernel +debug zebra packet +debug zebra events +debug zebra rib +! +interface lo + ip address 1.1.1.1/32 + ipv6 address ::ffff:0101:0101/128 +! +interface eth-rt2 + ip address 10.0.1.1/24 +! +interface eth-rt3 + ip address 10.0.2.1/24 +! +ip forwarding +ipv6 forwarding +! +line vty +! diff --git a/tests/topotests/bfd-ospf-topo1/rt2/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt2/bfdd.conf new file mode 100644 index 0000000000..437f063d8f --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt2/bfdd.conf @@ -0,0 +1,7 @@ +! +debug bfd network +debug bfd peer +debug bfd zebra +! +bfd +! diff --git a/tests/topotests/bfd-ospf-topo1/rt2/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt2/ospf6d.conf new file mode 100644 index 0000000000..2f35099564 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt2/ospf6d.conf @@ -0,0 +1,19 @@ +log file ospf6d.log +! +hostname rt2 +! +password 1 +! +interface eth-rt1 + ipv6 ospf6 network broadcast + ipv6 ospf6 bfd +! +interface eth-rt5 + ipv6 ospf6 network broadcast +! +router ospf6 + ospf6 router-id 2.2.2.2 + interface eth-rt1 area 0.0.0.0 + interface eth-rt5 area 0.0.0.0 + redistribute connected +! diff --git a/tests/topotests/bfd-ospf-topo1/rt2/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt2/ospfd.conf new file mode 100644 index 0000000000..a05d8b58c8 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt2/ospfd.conf @@ -0,0 +1,24 @@ +log file ospfd.log +! +hostname rt2 +! +password 1 +! +debug ospf event +debug ospf zebra +! +interface lo + ip ospf area 0.0.0.0 +! +interface eth-rt1 + ip ospf area 0.0.0.0 + ip ospf bfd +! +interface eth-rt5 + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 2.2.2.2 + passive interface lo + router-info area 0.0.0.0 +! diff --git a/tests/topotests/bfd-ospf-topo1/rt2/step2/show_bfd_peers.ref b/tests/topotests/bfd-ospf-topo1/rt2/step2/show_bfd_peers.ref new file mode 100644 index 0000000000..d6df1ebfb2 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt2/step2/show_bfd_peers.ref @@ -0,0 +1,14 @@ +[ + { + "interface": "eth-rt1", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt1", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + } +] diff --git a/tests/topotests/bfd-ospf-topo1/rt2/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt2/zebra.conf new file mode 100644 index 0000000000..5fc7fc5b28 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt2/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname rt2 +! +debug zebra kernel +debug zebra packet +! +interface lo + ip address 2.2.2.2/32 + ipv6 address ::ffff:0202:0202/128 +! +interface eth-rt1 + ip address 10.0.1.2/24 +! +interface eth-rt5 + ip address 10.0.3.1/24 +! +ip forwarding +ipv6 forwarding +! +line vty +! diff --git a/tests/topotests/bfd-ospf-topo1/rt3/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt3/bfdd.conf new file mode 100644 index 0000000000..437f063d8f --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt3/bfdd.conf @@ -0,0 +1,7 @@ +! +debug bfd network +debug bfd peer +debug bfd zebra +! +bfd +! diff --git a/tests/topotests/bfd-ospf-topo1/rt3/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt3/ospf6d.conf new file mode 100644 index 0000000000..3e8777019e --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt3/ospf6d.conf @@ -0,0 +1,19 @@ +log file ospf6d.log +! +hostname rt3 +! +password 1 +! +interface eth-rt1 + ipv6 ospf6 network broadcast + ipv6 ospf6 bfd +! +interface eth-rt4 + ipv6 ospf6 network broadcast +! +router ospf6 + ospf6 router-id 3.3.3.3 + interface eth-rt1 area 0.0.0.0 + interface eth-rt4 area 0.0.0.0 + redistribute connected +! diff --git a/tests/topotests/bfd-ospf-topo1/rt3/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt3/ospfd.conf new file mode 100644 index 0000000000..1196e6d189 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt3/ospfd.conf @@ -0,0 +1,24 @@ +log file ospfd.log +! +hostname rt3 +! +password 1 +! +debug ospf event +debug ospf zebra +! +interface lo + ip ospf area 0.0.0.0 +! +interface eth-rt1 + ip ospf area 0.0.0.0 + ip ospf bfd +! +interface eth-rt4 + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 3.3.3.3 + passive interface lo + router-info area 0.0.0.0 +! diff --git a/tests/topotests/bfd-ospf-topo1/rt3/step2/show_bfd_peers.ref b/tests/topotests/bfd-ospf-topo1/rt3/step2/show_bfd_peers.ref new file mode 100644 index 0000000000..d6df1ebfb2 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt3/step2/show_bfd_peers.ref @@ -0,0 +1,14 @@ +[ + { + "interface": "eth-rt1", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt1", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + } +] diff --git a/tests/topotests/bfd-ospf-topo1/rt3/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt3/zebra.conf new file mode 100644 index 0000000000..d368de9bbe --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt3/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname rt3 +! +debug zebra kernel +debug zebra packet +! +interface lo + ip address 3.3.3.3/32 + ipv6 address ::ffff:0303:0303/128 +! +interface eth-rt1 + ip address 10.0.2.2/24 +! +interface eth-rt4 + ip address 10.0.4.1/24 +! +ip forwarding +ipv6 forwarding +! +line vty +! diff --git a/tests/topotests/bfd-ospf-topo1/rt4/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt4/bfdd.conf new file mode 100644 index 0000000000..f35e772790 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt4/bfdd.conf @@ -0,0 +1,5 @@ +! +debug bfd network +debug bfd peer +debug bfd zebra +! diff --git a/tests/topotests/bfd-ospf-topo1/rt4/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt4/ospf6d.conf new file mode 100644 index 0000000000..bccd1e75bd --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt4/ospf6d.conf @@ -0,0 +1,18 @@ +log file ospf6d.log +! +hostname rt4 +! +password 1 +! +interface eth-rt3 + ipv6 ospf6 network broadcast +! +interface eth-rt5 + ipv6 ospf6 network broadcast +! +router ospf6 + ospf6 router-id 4.4.4.4 + interface eth-rt3 area 0.0.0.0 + interface eth-rt5 area 0.0.0.0 + redistribute connected +! diff --git a/tests/topotests/bfd-ospf-topo1/rt4/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt4/ospfd.conf new file mode 100644 index 0000000000..3a2568b4ab --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt4/ospfd.conf @@ -0,0 +1,23 @@ +log file ospfd.log +! +hostname rt4 +! +password 1 +! +debug ospf event +debug ospf zebra +! +interface lo + ip ospf area 0.0.0.0 +! +interface eth-rt3 + ip ospf area 0.0.0.0 +! +interface eth-rt5 + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 4.4.4.4 + passive interface lo + router-info area 0.0.0.0 +! diff --git a/tests/topotests/bfd-ospf-topo1/rt4/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt4/zebra.conf new file mode 100644 index 0000000000..7b053bac35 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt4/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname rt4 +! +debug zebra kernel +debug zebra packet +! +interface lo + ip address 4.4.4.4/32 + ipv6 address ::ffff:0404:0404/128 +! +interface eth-rt3 + ip address 10.0.4.2/24 +! +interface eth-rt5 + ip address 10.0.5.1/24 +! +ip forwarding +ipv6 forwarding +! +line vty +! diff --git a/tests/topotests/bfd-ospf-topo1/rt5/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt5/bfdd.conf new file mode 100644 index 0000000000..f35e772790 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt5/bfdd.conf @@ -0,0 +1,5 @@ +! +debug bfd network +debug bfd peer +debug bfd zebra +! diff --git a/tests/topotests/bfd-ospf-topo1/rt5/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt5/ospf6d.conf new file mode 100644 index 0000000000..766862276c --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt5/ospf6d.conf @@ -0,0 +1,18 @@ +log file ospf6d.log +! +hostname rt5 +! +password 1 +! +interface eth-rt2 + ipv6 ospf6 network broadcast +! +interface eth-rt4 + ipv6 ospf6 network broadcast +! +router ospf6 + ospf6 router-id 5.5.5.5 + interface eth-rt2 area 0.0.0.0 + interface eth-rt4 area 0.0.0.0 + redistribute connected +! diff --git a/tests/topotests/bfd-ospf-topo1/rt5/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt5/ospfd.conf new file mode 100644 index 0000000000..a35de5f45f --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt5/ospfd.conf @@ -0,0 +1,23 @@ +log file ospfd.log +! +hostname rt5 +! +password 1 +! +debug ospf event +debug ospf zebra +! +interface lo + ip ospf area 0.0.0.0 +! +interface eth-rt2 + ip ospf area 0.0.0.0 +! +interface eth-rt4 + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 5.5.5.5 + passive interface lo + router-info area 0.0.0.0 +! diff --git a/tests/topotests/bfd-ospf-topo1/rt5/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt5/zebra.conf new file mode 100644 index 0000000000..0b7c9e02f3 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt5/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname rt5 +! +debug zebra kernel +debug zebra packet +! +interface lo + ip address 5.5.5.5/32 + ipv6 address ::ffff:0505:0505/128 +! +interface eth-rt2 + ip address 10.0.3.2/24 +! +interface eth-rt4 + ip address 10.0.5.2/24 +! +ip forwarding +ipv6 forwarding +! +line vty +! diff --git a/tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py b/tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py new file mode 100755 index 0000000000..1cec62789b --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py @@ -0,0 +1,307 @@ +#!/usr/bin/env python + +# +# test_bfd_ospf_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# 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_bfd_ospf_topo1.py: + + +---------+ + | | + eth-rt2 (.1) | RT1 | eth-rt3 (.1) + +----------+ 1.1.1.1 +----------+ + | | | | + | +---------+ | + | | + | 10.0.2.0/24 | + | | + | eth-rt1 | (.2) + | 10.0.1.0/24 +----+----+ + | | | + | | RT3 | + | | 3.3.3.3 | + | | | + (.2) | eth-rt1 +----+----+ + +----+----+ eth-rt4 | (.1) + | | | + | RT2 | | + | 2.2.2.2 | 10.0.4.0/24 | + | | | + +----+----+ | + (.1) | eth-rt5 eth-rt3 | (.2) + | +----+----+ + | | | + | | RT4 | + | | 4.4.4.4 | + | | | + | +----+----+ + | 10.0.3.0/24 eth-rt5 | (.1) + | | + | | + | 10.0.5.0/24 | + | | + | +---------+ | + | | | | + +----------+ RT5 +----------+ + eth-rt2 (.2) | 5.5.5.5 | eth-rt4 (.2) + | | + +---------+ + +""" + +import os +import sys +import pytest +import json +import re +from time import sleep +from time import time +from functools import partial + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + + +class TemplateTopo(Topo): + "Test topology builder" + + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # + # Define FRR Routers + # + for router in ["rt1", "rt2", "rt3", "rt4", "rt5"]: + tgen.add_router(router) + + # + # Define connections + # + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["rt1"], nodeif="eth-rt2") + switch.add_link(tgen.gears["rt2"], nodeif="eth-rt1") + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["rt1"], nodeif="eth-rt3") + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt1") + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["rt2"], nodeif="eth-rt5") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt2") + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt4") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt3") + + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4") + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + # For all registered routers, load the zebra configuration file + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_OSPF6, os.path.join(CWD, "{}/ospf6d.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def print_cmd_result(rname, command): + print(get_topogen().gears[rname].vtysh_cmd(command, isjson=False)) + + +def router_compare_json_output(rname, command, reference, count=120, wait=0.5): + "Compare router JSON output" + + logger.info('Comparing router "%s" "%s" output', rname, command) + + tgen = get_topogen() + filename = "{}/{}/{}".format(CWD, rname, reference) + expected = json.loads(open(filename).read()) + + # Run test function until we get an result. Wait at most 60 seconds. + test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected) + _, diff = topotest.run_and_expect(test_func, None, count=count, wait=wait) + assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) + assert diff is None, assertmsg + + +## TEST STEPS + + +def test_rib_ospf_step1(): + logger.info("Test (step 1): verify RIB for OSPF") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router_compare_json_output( + "rt1", "show ip route ospf json", "step1/show_ip_route.ref" + ) + router_compare_json_output( + "rt1", "show ipv6 route ospf json", "step1/show_ipv6_route.ref" + ) + + +def test_bfd_ospf_sessions_step2(): + logger.info("Test (step 2): verify BFD peers for OSPF") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # BFD is just used on three routers + for rt in ["rt1", "rt2", "rt3"]: + router_compare_json_output( + rt, "show bfd peers json", "step2/show_bfd_peers.ref" + ) + + +def test_bfd_ospf_interface_failure_rt2_step3(): + logger.info("Test (step 3): Check failover handling with RT2 down") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Let's kill the interface on rt2 and see what happens with the RIB and BFD on rt1 + tgen.gears["rt2"].link_enable("eth-rt1", enabled=False) + + # By default BFD provides a recovery time of 900ms plus jitter, so let's wait + # initial 2 seconds to let the CI not suffer. + # TODO: add check for array size + sleep(2) + router_compare_json_output( + "rt1", "show ip route ospf json", "step3/show_ip_route_rt2_down.ref", 1, 0 + ) + router_compare_json_output( + "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_rt2_down.ref", 1, 0 + ) + router_compare_json_output( + "rt1", "show bfd peers json", "step3/show_bfd_peers_rt2_down.ref", 1, 0 + ) + + # Check recovery, this can take some time + tgen.gears["rt2"].link_enable("eth-rt1", enabled=True) + + router_compare_json_output( + "rt1", "show ip route ospf json", "step3/show_ip_route_healthy.ref" + ) + router_compare_json_output( + "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_healthy.ref" + ) + router_compare_json_output( + "rt1", "show bfd peers json", "step3/show_bfd_peers_healthy.ref" + ) + + +def test_bfd_ospf_interface_failure_rt3_step3(): + logger.info("Test (step 3): Check failover handling with RT3 down") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Let's kill the interface on rt3 and see what happens with the RIB and BFD on rt1 + tgen.gears["rt3"].link_enable("eth-rt1", enabled=False) + + # By default BFD provides a recovery time of 900ms plus jitter, so let's wait + # initial 2 seconds to let the CI not suffer. + # TODO: add check for array size + sleep(2) + router_compare_json_output( + "rt1", "show ip route ospf json", "step3/show_ip_route_rt3_down.ref", 1, 0 + ) + router_compare_json_output( + "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_rt3_down.ref", 1, 0 + ) + router_compare_json_output( + "rt1", "show bfd peers json", "step3/show_bfd_peers_rt3_down.ref", 1, 0 + ) + + # Check recovery, this can take some time + tgen.gears["rt3"].link_enable("eth-rt1", enabled=True) + + router_compare_json_output( + "rt1", "show ip route ospf json", "step3/show_ip_route_healthy.ref" + ) + router_compare_json_output( + "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_healthy.ref" + ) + router_compare_json_output( + "rt1", "show bfd peers json", "step3/show_bfd_peers_healthy.ref" + ) + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py index bd3b876eeb..6283f03ddf 100644 --- a/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py +++ b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py @@ -77,7 +77,8 @@ class BFDProfTopo(Topo): switch.add_link(tgen.gears["r1"]) switch.add_link(tgen.gears["r6"]) - +@pytest.mark.bfd +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(BFDProfTopo, mod.__name__) diff --git a/tests/topotests/bfd-topo1/test_bfd_topo1.py b/tests/topotests/bfd-topo1/test_bfd_topo1.py index 6e589d55eb..4c13fdcfc5 100644 --- a/tests/topotests/bfd-topo1/test_bfd_topo1.py +++ b/tests/topotests/bfd-topo1/test_bfd_topo1.py @@ -69,7 +69,7 @@ class BFDTopo(Topo): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r4"]) - +@pytest.mark.bfd def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(BFDTopo, mod.__name__) diff --git a/tests/topotests/bfd-topo2/test_bfd_topo2.py b/tests/topotests/bfd-topo2/test_bfd_topo2.py index feb4576bd3..5181a40f47 100644 --- a/tests/topotests/bfd-topo2/test_bfd_topo2.py +++ b/tests/topotests/bfd-topo2/test_bfd_topo2.py @@ -70,7 +70,7 @@ class BFDTopo(Topo): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r4"]) - +@pytest.mark.bfd def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(BFDTopo, mod.__name__) diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py index 5fed135f8d..956b526583 100644 --- a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py +++ b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py @@ -70,7 +70,7 @@ class BFDTopo(Topo): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r4"]) - +@pytest.mark.bfd def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(BFDTopo, mod.__name__) diff --git a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py index 6a24684649..4e37ab00a3 100644 --- a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py +++ b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py @@ -362,7 +362,7 @@ def config_hosts(tgen, hosts): host = tgen.gears[host_name] config_host(host_name, host) - +@pytest.mark.pim def setup_module(module): "Setup topology" tgen = Topogen(NetworkTopo, module.__name__) diff --git a/tests/topotests/bgp_peer-group/__init__.py b/tests/topotests/bgp_peer-group/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_peer-group/__init__.py diff --git a/tests/topotests/bgp_peer-group/r1/bgpd.conf b/tests/topotests/bgp_peer-group/r1/bgpd.conf new file mode 100644 index 0000000000..19b490a359 --- /dev/null +++ b/tests/topotests/bgp_peer-group/r1/bgpd.conf @@ -0,0 +1,8 @@ +! +router bgp 65001 + neighbor PG peer-group + neighbor PG remote-as external + neighbor PG timers 3 10 + neighbor 192.168.255.3 peer-group PG + neighbor r1-eth0 interface peer-group PG +! diff --git a/tests/topotests/bgp_peer-group/r1/zebra.conf b/tests/topotests/bgp_peer-group/r1/zebra.conf new file mode 100644 index 0000000000..e2c399e536 --- /dev/null +++ b/tests/topotests/bgp_peer-group/r1/zebra.conf @@ -0,0 +1,6 @@ +! +interface r1-eth0 + ip address 192.168.255.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_peer-group/r2/bgpd.conf b/tests/topotests/bgp_peer-group/r2/bgpd.conf new file mode 100644 index 0000000000..0880ee9fae --- /dev/null +++ b/tests/topotests/bgp_peer-group/r2/bgpd.conf @@ -0,0 +1,7 @@ +! +router bgp 65002 + neighbor PG peer-group + neighbor PG remote-as external + neighbor PG timers 3 10 + neighbor r2-eth0 interface peer-group PG +! diff --git a/tests/topotests/bgp_peer-group/r2/zebra.conf b/tests/topotests/bgp_peer-group/r2/zebra.conf new file mode 100644 index 0000000000..606c17bec9 --- /dev/null +++ b/tests/topotests/bgp_peer-group/r2/zebra.conf @@ -0,0 +1,6 @@ +! +interface r2-eth0 + ip address 192.168.255.2/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_peer-group/r3/bgpd.conf b/tests/topotests/bgp_peer-group/r3/bgpd.conf new file mode 100644 index 0000000000..eb2fca15fb --- /dev/null +++ b/tests/topotests/bgp_peer-group/r3/bgpd.conf @@ -0,0 +1,7 @@ +! +router bgp 65003 + neighbor PG peer-group + neighbor PG remote-as external + neighbor PG timers 3 10 + neighbor 192.168.255.1 peer-group PG +! diff --git a/tests/topotests/bgp_peer-group/r3/zebra.conf b/tests/topotests/bgp_peer-group/r3/zebra.conf new file mode 100644 index 0000000000..e9fdfb70c5 --- /dev/null +++ b/tests/topotests/bgp_peer-group/r3/zebra.conf @@ -0,0 +1,6 @@ +! +interface r3-eth0 + ip address 192.168.255.3/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_peer-group/test_bgp_peer-group.py b/tests/topotests/bgp_peer-group/test_bgp_peer-group.py new file mode 100644 index 0000000000..7c7a8b87ed --- /dev/null +++ b/tests/topotests/bgp_peer-group/test_bgp_peer-group.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2021 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +# 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 if peer-group works for numbered and unnumbered configurations. +""" + +import os +import sys +import json +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.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.items(), 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_peer_group(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def _bgp_peer_group_configured(): + output = json.loads(tgen.gears["r1"].vtysh_cmd("show ip bgp neighbor json")) + expected = { + "r1-eth0": {"peerGroup": "PG", "bgpState": "Established"}, + "192.168.255.3": {"peerGroup": "PG", "bgpState": "Established"}, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_peer_group_configured) + 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["r1"]) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py index 3ce1472ac0..bf94d39a4b 100644 --- a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py +++ b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py @@ -91,7 +91,7 @@ class NetworkTopo(Topo): ## ##################################################### - +@pytest.mark.eigrp def setup_module(module): "Setup topology" tgen = Topogen(NetworkTopo, module.__name__) diff --git a/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py b/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py index 265124132f..07623af063 100644 --- a/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py +++ b/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py @@ -97,7 +97,7 @@ class NetworkTopo(Topo): ## ##################################################### - +@pytest.mark.pim def setup_module(module): "Setup topology" tgen = Topogen(NetworkTopo, module.__name__) diff --git a/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py b/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py index 6f80ffd1aa..a655b418cf 100755 --- a/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py +++ b/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py @@ -163,7 +163,7 @@ class TemplateTopo(Topo): f_in.close() f_out.close() - +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) diff --git a/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py b/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py index 872fef8fdb..bb43e6b114 100755 --- a/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py +++ b/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py @@ -165,7 +165,7 @@ class TemplateTopo(Topo): f_in.close() f_out.close() - +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) diff --git a/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py b/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py index b1071310cf..bfd2f92a28 100755 --- a/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py +++ b/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py @@ -148,6 +148,7 @@ class TemplateTopo(Topo): switch.add_link(tgen.gears['rt6'], nodeif="eth-dst") switch.add_link(tgen.gears['dst'], nodeif="eth-rt6") +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" diff --git a/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py b/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py index 34eb6d90f6..63be3f78aa 100644 --- a/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py +++ b/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py @@ -134,7 +134,7 @@ class TemplateTopo(Topo): switch.add_link(tgen.gears["rt5"], nodeif="eth-rt6") switch.add_link(tgen.gears["rt6"], nodeif="eth-rt5") - +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) diff --git a/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py b/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py index a1263de8ad..83751fabcd 100755 --- a/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py +++ b/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py @@ -177,7 +177,7 @@ class TemplateTopo(Topo): f_in.close() f_out.close() - +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py index 12121e4ddf..a79c8a268b 100644 --- a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py +++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py @@ -82,7 +82,7 @@ class ISISTopo1(Topo): sw.add_link(tgen.gears["r4"]) sw.add_link(tgen.gears["r5"]) - +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(ISISTopo1, mod.__name__) diff --git a/tests/topotests/isis-topo1/test_isis_topo1.py b/tests/topotests/isis-topo1/test_isis_topo1.py index 71005a0362..25116d9452 100644 --- a/tests/topotests/isis-topo1/test_isis_topo1.py +++ b/tests/topotests/isis-topo1/test_isis_topo1.py @@ -84,7 +84,7 @@ class ISISTopo1(Topo): sw.add_link(tgen.gears["r4"]) sw.add_link(tgen.gears["r5"]) - +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(ISISTopo1, mod.__name__) diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py index 9822686dfc..dfe65f010e 100644 --- a/tests/topotests/ldp-topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py @@ -159,7 +159,7 @@ class NetworkTopo(Topo): ## ##################################################### - +@pytest.mark.ldp def setup_module(module): global topo, net global fatal_error diff --git a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py index ba94cd47d4..d659acb470 100644 --- a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py +++ b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py @@ -121,7 +121,8 @@ class TemplateTopo(Topo): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r3"]) - +@pytest.mark.ldp +@pytest.mark.ospf def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 68a7217dd6..22602cb460 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -692,8 +692,8 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True): config_data.append("{} activate".format(neigh_cxt)) disable_connected = peer.setdefault("disable_connected_check", False) - keep_alive = peer.setdefault("keepalivetimer", 60) - hold_down = peer.setdefault("holddowntimer", 180) + keep_alive = peer.setdefault("keepalivetimer", 3) + hold_down = peer.setdefault("holddowntimer", 10) password = peer.setdefault("password", None) no_password = peer.setdefault("no_password", None) max_hop_limit = peer.setdefault("ebgp_multihop", 1) diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 85e8c9caed..175d660d1e 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -1659,7 +1659,7 @@ def create_interfaces_cfg(tgen, topo, build=False): interface_data.append("no ip ospf " " hello-interval") else: interface_data.append( - "ip ospf " " hello-interval {}".format(intf_ospf_hello) + "ip ospf" " hello-interval {}".format(intf_ospf_hello) ) if "dead_interval" in ospf_data: @@ -1670,7 +1670,7 @@ def create_interfaces_cfg(tgen, topo, build=False): interface_data.append("no ip ospf" " dead-interval") else: interface_data.append( - "ip ospf " " dead-interval {}".format(intf_ospf_dead) + "ip ospf" " dead-interval {}".format(intf_ospf_dead) ) if "network" in ospf_data: @@ -3065,7 +3065,11 @@ def verify_rib( errormsg = ( "[DUT: {}]: tag value {}" " is not matched for" - " route {} in RIB \n".format(dut, _tag, st_rt,) + " route {} in RIB \n".format( + dut, + _tag, + st_rt, + ) ) return errormsg @@ -3082,7 +3086,11 @@ def verify_rib( errormsg = ( "[DUT: {}]: metric value " "{} is not matched for " - "route {} in RIB \n".format(dut, metric, st_rt,) + "route {} in RIB \n".format( + dut, + metric, + st_rt, + ) ) return errormsg diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 23b647d094..3e368cd7d3 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -62,7 +62,7 @@ def create_router_ospf(tgen, topo, input_dict=None, build=False, load_config=Tru "r1": { "ospf": { "router_id": "22.22.22.22", - "area": [{ "id":0.0.0.0, "type": "nssa"}] + "area": [{ "id": "0.0.0.0", "type": "nssa"}] } } @@ -327,7 +327,7 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config= "links": { "r2": { "ospf": { - "authentication": 'message-digest', + "authentication": "message-digest", "authentication-key": "ospf", "message-digest-key": "10" } @@ -376,6 +376,7 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config= if data_ospf_area: cmd = "ip ospf area {}".format(data_ospf_area) config_data.append(cmd) + # interface ospf auth if data_ospf_auth: if data_ospf_auth == "null": @@ -461,6 +462,32 @@ def clear_ospf(tgen, router): logger.debug("Exiting lib API: clear_ospf()") +def redistribute_ospf(tgen, topo, dut, route_type, **kwargs): + """ + Redstribution of routes inside ospf. + + Parameters + ---------- + * `tgen`: Topogen object + * `topo` : json file data + * `dut`: device under test + * `route_type`: "static" or "connected" or .... + * `kwargs`: pass extra information (see below) + + Usage + ----- + redistribute_ospf(tgen, topo, "r0", "static", delete=True) + redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4") + """ + + ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": route_type}]}}} + for k, v in kwargs.items(): + ospf_red[dut]["ospf"]["redistribute"][0][k] = v + + result = create_router_ospf(tgen, topo, ospf_red) + assert result is True, "Testcase : Failed \n Error: {}".format(result) + + ################################ # Verification procs ################################ @@ -522,7 +549,7 @@ def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False): logger.info("Verifying OSPF neighborship on router %s:", router) show_ospf_json = run_frr_cmd( - rnode, "show ip ospf neighbor all json", isjson=True + rnode, "show ip ospf neighbor all json", isjson=True ) # Verifying output dictionary show_ospf_json is empty or not @@ -844,19 +871,23 @@ def verify_ospf_rib( if "routeType" not in ospf_rib_json[st_rt]: errormsg = ( "[DUT: {}]: routeType missing" - "for route {} in OSPF RIB \n".format(dut, st_rt) + " for route {} in OSPF RIB \n".format( + dut, st_rt + ) ) return errormsg elif _rtype != ospf_rib_json[st_rt]["routeType"]: errormsg = ( "[DUT: {}]: routeType mismatch" - "for route {} in OSPF RIB \n".format(dut, st_rt) + " for route {} in OSPF RIB \n".format( + dut, st_rt + ) ) return errormsg else: logger.info( - "DUT: {}]: Found routeType {}" - "for route {}".format(dut, _rtype, st_rt) + "[DUT: {}]: Found routeType {}" + " for route {}".format(dut, _rtype, st_rt) ) if tag: if "tag" not in ospf_rib_json[st_rt]: diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py index 5ef6b9b0be..441368e8fa 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py @@ -65,6 +65,7 @@ from lib.ospf import ( verify_ospf_rib, create_router_ospf, verify_ospf_interface, + redistribute_ospf, ) topo = None @@ -184,38 +185,6 @@ def teardown_module(mod): logger.info("=" * 40) -def red_static(dut, config=True): - """Local def for Redstribute static routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}} - else: - ospf_red = { - dut: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}} - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase : Failed \n Error: {}".format(result) - - -def red_connected(dut, config=True): - """Local def for Redstribute connected routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "connected", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase: Failed \n Error: {}".format(result) - - # ################################## # Test cases start here. # ################################## @@ -264,7 +233,7 @@ def test_ospf_ecmp_tc16_p0(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) dut = "r0" - red_static(dut) + redistribute_ospf(tgen, topo, dut, "static") step("Verify that route in R2 in stalled with 8 next hops.") nh = [] @@ -345,7 +314,7 @@ def test_ospf_ecmp_tc16_p0(request): step(" Un configure static route on R0") dut = "r0" - red_static(dut, config=False) + redistribute_ospf(tgen, topo, dut, "static", delete=True) # Wait for R0 to flush external LSAs. sleep(10) @@ -376,7 +345,7 @@ def test_ospf_ecmp_tc16_p0(request): step("Re configure the static route in R0.") dut = "r0" - red_static(dut) + redistribute_ospf(tgen, topo, dut, "static") dut = "r1" result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) @@ -431,7 +400,7 @@ def test_ospf_ecmp_tc17_p0(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) dut = "r0" - red_static(dut) + redistribute_ospf(tgen, topo, dut, "static") step("Verify that route in R2 in stalled with 2 next hops.") @@ -450,7 +419,7 @@ def test_ospf_ecmp_tc17_p0(request): step(" Un configure static route on R0") dut = "r0" - red_static(dut, config=False) + redistribute_ospf(tgen, topo, dut, "static", delete=True) # sleep till the route gets withdrawn sleep(10) @@ -480,7 +449,7 @@ def test_ospf_ecmp_tc17_p0(request): step("Reconfigure the static route in R0.Change ECMP value to 2.") dut = "r0" - red_static(dut) + redistribute_ospf(tgen, topo, dut, "static") step("Configure cost on R0 as 100") r0_ospf_cost = {"r0": {"links": {"r1": {"ospf": {"cost": 100}}}}} diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py index 967bc44879..2da1dcd21a 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py @@ -66,6 +66,7 @@ from lib.ospf import ( verify_ospf_rib, create_router_ospf, verify_ospf_interface, + redistribute_ospf, ) from ipaddress import IPv4Address @@ -187,42 +188,6 @@ def teardown_module(): pass -def red_static(dut, config=True): - """Local def for Redstribute static routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "static", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase : Failed \n Error: {}".format(result) - - -def red_connected(dut, config=True): - """Local def for Redstribute connected routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "connected", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase: Failed \n Error: {}".format(result) - - # ################################## # Test cases start here. # ################################## @@ -275,7 +240,7 @@ def test_ospf_lan_ecmp_tc18_p0(request): ) dut = rtr - red_static(dut) + redistribute_ospf(tgen, topo, dut, "static") step( "Verify that route in R0 in stalled with 8 hops. " diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py index 0f1115f815..dac32090bc 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py @@ -183,42 +183,6 @@ def teardown_module(): pass -def red_static(dut, config=True): - """Local def for Redstribute static routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "static", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase : Failed \n Error: {}".format(result) - - -def red_connected(dut, config=True): - """Local def for Redstribute connected routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "connected", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase: Failed \n Error: {}".format(result) - - # ################################## # Test cases start here. # ################################## diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py index 82a34d046c..3644bff3dc 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py @@ -30,6 +30,7 @@ from lib.ospf import ( verify_ospf_rib, create_router_ospf, verify_ospf_interface, + redistribute_ospf, ) from lib.topojson import build_topo_from_json, build_config_from_json from lib.topolog import logger @@ -181,38 +182,6 @@ def teardown_module(mod): logger.info("=" * 40) -def red_static(dut, config=True): - """Local def for Redstribute static routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}} - else: - ospf_red = { - dut: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}} - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase : Failed \n Error: {}".format(result) - - -def red_connected(dut, config=True): - """Local def for Redstribute connected routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "connected", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase: Failed \n Error: {}".format(result) - - # ################################## # Test cases start here. # ################################## @@ -268,7 +237,7 @@ def test_ospf_learning_tc15_p0(request): step("Redistribute static route in R2 ospf.") dut = "r2" - red_static(dut) + redistribute_ospf(tgen, topo, dut, "static") step("Verify that Type 5 LSA is originated by R2.") dut = "r0" diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py index 88667a6ac8..ceadb3975b 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py @@ -62,6 +62,7 @@ from lib.ospf import ( verify_ospf_rib, create_router_ospf, verify_ospf_database, + redistribute_ospf, ) # Global variables @@ -226,9 +227,7 @@ def test_ospf_routemaps_functionality_tc19_p0(request): result = create_static_routes(tgen, input_dict) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - ospf_red_r1 = {"r0": {"ospf": {"redistribute": [{"redist_type": "static"}]}}} - result = create_router_ospf(tgen, topo, ospf_red_r1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + redistribute_ospf(tgen, topo, "r0", "static") dut = "r1" lsid = NETWORK["ipv4"][0].split("/")[0] @@ -240,13 +239,7 @@ def test_ospf_routemaps_functionality_tc19_p0(request): result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - ospf_red_r1 = { - "r0": { - "ospf": {"redistribute": [{"redist_type": "static", "del_action": True}]} - } - } - result = create_router_ospf(tgen, topo, ospf_red_r1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + redistribute_ospf(tgen, topo, "r0", "static", delete=True) step( "Create prefix-list in R0 to permit 10.0.20.1/32 prefix &" " deny 10.0.20.2/32" @@ -293,15 +286,7 @@ def test_ospf_routemaps_functionality_tc19_p0(request): " ospf using route map rmap1" ) - ospf_red_r1 = { - "r0": { - "ospf": { - "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red_r1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4") step("Change prefix rules to permit 10.0.20.2 and deny 10.0.20.1") # Create ip prefix list @@ -495,15 +480,7 @@ def test_ospf_routemaps_functionality_tc20_p0(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Redistribute to ospf using route map ( non existent route map)") - ospf_red_r1 = { - "r0": { - "ospf": { - "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red_r1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4") step( "Verify that routes are not allowed in OSPF even tough no " @@ -633,15 +610,7 @@ def test_ospf_routemaps_functionality_tc21_p0(request): result = create_static_routes(tgen, input_dict) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - ospf_red_r0 = { - "r0": { - "ospf": { - "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red_r0) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4") # Create route map routemaps = { @@ -877,15 +846,7 @@ def test_ospf_routemaps_functionality_tc24_p0(request): result = create_static_routes(tgen, input_dict) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - ospf_red_r0 = { - "r0": { - "ospf": { - "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red_r0) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4") # Create ip prefix list pfx_list = { diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py index 434d7f8ef5..5aa2779aee 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py @@ -61,6 +61,7 @@ from lib.ospf import ( clear_ospf, verify_ospf_rib, create_router_ospf, + redistribute_ospf, ) # Global variables @@ -183,42 +184,6 @@ def teardown_module(mod): logger.info("=" * 40) -def red_static(dut, config=True): - """Local def for Redstribute static routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "static", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase : Failed \n Error: {}".format(result) - - -def red_connected(dut, config=True): - """Local def for Redstribute connected routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "connected", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase: Failed \n Error: {}".format(result) - - # ################################## # Test cases start here. # ################################## @@ -486,8 +451,8 @@ def test_ospf_redistribution_tc8_p1(request): "advertised/exchaged via ospf" ) for rtr in topo["routers"]: - red_static(rtr) - red_connected(rtr) + redistribute_ospf(tgen, topo, rtr, "static") + redistribute_ospf(tgen, topo, rtr, "connected") for node in topo["routers"]: input_dict = { "r0": { @@ -544,13 +509,7 @@ def test_ospf_redistribution_tc8_p1(request): ) for rtr in topo["routers"]: - ospf_red = { - rtr: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}} - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result - ) + redistribute_ospf(tgen, topo, rtr, "static", delete=True) input_dict = { "r0": { diff --git a/tests/topotests/pbr-topo1/test_pbr_topo1.py b/tests/topotests/pbr-topo1/test_pbr_topo1.py index fcbe3c0adf..5161d5eec7 100644 --- a/tests/topotests/pbr-topo1/test_pbr_topo1.py +++ b/tests/topotests/pbr-topo1/test_pbr_topo1.py @@ -80,7 +80,7 @@ class NetworkTopo(Topo): ## ##################################################### - +@pytest.mark.pbr def setup_module(module): "Setup topology" tgen = Topogen(NetworkTopo, module.__name__) diff --git a/tests/topotests/pim-basic/test_pim.py b/tests/topotests/pim-basic/test_pim.py index e8a9f72b48..74a7fbf16e 100644 --- a/tests/topotests/pim-basic/test_pim.py +++ b/tests/topotests/pim-basic/test_pim.py @@ -80,7 +80,7 @@ class PIMTopo(Topo): sw.add_link(tgen.gears["r1"]) sw.add_link(tgen.gears["r3"]) - +@pytest.mark.pim def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(PIMTopo, mod.__name__) diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini index 6e8e749092..d1b18a57bb 100644 --- a/tests/topotests/pytest.ini +++ b/tests/topotests/pytest.ini @@ -1,6 +1,16 @@ # Skip pytests example directory [pytest] norecursedirs = .git example-test example-topojson-test lib docker +markers = + babel: Tests that run against BABEL + bfd: Tests that run against BFDD + eigrp: Tests that run against EIGRPD + isis: Tests that run against ISISD + ldp: Tests that run against LDPD + ospf: Tests that run against OSPF( v2 and v3 ) + pbr: Tests that run against PBRD + pim: Tests that run against pim + rip: Tests that run against RIP, both v4 and v6 [topogen] # Default configuration values diff --git a/tests/topotests/rip-topo1/test_rip_topo1.py b/tests/topotests/rip-topo1/test_rip_topo1.py index fdafa50aba..edad1ff65d 100644 --- a/tests/topotests/rip-topo1/test_rip_topo1.py +++ b/tests/topotests/rip-topo1/test_rip_topo1.py @@ -104,7 +104,7 @@ class NetworkTopo(Topo): ## ##################################################### - +@pytest.mark.rip def setup_module(module): global topo, net diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.py b/tests/topotests/ripng-topo1/test_ripng_topo1.py index 4702d33dae..47b63e5b26 100644 --- a/tests/topotests/ripng-topo1/test_ripng_topo1.py +++ b/tests/topotests/ripng-topo1/test_ripng_topo1.py @@ -104,7 +104,7 @@ class NetworkTopo(Topo): ## ##################################################### - +@pytest.mark.rip def setup_module(module): global topo, net diff --git a/tools/frr-reload.py b/tools/frr-reload.py index d5fa8ab6a3..0aa5f1e516 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -221,6 +221,7 @@ ip forwarding for ligne in lines: self.dlines[ligne] = True + def get_normalized_es_id(line): """ The es-id or es-sys-mac need to be converted to lower case @@ -233,6 +234,7 @@ def get_normalized_es_id(line): break return line + def get_normalized_mac_ip_line(line): if line.startswith("evpn mh es"): return get_normalized_es_id(line) @@ -242,6 +244,7 @@ def get_normalized_mac_ip_line(line): return line + class Config(object): """ @@ -640,7 +643,7 @@ end log.debug( "LINE %-50s: popping segment routing sub-context to ctx%-50s", line, - ctx_keys + ctx_keys, ) elif line in ["exit-address-family", "exit", "exit-vnc"]: @@ -654,7 +657,7 @@ end log.debug( "LINE %-50s: popping from subcontext to ctx%-50s", line, - ctx_keys + ctx_keys, ) elif line in ["exit-vni", "exit-ldp-if"]: @@ -755,7 +758,8 @@ end self.save_contexts(ctx_keys, current_context_lines) current_context_lines = [] log.debug( - "LINE %-50s: entering segment routing sub-context, append to ctx_keys", line + "LINE %-50s: entering segment routing sub-context, append to ctx_keys", + line, ) ctx_keys.append(line) @@ -770,7 +774,8 @@ end self.save_contexts(ctx_keys, current_context_lines) current_context_lines = [] log.debug( - "LINE %-50s: entering segment routing sub-context, append to ctx_keys", line + "LINE %-50s: entering segment routing sub-context, append to ctx_keys", + line, ) ctx_keys.append(line) @@ -785,7 +790,8 @@ end self.save_contexts(ctx_keys, current_context_lines) current_context_lines = [] log.debug( - "LINE %-50s: entering segment routing sub-context, append to ctx_keys", line + "LINE %-50s: entering segment routing sub-context, append to ctx_keys", + line, ) ctx_keys.append(line) @@ -803,7 +809,8 @@ end current_context_lines = [] main_ctx_key = copy.deepcopy(ctx_keys) log.debug( - "LINE %-50s: entering candidate-path sub-context, append to ctx_keys", line + "LINE %-50s: entering candidate-path sub-context, append to ctx_keys", + line, ) ctx_keys.append(line) @@ -836,7 +843,8 @@ end current_context_lines = [] main_ctx_key = copy.deepcopy(ctx_keys) log.debug( - "LINE %-50s: entering pce-config sub-context, append to ctx_keys", line + "LINE %-50s: entering pce-config sub-context, append to ctx_keys", + line, ) ctx_keys.append(line) @@ -1230,30 +1238,44 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): lines_to_add_to_del.append((ctx[0], None)) """ - ip/ipv6 prefix-list can be specified without a seq number. However, - the running config always adds 'seq x', where x is a number incremented - by 5 for every element, to the prefix list. So, ignore such lines as - well. Sample prefix-list lines: + ip/ipv6 prefix-lists and access-lists can be specified without a seq number. + However, the running config always adds 'seq x', where x is a number + incremented by 5 for every element of the prefix/access list. + So, ignore such lines as well. Sample prefix-list and acces-list lines: ip prefix-list PR-TABLE-2 seq 5 permit 20.8.2.0/24 le 32 ip prefix-list PR-TABLE-2 seq 10 permit 20.8.2.0/24 le 32 ipv6 prefix-list vrfdev6-12 permit 2000:9:2::/64 gt 64 + access-list FOO seq 5 permit 2.2.2.2/32 + ipv6 access-list BAR seq 5 permit 2:2:2::2/128 """ - re_ip_pfxlst = re.search( - "^(ip|ipv6)(\s+prefix-list\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", + re_acl_pfxlst = re.search( + "^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", ctx_keys[0], ) - if re_ip_pfxlst: + if re_acl_pfxlst: + found = False tmpline = ( - re_ip_pfxlst.group(1) - + re_ip_pfxlst.group(2) - + re_ip_pfxlst.group(3) - + re_ip_pfxlst.group(5) - + re_ip_pfxlst.group(6) + re_acl_pfxlst.group(1) + + re_acl_pfxlst.group(2) + + re_acl_pfxlst.group(3) + + re_acl_pfxlst.group(5) + + re_acl_pfxlst.group(6) ) for ctx in lines_to_add: if ctx[0][0] == tmpline: lines_to_del_to_del.append((ctx_keys, None)) lines_to_add_to_del.append(((tmpline,), None)) + found = True + """ + If prefix-lists or access-lists are being deleted and + not added (see comment above), add command with 'no' to + lines_to_add and remove from lines_to_del to improve + scaling performance. + """ + if found is False: + add_cmd = ("no " + ctx_keys[0],) + lines_to_add.append((add_cmd, None)) + lines_to_del_to_del.append((ctx_keys, None)) if ( len(ctx_keys) == 3 @@ -1451,14 +1473,9 @@ def compare_context_objects(newconf, running): # doing vtysh -c inefficient (and can time out.) For # these commands, instead of adding them to lines_to_del, # add the "no " version to lines_to_add. - elif ( - running_ctx_keys[0].startswith("ip route") - or running_ctx_keys[0].startswith("ipv6 route") - or running_ctx_keys[0].startswith("access-list") - or running_ctx_keys[0].startswith("ipv6 access-list") - or running_ctx_keys[0].startswith("ip prefix-list") - or running_ctx_keys[0].startswith("ipv6 prefix-list") - ): + elif running_ctx_keys[0].startswith("ip route") or running_ctx_keys[ + 0 + ].startswith("ipv6 route"): add_cmd = ("no " + running_ctx_keys[0],) lines_to_add.append((add_cmd, None)) @@ -1473,14 +1490,17 @@ def compare_context_objects(newconf, running): continue # same thing for a pseudowire sub-context inside an l2vpn context - elif (len(running_ctx_keys) > 1 and running_ctx_keys[0].startswith('l2vpn') and - running_ctx_keys[1].startswith('member pseudowire') and - (running_ctx_keys[:1], None) in lines_to_del): + elif ( + len(running_ctx_keys) > 1 + and running_ctx_keys[0].startswith("l2vpn") + and running_ctx_keys[1].startswith("member pseudowire") + and (running_ctx_keys[:1], None) in lines_to_del + ): continue # Segment routing and traffic engineering never need to be deleted elif ( - running_ctx_keys[0].startswith('segment-routing') + running_ctx_keys[0].startswith("segment-routing") and len(running_ctx_keys) < 3 ): continue @@ -1488,8 +1508,8 @@ def compare_context_objects(newconf, running): # Neither the pcep command elif ( len(running_ctx_keys) == 3 - and running_ctx_keys[0].startswith('segment-routing') - and running_ctx_keys[2].startswith('pcep') + and running_ctx_keys[0].startswith("segment-routing") + and running_ctx_keys[2].startswith("pcep") ): continue @@ -1497,8 +1517,8 @@ def compare_context_objects(newconf, running): # use them, so add them to a separate array that is going to be appended at the end elif ( len(running_ctx_keys) == 3 - and running_ctx_keys[0].startswith('segment-routing') - and running_ctx_keys[2].startswith('segment-list') + and running_ctx_keys[0].startswith("segment-routing") + and running_ctx_keys[2].startswith("segment-list") ): seglist_to_del.append((running_ctx_keys, None)) @@ -1506,8 +1526,8 @@ def compare_context_objects(newconf, running): # we add them to a separate array that is going to be appended at the end elif ( len(running_ctx_keys) == 3 - and running_ctx_keys[0].startswith('segment-routing') - and running_ctx_keys[2].startswith('policy') + and running_ctx_keys[0].startswith("segment-routing") + and running_ctx_keys[2].startswith("policy") ): pollist_to_del.append((running_ctx_keys, None)) @@ -1515,16 +1535,16 @@ def compare_context_objects(newconf, running): # to a separate array that is going to be appended at the end elif ( len(running_ctx_keys) >= 4 - and running_ctx_keys[0].startswith('segment-routing') - and running_ctx_keys[3].startswith('pce-config') + and running_ctx_keys[0].startswith("segment-routing") + and running_ctx_keys[3].startswith("pce-config") ): pceconf_to_del.append((running_ctx_keys, None)) # pcc must be deleted after the pce and pce-config too elif ( len(running_ctx_keys) >= 4 - and running_ctx_keys[0].startswith('segment-routing') - and running_ctx_keys[3].startswith('pcc') + and running_ctx_keys[0].startswith("segment-routing") + and running_ctx_keys[3].startswith("pcc") ): pcclist_to_del.append((running_ctx_keys, None)) @@ -1572,9 +1592,9 @@ def compare_context_objects(newconf, running): # so add them to a separate array that is going to be appended at the end if ( len(newconf_ctx_keys) == 3 - and newconf_ctx_keys[0].startswith('segment-routing') - and newconf_ctx_keys[2].startswith('policy ') - and line.startswith('candidate-path ') + and newconf_ctx_keys[0].startswith("segment-routing") + and newconf_ctx_keys[2].startswith("policy ") + and line.startswith("candidate-path ") ): candidates_to_add.append((newconf_ctx_keys, line)) @@ -1593,8 +1613,8 @@ def compare_context_objects(newconf, running): # so add them to a separate array that is going to be appended at the end if ( len(newconf_ctx_keys) == 4 - and newconf_ctx_keys[0].startswith('segment-routing') - and newconf_ctx_keys[3].startswith('candidate-path') + and newconf_ctx_keys[0].startswith("segment-routing") + and newconf_ctx_keys[3].startswith("candidate-path") ): candidates_to_add.append((newconf_ctx_keys, None)) for line in newconf_ctx.lines: @@ -1823,8 +1843,6 @@ if __name__ == "__main__": else: running.load_from_show_running(args.daemon) - - (lines_to_add, lines_to_del) = compare_context_objects(newconf, running) lines_to_configure = [] diff --git a/yang/frr-staticd.yang b/yang/frr-staticd.yang index 281b4903c0..98ff3a83c6 100644 --- a/yang/frr-staticd.yang +++ b/yang/frr-staticd.yang @@ -63,7 +63,13 @@ module frr-staticd { grouping staticd-prefix-attributes { list path-list { - key "distance"; + key "table-id distance"; + leaf table-id { + type uint32; + description + "Table-id"; + } + leaf distance { type frr-rt:administrative-distance; description @@ -77,13 +83,6 @@ module frr-staticd { "Route tag"; } - leaf table-id { - type uint32; - default "0"; - description - "Table-id"; - } - uses frr-nexthop:frr-nexthop; } } diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 51ce59c477..bf733e38f7 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -1236,7 +1236,13 @@ static int fpm_process_queue(struct thread *t) if (ctx == NULL) break; - fpm_nl_enqueue(fnc, ctx); + /* + * Intentionally ignoring the return value + * as that we are ensuring that we can write to + * the output data in the STREAM_WRITEABLE + * check above, so we can ignore the return + */ + (void)fpm_nl_enqueue(fnc, ctx); /* Account the processed entries. */ processed_contexts++; diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index 376721f83a..6753bf520c 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -29,6 +29,7 @@ #include "prefix.h" #include "vlan.h" #include "json.h" +#include "printfrr.h" #include "zebra/zserv.h" #include "zebra/debug.h" @@ -254,6 +255,37 @@ static void zebra_evpn_mac_get_access_info(zebra_mac_t *mac, } } +#define MAC_BUF_SIZE 256 +static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac_t_ *mac, char *buf, + size_t len) +{ + if (mac->flags == 0) { + snprintfrr(buf, len, "None "); + return buf; + } + + snprintfrr( + buf, len, "%s%s%s%s%s%s%s%s%s%s%s%s", + CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) ? "LOC " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ? "REM " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) ? "AUTO " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? "STICKY " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_RMAC) ? "REM Router " + : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) ? "Default GW " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? "REM DEF GW " + : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) ? "DUP " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_FPM_SENT) ? "FPM " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE) ? "LOC Active " + : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE) + ? "LOC Inactive " + : ""); + return buf; +} + static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t) { struct zebra_vrf *zvrf = NULL; @@ -278,12 +310,17 @@ static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t) if (!mac) return 0; - if (IS_ZEBRA_DEBUG_VXLAN) + if (IS_ZEBRA_DEBUG_VXLAN) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "%s: duplicate addr mac %s flags 0x%x learn count %u host count %u auto recovery expired", + "%s: duplicate addr mac %s flags %slearn count %u host count %u auto recovery expired", __func__, prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), - mac->flags, mac->dad_count, listcount(mac->neigh_list)); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + mac->dad_count, listcount(mac->neigh_list)); + } /* Remove all IPs as duplicate associcated with this MAC */ for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) { @@ -350,14 +387,17 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, * Remote MAC event -> hold on installing it. */ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) { - if (IS_ZEBRA_DEBUG_VXLAN) + if (IS_ZEBRA_DEBUG_VXLAN) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "%s: duplicate addr MAC %s flags 0x%x skip update to client, learn count %u recover time %u", + "%s: duplicate addr MAC %s flags %sskip update to client, learn count %u recover time %u", __func__, prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), - mac->flags, mac->dad_count, - zvrf->dad_freeze_time); - + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + mac->dad_count, zvrf->dad_freeze_time); + } /* For duplicate MAC do not update * client but update neigh due to * this MAC update. @@ -385,12 +425,17 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, } if (reset_params) { - if (IS_ZEBRA_DEBUG_VXLAN) + if (IS_ZEBRA_DEBUG_VXLAN) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "%s: duplicate addr MAC %s flags 0x%x detection time passed, reset learn count %u", + "%s: duplicate addr MAC %s flags %sdetection time passed, reset learn count %u", __func__, prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), - mac->flags, mac->dad_count); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + mac->dad_count); + } mac->dad_count = 0; /* Start dup. addr detection (DAD) start time, @@ -452,13 +497,18 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, /* Start auto recovery timer for this MAC */ THREAD_OFF(mac->dad_mac_auto_recovery_timer); if (zvrf->dad_freeze && zvrf->dad_freeze_time) { - if (IS_ZEBRA_DEBUG_VXLAN) + if (IS_ZEBRA_DEBUG_VXLAN) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "%s: duplicate addr MAC %s flags 0x%x auto recovery time %u start", + "%s: duplicate addr MAC %s flags %sauto recovery time %u start", __func__, prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), - mac->flags, zvrf->dad_freeze_time); + zebra_evpn_zebra_mac_flag_dump( + mac, mac_buf, sizeof(mac_buf)), + zvrf->dad_freeze_time); + } thread_add_timer(zrouter.master, zebra_evpn_dad_mac_auto_recovery_exp, @@ -694,7 +744,7 @@ void zebra_evpn_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json) } static char *zebra_evpn_print_mac_flags(zebra_mac_t *mac, char *flags_buf, - uint32_t flags_buf_sz) + size_t flags_buf_sz) { snprintf(flags_buf, flags_buf_sz, "%s%s%s%s", mac->sync_neigh_cnt ? @@ -903,14 +953,19 @@ int zebra_evpn_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr, /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); - if (IS_ZEBRA_DEBUG_VXLAN) + if (IS_ZEBRA_DEBUG_VXLAN) { + char flag_buf[MACIP_BUF_SIZE]; + zlog_debug( - "Send MACIP %s f 0x%x MAC %s IP %s seq %u L2-VNI %u ESI %s to %s", - (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", flags, + "Send MACIP %s f %s MAC %s IP %s seq %u L2-VNI %u ESI %s to %s", + (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", + zclient_evpn_dump_macip_flags(flags, flag_buf, + sizeof(flag_buf)), prefix_mac2str(macaddr, buf, sizeof(buf)), ipaddr2str(ip, buf2, sizeof(buf2)), seq, vni, es ? es->esi_str : "-", zebra_route_string(client->proto)); + } if (cmd == ZEBRA_MACIP_ADD) client->macipadd_cnt++; @@ -982,10 +1037,12 @@ zebra_mac_t *zebra_evpn_mac_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr) mac->uptime = monotime(NULL); if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char buf[ETHER_ADDR_STRLEN]; + char mac_buf[MAC_BUF_SIZE]; - zlog_debug("%s: MAC %s flags 0x%x", __func__, + zlog_debug("%s: MAC %s flags %s", __func__, prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), - mac->flags); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } return mac; } @@ -999,10 +1056,12 @@ int zebra_evpn_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac) if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char buf[ETHER_ADDR_STRLEN]; + char mac_buf[MAC_BUF_SIZE]; - zlog_debug("%s: MAC %s flags 0x%x", __func__, + zlog_debug("%s: MAC %s flags %s", __func__, prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), - mac->flags); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } /* If the MAC is freed before the neigh we will end up @@ -1047,11 +1106,13 @@ static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx, && !listcount(mac->neigh_list)) { if (IS_ZEBRA_DEBUG_VXLAN) { char buf[ETHER_ADDR_STRLEN]; + char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "%s: Del MAC %s flags 0x%x", __func__, + "%s: Del MAC %s flags %s", __func__, prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), - mac->flags); + zebra_evpn_zebra_mac_flag_dump( + mac, mac_buf, sizeof(mac_buf))); } wctx->uninstall = 0; @@ -1204,24 +1265,34 @@ int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive, zebra_evpn_mac_get_access_info(mac, &ifp, &vid); if (!ifp) { - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no access-port", + "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no access-port", caller, zevpn->vni, &mac->macaddr, - mac->es ? mac->es->esi_str : "-", mac->flags, + mac->es ? mac->es->esi_str : "-", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), set_inactive ? "inactive " : ""); + } return -1; } zif = ifp->info; br_ifp = zif->brslave_info.br_if; if (!br_ifp) { - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no br", + "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no br", caller, zevpn->vni, &mac->macaddr, - mac->es ? mac->es->esi_str : "-", mac->flags, + mac->es ? mac->es->esi_str : "-", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), set_inactive ? "inactive " : ""); + } return -1; } @@ -1236,13 +1307,18 @@ int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive, * supported and if the local ES is oper-down. */ if (mac->es && zebra_evpn_es_local_mac_via_network_port(mac->es)) { - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "dp-%s sync-nw-mac vni %u mac %pEA es %s 0x%x %s", + "dp-%s sync-nw-mac vni %u mac %pEA es %s %s%s", set_static ? "install" : "uninstall", zevpn->vni, &mac->macaddr, - mac->es ? mac->es->esi_str : "-", mac->flags, + mac->es ? mac->es->esi_str : "-", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), set_inactive ? "inactive " : ""); + } if (set_static) /* XXX - old_static needs to be computed more * accurately @@ -1256,13 +1332,17 @@ int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive, return 0; } - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) - zlog_debug( - "dp-install sync-mac vni %u mac %pEA es %s 0x%x %s%s", - zevpn->vni, &mac->macaddr, - mac->es ? mac->es->esi_str : "-", mac->flags, - set_static ? "static " : "", - set_inactive ? "inactive " : ""); + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { + char mac_buf[MAC_BUF_SIZE]; + + zlog_debug("dp-install sync-mac vni %u mac %pEA es %s %s%s%s", + zevpn->vni, &mac->macaddr, + mac->es ? mac->es->esi_str : "-", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + set_static ? "static " : "", + set_inactive ? "inactive " : ""); + } dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky, set_static, set_inactive); @@ -1310,12 +1390,17 @@ static int zebra_evpn_mac_hold_exp_cb(struct thread *t) new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); new_static = zebra_evpn_mac_is_static(mac); - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "sync-mac vni %u mac %s es %s 0x%x hold expired", + "sync-mac vni %u mac %s es %s %shold expired", mac->zevpn->vni, prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)), - mac->es ? mac->es->esi_str : "-", mac->flags); + mac->es ? mac->es->esi_str : "-", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); + } /* re-program the local mac in the dataplane if the mac is no * longer static @@ -1340,12 +1425,17 @@ static inline void zebra_evpn_mac_start_hold_timer(zebra_mac_t *mac) if (mac->hold_timer) return; - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "sync-mac vni %u mac %s es %s 0x%x hold started", + "sync-mac vni %u mac %s es %s %shold started", mac->zevpn->vni, prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)), - mac->es ? mac->es->esi_str : "-", mac->flags); + mac->es ? mac->es->esi_str : "-", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); + } thread_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac, zmh_info->mac_hold_time, &mac->hold_timer); } @@ -1357,12 +1447,18 @@ void zebra_evpn_mac_stop_hold_timer(zebra_mac_t *mac) if (!mac->hold_timer) return; - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "sync-mac vni %u mac %s es %s 0x%x hold stopped", + "sync-mac vni %u mac %s es %s %shold stopped", mac->zevpn->vni, prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)), - mac->es ? mac->es->esi_str : "-", mac->flags); + mac->es ? mac->es->esi_str : "-", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); + } + THREAD_OFF(mac->hold_timer); } @@ -1372,13 +1468,18 @@ void zebra_evpn_sync_mac_del(zebra_mac_t *mac) bool old_static; bool new_static; - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "sync-mac del vni %u mac %s es %s seq %d f 0x%x", + "sync-mac del vni %u mac %s es %s seq %d f %s", mac->zevpn->vni, prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)), mac->es ? mac->es->esi_str : "-", mac->loc_seq, - mac->flags); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); + } + old_static = zebra_evpn_mac_is_static(mac); UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)) @@ -1418,9 +1519,12 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn, */ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) { - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC + || IS_ZEBRA_DEBUG_VXLAN) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "%s-macip accept vni %u %s-mac %s%s%s lower seq %u f 0x%x", + "%s-macip accept vni %u %s-mac %s%s%s lower seq %u f %s", sync ? "sync" : "rem", zevpn->vni, n_type, prefix_mac2str(&mac->macaddr, macbuf, @@ -1429,13 +1533,19 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn, ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) : "", - tmp_seq, mac->flags); + tmp_seq, + zebra_evpn_zebra_mac_flag_dump( + mac, mac_buf, sizeof(mac_buf))); + } + return true; } - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "%s-macip ignore vni %u %s-mac %s%s%s as existing has higher seq %u f 0x%x", + "%s-macip ignore vni %u %s-mac %s%s%s as existing has higher seq %u f %s", sync ? "sync" : "rem", zevpn->vni, n_type, prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)), @@ -1443,7 +1553,10 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn, ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) : "", - tmp_seq, mac->flags); + tmp_seq, + zebra_evpn_zebra_mac_flag_dump( + mac, mac_buf, sizeof(mac_buf))); + } return false; } @@ -1574,12 +1687,20 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr, memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); mac->flags = new_flags; - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags)) + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags)) { + char mac_buf[MAC_BUF_SIZE], omac_buf[MAC_BUF_SIZE]; + struct zebra_mac_t_ omac; + + omac.flags = old_flags; zlog_debug( - "sync-mac vni %u mac %s old_f 0x%x new_f 0x%x", + "sync-mac vni %u mac %s old_f %snew_f %s", zevpn->vni, prefix_mac2str(macaddr, macbuf, sizeof(macbuf)), - old_flags, mac->flags); + zebra_evpn_zebra_mac_flag_dump( + &omac, omac_buf, sizeof(omac_buf)), + zebra_evpn_zebra_mac_flag_dump( + mac, mac_buf, sizeof(mac_buf))); + } /* update es */ es_change = zebra_evpn_es_mac_ref(mac, esi); @@ -1613,13 +1734,18 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr, inform_bgp = true; } - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) - zlog_debug("sync-mac %s vni %u mac %s es %s seq %d f 0x%x%s%s", + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { + char mac_buf[MAC_BUF_SIZE]; + + zlog_debug("sync-mac %s vni %u mac %s es %s seq %d f %s%s%s", ctx->mac_created ? "created" : "updated", zevpn->vni, prefix_mac2str(macaddr, macbuf, sizeof(macbuf)), mac->es ? mac->es->esi_str : "-", mac->loc_seq, - mac->flags, inform_bgp ? " inform_bgp" : "", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + inform_bgp ? "inform_bgp" : "", inform_dataplane ? " inform_dp" : ""); + } if (inform_bgp) zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, @@ -1869,14 +1995,20 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { /* force drop the sync flags */ old_static = zebra_evpn_mac_is_static(mac); - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "sync-mac->remote vni %u mac %s es %s seq %d f 0x%x", + "sync-mac->remote vni %u mac %s es %s seq %d f %s", zevpn->vni, prefix_mac2str(macaddr, buf, sizeof(buf)), mac->es ? mac->es->esi_str : "-", - mac->loc_seq, mac->flags); + mac->loc_seq, + zebra_evpn_zebra_mac_flag_dump( + mac, mac_buf, sizeof(mac_buf))); + } + zebra_evpn_mac_clear_sync_info(mac); zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr, mac->flags, @@ -1970,14 +2102,18 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); inform_client = true; } else { - if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) + if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags 0x%x", + "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags %s", sticky ? "sticky " : "", prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, ifp->ifindex, vid, zevpn->vni, local_inactive ? "local-inactive " : "", - mac->flags); + zebra_evpn_zebra_mac_flag_dump( + mac, mac_buf, sizeof(mac_buf))); + } if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { struct interface *old_ifp; @@ -2125,14 +2261,19 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, */ if ((old_local_inactive != local_inactive) || (new_bgp_ready != old_bgp_ready)) { - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "local mac vni %u mac %s es %s seq %d f 0x%x%s", + "local mac vni %u mac %s es %s seq %d f %s%s", zevpn->vni, prefix_mac2str(macaddr, buf, sizeof(buf)), mac->es ? mac->es->esi_str : "", mac->loc_seq, - mac->flags, - local_inactive ? " local-inactive" : ""); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + local_inactive ? "local-inactive" : ""); + } + if (!is_dup_detect) inform_client = true; } @@ -2177,12 +2318,18 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, struct ethaddr *macaddr, if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) return 0; - if (IS_ZEBRA_DEBUG_VXLAN) + if (IS_ZEBRA_DEBUG_VXLAN) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "DEL MAC %s intf %s(%u) VID %u -> VNI %u seq %u flags 0x%x nbr count %u", + "DEL MAC %s intf %s(%u) VID %u -> VNI %u seq %u flags %snbr count %u", prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, ifp->ifindex, mac->fwd_info.local.vid, zevpn->vni, - mac->loc_seq, mac->flags, listcount(mac->neigh_list)); + mac->loc_seq, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + listcount(mac->neigh_list)); + } old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); if (zebra_evpn_mac_is_static(mac)) { @@ -2191,13 +2338,17 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, struct ethaddr *macaddr, */ memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { + char mac_buf[MAC_BUF_SIZE]; + zlog_debug( - "re-add sync-mac vni %u mac %s es %s seq %d f 0x%x", + "re-add sync-mac vni %u mac %s es %s seq %d f %s", zevpn->vni, prefix_mac2str(macaddr, buf, sizeof(buf)), mac->es ? mac->es->esi_str : "-", mac->loc_seq, - mac->flags); + zebra_evpn_zebra_mac_flag_dump( + mac, mac_buf, sizeof(mac_buf))); + } /* inform-bgp about change in local-activity if any */ if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)) { diff --git a/zebra/zebra_evpn_mac.h b/zebra/zebra_evpn_mac.h index 1730991f1e..e21b610501 100644 --- a/zebra/zebra_evpn_mac.h +++ b/zebra/zebra_evpn_mac.h @@ -56,6 +56,7 @@ struct zebra_mac_t_ { /* MAC address. */ struct ethaddr macaddr; + /* When modifying flags please fixup zebra_evpn_zebra_mac_flag_dump */ uint32_t flags; #define ZEBRA_MAC_LOCAL 0x01 #define ZEBRA_MAC_REMOTE 0x02 diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 2bf48c6277..18ccbb79fb 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -273,6 +273,11 @@ struct zfpm_glob { * If non-zero, the last time when statistics were cleared. */ time_t last_stats_clear_time; + + /* + * Flag to track the MAC dump status to FPM + */ + bool fpm_mac_dump_done; }; static struct zfpm_glob zfpm_glob_space; @@ -517,8 +522,6 @@ static int zfpm_conn_up_thread_cb(struct thread *thread) struct zfpm_rnodes_iter *iter; rib_dest_t *dest; - zfpm_g->t_conn_up = NULL; - iter = &zfpm_g->t_conn_up_state.iter; if (zfpm_g->state != ZFPM_STATE_ESTABLISHED) { @@ -528,8 +531,13 @@ static int zfpm_conn_up_thread_cb(struct thread *thread) goto done; } - /* Enqueue FPM updates for all the RMAC entries */ - hash_iterate(zrouter.l3vni_table, zfpm_iterate_rmac_table, NULL); + if (!zfpm_g->fpm_mac_dump_done) { + /* Enqueue FPM updates for all the RMAC entries */ + hash_iterate(zrouter.l3vni_table, zfpm_iterate_rmac_table, + NULL); + /* mark dump done so that its not repeated after yield */ + zfpm_g->fpm_mac_dump_done = true; + } while ((rnode = zfpm_rnodes_iter_next(iter))) { dest = rib_dest_from_rnode(rnode); @@ -547,7 +555,6 @@ static int zfpm_conn_up_thread_cb(struct thread *thread) zfpm_g->stats.t_conn_up_yields++; zfpm_rnodes_iter_pause(iter); - zfpm_g->t_conn_up = NULL; thread_add_timer_msec(zfpm_g->master, zfpm_conn_up_thread_cb, NULL, 0, &zfpm_g->t_conn_up); return 0; @@ -575,12 +582,13 @@ static void zfpm_connection_up(const char *detail) /* * Start thread to push existing routes to the FPM. */ - assert(!zfpm_g->t_conn_up); + thread_cancel(&zfpm_g->t_conn_up); zfpm_rnodes_iter_init(&zfpm_g->t_conn_up_state.iter); + zfpm_g->fpm_mac_dump_done = false; zfpm_debug("Starting conn_up thread"); - zfpm_g->t_conn_up = NULL; + thread_add_timer_msec(zfpm_g->master, zfpm_conn_up_thread_cb, NULL, 0, &zfpm_g->t_conn_up); zfpm_g->stats.t_conn_up_starts++; diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 44f574073c..f7c5da5dec 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -133,6 +133,7 @@ struct netlink_nh_info { * A structure for holding information for a netlink route message. */ struct netlink_route_info { + uint32_t nlmsg_pid; uint16_t nlmsg_type; uint8_t rtm_type; uint32_t rtm_table; @@ -244,14 +245,20 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd, rib_dest_t *dest, struct route_entry *re) { struct nexthop *nexthop; + struct rib_table_info *table_info = + rib_table_info(rib_dest_table(dest)); + struct zebra_vrf *zvrf = table_info->zvrf; memset(ri, 0, sizeof(*ri)); ri->prefix = rib_dest_prefix(dest); ri->af = rib_dest_af(dest); + if (zvrf && zvrf->zns) + ri->nlmsg_pid = zvrf->zns->netlink_dplane.snl.nl_pid; + ri->nlmsg_type = cmd; - ri->rtm_table = rib_table_info(rib_dest_table(dest))->table_id; + ri->rtm_table = table_info->table_id; ri->rtm_protocol = RTPROT_UNSPEC; /* @@ -357,6 +364,7 @@ static int netlink_route_info_encode(struct netlink_route_info *ri, req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + req->n.nlmsg_pid = ri->nlmsg_pid; req->n.nlmsg_type = ri->nlmsg_type; req->r.rtm_family = ri->af; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 40b30e0547..7c86735545 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -38,6 +38,7 @@ #include "workqueue.h" #include "nexthop_group_private.h" #include "frr_pthread.h" +#include "printfrr.h" #include "zebra/zebra_router.h" #include "zebra/connected.h" @@ -148,6 +149,30 @@ _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn, zlog(priority, "%s: (%u:%u):%s: %s", _func, vrf_id, table, buf, msgbuf); } +static char *_dump_re_status(const struct route_entry *re, char *buf, + size_t len) +{ + if (re->status == 0) { + snprintfrr(buf, len, "None "); + return buf; + } + + snprintfrr( + buf, len, "%s%s%s%s%s%s%s", + CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED) ? "Removed " : "", + CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED) ? "Changed " : "", + CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED) + ? "Label Changed " + : "", + CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED) ? "Queued " : "", + CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "Installed " + : "", + CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED) ? "Failed " : "", + CHECK_FLAG(re->status, ROUTE_ENTRY_USE_FIB_NHG) ? "Fib NHG " + : ""); + return buf; +} + #define rnode_debug(node, vrf_id, ...) \ _rnode_zlog(__func__, vrf_id, node, LOG_DEBUG, __VA_ARGS__) #define rnode_info(node, ...) \ @@ -1080,12 +1105,20 @@ static void rib_process(struct route_node *rn) } RNODE_FOREACH_RE_SAFE (rn, re, next) { - if (IS_ZEBRA_DEBUG_RIB_DETAILED) + if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + char flags_buf[128]; + char status_buf[128]; + zlog_debug( - "%s(%u:%u):%s: Examine re %p (%s) status %x flags %x dist %d metric %d", + "%s(%u:%u):%s: Examine re %p (%s) status: %sflags: %sdist %d metric %d", VRF_LOGNAME(vrf), vrf_id, re->table, buf, re, - zebra_route_string(re->type), re->status, - re->flags, re->distance, re->metric); + zebra_route_string(re->type), + _dump_re_status(re, status_buf, + sizeof(status_buf)), + zclient_dump_route_flags(re->flags, flags_buf, + sizeof(flags_buf)), + re->distance, re->metric); + } /* Currently selected re. */ if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) { @@ -2799,6 +2832,8 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, bool is_srcdst = src_p && src_p->prefixlen; char straddr[PREFIX_STRLEN]; char srcaddr[PREFIX_STRLEN]; + char flags_buf[128]; + char status_buf[128]; struct nexthop *nexthop; struct vrf *vrf = vrf_lookup_by_id(re->vrf_id); struct nexthop_group *nhg; @@ -2812,9 +2847,12 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, zlog_debug("%s: uptime == %lu, type == %u, instance == %d, table == %d", straddr, (unsigned long)re->uptime, re->type, re->instance, re->table); - zlog_debug("%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u", - straddr, re->metric, re->mtu, re->distance, re->flags, - re->status); + zlog_debug( + "%s: metric == %u, mtu == %u, distance == %u, flags == %sstatus == %s", + straddr, re->metric, re->mtu, re->distance, + zclient_dump_route_flags(re->flags, flags_buf, + sizeof(flags_buf)), + _dump_re_status(re, status_buf, sizeof(status_buf))); zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr, nexthop_group_nexthop_num(&(re->nhe->nhg)), nexthop_group_active_nexthop_num(&(re->nhe->nhg))); |
