diff options
112 files changed, 4381 insertions, 2234 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index cf0d28887e..1385345d64 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1885,7 +1885,7 @@ static const char *aspath_gettoken(const char *buf, enum as_token *token, const char *p = buf; /* Skip seperators (space for sequences, ',' for sets). */ - while (isspace((int)*p) || *p == ',') + while (isspace((unsigned char)*p) || *p == ',') p++; /* Check the end of the string and type specify characters @@ -1920,14 +1920,14 @@ static const char *aspath_gettoken(const char *buf, enum as_token *token, } /* Check actual AS value. */ - if (isdigit((int)*p)) { + if (isdigit((unsigned char)*p)) { as_t asval; *token = as_token_asval; asval = (*p - '0'); p++; - while (isdigit((int)*p)) { + while (isdigit((unsigned char)*p)) { asval *= 10; asval += (*p - '0'); p++; diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index ff2ea6f7cd..29e668d179 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -157,7 +157,7 @@ community_list_insert(struct community_list_handler *ch, const char *name, /* If name is made by all digit character. We treat it as number. */ for (number = 0, i = 0; i < strlen(name); i++) { - if (isdigit((int)name[i])) + if (isdigit((unsigned char)name[i])) number = (number * 10) + (name[i] - '0'); else break; @@ -823,6 +823,7 @@ struct community *community_list_match_delete(struct community *com, /* Delete all of the communities we flagged for deletion */ for (i = delete_index - 1; i >= 0; i--) { val = community_val_get(com, com_index_to_delete[i]); + val = htonl(val); community_del_val(com, &val); } diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index 6fc52ff9e0..22d61f702d 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -651,7 +651,7 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val) const char *p = buf; /* Skip white space. */ - while (isspace((int)*p)) + while (isspace((unsigned char)*p)) p++; /* Check the end of the line. */ @@ -659,7 +659,7 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val) return NULL; /* Well known community string check. */ - if (isalpha((int)*p)) { + if (isalpha((unsigned char)*p)) { if (strncmp(p, "internet", strlen("internet")) == 0) { *val = COMMUNITY_INTERNET; *token = community_token_no_export; @@ -770,13 +770,13 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val) } /* Community value. */ - if (isdigit((int)*p)) { + if (isdigit((unsigned char)*p)) { int separator = 0; int digit = 0; uint32_t community_low = 0; uint32_t community_high = 0; - while (isdigit((int)*p) || *p == ':') { + while (isdigit((unsigned char)*p) || *p == ':') { if (*p == ':') { if (separator) { *token = community_token_unknown; diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 7ea6ae586b..535f36ab5e 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -584,7 +584,7 @@ static unsigned int bgp_dump_parse_time(const char *str) len = strlen(str); for (i = 0; i < len; i++) { - if (isdigit((int)str[i])) { + if (isdigit((unsigned char)str[i])) { time *= 10; time += str[i] - '0'; } else if (str[i] == 'H' || str[i] == 'h') { diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 76bd0e815e..850b85aa6a 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -352,7 +352,7 @@ static const char *ecommunity_gettoken(const char *str, char buf[INET_ADDRSTRLEN + 1]; /* Skip white space. */ - while (isspace((int)*p)) { + while (isspace((unsigned char)*p)) { p++; str++; } @@ -362,38 +362,38 @@ static const char *ecommunity_gettoken(const char *str, return NULL; /* "rt" and "soo" keyword parse. */ - if (!isdigit((int)*p)) { + if (!isdigit((unsigned char)*p)) { /* "rt" match check. */ - if (tolower((int)*p) == 'r') { + if (tolower((unsigned char)*p) == 'r') { p++; - if (tolower((int)*p) == 't') { + if (tolower((unsigned char)*p) == 't') { p++; *token = ecommunity_token_rt; return p; } - if (isspace((int)*p) || *p == '\0') { + if (isspace((unsigned char)*p) || *p == '\0') { *token = ecommunity_token_rt; return p; } goto error; } /* "soo" match check. */ - else if (tolower((int)*p) == 's') { + else if (tolower((unsigned char)*p) == 's') { p++; - if (tolower((int)*p) == 'o') { + if (tolower((unsigned char)*p) == 'o') { p++; - if (tolower((int)*p) == 'o') { + if (tolower((unsigned char)*p) == 'o') { p++; *token = ecommunity_token_soo; return p; } - if (isspace((int)*p) || *p == '\0') { + if (isspace((unsigned char)*p) || *p == '\0') { *token = ecommunity_token_soo; return p; } goto error; } - if (isspace((int)*p) || *p == '\0') { + if (isspace((unsigned char)*p) || *p == '\0') { *token = ecommunity_token_soo; return p; } @@ -415,7 +415,7 @@ static const char *ecommunity_gettoken(const char *str, * OPQR: Four byte value * */ - while (isdigit((int)*p) || *p == ':' || *p == '.') { + while (isdigit((unsigned char)*p) || *p == ':' || *p == '.') { if (*p == ':') { if (separator) goto error; diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index d4f608d40f..30a964a22c 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -193,7 +193,7 @@ static struct as_list *as_list_insert(const char *name) /* If name is made by all digit character. We treat it as number. */ for (number = 0, i = 0; i < strlen(name); i++) { - if (isdigit((int)name[i])) + if (isdigit((unsigned char)name[i])) number = (number * 10) + (name[i] - '0'); else break; diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index 098374fa9f..2b09a2954e 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -359,7 +359,7 @@ static const char *lcommunity_gettoken(const char *str, const char *p = str; /* Skip white space. */ - while (isspace((int)*p)) { + while (isspace((unsigned char)*p)) { p++; str++; } @@ -369,14 +369,14 @@ static const char *lcommunity_gettoken(const char *str, return NULL; /* Community value. */ - if (isdigit((int)*p)) { + if (isdigit((unsigned char)*p)) { int separator = 0; int digit = 0; uint32_t globaladmin = 0; uint32_t localdata1 = 0; uint32_t localdata2 = 0; - while (isdigit((int)*p) || *p == ':') { + while (isdigit((unsigned char)*p) || *p == ':') { if (*p == ':') { if (separator == 2) { *token = lcommunity_token_unknown; diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index dd3382a1e7..5ffc416dc5 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2091,12 +2091,19 @@ route_set_lcommunity_delete(void *rule, const struct prefix *pfx, static void *route_set_lcommunity_delete_compile(const char *arg) { struct rmap_community *rcom; + char **splits; + int num; - rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community)); + frrstr_split(arg, " ", &splits, &num); - rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); + rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community)); + rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, splits[0]); rcom->name_hash = bgp_clist_hash_key(rcom->name); + for (int i = 0; i < num; i++) + XFREE(MTYPE_TMP, splits[i]); + XFREE(MTYPE_TMP, splits); + return rcom; } @@ -2174,12 +2181,19 @@ route_set_community_delete(void *rule, const struct prefix *prefix, static void *route_set_community_delete_compile(const char *arg) { struct rmap_community *rcom; + char **splits; + int num; - rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community)); + frrstr_split(arg, " ", &splits, &num); - rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); + rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community)); + rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, splits[0]); rcom->name_hash = bgp_clist_hash_key(rcom->name); + for (int i = 0; i < num; i++) + XFREE(MTYPE_TMP, splits[i]); + XFREE(MTYPE_TMP, splits); + return rcom; } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 27042017dd..58a202d510 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -7770,7 +7770,7 @@ static void bgp_show_bestpath_json(struct bgp *bgp, json_object *json) /* Show BGP peer's summary information. */ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, - bool use_json, json_object *json) + bool use_json) { struct peer *peer; struct listnode *node, *nnode; @@ -7781,6 +7781,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, int len; int max_neighbor_width = 0; int pfx_rcd_safi; + json_object *json = NULL; json_object *json_peer = NULL; json_object *json_peers = NULL; struct peer_af *paf; @@ -7795,9 +7796,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, pfx_rcd_safi = safi; if (use_json) { - if (json == NULL) - json = json_object_new_object(); - + json = json_object_new_object(); json_peers = json_object_new_object(); } else { /* Loop over all neighbors that will be displayed to determine @@ -8202,8 +8201,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, } static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, - int safi, bool use_json, - json_object *json) + int safi, bool use_json) { int is_first = 1; int afi_wildcard = (afi == AFI_MAX); @@ -8221,6 +8219,7 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, while (safi < SAFI_MAX) { if (bgp_afi_safi_peer_exists(bgp, afi, safi)) { nbr_output = true; + if (is_wildcard) { /* * So limit output to those afi/safi @@ -8229,8 +8228,6 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, * them */ if (use_json) { - json = json_object_new_object(); - if (!is_first) vty_out(vty, ",\n"); else @@ -8245,8 +8242,7 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, safi)); } } - bgp_show_summary(vty, bgp, afi, safi, use_json, - json); + bgp_show_summary(vty, bgp, afi, safi, use_json); } safi++; if (!safi_wildcard) @@ -8272,7 +8268,6 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, { struct listnode *node, *nnode; struct bgp *bgp; - json_object *json = NULL; int is_first = 1; bool nbr_output = false; @@ -8282,8 +8277,6 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { nbr_output = true; if (use_json) { - json = json_object_new_object(); - if (!is_first) vty_out(vty, ",\n"); else @@ -8299,7 +8292,7 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, ? VRF_DEFAULT_NAME : bgp->name); } - bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json, json); + bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json); } if (use_json) @@ -8330,8 +8323,8 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, return CMD_WARNING; } - bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json, - NULL); + bgp_show_summary_afi_safi(vty, bgp, afi, safi, + use_json); return CMD_SUCCESS; } } @@ -8339,7 +8332,7 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, bgp = bgp_get_default(); if (bgp) - bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json, NULL); + bgp_show_summary_afi_safi(vty, bgp, afi, safi, use_json); else { if (use_json) vty_out(vty, "{}\n"); diff --git a/debian/.gitignore b/debian/.gitignore new file mode 100644 index 0000000000..0b267c6f5c --- /dev/null +++ b/debian/.gitignore @@ -0,0 +1,13 @@ + +/.debhelper/ +/*/ +!/tests/ +!/source + +/*.log +/*.substvars +/*.debhelper +/autoreconf.* +/files +/frr.init +/frr.service diff --git a/doc/developer/building-frr-for-centos6.rst b/doc/developer/building-frr-for-centos6.rst index ee0ffc2bf7..3d9edbe3a1 100644 --- a/doc/developer/building-frr-for-centos6.rst +++ b/doc/developer/building-frr-for-centos6.rst @@ -45,7 +45,7 @@ Add packages: sudo yum install git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig \ - json-c-devel pam-devel flex epel-release c-ares-devel + json-c-devel pam-devel flex epel-release c-ares-devel libcap-devel Install newer version of bison (CentOS 6 package source is too old) from CentOS 7: diff --git a/doc/developer/building-frr-for-centos7.rst b/doc/developer/building-frr-for-centos7.rst index 67f71bc3a5..cd90d41ffb 100644 --- a/doc/developer/building-frr-for-centos7.rst +++ b/doc/developer/building-frr-for-centos7.rst @@ -21,7 +21,7 @@ Add packages: sudo yum install git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig \ json-c-devel pam-devel bison flex pytest c-ares-devel \ - python-devel systemd-devel python-sphinx + python-devel systemd-devel python-sphinx libcap-devel .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-debian8.rst b/doc/developer/building-frr-for-debian8.rst index 76f927853d..c12bf46f8d 100644 --- a/doc/developer/building-frr-for-debian8.rst +++ b/doc/developer/building-frr-for-debian8.rst @@ -18,7 +18,7 @@ Add packages: sudo apt-get install git autoconf automake libtool make \ libreadline-dev texinfo libjson-c-dev pkg-config bison flex python3-pip \ libc-ares-dev python3-dev python3-sphinx build-essential libsystemd-dev \ - libsnmp-dev + libsnmp-dev libcap-dev Install newer pytest (>3.0) from pip diff --git a/doc/developer/building-frr-for-debian9.rst b/doc/developer/building-frr-for-debian9.rst index e58c59f451..f976b9f49a 100644 --- a/doc/developer/building-frr-for-debian9.rst +++ b/doc/developer/building-frr-for-debian9.rst @@ -11,7 +11,7 @@ Add packages: sudo apt-get install git autoconf automake libtool make \ libreadline-dev texinfo libjson-c-dev pkg-config bison flex \ libc-ares-dev python3-dev python3-pytest python3-sphinx build-essential \ - libsnmp-dev libsystemd-dev + libsnmp-dev libsystemd-dev libcap-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-fedora.rst b/doc/developer/building-frr-for-fedora.rst index 0bfd43e93c..d8405eb351 100644 --- a/doc/developer/building-frr-for-fedora.rst +++ b/doc/developer/building-frr-for-fedora.rst @@ -14,7 +14,7 @@ Installing Dependencies sudo dnf install git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig json-c-devel \ pam-devel python3-pytest bison flex c-ares-devel python3-devel \ - python3-sphinx perl-core patch systemd-devel + python3-sphinx perl-core patch systemd-devel libcap-devel .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu1404.rst b/doc/developer/building-frr-for-ubuntu1404.rst index 569b3bded1..cc54415266 100644 --- a/doc/developer/building-frr-for-ubuntu1404.rst +++ b/doc/developer/building-frr-for-ubuntu1404.rst @@ -14,7 +14,7 @@ Installing Dependencies git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ libc-ares-dev python3-dev python3-sphinx install-info build-essential \ - libsnmp-dev perl + libsnmp-dev perl libcap-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu1604.rst b/doc/developer/building-frr-for-ubuntu1604.rst index 03852a62aa..63c6f8648c 100644 --- a/doc/developer/building-frr-for-ubuntu1604.rst +++ b/doc/developer/building-frr-for-ubuntu1604.rst @@ -14,7 +14,7 @@ Installing Dependencies git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ - install-info build-essential libsystemd-dev libsnmp-dev perl + install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst index 96c0efe02a..9d85957d88 100644 --- a/doc/developer/building-frr-for-ubuntu1804.rst +++ b/doc/developer/building-frr-for-ubuntu1804.rst @@ -14,7 +14,7 @@ Installing Dependencies git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ - install-info build-essential libsystemd-dev libsnmp-dev perl + install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev .. include:: building-libyang.rst diff --git a/doc/developer/lists.rst b/doc/developer/lists.rst index fc47a67e42..5f020060ce 100644 --- a/doc/developer/lists.rst +++ b/doc/developer/lists.rst @@ -611,6 +611,38 @@ Head removal (pop) and deallocation: * note nothing between wrlock() and unlock() */ XFREE(MTYPE_ITEM, i); +FAQ +--- + +Why is the list head not ``const`` in the list APIs? + The semantics that a ``const`` list head would imply are not obvious. It + could mean any of the following: + + * the list just shouldn't be allocated/deallocated, but may be modified. + This doesn't actually work since the list head needs to be modified for + inserting or deleting items. + + * the list shouldn't be modified, but items can. This may make sense for + iterating, but it's not exactly consistent - an item might be on more + than one list, does it apply to all of them? If not, which one? + + * neither the list nor the items should be modified. This is consistent, + but hard to do without creating a ``const`` copy of every single list + function. Ease of use trumps this. + +Why is there no "is this item on a/the list" test? + It's slow for several of the data structures, and the work of adding it + just hasn't been done. It can certainly be added if it's needed. + +Why is it ``PREDECL`` + ``DECLARE`` instead of ``DECLARE`` + ``DEFINE``? + The rule is that a ``DEFINE`` must be in a ``.c`` file, and linked exactly + once because it defines some kind of global symbol. This is not the case + for the data structure macros; they only define ``static`` symbols and it + is perfectly fine to include both ``PREDECL`` and ``DECLARE`` in a header + file. It is also perfectly fine to have the same ``DECLARE`` statement in + 2 ``.c`` files, but only **if the macro arguments are identical.** Maybe + don't do that unless you really need it. + FRR lists --------- diff --git a/doc/figures/nodes.dot b/doc/figures/nodes.dot index d0e234958f..b548b5529a 100644 --- a/doc/figures/nodes.dot +++ b/doc/figures/nodes.dot @@ -55,7 +55,6 @@ digraph climodes { CONFIG_NODE -> KEYCHAIN_KEY_NODE [ label="key (0-2147483647)" ]; KEYCHAIN_NODE -> KEYCHAIN_KEY_NODE [ label="key (0-2147483647)" ]; KEYCHAIN_KEY_NODE -> KEYCHAIN_NODE [ label="no key (0-2147483647)" ]; - CONFIG_NODE -> LOGICALROUTER_NODE [ label="logical-router (1-65535) ns NAME" ]; CONFIG_NODE -> VRF_NODE [ label="vrf NAME" ]; CONFIG_NODE -> INTERFACE_NODE [ label="interface IFNAME vrf NAME" ]; INTERFACE_NODE -> LINK_PARAMS_NODE [ label="link-params" ]; diff --git a/doc/user/installation.rst b/doc/user/installation.rst index b45c83ca1c..45549dccad 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -149,6 +149,11 @@ options from the list below. Turn off building of pimd. On some BSD platforms pimd will not build properly due to lack of kernel support. +.. option:: --disable-vrrpd + + Turn off building of vrrpd. Linux is required for vrrpd support; + other platforms are not supported. + .. option:: --disable-pbrd Turn off building of pbrd. This daemon currently requires linux in order to function @@ -194,11 +199,6 @@ options from the list below. Disable building of the example OSPF-API client. -.. option:: --disable-ospf-ri - - Disable support for OSPF Router Information (RFC4970 & RFC5088) this - requires support for Opaque LSAs and Traffic Engineering. - .. option:: --disable-isisd Do not build isisd. @@ -211,10 +211,6 @@ options from the list below. Enable IS-IS topology generator. -.. option:: --enable-isis-te - - Enable Traffic Engineering Extension for ISIS (RFC5305) - .. option:: --enable-realms Enable the support of Linux Realms. Convert tag values from 1-255 into a diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index f7607a54f7..6684a83e1f 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -423,6 +423,12 @@ Showing ISIS information Traffic Engineering =================== +.. note:: + + At this time, FRR offers partial support for some of the routing + protocol extensions that can be used with MPLS-TE. FRR does not + support a complete RSVP-TE solution currently. + .. index:: mpls-te on .. clicmd:: mpls-te on diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 6413c62995..2300cb0e19 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -195,7 +195,7 @@ Example of ospf6d configured on one interface and area: ipv6 ospf6 instance-id 0 ! router ospf6 - router-id 212.17.55.53 + ospf6 router-id 212.17.55.53 area 0.0.0.0 range 2001:770:105:2::/64 interface eth0 area 0.0.0.0 ! diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 83e14d474f..3772cf9556 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -69,7 +69,7 @@ The instance number should be specified in the config when addressing a particul .. code-block:: frr router ospf 5 - router-id 1.2.3.4 + ospf router-id 1.2.3.4 area 0.0.0.0 authentication message-digest ... @@ -906,10 +906,13 @@ Opaque LSA .. index:: no capability opaque .. clicmd:: no capability opaque - *ospfd* supports Opaque LSA (:rfc:`2370`) as fundamental for MPLS Traffic - Engineering LSA. Prior to used MPLS TE, opaque-lsa must be enable in the - configuration file. Alternate command could be "mpls-te on" - (:ref:`ospf-traffic-engineering`). + *ospfd* supports Opaque LSA (:rfc:`2370`) as partial support for + MPLS Traffic Engineering LSAs. The opaque-lsa capability must be + enabled in the configuration. An alternate command could be + "mpls-te on" (:ref:`ospf-traffic-engineering`). Note that FRR + offers only partial support for some of the routing protocol + extensions that are used with MPLS-TE; it does not support a + complete RSVP-TE solution. .. index:: show ip ospf database (opaque-link|opaque-area|opaque-external) .. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) @@ -936,6 +939,12 @@ Opaque LSA Traffic Engineering =================== +.. note:: + + At this time, FRR offers partial support for some of the routing + protocol extensions that can be used with MPLS-TE. FRR does not + support a complete RSVP-TE solution currently. + .. index:: mpls-te on .. clicmd:: mpls-te on diff --git a/doc/user/overview.rst b/doc/user/overview.rst index 7f8ea392dc..5f9a7b937e 100644 --- a/doc/user/overview.rst +++ b/doc/user/overview.rst @@ -239,6 +239,15 @@ The indicators have the following semantics: * :mark:`CP` - control plane only (i.e. BGP route server / route reflector) * :mark:`N` - daemon/feature not supported by operating system + +Known Kernel Issues: +==================== + +- Linux + v6 Route Replacement - Linux kernels before 4.11 can cause issues with v6 route deletion when you + have ecmp routes installed into the kernel. This especially becomes apparent if the route is being + transformed from one ecmp path to another. + .. _supported-rfcs: Supported RFCs diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index bac61cbc58..09cbd7c7b0 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -153,8 +153,8 @@ Route Map Match Command Matches the specified `ipv4_addr`. -.. index:: match aspath AS_PATH -.. clicmd:: match aspath AS_PATH +.. index:: match as-path AS_PATH +.. clicmd:: match as-path AS_PATH Matches the specified `as_path`. diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index 4568c2a901..111e9dc9e8 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -71,7 +71,7 @@ keyword. At present, no sharp commands will be preserved in the config. be used for pop and forward operations when the specified label is seen. .. index:: sharp watch -.. clicmd:: [no] sharp watch <nexthop|import> <A.B.C.D|X:X::X:X> [connected] +.. clicmd:: [no] sharp watch <nexthop <A.B.C.D|X:X::X:X>|import <A.B.C.D/M:X:X::X:X/M> [connected] Instruct zebra to monitor and notify sharp when the specified nexthop is changed. The notification from zebra is written into the debug log. diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 2744cb66ed..50c518d456 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -193,18 +193,25 @@ Standard Commands Link Parameters Commands ------------------------ +.. note:: + + At this time, FRR offers partial support for some of the routing + protocol extensions that can be used with MPLS-TE. FRR does not + support a complete RSVP-TE solution currently. + .. index:: link-params .. clicmd:: link-params .. index:: no link-param .. clicmd:: no link-param - Enter into the link parameters sub node. At least 'enable' must be set to - activate the link parameters, and consequently Traffic Engineering on this - interface. MPLS-TE must be enable at the OSPF - (:ref:`ospf-traffic-engineering`) or ISIS (:ref:`isis-traffic-engineering`) - router level in complement to this. Disable link parameters for this - interface. + Enter into the link parameters sub node. At least 'enable' must be + set to activate the link parameters, and consequently routing + information that could be used as part of Traffic Engineering on + this interface. MPLS-TE must be enable at the OSPF + (:ref:`ospf-traffic-engineering`) or ISIS + (:ref:`isis-traffic-engineering`) router level in complement to + this. Disable link parameters for this interface. Under link parameter statement, the following commands set the different TE values: diff --git a/eigrpd/eigrp_cli.c b/eigrpd/eigrp_cli.c new file mode 100644 index 0000000000..ba657a7d5d --- /dev/null +++ b/eigrpd/eigrp_cli.c @@ -0,0 +1,920 @@ +/* + * EIGRP daemon CLI implementation. + * + * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF") + * Rafael Zalamena + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ + +#include <zebra.h> + +#include "lib/command.h" +#include "lib/log.h" +#include "lib/northbound_cli.h" + +#include "eigrp_structs.h" +#include "eigrpd.h" +#include "eigrp_zebra.h" + +#ifndef VTYSH_EXTRACT_PL +#include "eigrpd/eigrp_cli_clippy.c" +#endif /* VTYSH_EXTRACT_PL */ + +/* + * XPath: /frr-eigrpd:eigrpd/instance + */ +DEFPY_NOSH( + router_eigrp, + router_eigrp_cmd, + "router eigrp (1-65535)$as", + ROUTER_STR + EIGRP_STR + AS_STR) +{ + char xpath[XPATH_MAXLEN]; + int rv; + + snprintf(xpath, sizeof(xpath), + "/frr-eigrpd:eigrpd/instance[asn='%s'][vrf='']", + as_str); + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + rv = nb_cli_apply_changes(vty, NULL); + if (rv == CMD_SUCCESS) + VTY_PUSH_XPATH(EIGRP_NODE, xpath); + + return rv; +} + +DEFPY_NOSH( + no_router_eigrp, + no_router_eigrp_cmd, + "no router eigrp (1-65535)$as", + NO_STR + ROUTER_STR + EIGRP_STR + AS_STR) +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), + "/frr-eigrpd:eigrpd/instance[asn='%s'][vrf='']", + as_str); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *asn = yang_dnode_get_string(dnode, "./asn"); + + vty_out(vty, "router eigrp %s\n", asn); +} + +void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode) +{ + vty_out(vty, "!\n"); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/router-id + */ +DEFPY( + eigrp_router_id, + eigrp_router_id_cmd, + "eigrp router-id A.B.C.D$addr", + EIGRP_STR + "Router ID for this EIGRP process\n" + "EIGRP Router-ID in IP address format\n") +{ + nb_cli_enqueue_change(vty, "./router-id", NB_OP_MODIFY, addr_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_router_id, + no_eigrp_router_id_cmd, + "no eigrp router-id [A.B.C.D]", + NO_STR + EIGRP_STR + "Router ID for this EIGRP process\n" + "EIGRP Router-ID in IP address format\n") +{ + nb_cli_enqueue_change(vty, "./router-id", NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *router_id = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " eigrp router-id %s\n", router_id); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/passive-interface + */ +DEFPY( + eigrp_passive_interface, + eigrp_passive_interface_cmd, + "[no] passive-interface IFNAME", + NO_STR + "Suppress routing updates on an interface\n" + "Interface to suppress on\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./passive-interface", + NB_OP_DESTROY, ifname); + else + nb_cli_enqueue_change(vty, "./passive-interface", + NB_OP_CREATE, ifname); + + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_passive_interface(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *ifname = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " passive-interface %s\n", ifname); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/active-time + */ +DEFPY( + eigrp_timers_active, + eigrp_timers_active_cmd, + "timers active-time <(1-65535)$timer|disabled$disabled>", + "Adjust routing timers\n" + "Time limit for active state\n" + "Active state time limit in seconds\n" + "Disable time limit for active state\n") +{ + if (disabled) + nb_cli_enqueue_change(vty, "./active-time", NB_OP_MODIFY, "0"); + else + nb_cli_enqueue_change(vty, "./active-time", + NB_OP_MODIFY, timer_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_timers_active, + no_eigrp_timers_active_cmd, + "no timers active-time [<(1-65535)|disabled>]", + NO_STR + "Adjust routing timers\n" + "Time limit for active state\n" + "Active state time limit in seconds\n" + "Disable time limit for active state\n") +{ + nb_cli_enqueue_change(vty, "./active-time", NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *timer = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " timers active-time %s\n", timer); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/variance + */ +DEFPY( + eigrp_variance, + eigrp_variance_cmd, + "variance (1-128)$variance", + "Control load balancing variance\n" + "Metric variance multiplier\n") +{ + nb_cli_enqueue_change(vty, "./variance", NB_OP_MODIFY, variance_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_variance, + no_eigrp_variance_cmd, + "no variance [(1-128)]", + NO_STR + "Control load balancing variance\n" + "Metric variance multiplier\n") +{ + nb_cli_enqueue_change(vty, "./variance", NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *variance = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " variance %s\n", variance); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/maximum-paths + */ +DEFPY( + eigrp_maximum_paths, + eigrp_maximum_paths_cmd, + "maximum-paths (1-32)$maximum_paths", + "Forward packets over multiple paths\n" + "Number of paths\n") +{ + nb_cli_enqueue_change(vty, "./maximum-paths", NB_OP_MODIFY, + maximum_paths_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_maximum_paths, + no_eigrp_maximum_paths_cmd, + "no maximum-paths [(1-32)]", + NO_STR + "Forward packets over multiple paths\n" + "Number of paths\n") +{ + nb_cli_enqueue_change(vty, "./maximum-paths", NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_maximum_paths(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *maximum_paths = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " maximum-paths %s\n", maximum_paths); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K1 + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K2 + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K3 + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K4 + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K5 + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K6 + */ +DEFPY( + eigrp_metric_weights, + eigrp_metric_weights_cmd, + "metric weights (0-255)$k1 (0-255)$k2 (0-255)$k3 (0-255)$k4 (0-255)$k5 [(0-255)$k6]", + "Modify metrics and parameters for advertisement\n" + "Modify metric coefficients\n" + "K1\n" + "K2\n" + "K3\n" + "K4\n" + "K5\n" + "K6\n") +{ + nb_cli_enqueue_change(vty, "./metric-weights/K1", NB_OP_MODIFY, k1_str); + nb_cli_enqueue_change(vty, "./metric-weights/K2", NB_OP_MODIFY, k2_str); + nb_cli_enqueue_change(vty, "./metric-weights/K3", NB_OP_MODIFY, k3_str); + nb_cli_enqueue_change(vty, "./metric-weights/K4", NB_OP_MODIFY, k4_str); + nb_cli_enqueue_change(vty, "./metric-weights/K5", NB_OP_MODIFY, k5_str); + if (k6) + nb_cli_enqueue_change(vty, "./metric-weights/K6", + NB_OP_MODIFY, k6_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_metric_weights, + no_eigrp_metric_weights_cmd, + "no metric weights [(0-255) (0-255) (0-255) (0-255) (0-255) (0-255)]", + NO_STR + "Modify metrics and parameters for advertisement\n" + "Modify metric coefficients\n" + "K1\n" + "K2\n" + "K3\n" + "K4\n" + "K5\n" + "K6\n") +{ + nb_cli_enqueue_change(vty, "./metric-weights/K1", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./metric-weights/K2", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./metric-weights/K3", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./metric-weights/K4", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./metric-weights/K5", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./metric-weights/K6", NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *k1, *k2, *k3, *k4, *k5, *k6; + + k1 = yang_dnode_exists(dnode, "./K1") ? + yang_dnode_get_string(dnode, "./K1") : "0"; + k2 = yang_dnode_exists(dnode, "./K2") ? + yang_dnode_get_string(dnode, "./K2") : "0"; + k3 = yang_dnode_exists(dnode, "./K3") ? + yang_dnode_get_string(dnode, "./K3") : "0"; + k4 = yang_dnode_exists(dnode, "./K4") ? + yang_dnode_get_string(dnode, "./K4") : "0"; + k5 = yang_dnode_exists(dnode, "./K5") ? + yang_dnode_get_string(dnode, "./K5") : "0"; + k6 = yang_dnode_exists(dnode, "./K6") ? + yang_dnode_get_string(dnode, "./K6") : "0"; + + vty_out(vty, " metric weights %s %s %s %s %s", + k1, k2, k3, k4, k5); + if (k6) + vty_out(vty, " %s", k6); + vty_out(vty, "\n"); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/network + */ +DEFPY( + eigrp_network, + eigrp_network_cmd, + "[no] network A.B.C.D/M$prefix", + NO_STR + "Enable routing on an IP network\n" + "EIGRP network prefix\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./network", NB_OP_DESTROY, + prefix_str); + else + nb_cli_enqueue_change(vty, "./network", NB_OP_CREATE, + prefix_str); + + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *prefix = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " network %s\n", prefix); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/neighbor + */ +DEFPY( + eigrp_neighbor, + eigrp_neighbor_cmd, + "[no] neighbor A.B.C.D$addr", + NO_STR + "Specify a neighbor router\n" + "Neighbor address\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./neighbor", NB_OP_DESTROY, + addr_str); + else + nb_cli_enqueue_change(vty, "./neighbor", NB_OP_CREATE, + addr_str); + + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *prefix = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " neighbor %s\n", prefix); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/route-map + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/bandwidth + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/delay + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/reliability + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/load + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/mtu + */ +DEFPY( + eigrp_redistribute_source_metric, + eigrp_redistribute_source_metric_cmd, + "[no] redistribute " FRR_REDIST_STR_EIGRPD + "$proto [metric (1-4294967295)$bw (0-4294967295)$delay (0-255)$rlbt (1-255)$load (1-65535)$mtu]", + NO_STR + REDIST_STR + FRR_REDIST_HELP_STR_EIGRPD + "Metric for redistributed routes\n" + "Bandwidth metric in Kbits per second\n" + "EIGRP delay metric, in 10 microsecond units\n" + "EIGRP reliability metric where 255 is 100% reliable2 ?\n" + "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n" + "EIGRP MTU of the path\n") +{ + char xpath[XPATH_MAXLEN], xpath_metric[XPATH_MAXLEN + 64]; + + snprintf(xpath, sizeof(xpath), "./redistribute[protocol='%s']", proto); + + if (no) { + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); + } + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (bw == 0 || delay == 0 || rlbt == 0 || load == 0 || mtu == 0) + return nb_cli_apply_changes(vty, NULL); + + snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/bandwidth", + xpath); + nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, bw_str); + snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/delay", xpath); + nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, delay_str); + snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/reliability", + xpath); + nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, rlbt_str); + snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/load", xpath); + nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, load_str); + snprintf(xpath_metric, sizeof(xpath_metric), "%s/metrics/mtu", xpath); + nb_cli_enqueue_change(vty, xpath_metric, NB_OP_MODIFY, mtu_str); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_redistribute(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *proto = yang_dnode_get_string(dnode, "./protocol"); + const char *bw, *delay, *load, *mtu, *rlbt; + + bw = yang_dnode_exists(dnode, "./metrics/bandwidth") ? + yang_dnode_get_string(dnode, "./metrics/bandwidth") : NULL; + delay = yang_dnode_exists(dnode, "./metrics/delay") ? + yang_dnode_get_string(dnode, "./metrics/delay") : NULL; + rlbt = yang_dnode_exists(dnode, "./metrics/reliability") ? + yang_dnode_get_string(dnode, "./metrics/reliability") : NULL; + load = yang_dnode_exists(dnode, "./metrics/load") ? + yang_dnode_get_string(dnode, "./metrics/load") : NULL; + mtu = yang_dnode_exists(dnode, "./metrics/mtu") ? + yang_dnode_get_string(dnode, "./metrics/mtu") : NULL; + + vty_out(vty, " redistribute %s", proto); + if (bw || rlbt || delay || load || mtu) + vty_out(vty, " metric %s %s %s %s %s", bw, delay, rlbt, load, + mtu); + vty_out(vty, "\n"); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/delay + */ +DEFPY( + eigrp_if_delay, + eigrp_if_delay_cmd, + "delay (1-16777215)$delay", + "Specify interface throughput delay\n" + "Throughput delay (tens of microseconds)\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/delay", + NB_OP_MODIFY, delay_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_if_delay, + no_eigrp_if_delay_cmd, + "no delay [(1-16777215)]", + NO_STR + "Specify interface throughput delay\n" + "Throughput delay (tens of microseconds)\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/delay", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *delay = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " delay %s\n", delay); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/bandwidth + */ +DEFPY( + eigrp_if_bandwidth, + eigrp_if_bandwidth_cmd, + "eigrp bandwidth (1-10000000)$bw", + EIGRP_STR + "Set bandwidth informational parameter\n" + "Bandwidth in kilobits\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/bandwidth", + NB_OP_MODIFY, bw_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_if_bandwidth, + no_eigrp_if_bandwidth_cmd, + "no eigrp bandwidth [(1-10000000)]", + NO_STR + EIGRP_STR + "Set bandwidth informational parameter\n" + "Bandwidth in kilobits\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/bandwidth", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *bandwidth = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " eigrp bandwidth %s\n", bandwidth); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/hello-interval + */ +DEFPY( + eigrp_if_ip_hellointerval, + eigrp_if_ip_hellointerval_cmd, + "ip hello-interval eigrp (1-65535)$hello", + "Interface Internet Protocol config commands\n" + "Configures EIGRP hello interval\n" + EIGRP_STR + "Seconds between hello transmissions\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/hello-interval", + NB_OP_MODIFY, hello_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_if_ip_hellointerval, + no_eigrp_if_ip_hellointerval_cmd, + "no ip hello-interval eigrp [(1-65535)]", + NO_STR + "Interface Internet Protocol config commands\n" + "Configures EIGRP hello interval\n" + EIGRP_STR + "Seconds between hello transmissions\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/hello-interval", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + + +void eigrp_cli_show_hello_interval(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *hello = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " ip hello-interval eigrp %s\n", hello); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/hold-time + */ +DEFPY( + eigrp_if_ip_holdinterval, + eigrp_if_ip_holdinterval_cmd, + "ip hold-time eigrp (1-65535)$hold", + "Interface Internet Protocol config commands\n" + "Configures EIGRP IPv4 hold time\n" + EIGRP_STR + "Seconds before neighbor is considered down\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/hold-time", + NB_OP_MODIFY, hold_str); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_if_ip_holdinterval, + no_eigrp_if_ip_holdinterval_cmd, + "no ip hold-time eigrp [(1-65535)]", + NO_STR + "Interface Internet Protocol config commands\n" + "Configures EIGRP IPv4 hold time\n" + EIGRP_STR + "Seconds before neighbor is considered down\n") +{ + nb_cli_enqueue_change(vty, "./frr-eigrpd:eigrp/hold-time", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *holdtime = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " ip hold-time eigrp %s\n", holdtime); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/split-horizon + */ +/* NOT implemented. */ + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/summarize-addresses + */ +DEFPY( + eigrp_ip_summary_address, + eigrp_ip_summary_address_cmd, + "ip summary-address eigrp (1-65535)$as A.B.C.D/M$prefix", + "Interface Internet Protocol config commands\n" + "Perform address summarization\n" + EIGRP_STR + AS_STR + "Summary <network>/<length>, e.g. 192.168.0.0/16\n") +{ + char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64]; + + snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']", + as_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-address", xpath); + nb_cli_enqueue_change(vty, xpath_auth, NB_OP_CREATE, prefix_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_ip_summary_address, + no_eigrp_ip_summary_address_cmd, + "no ip summary-address eigrp (1-65535)$as A.B.C.D/M$prefix", + NO_STR + "Interface Internet Protocol config commands\n" + "Perform address summarization\n" + EIGRP_STR + AS_STR + "Summary <network>/<length>, e.g. 192.168.0.0/16\n") +{ + char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64]; + + snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']", + as_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-address", xpath); + nb_cli_enqueue_change(vty, xpath_auth, NB_OP_DESTROY, prefix_str); + + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_summarize_address(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL, + true); + const char *summarize_address = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " ip summary-address eigrp %d %s\n", + eif->eigrp->AS, summarize_address); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/authentication + */ +DEFPY( + eigrp_authentication_mode, + eigrp_authentication_mode_cmd, + "ip authentication mode eigrp (1-65535)$as <md5|hmac-sha-256>$crypt", + "Interface Internet Protocol config commands\n" + "Authentication subcommands\n" + "Mode\n" + EIGRP_STR + AS_STR + "Keyed message digest\n" + "HMAC SHA256 algorithm \n") +{ + char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64]; + + snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']", + as_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_auth, sizeof(xpath_auth), "%s/authentication", xpath); + nb_cli_enqueue_change(vty, xpath_auth, NB_OP_MODIFY, crypt); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_authentication_mode, + no_eigrp_authentication_mode_cmd, + "no ip authentication mode eigrp (1-65535)$as [<md5|hmac-sha-256>]", + NO_STR + "Interface Internet Protocol config commands\n" + "Authentication subcommands\n" + "Mode\n" + EIGRP_STR + AS_STR + "Keyed message digest\n" + "HMAC SHA256 algorithm \n") +{ + char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64]; + + snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']", + as_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_auth, sizeof(xpath_auth), "%s/authentication", xpath); + nb_cli_enqueue_change(vty, xpath_auth, NB_OP_MODIFY, "none"); + + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_authentication(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL, + true); + const char *crypt = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " ip authentication mode eigrp %d %s\n", + eif->eigrp->AS, crypt); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/keychain + */ +DEFPY( + eigrp_authentication_keychain, + eigrp_authentication_keychain_cmd, + "ip authentication key-chain eigrp (1-65535)$as WORD$name", + "Interface Internet Protocol config commands\n" + "Authentication subcommands\n" + "Key-chain\n" + EIGRP_STR + AS_STR + "Name of key-chain\n") +{ + char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64]; + + snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']", + as_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_auth, sizeof(xpath_auth), "%s/keychain", xpath); + nb_cli_enqueue_change(vty, xpath_auth, NB_OP_MODIFY, name); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY( + no_eigrp_authentication_keychain, + no_eigrp_authentication_keychain_cmd, + "no ip authentication key-chain eigrp (1-65535)$as [WORD]", + NO_STR + "Interface Internet Protocol config commands\n" + "Authentication subcommands\n" + "Key-chain\n" + EIGRP_STR + AS_STR + "Name of key-chain\n") +{ + char xpath[XPATH_MAXLEN], xpath_auth[XPATH_MAXLEN + 64]; + + snprintf(xpath, sizeof(xpath), "./frr-eigrpd:eigrp/instance[asn='%s']", + as_str); + snprintf(xpath_auth, sizeof(xpath_auth), "%s/keychain", xpath); + nb_cli_enqueue_change(vty, xpath_auth, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL, + true); + const char *keychain = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " ip authentication key-chain eigrp %d %s\n", + eif->eigrp->AS, keychain); +} + + +/* + * CLI installation procedures. + */ +static struct cmd_node eigrp_node = {EIGRP_NODE, "%s(config-router)# ", 1}; + +static int eigrp_config_write(struct vty *vty) +{ + struct lyd_node *dnode; + int written = 0; + + dnode = yang_dnode_get(running_config->dnode, "/frr-eigrpd:eigrpd"); + if (dnode) { + nb_cli_show_dnode_cmds(vty, dnode, false); + written = 1; + } + + return written; +} + +static struct cmd_node eigrp_interface_node = {INTERFACE_NODE, + "%s(config-if)# ", 1}; + + +static int eigrp_write_interface(struct vty *vty) +{ + struct lyd_node *dnode; + struct interface *ifp; + struct vrf *vrf; + int written = 0; + + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { + FOR_ALL_INTERFACES(vrf, ifp) { + dnode = yang_dnode_get( + running_config->dnode, + "/frr-interface:lib/interface[name='%s'][vrf='%s']", + ifp->name, vrf->name); + if (dnode == NULL) + continue; + + written = 1; + nb_cli_show_dnode_cmds(vty, dnode, false); + } + } + + return written; +} + +void +eigrp_cli_init(void) +{ + install_element(CONFIG_NODE, &router_eigrp_cmd); + install_element(CONFIG_NODE, &no_router_eigrp_cmd); + + install_node(&eigrp_node, eigrp_config_write); + install_default(EIGRP_NODE); + + install_element(EIGRP_NODE, &eigrp_router_id_cmd); + install_element(EIGRP_NODE, &no_eigrp_router_id_cmd); + install_element(EIGRP_NODE, &eigrp_passive_interface_cmd); + install_element(EIGRP_NODE, &eigrp_timers_active_cmd); + install_element(EIGRP_NODE, &no_eigrp_timers_active_cmd); + install_element(EIGRP_NODE, &eigrp_variance_cmd); + install_element(EIGRP_NODE, &no_eigrp_variance_cmd); + install_element(EIGRP_NODE, &eigrp_maximum_paths_cmd); + install_element(EIGRP_NODE, &no_eigrp_maximum_paths_cmd); + install_element(EIGRP_NODE, &eigrp_metric_weights_cmd); + install_element(EIGRP_NODE, &no_eigrp_metric_weights_cmd); + install_element(EIGRP_NODE, &eigrp_network_cmd); + install_element(EIGRP_NODE, &eigrp_neighbor_cmd); + install_element(EIGRP_NODE, &eigrp_redistribute_source_metric_cmd); + + install_node(&eigrp_interface_node, eigrp_write_interface); + if_cmd_init(); + + install_element(INTERFACE_NODE, &eigrp_if_delay_cmd); + install_element(INTERFACE_NODE, &no_eigrp_if_delay_cmd); + install_element(INTERFACE_NODE, &eigrp_if_bandwidth_cmd); + install_element(INTERFACE_NODE, &no_eigrp_if_bandwidth_cmd); + install_element(INTERFACE_NODE, &eigrp_if_ip_hellointerval_cmd); + install_element(INTERFACE_NODE, &no_eigrp_if_ip_hellointerval_cmd); + install_element(INTERFACE_NODE, &eigrp_if_ip_holdinterval_cmd); + install_element(INTERFACE_NODE, &no_eigrp_if_ip_holdinterval_cmd); + install_element(INTERFACE_NODE, &eigrp_ip_summary_address_cmd); + install_element(INTERFACE_NODE, &no_eigrp_ip_summary_address_cmd); + install_element(INTERFACE_NODE, &eigrp_authentication_mode_cmd); + install_element(INTERFACE_NODE, &no_eigrp_authentication_mode_cmd); + install_element(INTERFACE_NODE, &eigrp_authentication_keychain_cmd); + install_element(INTERFACE_NODE, &no_eigrp_authentication_keychain_cmd); +} diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c index 3db59a838b..1781a88173 100644 --- a/eigrpd/eigrp_main.c +++ b/eigrpd/eigrp_main.c @@ -90,10 +90,16 @@ struct option longopts[] = {{0}}; /* Master of threads. */ struct thread_master *master; +/* Forward declaration of daemon info structure. */ +static struct frr_daemon_info eigrpd_di; + /* SIGHUP handler. */ static void sighup(void) { zlog_info("SIGHUP received"); + + /* Reload config file. */ + vty_read_config(NULL, eigrpd_di.config_file, config_default); } /* SIGINT / SIGTERM handler. */ @@ -131,6 +137,7 @@ struct quagga_signal_t eigrp_signals[] = { }; static const struct frr_yang_module_info *eigrpd_yang_modules[] = { + &frr_eigrpd_info, &frr_interface_info, }; @@ -187,7 +194,7 @@ int main(int argc, char **argv, char **envp) eigrp_vty_init(); keychain_init(); eigrp_vty_show_init(); - eigrp_vty_if_init(); + eigrp_cli_init(); #ifdef HAVE_SNMP eigrp_snmp_init(); diff --git a/eigrpd/eigrp_northbound.c b/eigrpd/eigrp_northbound.c new file mode 100644 index 0000000000..5f0c91809e --- /dev/null +++ b/eigrpd/eigrp_northbound.c @@ -0,0 +1,1584 @@ +/* + * EIGRP daemon northbound implementation. + * + * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF") + * Rafael Zalamena + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ + +#include <zebra.h> + +#include "lib/keychain.h" +#include "lib/log.h" +#include "lib/northbound.h" +#include "lib/table.h" +#include "lib/vrf.h" +#include "lib/zclient.h" + +#include "eigrp_structs.h" +#include "eigrpd.h" +#include "eigrp_interface.h" +#include "eigrp_network.h" +#include "eigrp_zebra.h" + +/* Helper functions. */ +static void redistribute_get_metrics(const struct lyd_node *dnode, + struct eigrp_metrics *em) +{ + memset(em, 0, sizeof(*em)); + + if (yang_dnode_exists(dnode, "./bandwidth")) + em->bandwidth = yang_dnode_get_uint32(dnode, "./bandwidth"); + if (yang_dnode_exists(dnode, "./delay")) + em->delay = yang_dnode_get_uint32(dnode, "./delay"); +#if 0 /* TODO: How does MTU work? */ + if (yang_dnode_exists(dnode, "./mtu")) + em->mtu[0] = yang_dnode_get_uint32(dnode, "./mtu"); +#endif + if (yang_dnode_exists(dnode, "./load")) + em->load = yang_dnode_get_uint32(dnode, "./load"); + if (yang_dnode_exists(dnode, "./reliability")) + em->reliability = yang_dnode_get_uint32(dnode, "./reliability"); +} + +static struct eigrp_interface *eigrp_interface_lookup(const struct eigrp *eigrp, + const char *ifname) +{ + struct eigrp_interface *eif; + struct listnode *ln; + + for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, ln, eif)) { + if (strcmp(ifname, eif->ifp->name)) + continue; + + return eif; + } + + return NULL; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance + */ +static int eigrpd_instance_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + /* NOTHING */ + break; + case NB_EV_PREPARE: + eigrp = eigrp_get(yang_dnode_get_string(dnode, "./asn")); + resource->ptr = eigrp; + break; + case NB_EV_ABORT: + eigrp_finish_final(resource->ptr); + break; + case NB_EV_APPLY: + nb_running_set_entry(dnode, resource->ptr); + break; + } + + return NB_OK; +} + +static int eigrpd_instance_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_unset_entry(dnode); + eigrp_finish_final(eigrp); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/router-id + */ +static int eigrpd_instance_router_id_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + yang_dnode_get_ipv4(&eigrp->router_id_static, dnode, NULL); + break; + } + + return NB_OK; +} + +static int eigrpd_instance_router_id_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->router_id_static.s_addr = 0; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/passive-interface + */ +static int +eigrpd_instance_passive_interface_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp_interface *eif; + struct eigrp *eigrp; + const char *ifname; + + switch (event) { + case NB_EV_VALIDATE: + eigrp = nb_running_get_entry(dnode, NULL, false); + if (eigrp == NULL) { + /* + * XXX: we can't verify if the interface exists + * and is active until EIGRP is up. + */ + break; + } + + ifname = yang_dnode_get_string(dnode, NULL); + eif = eigrp_interface_lookup(eigrp, ifname); + if (eif == NULL) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + ifname = yang_dnode_get_string(dnode, NULL); + eif = eigrp_interface_lookup(eigrp, ifname); + if (eif == NULL) + return NB_ERR_INCONSISTENCY; + + eif->params.passive_interface = EIGRP_IF_PASSIVE; + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_passive_interface_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp_interface *eif; + struct eigrp *eigrp; + const char *ifname; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + ifname = yang_dnode_get_string(dnode, NULL); + eif = eigrp_interface_lookup(eigrp, ifname); + if (eif == NULL) + break; + + eif->params.passive_interface = EIGRP_IF_ACTIVE; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/active-time + */ +static int eigrpd_instance_active_time_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/variance + */ +static int eigrpd_instance_variance_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->variance = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int eigrpd_instance_variance_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->variance = EIGRP_VARIANCE_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/maximum-paths + */ +static int eigrpd_instance_maximum_paths_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->max_paths = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int eigrpd_instance_maximum_paths_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->max_paths = EIGRP_MAX_PATHS_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K1 + */ +static int +eigrpd_instance_metric_weights_K1_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[0] = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_metric_weights_K1_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[0] = EIGRP_K1_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K2 + */ +static int +eigrpd_instance_metric_weights_K2_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[1] = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_metric_weights_K2_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[1] = EIGRP_K2_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K3 + */ +static int +eigrpd_instance_metric_weights_K3_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[2] = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_metric_weights_K3_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[2] = EIGRP_K3_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K4 + */ +static int +eigrpd_instance_metric_weights_K4_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[3] = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_metric_weights_K4_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[3] = EIGRP_K4_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K5 + */ +static int +eigrpd_instance_metric_weights_K5_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[4] = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_metric_weights_K5_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[4] = EIGRP_K5_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/metric-weights/K6 + */ +static int +eigrpd_instance_metric_weights_K6_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[5] = yang_dnode_get_uint8(dnode, NULL); + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_metric_weights_K6_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp->k_values[5] = EIGRP_K6_DEFAULT; + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/network + */ +static int eigrpd_instance_network_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct route_node *rnode; + struct prefix prefix; + struct eigrp *eigrp; + int exists; + + yang_dnode_get_ipv4p(&prefix, dnode, NULL); + + switch (event) { + case NB_EV_VALIDATE: + eigrp = nb_running_get_entry(dnode, NULL, false); + /* If entry doesn't exist it means the list is empty. */ + if (eigrp == NULL) + break; + + rnode = route_node_get(eigrp->networks, &prefix); + exists = (rnode->info != NULL); + route_unlock_node(rnode); + if (exists) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + if (eigrp_network_set(eigrp, &prefix) == 0) + return NB_ERR_INCONSISTENCY; + break; + } + + return NB_OK; +} + +static int eigrpd_instance_network_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct route_node *rnode; + struct prefix prefix; + struct eigrp *eigrp; + int exists = 0; + + yang_dnode_get_ipv4p(&prefix, dnode, NULL); + + switch (event) { + case NB_EV_VALIDATE: + eigrp = nb_running_get_entry(dnode, NULL, false); + /* If entry doesn't exist it means the list is empty. */ + if (eigrp == NULL) + break; + + rnode = route_node_get(eigrp->networks, &prefix); + exists = (rnode->info != NULL); + route_unlock_node(rnode); + if (exists == 0) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + eigrp_network_unset(eigrp, &prefix); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/neighbor + */ +static int eigrpd_instance_neighbor_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +static int eigrpd_instance_neighbor_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute + */ +static int eigrpd_instance_redistribute_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp_metrics metrics; + struct eigrp *eigrp; + uint32_t proto; + + switch (event) { + case NB_EV_VALIDATE: + proto = yang_dnode_get_enum(dnode, "./protocol"); + if (vrf_bitmap_check(zclient->redist[AFI_IP][proto], + VRF_DEFAULT)) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + proto = yang_dnode_get_enum(dnode, "./protocol"); + redistribute_get_metrics(dnode, &metrics); + eigrp_redistribute_set(eigrp, proto, metrics); + break; + } + + return NB_OK; +} + +static int eigrpd_instance_redistribute_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp *eigrp; + uint32_t proto; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + proto = yang_dnode_get_enum(dnode, "./protocol"); + eigrp_redistribute_unset(eigrp, proto); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/route-map + */ +static int +eigrpd_instance_redistribute_route_map_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +static int +eigrpd_instance_redistribute_route_map_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/bandwidth + */ +static int eigrpd_instance_redistribute_metrics_bandwidth_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp_metrics metrics; + struct eigrp *eigrp; + uint32_t proto; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + proto = yang_dnode_get_enum(dnode, "../../protocol"); + redistribute_get_metrics(dnode, &metrics); + eigrp_redistribute_set(eigrp, proto, metrics); + break; + } + + return NB_OK; +} + +static int eigrpd_instance_redistribute_metrics_bandwidth_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + struct eigrp_metrics metrics; + struct eigrp *eigrp; + uint32_t proto; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eigrp = nb_running_get_entry(dnode, NULL, true); + proto = yang_dnode_get_enum(dnode, "../../protocol"); + redistribute_get_metrics(dnode, &metrics); + eigrp_redistribute_set(eigrp, proto, metrics); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/delay + */ +static int +eigrpd_instance_redistribute_metrics_delay_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_modify(event, + dnode, + resource); +} + +static int +eigrpd_instance_redistribute_metrics_delay_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_destroy(event, + dnode); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/reliability + */ +static int eigrpd_instance_redistribute_metrics_reliability_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_modify(event, + dnode, + resource); +} + +static int eigrpd_instance_redistribute_metrics_reliability_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_destroy(event, + dnode); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/load + */ +static int +eigrpd_instance_redistribute_metrics_load_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_modify(event, + dnode, + resource); +} + +static int +eigrpd_instance_redistribute_metrics_load_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_destroy(event, + dnode); +} + +/* + * XPath: /frr-eigrpd:eigrpd/instance/redistribute/metrics/mtu + */ +static int +eigrpd_instance_redistribute_metrics_mtu_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_modify(event, + dnode, + resource); +} + +static int +eigrpd_instance_redistribute_metrics_mtu_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + return eigrpd_instance_redistribute_metrics_bandwidth_destroy(event, + dnode); +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/delay + */ +static int lib_interface_eigrp_delay_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp_interface *ei; + struct interface *ifp; + + switch (event) { + case NB_EV_VALIDATE: + ifp = nb_running_get_entry(dnode, NULL, false); + if (ifp == NULL) { + /* + * XXX: we can't verify if the interface exists + * and is active until EIGRP is up. + */ + break; + } + + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(dnode, NULL, true); + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + + ei->params.delay = yang_dnode_get_uint32(dnode, NULL); + eigrp_if_reset(ifp); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/bandwidth + */ +static int lib_interface_eigrp_bandwidth_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct interface *ifp; + struct eigrp_interface *ei; + + switch (event) { + case NB_EV_VALIDATE: + ifp = nb_running_get_entry(dnode, NULL, false); + if (ifp == NULL) { + /* + * XXX: we can't verify if the interface exists + * and is active until EIGRP is up. + */ + break; + } + + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(dnode, NULL, true); + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + + ei->params.bandwidth = yang_dnode_get_uint32(dnode, NULL); + eigrp_if_reset(ifp); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/hello-interval + */ +static int +lib_interface_eigrp_hello_interval_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct interface *ifp; + struct eigrp_interface *ei; + + switch (event) { + case NB_EV_VALIDATE: + ifp = nb_running_get_entry(dnode, NULL, false); + if (ifp == NULL) { + /* + * XXX: we can't verify if the interface exists + * and is active until EIGRP is up. + */ + break; + } + + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(dnode, NULL, true); + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + + ei->params.v_hello = yang_dnode_get_uint16(dnode, NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/hold-time + */ +static int lib_interface_eigrp_hold_time_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct interface *ifp; + struct eigrp_interface *ei; + + switch (event) { + case NB_EV_VALIDATE: + ifp = nb_running_get_entry(dnode, NULL, false); + if (ifp == NULL) { + /* + * XXX: we can't verify if the interface exists + * and is active until EIGRP is up. + */ + break; + } + + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(dnode, NULL, true); + ei = ifp->info; + if (ei == NULL) + return NB_ERR_INCONSISTENCY; + + ei->params.v_wait = yang_dnode_get_uint16(dnode, NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/split-horizon + */ +static int +lib_interface_eigrp_split_horizon_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance + */ +static int lib_interface_eigrp_instance_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp_interface *eif; + struct interface *ifp; + struct eigrp *eigrp; + + switch (event) { + case NB_EV_VALIDATE: + ifp = nb_running_get_entry(dnode, NULL, false); + if (ifp == NULL) { + /* + * XXX: we can't verify if the interface exists + * and is active until EIGRP is up. + */ + break; + } + + eigrp = eigrp_get(yang_dnode_get_string(dnode, "./asn")); + eif = eigrp_interface_lookup(eigrp, ifp->name); + if (eif == NULL) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(dnode, NULL, true); + eigrp = eigrp_get(yang_dnode_get_string(dnode, "./asn")); + eif = eigrp_interface_lookup(eigrp, ifp->name); + if (eif == NULL) + return NB_ERR_INCONSISTENCY; + + nb_running_set_entry(dnode, eif); + break; + } + + return NB_OK; +} + +static int lib_interface_eigrp_instance_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + nb_running_unset_entry(dnode); + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/summarize-addresses + */ +static int lib_interface_eigrp_instance_summarize_addresses_create( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +static int lib_interface_eigrp_instance_summarize_addresses_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + switch (event) { + case NB_EV_VALIDATE: + /* TODO: Not implemented. */ + return NB_ERR_INCONSISTENCY; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/authentication + */ +static int +lib_interface_eigrp_instance_authentication_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp_interface *eif; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eif = nb_running_get_entry(dnode, NULL, true); + eif->params.auth_type = yang_dnode_get_enum(dnode, NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-eigrpd:eigrp/instance/keychain + */ +static int +lib_interface_eigrp_instance_keychain_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct eigrp_interface *eif; + struct keychain *keychain; + + switch (event) { + case NB_EV_VALIDATE: + keychain = keychain_lookup(yang_dnode_get_string(dnode, NULL)); + if (keychain == NULL) + return NB_ERR_INCONSISTENCY; + break; + case NB_EV_PREPARE: + resource->ptr = strdup(yang_dnode_get_string(dnode, NULL)); + if (resource->ptr == NULL) + return NB_ERR_RESOURCE; + break; + case NB_EV_ABORT: + free(resource->ptr); + resource->ptr = NULL; + break; + case NB_EV_APPLY: + eif = nb_running_get_entry(dnode, NULL, true); + if (eif->params.auth_keychain) + free(eif->params.auth_keychain); + + eif->params.auth_keychain = resource->ptr; + break; + } + + return NB_OK; +} + +static int +lib_interface_eigrp_instance_keychain_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct eigrp_interface *eif; + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + eif = nb_running_get_entry(dnode, NULL, true); + if (eif->params.auth_keychain) + free(eif->params.auth_keychain); + + eif->params.auth_keychain = NULL; + break; + } + + return NB_OK; +} + +/* clang-format off */ +const struct frr_yang_module_info frr_eigrpd_info = { + .name = "frr-eigrpd", + .nodes = { + { + .xpath = "/frr-eigrpd:eigrpd/instance", + .cbs = { + .create = eigrpd_instance_create, + .destroy = eigrpd_instance_destroy, + .cli_show = eigrp_cli_show_header, + .cli_show_end = eigrp_cli_show_end_header, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/router-id", + .cbs = { + .modify = eigrpd_instance_router_id_modify, + .destroy = eigrpd_instance_router_id_destroy, + .cli_show = eigrp_cli_show_router_id, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/passive-interface", + .cbs = { + .create = eigrpd_instance_passive_interface_create, + .destroy = eigrpd_instance_passive_interface_destroy, + .cli_show = eigrp_cli_show_passive_interface, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/active-time", + .cbs = { + .modify = eigrpd_instance_active_time_modify, + .cli_show = eigrp_cli_show_active_time, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/variance", + .cbs = { + .modify = eigrpd_instance_variance_modify, + .destroy = eigrpd_instance_variance_destroy, + .cli_show = eigrp_cli_show_variance, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/maximum-paths", + .cbs = { + .modify = eigrpd_instance_maximum_paths_modify, + .destroy = eigrpd_instance_maximum_paths_destroy, + .cli_show = eigrp_cli_show_maximum_paths, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights", + .cbs = { + .cli_show = eigrp_cli_show_metrics, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K1", + .cbs = { + .modify = eigrpd_instance_metric_weights_K1_modify, + .destroy = eigrpd_instance_metric_weights_K1_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K2", + .cbs = { + .modify = eigrpd_instance_metric_weights_K2_modify, + .destroy = eigrpd_instance_metric_weights_K2_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K3", + .cbs = { + .modify = eigrpd_instance_metric_weights_K3_modify, + .destroy = eigrpd_instance_metric_weights_K3_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K4", + .cbs = { + .modify = eigrpd_instance_metric_weights_K4_modify, + .destroy = eigrpd_instance_metric_weights_K4_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K5", + .cbs = { + .modify = eigrpd_instance_metric_weights_K5_modify, + .destroy = eigrpd_instance_metric_weights_K5_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/metric-weights/K6", + .cbs = { + .modify = eigrpd_instance_metric_weights_K6_modify, + .destroy = eigrpd_instance_metric_weights_K6_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/network", + .cbs = { + .create = eigrpd_instance_network_create, + .destroy = eigrpd_instance_network_destroy, + .cli_show = eigrp_cli_show_network, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/neighbor", + .cbs = { + .create = eigrpd_instance_neighbor_create, + .destroy = eigrpd_instance_neighbor_destroy, + .cli_show = eigrp_cli_show_neighbor, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/redistribute", + .cbs = { + .create = eigrpd_instance_redistribute_create, + .destroy = eigrpd_instance_redistribute_destroy, + .cli_show = eigrp_cli_show_redistribute, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/route-map", + .cbs = { + .modify = eigrpd_instance_redistribute_route_map_modify, + .destroy = eigrpd_instance_redistribute_route_map_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/bandwidth", + .cbs = { + .modify = eigrpd_instance_redistribute_metrics_bandwidth_modify, + .destroy = eigrpd_instance_redistribute_metrics_bandwidth_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/delay", + .cbs = { + .modify = eigrpd_instance_redistribute_metrics_delay_modify, + .destroy = eigrpd_instance_redistribute_metrics_delay_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/reliability", + .cbs = { + .modify = eigrpd_instance_redistribute_metrics_reliability_modify, + .destroy = eigrpd_instance_redistribute_metrics_reliability_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/load", + .cbs = { + .modify = eigrpd_instance_redistribute_metrics_load_modify, + .destroy = eigrpd_instance_redistribute_metrics_load_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/redistribute/metrics/mtu", + .cbs = { + .modify = eigrpd_instance_redistribute_metrics_mtu_modify, + .destroy = eigrpd_instance_redistribute_metrics_mtu_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/delay", + .cbs = { + .modify = lib_interface_eigrp_delay_modify, + .cli_show = eigrp_cli_show_delay, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/bandwidth", + .cbs = { + .modify = lib_interface_eigrp_bandwidth_modify, + .cli_show = eigrp_cli_show_bandwidth, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/hello-interval", + .cbs = { + .modify = lib_interface_eigrp_hello_interval_modify, + .cli_show = eigrp_cli_show_hello_interval, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/hold-time", + .cbs = { + .modify = lib_interface_eigrp_hold_time_modify, + .cli_show = eigrp_cli_show_hold_time, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/split-horizon", + .cbs = { + .modify = lib_interface_eigrp_split_horizon_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/instance", + .cbs = { + .create = lib_interface_eigrp_instance_create, + .destroy = lib_interface_eigrp_instance_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/instance/summarize-addresses", + .cbs = { + .create = lib_interface_eigrp_instance_summarize_addresses_create, + .destroy = lib_interface_eigrp_instance_summarize_addresses_destroy, + .cli_show = eigrp_cli_show_summarize_address, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/instance/authentication", + .cbs = { + .modify = lib_interface_eigrp_instance_authentication_modify, + .cli_show = eigrp_cli_show_authentication, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-eigrpd:eigrp/instance/keychain", + .cbs = { + .modify = lib_interface_eigrp_instance_keychain_modify, + .destroy = lib_interface_eigrp_instance_keychain_destroy, + .cli_show = eigrp_cli_show_keychain, + } + }, + { + .xpath = NULL, + }, + } +}; diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c index d51faaac59..207622e659 100644 --- a/eigrpd/eigrp_vty.c +++ b/eigrpd/eigrp_vty.c @@ -59,402 +59,6 @@ #include "eigrpd/eigrp_vty_clippy.c" #endif -static int config_write_network(struct vty *vty, struct eigrp *eigrp) -{ - struct route_node *rn; - int i; - - /* `network area' print. */ - for (rn = route_top(eigrp->networks); rn; rn = route_next(rn)) - if (rn->info) { - /* Network print. */ - vty_out(vty, " network %s/%d \n", - inet_ntoa(rn->p.u.prefix4), rn->p.prefixlen); - } - - if (eigrp->max_paths != EIGRP_MAX_PATHS_DEFAULT) - vty_out(vty, " maximum-paths %d\n", eigrp->max_paths); - - if (eigrp->variance != EIGRP_VARIANCE_DEFAULT) - vty_out(vty, " variance %d\n", eigrp->variance); - - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - if (i != zclient->redist_default - && vrf_bitmap_check(zclient->redist[AFI_IP][i], - VRF_DEFAULT)) - vty_out(vty, " redistribute %s\n", - zebra_route_string(i)); - - /*Separate EIGRP configuration from the rest of the config*/ - vty_out(vty, "!\n"); - - return 0; -} - -static int config_write_interfaces(struct vty *vty, struct eigrp *eigrp) -{ - struct eigrp_interface *ei; - struct listnode *node; - - for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) { - vty_frame(vty, "interface %s\n", ei->ifp->name); - - if (ei->params.auth_type == EIGRP_AUTH_TYPE_MD5) { - vty_out(vty, " ip authentication mode eigrp %d md5\n", - eigrp->AS); - } - - if (ei->params.auth_type == EIGRP_AUTH_TYPE_SHA256) { - vty_out(vty, - " ip authentication mode eigrp %d hmac-sha-256\n", - eigrp->AS); - } - - if (ei->params.auth_keychain) { - vty_out(vty, - " ip authentication key-chain eigrp %d %s\n", - eigrp->AS, ei->params.auth_keychain); - } - - if (ei->params.v_hello != EIGRP_HELLO_INTERVAL_DEFAULT) { - vty_out(vty, " ip hello-interval eigrp %d\n", - ei->params.v_hello); - } - - if (ei->params.v_wait != EIGRP_HOLD_INTERVAL_DEFAULT) { - vty_out(vty, " ip hold-time eigrp %d\n", - ei->params.v_wait); - } - - /*Separate this EIGRP interface configuration from the others*/ - vty_endframe(vty, "!\n"); - } - - return 0; -} - -static int eigrp_write_interface(struct vty *vty) -{ - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); - struct interface *ifp; - struct eigrp_interface *ei; - - FOR_ALL_INTERFACES (vrf, ifp) { - ei = ifp->info; - if (!ei) - continue; - - vty_frame(vty, "interface %s\n", ifp->name); - - if (ifp->desc) - vty_out(vty, " description %s\n", ifp->desc); - - if (ei->params.bandwidth != EIGRP_BANDWIDTH_DEFAULT) - vty_out(vty, " bandwidth %u\n", ei->params.bandwidth); - if (ei->params.delay != EIGRP_DELAY_DEFAULT) - vty_out(vty, " delay %u\n", ei->params.delay); - if (ei->params.v_hello != EIGRP_HELLO_INTERVAL_DEFAULT) - vty_out(vty, " ip hello-interval eigrp %u\n", - ei->params.v_hello); - if (ei->params.v_wait != EIGRP_HOLD_INTERVAL_DEFAULT) - vty_out(vty, " ip hold-time eigrp %u\n", - ei->params.v_wait); - - vty_endframe(vty, "!\n"); - } - - return 0; -} - -/** - * Writes distribute lists to config - */ -static int config_write_eigrp_distribute(struct vty *vty, struct eigrp *eigrp) -{ - int write = 0; - - /* Distribute configuration. */ - write += config_write_distribute(vty, eigrp->distribute_ctx); - - return write; -} - -/** - * Writes 'router eigrp' section to config - */ -static int config_write_eigrp_router(struct vty *vty, struct eigrp *eigrp) -{ - int write = 0; - - /* `router eigrp' print. */ - vty_out(vty, "router eigrp %d\n", eigrp->AS); - - write++; - - /* Router ID print. */ - if (eigrp->router_id_static.s_addr != 0) { - vty_out(vty, " eigrp router-id %s\n", - inet_ntoa(eigrp->router_id_static)); - } - - /* Network area print. */ - config_write_network(vty, eigrp); - - /* Distribute-list and default-information print. */ - config_write_eigrp_distribute(vty, eigrp); - - /*Separate EIGRP configuration from the rest of the config*/ - vty_out(vty, "!\n"); - - return write; -} - -DEFUN_NOSH (router_eigrp, - router_eigrp_cmd, - "router eigrp (1-65535)", - "Enable a routing process\n" - "Start EIGRP configuration\n" - "AS Number to use\n") -{ - struct eigrp *eigrp = eigrp_get(argv[2]->arg); - VTY_PUSH_CONTEXT(EIGRP_NODE, eigrp); - - return CMD_SUCCESS; -} - -DEFUN (no_router_eigrp, - no_router_eigrp_cmd, - "no router eigrp (1-65535)", - NO_STR - "Routing process\n" - "EIGRP configuration\n" - "AS number to use\n") -{ - vty->node = CONFIG_NODE; - - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (eigrp->AS != atoi(argv[3]->arg)) { - vty_out(vty, "%% Attempting to deconfigure non-existent AS\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - eigrp_finish_final(eigrp); - - return CMD_SUCCESS; -} - -DEFPY (eigrp_router_id, - eigrp_router_id_cmd, - "eigrp router-id A.B.C.D$addr", - "EIGRP specific commands\n" - "Router ID for this EIGRP process\n" - "EIGRP Router-ID in IP address format\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - - eigrp->router_id_static = addr; - - return CMD_SUCCESS; -} - -DEFPY (no_eigrp_router_id, - no_eigrp_router_id_cmd, - "no eigrp router-id [A.B.C.D$addr]", - NO_STR - "EIGRP specific commands\n" - "Router ID for this EIGRP process\n" - "EIGRP Router-ID in IP address format\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - - eigrp->router_id_static.s_addr = 0; - - return CMD_SUCCESS; -} - -DEFUN (eigrp_passive_interface, - eigrp_passive_interface_cmd, - "passive-interface IFNAME", - "Suppress routing updates on an interface\n" - "Interface to suppress on\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - struct eigrp_interface *ei; - struct listnode *node; - char *ifname = argv[1]->arg; - - for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) { - if (strcmp(ifname, ei->ifp->name) == 0) { - ei->params.passive_interface = EIGRP_IF_PASSIVE; - return CMD_SUCCESS; - } - } - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_passive_interface, - no_eigrp_passive_interface_cmd, - "no passive-interface IFNAME", - NO_STR - "Suppress routing updates on an interface\n" - "Interface to suppress on\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - struct eigrp_interface *ei; - struct listnode *node; - char *ifname = argv[2]->arg; - - for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) { - if (strcmp(ifname, ei->ifp->name) == 0) { - ei->params.passive_interface = EIGRP_IF_ACTIVE; - return CMD_SUCCESS; - } - } - - return CMD_SUCCESS; -} - -DEFUN (eigrp_timers_active, - eigrp_timers_active_cmd, - "timers active-time <(1-65535)|disabled>", - "Adjust routing timers\n" - "Time limit for active state\n" - "Active state time limit in seconds\n" - "Disable time limit for active state\n") -{ - // struct eigrp *eigrp = vty->index; - /*TODO: */ - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_timers_active, - no_eigrp_timers_active_cmd, - "no timers active-time <(1-65535)|disabled>", - NO_STR - "Adjust routing timers\n" - "Time limit for active state\n" - "Active state time limit in seconds\n" - "Disable time limit for active state\n") -{ - // struct eigrp *eigrp = vty->index; - /*TODO: */ - - return CMD_SUCCESS; -} - - -DEFUN (eigrp_metric_weights, - eigrp_metric_weights_cmd, - "metric weights (0-255) (0-255) (0-255) (0-255) (0-255) ", - "Modify metrics and parameters for advertisement\n" - "Modify metric coefficients\n" - "K1\n" - "K2\n" - "K3\n" - "K4\n" - "K5\n") -{ - // struct eigrp *eigrp = vty->index; - /*TODO: */ - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_metric_weights, - no_eigrp_metric_weights_cmd, - "no metric weights (0-255) (0-255) (0-255) (0-255) (0-255)", - NO_STR - "Modify metrics and parameters for advertisement\n" - "Modify metric coefficients\n" - "K1\n" - "K2\n" - "K3\n" - "K4\n" - "K5\n") -{ - // struct eigrp *eigrp = vty->index; - /*TODO: */ - - return CMD_SUCCESS; -} - - -DEFUN (eigrp_network, - eigrp_network_cmd, - "network A.B.C.D/M", - "Enable routing on an IP network\n" - "EIGRP network prefix\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - struct prefix p; - int ret; - - (void)str2prefix(argv[1]->arg, &p); - - ret = eigrp_network_set(eigrp, &p); - - if (ret == 0) { - vty_out(vty, "There is already same network statement.\n"); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_network, - no_eigrp_network_cmd, - "no network A.B.C.D/M", - NO_STR - "Disable routing on an IP network\n" - "EIGRP network prefix\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - struct prefix p; - int ret; - - (void)str2prefix(argv[2]->arg, &p); - - ret = eigrp_network_unset(eigrp, &p); - - if (ret == 0) { - vty_out(vty, "Can't find specified network configuration.\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - -DEFUN (eigrp_neighbor, - eigrp_neighbor_cmd, - "neighbor A.B.C.D", - "Specify a neighbor router\n" - "Neighbor address\n") -{ - // struct eigrp *eigrp = vty->index; - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_neighbor, - no_eigrp_neighbor_cmd, - "no neighbor A.B.C.D", - NO_STR - "Specify a neighbor router\n" - "Neighbor address\n") -{ - // struct eigrp *eigrp = vty->index; - - return CMD_SUCCESS; -} - static void eigrp_vty_display_prefix_entry(struct vty *vty, struct eigrp *eigrp, struct eigrp_prefix_entry *pe, @@ -650,585 +254,6 @@ DEFUN (show_ip_eigrp_neighbors, return CMD_SUCCESS; } -DEFUN (eigrp_if_delay, - eigrp_if_delay_cmd, - "delay (1-16777215)", - "Specify interface throughput delay\n" - "Throughput delay (tens of microseconds)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - uint32_t delay; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - delay = atoi(argv[1]->arg); - - ei->params.delay = delay; - eigrp_if_reset(ifp); - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_if_delay, - no_eigrp_if_delay_cmd, - "no delay (1-16777215)", - NO_STR - "Specify interface throughput delay\n" - "Throughput delay (tens of microseconds)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - - return CMD_SUCCESS; - } - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - ei->params.delay = EIGRP_DELAY_DEFAULT; - eigrp_if_reset(ifp); - - return CMD_SUCCESS; -} - -DEFPY (eigrp_if_bandwidth, - eigrp_if_bandwidth_cmd, - "eigrp bandwidth (1-10000000)$bw", - "EIGRP specific commands\n" - "Set bandwidth informational parameter\n" - "Bandwidth in kilobits\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - ei->params.bandwidth = bw; - eigrp_if_reset(ifp); - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_if_bandwidth, - no_eigrp_if_bandwidth_cmd, - "no eigrp bandwidth [(1-10000000)]", - NO_STR - "EIGRP specific commands\n" - "Set bandwidth informational parameter\n" - "Bandwidth in kilobits\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - ei->params.bandwidth = EIGRP_BANDWIDTH_DEFAULT; - eigrp_if_reset(ifp); - - return CMD_SUCCESS; -} - -DEFUN (eigrp_if_ip_hellointerval, - eigrp_if_ip_hellointerval_cmd, - "ip hello-interval eigrp (1-65535)", - "Interface Internet Protocol config commands\n" - "Configures EIGRP hello interval\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "Seconds between hello transmissions\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - uint32_t hello; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - hello = atoi(argv[3]->arg); - - ei->params.v_hello = hello; - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_if_ip_hellointerval, - no_eigrp_if_ip_hellointerval_cmd, - "no ip hello-interval eigrp [(1-65535)]", - NO_STR - "Interface Internet Protocol config commands\n" - "Configures EIGRP hello interval\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "Seconds between hello transmissions\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - ei->params.v_hello = EIGRP_HELLO_INTERVAL_DEFAULT; - - THREAD_TIMER_OFF(ei->t_hello); - thread_add_timer(master, eigrp_hello_timer, ei, 1, &ei->t_hello); - - return CMD_SUCCESS; -} - -DEFUN (eigrp_if_ip_holdinterval, - eigrp_if_ip_holdinterval_cmd, - "ip hold-time eigrp (1-65535)", - "Interface Internet Protocol config commands\n" - "Configures EIGRP IPv4 hold time\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "Seconds before neighbor is considered down\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - uint32_t hold; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - hold = atoi(argv[3]->arg); - - ei->params.v_wait = hold; - - return CMD_SUCCESS; -} - -DEFUN (eigrp_ip_summary_address, - eigrp_ip_summary_address_cmd, - "ip summary-address eigrp (1-65535) A.B.C.D/M", - "Interface Internet Protocol config commands\n" - "Perform address summarization\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "AS number\n" - "Summary <network>/<length>, e.g. 192.168.0.0/16\n") -{ - // VTY_DECLVAR_CONTEXT(interface, ifp); - // uint32_t AS; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - // AS = atoi (argv[3]->arg); - - /*TODO: */ - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_ip_summary_address, - no_eigrp_ip_summary_address_cmd, - "no ip summary-address eigrp (1-65535) A.B.C.D/M", - NO_STR - "Interface Internet Protocol config commands\n" - "Perform address summarization\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "AS number\n" - "Summary <network>/<length>, e.g. 192.168.0.0/16\n") -{ - // VTY_DECLVAR_CONTEXT(interface, ifp); - // uint32_t AS; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - // AS = atoi (argv[4]->arg); - - /*TODO: */ - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_if_ip_holdinterval, - no_eigrp_if_ip_holdinterval_cmd, - "no ip hold-time eigrp", - NO_STR - "Interface Internet Protocol config commands\n" - "Configures EIGRP hello interval\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - ei->params.v_wait = EIGRP_HOLD_INTERVAL_DEFAULT; - - return CMD_SUCCESS; -} - -static int str2auth_type(const char *str, struct eigrp_interface *ei) -{ - /* Sanity check. */ - if (str == NULL) - return CMD_WARNING_CONFIG_FAILED; - - if (strncmp(str, "md5", 3) == 0) { - ei->params.auth_type = EIGRP_AUTH_TYPE_MD5; - return CMD_SUCCESS; - } else if (strncmp(str, "hmac-sha-256", 12) == 0) { - ei->params.auth_type = EIGRP_AUTH_TYPE_SHA256; - return CMD_SUCCESS; - } - - return CMD_WARNING_CONFIG_FAILED; -} - -DEFUN (eigrp_authentication_mode, - eigrp_authentication_mode_cmd, - "ip authentication mode eigrp (1-65535) <md5|hmac-sha-256>", - "Interface Internet Protocol config commands\n" - "Authentication subcommands\n" - "Mode\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "Autonomous system number\n" - "Keyed message digest\n" - "HMAC SHA256 algorithm \n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - // if(strncmp(argv[2], "md5",3)) - // IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_MD5; - // else if(strncmp(argv[2], "hmac-sha-256",12)) - // IF_DEF_PARAMS (ifp)->auth_type = EIGRP_AUTH_TYPE_SHA256; - - return str2auth_type(argv[5]->arg, ei); -} - -DEFUN (no_eigrp_authentication_mode, - no_eigrp_authentication_mode_cmd, - "no ip authentication mode eigrp (1-65535) <md5|hmac-sha-256>", - "Disable\n" - "Interface Internet Protocol config commands\n" - "Authentication subcommands\n" - "Mode\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "Autonomous system number\n" - "Keyed message digest\n" - "HMAC SHA256 algorithm \n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, " EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - ei->params.auth_type = EIGRP_AUTH_TYPE_NONE; - - return CMD_SUCCESS; -} - -DEFPY (eigrp_authentication_keychain, - eigrp_authentication_keychain_cmd, - "[no] ip authentication key-chain eigrp (1-65535)$as WORD$name", - NO_STR - "Interface Internet Protocol config commands\n" - "Authentication subcommands\n" - "Key-chain\n" - "Enhanced Interior Gateway Routing Protocol (EIGRP)\n" - "Autonomous system number\n" - "Name of key-chain\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct eigrp_interface *ei = ifp->info; - struct eigrp *eigrp; - struct keychain *keychain; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, "EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - if (!ei) { - vty_out(vty, " EIGRP not configured on this interface\n"); - return CMD_SUCCESS; - } - - if (no) { - if ((ei->params.auth_keychain != NULL) - && (strcmp(ei->params.auth_keychain, name) == 0)) { - free(ei->params.auth_keychain); - ei->params.auth_keychain = NULL; - } else - vty_out(vty, - "Key chain with specified name not configured on interface\n"); - return CMD_SUCCESS; - } - - keychain = keychain_lookup(name); - if (keychain != NULL) { - if (ei->params.auth_keychain) { - free(ei->params.auth_keychain); - ei->params.auth_keychain = strdup(keychain->name); - } else - ei->params.auth_keychain = strdup(keychain->name); - } else { - vty_out(vty, - "Key chain with specified name not found\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - -DEFUN (eigrp_redistribute_source_metric, - eigrp_redistribute_source_metric_cmd, - "redistribute " FRR_REDIST_STR_EIGRPD - " [metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)]", - REDIST_STR - FRR_REDIST_HELP_STR_EIGRPD - "Metric for redistributed routes\n" - "Bandwidth metric in Kbits per second\n" - "EIGRP delay metric, in 10 microsecond units\n" - "EIGRP reliability metric where 255 is 100% reliable2 ?\n" - "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n" - "EIGRP MTU of the path\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - struct eigrp_metrics metrics_from_command = {0}; - int source; - int idx = 0; - - /* Get distribute source. */ - argv_find(argv, argc, "redistribute", &idx); - source = proto_redistnum(AFI_IP, argv[idx + 1]->text); - if (source < 0) { - vty_out(vty, "%% Invalid route type\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Get metrics values */ - - return eigrp_redistribute_set(eigrp, source, metrics_from_command); -} - -DEFUN (no_eigrp_redistribute_source_metric, - no_eigrp_redistribute_source_metric_cmd, - "no redistribute " FRR_REDIST_STR_EIGRPD - " [metric (1-4294967295) (0-4294967295) (0-255) (1-255) (1-65535)]", - "Disable\n" - REDIST_STR - FRR_REDIST_HELP_STR_EIGRPD - "Metric for redistributed routes\n" - "Bandwidth metric in Kbits per second\n" - "EIGRP delay metric, in 10 microsecond units\n" - "EIGRP reliability metric where 255 is 100% reliable2 ?\n" - "EIGRP Effective bandwidth metric (Loading) where 255 is 100% loaded\n" - "EIGRP MTU of the path\n") -{ - VTY_DECLVAR_CONTEXT(eigrp, eigrp); - int source; - int idx = 0; - - /* Get distribute source. */ - argv_find(argv, argc, "redistribute", &idx); - source = proto_redistnum(AFI_IP, argv[idx + 1]->text); - if (source < 0) { - vty_out(vty, "%% Invalid route type\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Get metrics values */ - - return eigrp_redistribute_unset(eigrp, source); -} - -DEFUN (eigrp_variance, - eigrp_variance_cmd, - "variance (1-128)", - "Control load balancing variance\n" - "Metric variance multiplier\n") -{ - struct eigrp *eigrp; - uint8_t variance; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, "EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - variance = atoi(argv[1]->arg); - - eigrp->variance = variance; - - /*TODO: */ - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_variance, - no_eigrp_variance_cmd, - "no variance (1-128)", - "Disable\n" - "Control load balancing variance\n" - "Metric variance multiplier\n") -{ - struct eigrp *eigrp; - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, "EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - eigrp->variance = EIGRP_VARIANCE_DEFAULT; - - /*TODO: */ - - return CMD_SUCCESS; -} - -DEFUN (eigrp_maximum_paths, - eigrp_maximum_paths_cmd, - "maximum-paths (1-32)", - "Forward packets over multiple paths\n" - "Number of paths\n") -{ - struct eigrp *eigrp; - uint8_t max; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, "EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - max = atoi(argv[1]->arg); - - eigrp->max_paths = max; - - /*TODO: */ - - return CMD_SUCCESS; -} - -DEFUN (no_eigrp_maximum_paths, - no_eigrp_maximum_paths_cmd, - "no maximum-paths (1-32)", - NO_STR - "Forward packets over multiple paths\n" - "Number of paths\n") -{ - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp == NULL) { - vty_out(vty, "EIGRP Routing Process not enabled\n"); - return CMD_SUCCESS; - } - - eigrp->max_paths = EIGRP_MAX_PATHS_DEFAULT; - - /*TODO: */ - - return CMD_SUCCESS; -} - /* * Execute hard restart for all neighbors */ @@ -1492,40 +517,6 @@ DEFUN (clear_ip_eigrp_neighbors_IP_soft, return CMD_SUCCESS; } -static struct cmd_node eigrp_node = {EIGRP_NODE, "%s(config-router)# ", 1}; - -/* Save EIGRP configuration */ -static int eigrp_config_write(struct vty *vty) -{ - struct eigrp *eigrp; - - eigrp = eigrp_lookup(); - if (eigrp != NULL) { - /* Writes 'router eigrp' section to config */ - config_write_eigrp_router(vty, eigrp); - - /* Interface config print */ - config_write_interfaces(vty, eigrp); - // - // /* static neighbor print. */ - // config_write_eigrp_nbr_nbma (vty, eigrp); - // - // /* Virtual-Link print. */ - // config_write_virtual_link (vty, eigrp); - // - // /* Default metric configuration. */ - // config_write_eigrp_default_metric (vty, eigrp); - // - // /* Distribute-list and default-information print. */ - // config_write_eigrp_distribute (vty, eigrp); - // - // /* Distance configuration. */ - // config_write_eigrp_distance (vty, eigrp) - } - - return 0; -} - void eigrp_vty_show_init(void) { install_element(VIEW_NODE, &show_ip_eigrp_interfaces_cmd); @@ -1536,69 +527,9 @@ void eigrp_vty_show_init(void) install_element(VIEW_NODE, &show_ip_eigrp_topology_all_cmd); } -/* eigrpd's interface node. */ -static struct cmd_node eigrp_interface_node = {INTERFACE_NODE, - "%s(config-if)# ", 1}; - -void eigrp_vty_if_init(void) -{ - install_node(&eigrp_interface_node, eigrp_write_interface); - if_cmd_init(); - - /* Delay and bandwidth configuration commands*/ - install_element(INTERFACE_NODE, &eigrp_if_delay_cmd); - install_element(INTERFACE_NODE, &no_eigrp_if_delay_cmd); - install_element(INTERFACE_NODE, &eigrp_if_bandwidth_cmd); - install_element(INTERFACE_NODE, &no_eigrp_if_bandwidth_cmd); - - /*Hello-interval and hold-time interval configuration commands*/ - install_element(INTERFACE_NODE, &eigrp_if_ip_holdinterval_cmd); - install_element(INTERFACE_NODE, &no_eigrp_if_ip_holdinterval_cmd); - install_element(INTERFACE_NODE, &eigrp_if_ip_hellointerval_cmd); - install_element(INTERFACE_NODE, &no_eigrp_if_ip_hellointerval_cmd); - - /* "Authentication configuration commands */ - install_element(INTERFACE_NODE, &eigrp_authentication_mode_cmd); - install_element(INTERFACE_NODE, &no_eigrp_authentication_mode_cmd); - install_element(INTERFACE_NODE, &eigrp_authentication_keychain_cmd); - - /*EIGRP Summarization commands*/ - install_element(INTERFACE_NODE, &eigrp_ip_summary_address_cmd); - install_element(INTERFACE_NODE, &no_eigrp_ip_summary_address_cmd); -} - -static void eigrp_vty_zebra_init(void) -{ - install_element(EIGRP_NODE, &eigrp_redistribute_source_metric_cmd); - install_element(EIGRP_NODE, &no_eigrp_redistribute_source_metric_cmd); -} - /* Install EIGRP related vty commands. */ void eigrp_vty_init(void) { - install_node(&eigrp_node, eigrp_config_write); - - install_default(EIGRP_NODE); - - install_element(CONFIG_NODE, &router_eigrp_cmd); - install_element(CONFIG_NODE, &no_router_eigrp_cmd); - install_element(EIGRP_NODE, &eigrp_network_cmd); - install_element(EIGRP_NODE, &no_eigrp_network_cmd); - install_element(EIGRP_NODE, &eigrp_variance_cmd); - install_element(EIGRP_NODE, &no_eigrp_variance_cmd); - install_element(EIGRP_NODE, &eigrp_router_id_cmd); - install_element(EIGRP_NODE, &no_eigrp_router_id_cmd); - install_element(EIGRP_NODE, &eigrp_passive_interface_cmd); - install_element(EIGRP_NODE, &no_eigrp_passive_interface_cmd); - install_element(EIGRP_NODE, &eigrp_timers_active_cmd); - install_element(EIGRP_NODE, &no_eigrp_timers_active_cmd); - install_element(EIGRP_NODE, &eigrp_metric_weights_cmd); - install_element(EIGRP_NODE, &no_eigrp_metric_weights_cmd); - install_element(EIGRP_NODE, &eigrp_maximum_paths_cmd); - install_element(EIGRP_NODE, &no_eigrp_maximum_paths_cmd); - install_element(EIGRP_NODE, &eigrp_neighbor_cmd); - install_element(EIGRP_NODE, &no_eigrp_neighbor_cmd); - /* commands for manual hard restart */ install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_cmd); install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_int_cmd); @@ -1607,6 +538,4 @@ void eigrp_vty_init(void) install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_soft_cmd); install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_int_soft_cmd); install_element(ENABLE_NODE, &clear_ip_eigrp_neighbors_IP_soft_cmd); - - eigrp_vty_zebra_init(); } diff --git a/eigrpd/eigrp_vty.h b/eigrpd/eigrp_vty.h index 3fbadf6dfb..ebbf503857 100644 --- a/eigrpd/eigrp_vty.h +++ b/eigrpd/eigrp_vty.h @@ -35,6 +35,5 @@ /* Prototypes. */ extern void eigrp_vty_init(void); extern void eigrp_vty_show_init(void); -extern void eigrp_vty_if_init(void); #endif /* _Quagga_EIGRP_VTY_H_ */ diff --git a/eigrpd/eigrpd.h b/eigrpd/eigrpd.h index de7c881ac0..3ef3a9c0cc 100644 --- a/eigrpd/eigrpd.h +++ b/eigrpd/eigrpd.h @@ -52,4 +52,51 @@ extern struct eigrp *eigrp_get(const char *); extern struct eigrp *eigrp_lookup(void); 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; + #endif /* _ZEBRA_EIGRPD_H */ diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am index 4503030fdf..cc46766586 100644 --- a/eigrpd/subdir.am +++ b/eigrpd/subdir.am @@ -7,6 +7,7 @@ noinst_LIBRARIES += eigrpd/libeigrp.a sbin_PROGRAMS += eigrpd/eigrpd dist_examples_DATA += eigrpd/eigrpd.conf.sample vtysh_scan += \ + $(top_srcdir)/eigrpd/eigrp_cli.c \ $(top_srcdir)/eigrpd/eigrp_dump.c \ $(top_srcdir)/eigrpd/eigrp_vty.c \ # end @@ -15,6 +16,7 @@ man8 += $(MANBUILD)/eigrpd.8 endif eigrpd_libeigrp_a_SOURCES = \ + eigrpd/eigrp_cli.c \ eigrpd/eigrp_dump.c \ eigrpd/eigrp_errors.c \ eigrpd/eigrp_filter.c \ @@ -24,6 +26,7 @@ eigrpd_libeigrp_a_SOURCES = \ eigrpd/eigrp_memory.c \ eigrpd/eigrp_neighbor.c \ eigrpd/eigrp_network.c \ + eigrpd/eigrp_northbound.c \ eigrpd/eigrp_packet.c \ eigrpd/eigrp_query.c \ eigrpd/eigrp_reply.c \ @@ -47,6 +50,9 @@ eigrpdheader_HEADERS = \ eigrpd/eigrp_vty_clippy.c: $(CLIPPY_DEPS) eigrpd/eigrp_vty.$(OBJEXT): eigrpd/eigrp_vty_clippy.c +eigrpd/eigrp_cli_clippy.c: $(CLIPPY_DEPS) +eigrpd/eigrp_cli.$(OBJEXT): eigrpd/eigrp_cli_clippy.c + noinst_HEADERS += \ eigrpd/eigrp_const.h \ eigrpd/eigrp_errors.h \ @@ -64,5 +70,9 @@ noinst_HEADERS += \ eigrpd/eigrp_zebra.h \ # end +nodist_eigrpd_eigrpd_SOURCES = \ + yang/frr-eigrpd.yang.c \ + # end + eigrpd_eigrpd_SOURCES = eigrpd/eigrp_main.c eigrpd_eigrpd_LDADD = eigrpd/libeigrp.a lib/libfrr.la $(LIBCAP) diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index 3ad8278e10..a7f491e87d 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -117,7 +117,8 @@ int dotformat2buff(uint8_t *buff, const char *dotted) break; } - if ((isxdigit((int)*pos)) && (isxdigit((int)*(pos + 1)))) { + if ((isxdigit((unsigned char)*pos)) && + (isxdigit((unsigned char)*(pos + 1)))) { memcpy(number, pos, 2); pos += 2; } else { @@ -157,7 +158,8 @@ int sysid2buff(uint8_t *buff, const char *dotted) pos++; continue; } - if ((isxdigit((int)*pos)) && (isxdigit((int)*(pos + 1)))) { + if ((isxdigit((unsigned char)*pos)) && + (isxdigit((unsigned char)*(pos + 1)))) { memcpy(number, pos, 2); pos += 2; } else { diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 6edfeb4c97..488dfedae4 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -1478,7 +1478,7 @@ static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context, bool sane = true; for (uint8_t i = 0; i < tlv_len; i++) { if ((unsigned char)tlvs->hostname[i] > 127 - || !isprint((int)tlvs->hostname[i])) { + || !isprint((unsigned char)tlvs->hostname[i])) { sane = false; tlvs->hostname[i] = '?'; } diff --git a/ldpd/lde.c b/ldpd/lde.c index 0ddf4f07d9..ac680b47a9 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -1654,6 +1654,19 @@ lde_del_label_chunk(void *val) } static int +lde_release_label_chunk(uint32_t start, uint32_t end) +{ + int ret; + + ret = lm_release_label_chunk(zclient_sync, start, end); + if (ret < 0) { + log_warnx("Error releasing label chunk!"); + return (-1); + } + return (0); +} + +static int lde_get_label_chunk(void) { int ret; @@ -1709,6 +1722,32 @@ on_get_label_chunk_response(uint32_t start, uint32_t end) current_label_chunk = listtail(label_chunk_list); } +void +lde_free_label(uint32_t label) +{ + struct listnode *node; + struct label_chunk *label_chunk; + uint64_t pos; + + for (ALL_LIST_ELEMENTS_RO(label_chunk_list, node, label_chunk)) { + if (label <= label_chunk->end && label >= label_chunk->start) { + pos = 1ULL << (label - label_chunk->start); + label_chunk->used_mask &= ~pos; + /* if nobody is using this chunk and it's not current_label_chunk, then free it */ + if (!label_chunk->used_mask && (current_label_chunk != node)) { + if (lde_release_label_chunk(label_chunk->start, label_chunk->end) != 0) + log_warnx("%s: Error releasing label chunk!", __func__); + else { + listnode_delete(label_chunk_list, label_chunk); + lde_del_label_chunk(label_chunk); + } + } + break; + } + } + return; +} + static uint32_t lde_get_next_label(void) { diff --git a/ldpd/lde.h b/ldpd/lde.h index 94077d1631..0a7d0a58fe 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -147,6 +147,7 @@ void lde_imsg_compose_parent_sync(int, pid_t, void *, uint16_t); int lde_imsg_compose_ldpe(int, uint32_t, pid_t, void *, uint16_t); int lde_acl_check(char *, int, union ldpd_addr *, uint8_t); uint32_t lde_update_label(struct fec_node *); +void lde_free_label(uint32_t label); void lde_send_change_klabel(struct fec_node *, struct fec_nh *); void lde_send_delete_klabel(struct fec_node *, struct fec_nh *); void lde_fec2map(struct fec *, struct map *); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 28e455c7a5..0957a5455e 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -919,6 +919,9 @@ lde_gc_timer(struct thread *thread) !RB_EMPTY(lde_map_head, &fn->upstream)) continue; + if (fn->local_label != NO_LABEL) + lde_free_label(fn->local_label); + fec_remove(&ft, &fn->fec); free(fn); count++; diff --git a/lib/atomlist.h b/lib/atomlist.h index e4098ccb54..621db6824f 100644 --- a/lib/atomlist.h +++ b/lib/atomlist.h @@ -135,8 +135,10 @@ macro_inline void prefix ## _add_tail(struct prefix##_head *h, type *item) \ macro_inline void prefix ## _del_hint(struct prefix##_head *h, type *item, \ _Atomic atomptr_t *hint) \ { atomlist_del_hint(&h->ah, &item->field.ai, hint); } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ -{ atomlist_del_hint(&h->ah, &item->field.ai, NULL); } \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ +{ atomlist_del_hint(&h->ah, &item->field.ai, NULL); \ + /* TODO: Return NULL if not found */ \ + return item; } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { char *p = (char *)atomlist_pop(&h->ah); \ return p ? (type *)(p - offsetof(type, field)) : NULL; } \ @@ -273,9 +275,11 @@ macro_inline void prefix ## _del_hint(struct prefix##_head *h, type *item, \ { \ atomsort_del_hint(&h->ah, &item->field.ai, hint); \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ atomsort_del_hint(&h->ah, &item->field.ai, NULL); \ + /* TODO: Return NULL if not found */ \ + return item; \ } \ macro_inline size_t prefix ## _count(struct prefix##_head *h) \ { \ diff --git a/lib/command.c b/lib/command.c index c8fbf22721..9dabc2af7e 100644 --- a/lib/command.c +++ b/lib/command.c @@ -89,7 +89,6 @@ const char *node_names[] = { "aaa", // AAA_NODE, "keychain", // KEYCHAIN_NODE, "keychain key", // KEYCHAIN_KEY_NODE, - "logical-router", // LOGICALROUTER_NODE, "static ip", // IP_NODE, "vrf", // VRF_NODE, "interface", // INTERFACE_NODE, @@ -290,7 +289,7 @@ vector cmd_make_strvec(const char *string) const char *copy = string; /* skip leading whitespace */ - while (isspace((int)*copy) && *copy != '\0') + while (isspace((unsigned char)*copy) && *copy != '\0') copy++; /* if the entire string was whitespace or a comment, return */ @@ -1456,7 +1455,6 @@ void cmd_exit(struct vty *vty) break; case INTERFACE_NODE: case PW_NODE: - case LOGICALROUTER_NODE: case VRF_NODE: case NH_GROUP_NODE: case ZEBRA_NODE: @@ -1936,7 +1934,7 @@ DEFUN(config_domainname, { struct cmd_token *word = argv[1]; - if (!isalpha((int)word->arg[0])) { + if (!isalpha((unsigned char)word->arg[0])) { vty_out(vty, "Please specify string starting with alphabet\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -1970,7 +1968,7 @@ DEFUN (config_hostname, { struct cmd_token *word = argv[1]; - if (!isalnum((int)word->arg[0])) { + if (!isalnum((unsigned char)word->arg[0])) { vty_out(vty, "Please specify string starting with alphabet or number\n"); return CMD_WARNING_CONFIG_FAILED; @@ -2018,7 +2016,7 @@ DEFUN (config_password, return CMD_SUCCESS; } - if (!isalnum((int)argv[idx_8]->arg[0])) { + if (!isalnum((unsigned char)argv[idx_8]->arg[0])) { vty_out(vty, "Please specify string starting with alphanumeric\n"); return CMD_WARNING_CONFIG_FAILED; @@ -2098,7 +2096,7 @@ DEFUN (config_enable_password, } } - if (!isalnum((int)argv[idx_8]->arg[0])) { + if (!isalnum((unsigned char)argv[idx_8]->arg[0])) { vty_out(vty, "Please specify string starting with alphanumeric\n"); return CMD_WARNING_CONFIG_FAILED; diff --git a/lib/command.h b/lib/command.h index 08d6128af4..8dc35a0fdc 100644 --- a/lib/command.h +++ b/lib/command.h @@ -98,7 +98,6 @@ enum node_type { AAA_NODE, /* AAA node. */ KEYCHAIN_NODE, /* Key-chain node. */ KEYCHAIN_KEY_NODE, /* Key-chain key node. */ - LOGICALROUTER_NODE, /* Logical-Router node. */ IP_NODE, /* Static ip route node. */ VRF_NODE, /* VRF mode node. */ INTERFACE_NODE, /* Interface mode node. */ diff --git a/lib/command_graph.c b/lib/command_graph.c index 4757fd951f..d30d9ab702 100644 --- a/lib/command_graph.c +++ b/lib/command_graph.c @@ -97,7 +97,7 @@ void cmd_token_varname_set(struct cmd_token *token, const char *varname) token->varname[i] = '_'; break; default: - token->varname[i] = tolower((int)varname[i]); + token->varname[i] = tolower((unsigned char)varname[i]); } token->varname[len] = '\0'; } diff --git a/lib/command_match.c b/lib/command_match.c index 9456e1585a..26d763849d 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -714,7 +714,7 @@ static enum match_type match_ipv4(const char *str) dots++; break; } - if (!isdigit((int)*str)) + if (!isdigit((unsigned char)*str)) return no_match; str++; @@ -765,7 +765,7 @@ static enum match_type match_ipv4_prefix(const char *str) break; } - if (!isdigit((int)*str)) + if (!isdigit((unsigned char)*str)) return no_match; str++; @@ -797,7 +797,7 @@ static enum match_type match_ipv4_prefix(const char *str) sp = str; while (*str != '\0') { - if (!isdigit((int)*str)) + if (!isdigit((unsigned char)*str)) return no_match; str++; diff --git a/lib/filter.c b/lib/filter.c index 14b89217b8..fe62ca1c13 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -273,7 +273,7 @@ static struct access_list *access_list_insert(afi_t afi, const char *name) /* If name is made by all digit character. We treat it as number. */ for (number = 0, i = 0; i < strlen(name); i++) { - if (isdigit((int)name[i])) + if (isdigit((unsigned char)name[i])) number = (number * 10) + (name[i] - '0'); else break; diff --git a/lib/frrstr.c b/lib/frrstr.c index c575c0b568..8a72a35af0 100644 --- a/lib/frrstr.c +++ b/lib/frrstr.c @@ -209,7 +209,7 @@ bool frrstr_endswith(const char *str, const char *suffix) int all_digit(const char *str) { for (; *str != '\0'; str++) - if (!isdigit((int)*str)) + if (!isdigit((unsigned char)*str)) return 0; return 1; } @@ -387,10 +387,8 @@ void vzlog(int priority, const char *format, va_list args) /* If it doesn't match on a filter, do nothing with the debug log */ if ((priority == LOG_DEBUG) && zlog_filter_count - && vzlog_filter(zl, &tsctl, proto_str, priority, msg)) { - pthread_mutex_unlock(&loglock); + && vzlog_filter(zl, &tsctl, proto_str, priority, msg)) goto out; - } /* call external hook */ hook_call(zebra_ext_log, priority, format, args); @@ -1267,6 +1265,7 @@ void zlog_hexdump(const void *mem, unsigned int len) size_t bs = ((len / 8) + 1) * 53 + 1; char buf[bs]; char *s = buf; + const unsigned char *memch = mem; memset(buf, 0, sizeof(buf)); @@ -1275,12 +1274,11 @@ void zlog_hexdump(const void *mem, unsigned int len) /* print offset */ if (i % columns == 0) s += snprintf(s, bs - (s - buf), - "0x%016lx: ", (unsigned long)mem + i); + "0x%016lx: ", (unsigned long)memch + i); /* print hex data */ if (i < len) - s += snprintf(s, bs - (s - buf), "%02x ", - 0xFF & ((const char *)mem)[i]); + s += snprintf(s, bs - (s - buf), "%02x ", memch[i]); /* end of block, just aligning for ASCII dump */ else @@ -1292,10 +1290,9 @@ void zlog_hexdump(const void *mem, unsigned int len) /* end of block not really printing */ if (j >= len) s += snprintf(s, bs - (s - buf), " "); - else if (isprint((int)((const char *)mem)[j])) - s += snprintf( - s, bs - (s - buf), "%c", - 0xFF & ((const char *)mem)[j]); + else if (isprint(memch[j])) + s += snprintf(s, bs - (s - buf), "%c", + memch[j]); else /* other char */ s += snprintf(s, bs - (s - buf), "."); } diff --git a/lib/logicalrouter.c b/lib/logicalrouter.c deleted file mode 100644 index da69ae5312..0000000000 --- a/lib/logicalrouter.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Logical Router functions. - * Copyright (C) 2018 6WIND S.A. - * - * 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> - -#include "ns.h" -#include "log.h" -#include "memory.h" - -#include "command.h" -#include "vty.h" -#include "logicalrouter.h" - -/* Comment that useless define to avoid compilation error - * in order to use it, one could provide the kind of NETNS to NS backend - * so that the allocation will match the logical router - * DEFINE_MTYPE_STATIC(LIB, LOGICALROUTER, "LogicalRouter Context") - */ -DEFINE_MTYPE_STATIC(LIB, LOGICALROUTER_NAME, "Logical Router Name") - -/* Logical Router node has no interface. */ -static struct cmd_node logicalrouter_node = {LOGICALROUTER_NODE, "", 1}; - -static int logicalrouter_backend; - -/* Get a NS. If not found, create one. */ -static struct ns *logicalrouter_get(ns_id_t ns_id) -{ - struct ns *ns; - - ns = ns_lookup(ns_id); - if (ns) - return (ns); - ns = ns_get_created(ns, NULL, ns_id); - return ns; -} - -static int logicalrouter_is_backend_netns(void) -{ - return (logicalrouter_backend == LOGICALROUTER_BACKEND_NETNS); -} - - -DEFUN_NOSH (logicalrouter, - logicalrouter_cmd, - "logical-router (1-65535) ns NAME", - "Enable a logical-router\n" - "Specify the logical-router indentifier\n" - "The Name Space\n" - "The file name in " NS_RUN_DIR ", or a full pathname\n") -{ - int idx_number = 1; - int idx_name = 3; - ns_id_t ns_id; - struct ns *ns = NULL; - char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg); - - if (!pathname) - return CMD_WARNING_CONFIG_FAILED; - - ns_id = strtoul(argv[idx_number]->arg, NULL, 10); - ns = logicalrouter_get(ns_id); - - if (ns->name && strcmp(ns->name, pathname) != 0) { - vty_out(vty, "NS %u is already configured with NETNS %s\n", - ns->ns_id, ns->name); - return CMD_WARNING; - } - - if (!ns->name) - ns->name = XSTRDUP(MTYPE_LOGICALROUTER_NAME, pathname); - - if (!ns_enable(ns, NULL)) { - vty_out(vty, "Can not associate NS %u with NETNS %s\n", - ns->ns_id, ns->name); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - -DEFUN (no_logicalrouter, - no_logicalrouter_cmd, - "no logical-router (1-65535) ns NAME", - NO_STR - "Enable a Logical-Router\n" - "Specify the Logical-Router identifier\n" - "The Name Space\n" - "The file name in " NS_RUN_DIR ", or a full pathname\n") -{ - int idx_number = 2; - int idx_name = 4; - ns_id_t ns_id; - struct ns *ns = NULL; - char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg); - - if (!pathname) - return CMD_WARNING_CONFIG_FAILED; - - ns_id = strtoul(argv[idx_number]->arg, NULL, 10); - ns = ns_lookup(ns_id); - - if (!ns) { - vty_out(vty, "NS %u is not found\n", ns_id); - return CMD_SUCCESS; - } - - if (ns->name && strcmp(ns->name, pathname) != 0) { - vty_out(vty, "Incorrect NETNS file name\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - ns_disable(ns); - - if (ns->name) { - XFREE(MTYPE_LOGICALROUTER_NAME, ns->name); - ns->name = NULL; - } - - return CMD_SUCCESS; -} - -/* Initialize NS module. */ -void logicalrouter_init(int (*writefunc)(struct vty *vty)) -{ - if (ns_have_netns() && logicalrouter_is_backend_netns()) { - /* Install LogicalRouter commands. */ - install_node(&logicalrouter_node, writefunc); - install_element(CONFIG_NODE, &logicalrouter_cmd); - install_element(CONFIG_NODE, &no_logicalrouter_cmd); - } -} - -void logicalrouter_terminate(void) -{ - ns_terminate(); -} - -void logicalrouter_configure_backend(int backend_netns) -{ - logicalrouter_backend = backend_netns; -} diff --git a/lib/logicalrouter.h b/lib/logicalrouter.h deleted file mode 100644 index d18832ef70..0000000000 --- a/lib/logicalrouter.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Logical Router related header. - * Copyright (C) 2018 6WIND S.A. - * - * 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 _ZEBRA_LOGICAL_ROUTER_H -#define _ZEBRA_LOGICAL_ROUTER_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Logical Router Backend defines */ -#define LOGICALROUTER_BACKEND_OFF 0 -#define LOGICALROUTER_BACKEND_NETNS 1 - -/* - * Logical Router initializer/destructor - */ -extern void logicalrouter_init(int (*writefunc)(struct vty *vty)); -extern void logicalrouter_terminate(void); - -/* used to configure backend for logical router - * Currently, the whole NETNS feature is exclusively shared - * between logical router and VRF backend NETNS - * However, when logical router feature will be available, - * one can think of having exclusivity only per NETNS - */ -extern void logicalrouter_configure_backend(int backend_netns); - -#ifdef __cplusplus -} -#endif - -#endif /*_ZEBRA_LOGICAL_ROUTER_H*/ diff --git a/lib/netns_other.c b/lib/netns_other.c index 4c7be05fab..b0aae4f8df 100644 --- a/lib/netns_other.c +++ b/lib/netns_other.c @@ -82,7 +82,7 @@ const char *ns_get_name(struct ns *ns) } /* only called from vrf ( when removing netns from vrf) - * or at VRF or logical router termination + * or at VRF termination */ void ns_delete(struct ns *ns) { @@ -41,7 +41,7 @@ typedef uint32_t ns_id_t; #ifdef HAVE_NETNS #define NS_DEFAULT_NAME "/proc/self/ns/net" #else /* !HAVE_NETNS */ -#define NS_DEFAULT_NAME "Default-logical-router" +#define NS_DEFAULT_NAME "default-netns" #endif /* HAVE_NETNS */ struct ns { @@ -82,10 +82,10 @@ extern struct ns_head ns_tree; * NS hooks */ -#define NS_NEW_HOOK 0 /* a new logical-router is just created */ -#define NS_DELETE_HOOK 1 /* a logical-router is to be deleted */ -#define NS_ENABLE_HOOK 2 /* a logical-router is ready to use */ -#define NS_DISABLE_HOOK 3 /* a logical-router is to be unusable */ +#define NS_NEW_HOOK 0 /* a new netns is just created */ +#define NS_DELETE_HOOK 1 /* a netns is to be deleted */ +#define NS_ENABLE_HOOK 2 /* a netns is ready to use */ +#define NS_DISABLE_HOOK 3 /* a netns is to be unusable */ /* * Add a specific hook ns module. @@ -128,7 +128,7 @@ extern void ns_walk_func(int (*func)(struct ns *)); extern const char *ns_get_name(struct ns *ns); /* only called from vrf ( when removing netns from vrf) - * or at VRF or logical router termination + * or at VRF termination */ extern void ns_delete(struct ns *ns); diff --git a/lib/plist.c b/lib/plist.c index 1ba8982499..64571a05b7 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -218,7 +218,7 @@ static struct prefix_list *prefix_list_insert(afi_t afi, int orf, /* If name is made by all digit character. We treat it as number. */ for (number = 0, i = 0; i < strlen(name); i++) { - if (isdigit((int)name[i])) + if (isdigit((unsigned char)name[i])) number = (number * 10) + (name[i] - '0'); else break; diff --git a/lib/pqueue.c b/lib/pqueue.c deleted file mode 100644 index 87b54a681a..0000000000 --- a/lib/pqueue.c +++ /dev/null @@ -1,185 +0,0 @@ -/* Priority queue functions. - * Copyright (C) 2003 Yasuhiro Ohara - * - * 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 <zebra.h> - -#include "memory.h" -#include "pqueue.h" - -DEFINE_MTYPE_STATIC(LIB, PQUEUE, "Priority queue") -DEFINE_MTYPE_STATIC(LIB, PQUEUE_DATA, "Priority queue data") - -/* priority queue using heap sort */ - -/* pqueue->cmp() controls the order of sorting (i.e, ascending or - descending). If you want the left node to move upper of the heap - binary tree, make cmp() to return less than 0. for example, if cmp - (10, 20) returns -1, the sorting is ascending order. if cmp (10, - 20) returns 1, the sorting is descending order. if cmp (10, 20) - returns 0, this library does not do sorting (which will not be what - you want). To be brief, if the contents of cmp_func (left, right) - is left - right, dequeue () returns the smallest node. Otherwise - (if the contents is right - left), dequeue () returns the largest - node. */ - -#define DATA_SIZE (sizeof (void *)) -#define PARENT_OF(x) ((x - 1) / 2) -#define LEFT_OF(x) (2 * x + 1) -#define RIGHT_OF(x) (2 * x + 2) -#define HAVE_CHILD(x,q) (x < (q)->size / 2) - -void trickle_up(int index, struct pqueue *queue) -{ - void *tmp; - - /* Save current node as tmp node. */ - tmp = queue->array[index]; - - /* Continue until the node reaches top or the place where the parent - node should be upper than the tmp node. */ - while (index > 0 - && (*queue->cmp)(tmp, queue->array[PARENT_OF(index)]) < 0) { - /* actually trickle up */ - queue->array[index] = queue->array[PARENT_OF(index)]; - if (queue->update != NULL) - (*queue->update)(queue->array[index], index); - index = PARENT_OF(index); - } - - /* Restore the tmp node to appropriate place. */ - queue->array[index] = tmp; - if (queue->update != NULL) - (*queue->update)(tmp, index); -} - -void trickle_down(int index, struct pqueue *queue) -{ - void *tmp; - int which; - - /* Save current node as tmp node. */ - tmp = queue->array[index]; - - /* Continue until the node have at least one (left) child. */ - while (HAVE_CHILD(index, queue)) { - /* If right child exists, and if the right child is more proper - to be moved upper. */ - if (RIGHT_OF(index) < queue->size - && (*queue->cmp)(queue->array[LEFT_OF(index)], - queue->array[RIGHT_OF(index)]) - > 0) - which = RIGHT_OF(index); - else - which = LEFT_OF(index); - - /* If the tmp node should be upper than the child, break. */ - if ((*queue->cmp)(queue->array[which], tmp) > 0) - break; - - /* Actually trickle down the tmp node. */ - queue->array[index] = queue->array[which]; - if (queue->update != NULL) - (*queue->update)(queue->array[index], index); - index = which; - } - - /* Restore the tmp node to appropriate place. */ - queue->array[index] = tmp; - if (queue->update != NULL) - (*queue->update)(tmp, index); -} - -struct pqueue *pqueue_create(void) -{ - struct pqueue *queue; - - queue = XCALLOC(MTYPE_PQUEUE, sizeof(struct pqueue)); - - queue->array = - XCALLOC(MTYPE_PQUEUE_DATA, DATA_SIZE * PQUEUE_INIT_ARRAYSIZE); - queue->array_size = PQUEUE_INIT_ARRAYSIZE; - - /* By default we want nothing to happen when a node changes. */ - queue->update = NULL; - return queue; -} - -void pqueue_delete(struct pqueue *queue) -{ - XFREE(MTYPE_PQUEUE_DATA, queue->array); - XFREE(MTYPE_PQUEUE, queue); -} - -static int pqueue_expand(struct pqueue *queue) -{ - void **newarray; - - newarray = - XCALLOC(MTYPE_PQUEUE_DATA, queue->array_size * DATA_SIZE * 2); - - memcpy(newarray, queue->array, queue->array_size * DATA_SIZE); - - XFREE(MTYPE_PQUEUE_DATA, queue->array); - queue->array = newarray; - queue->array_size *= 2; - - return 1; -} - -void pqueue_enqueue(void *data, struct pqueue *queue) -{ - if (queue->size + 2 >= queue->array_size && !pqueue_expand(queue)) - return; - - queue->array[queue->size] = data; - if (queue->update != NULL) - (*queue->update)(data, queue->size); - trickle_up(queue->size, queue); - queue->size++; -} - -void *pqueue_dequeue(struct pqueue *queue) -{ - void *data = queue->array[0]; - queue->array[0] = queue->array[--queue->size]; - trickle_down(0, queue); - return data; -} - -void pqueue_remove_at(int index, struct pqueue *queue) -{ - queue->array[index] = queue->array[--queue->size]; - - if (index > 0 - && (*queue->cmp)(queue->array[index], - queue->array[PARENT_OF(index)]) - < 0) { - trickle_up(index, queue); - } else { - trickle_down(index, queue); - } -} - -void pqueue_remove(void *data, struct pqueue *queue) -{ - for (int i = 0; i < queue->size; i++) - if (queue->array[i] == data) - pqueue_remove_at(i, queue); -} diff --git a/lib/pqueue.h b/lib/pqueue.h deleted file mode 100644 index 032ee9db4c..0000000000 --- a/lib/pqueue.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Priority queue functions. - * Copyright (C) 2003 Yasuhiro Ohara - * - * 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_PQUEUE_H -#define _ZEBRA_PQUEUE_H - -#ifdef __cplusplus -extern "C" { -#endif - -struct pqueue { - void **array; - int array_size; - int size; - - int (*cmp)(void *, void *); - void (*update)(void *node, int actual_position); -}; - -#define PQUEUE_INIT_ARRAYSIZE 32 - -extern struct pqueue *pqueue_create(void); -extern void pqueue_delete(struct pqueue *queue); - -extern void pqueue_enqueue(void *data, struct pqueue *queue); -extern void *pqueue_dequeue(struct pqueue *queue); -extern void pqueue_remove_at(int index, struct pqueue *queue); -extern void pqueue_remove(void *data, struct pqueue *queue); - -extern void trickle_down(int index, struct pqueue *queue); -extern void trickle_up(int index, struct pqueue *queue); - -#ifdef __cplusplus -} -#endif - -#endif /* _ZEBRA_PQUEUE_H */ diff --git a/lib/ptm_lib.c b/lib/ptm_lib.c index 7f868beda4..a2ce9a0e2f 100644 --- a/lib/ptm_lib.c +++ b/lib/ptm_lib.c @@ -125,7 +125,7 @@ static int _ptm_lib_decode_header(csv_t *csv, int *msglen, int *version, } /* remove leading spaces */ for (i = j = 0; i < csv_field_len(fld); i++) { - if (!isspace((int)hdr[i])) { + if (!isspace((unsigned char)hdr[i])) { client_name[j] = hdr[i]; j++; } diff --git a/lib/subdir.am b/lib/subdir.am index becc80c3f3..2be7537bcc 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -62,7 +62,6 @@ lib_libfrr_la_SOURCES = \ lib/openbsd-tree.c \ lib/pid_output.c \ lib/plist.c \ - lib/pqueue.c \ lib/prefix.c \ lib/privs.c \ lib/ptm_lib.c \ @@ -96,7 +95,6 @@ lib_libfrr_la_SOURCES = \ lib/yang_translator.c \ lib/yang_wrappers.c \ lib/zclient.c \ - lib/logicalrouter.c \ lib/printf/printf-pos.c \ lib/printf/vfprintf.c \ lib/printf/glue.c \ @@ -114,7 +112,6 @@ vtysh_scan += \ $(top_srcdir)/lib/if.c \ $(top_srcdir)/lib/if_rmap.c \ $(top_srcdir)/lib/keychain.c \ - $(top_srcdir)/lib/logicalrouter.c \ $(top_srcdir)/lib/nexthop_group.c \ $(top_srcdir)/lib/plist.c \ $(top_srcdir)/lib/routemap.c \ @@ -202,7 +199,6 @@ pkginclude_HEADERS += \ lib/openbsd-queue.h \ lib/openbsd-tree.h \ lib/plist.h \ - lib/pqueue.h \ lib/prefix.h \ lib/printfrr.h \ lib/privs.h \ @@ -243,7 +239,6 @@ pkginclude_HEADERS += \ lib/zassert.h \ lib/zclient.h \ lib/zebra.h \ - lib/logicalrouter.h \ lib/pbr.h \ # end diff --git a/lib/thread.c b/lib/thread.c index 0436f31c3d..5756ebc1f9 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -28,7 +28,6 @@ #include "frrcu.h" #include "log.h" #include "hash.h" -#include "pqueue.h" #include "command.h" #include "sigevent.h" #include "network.h" @@ -43,6 +42,22 @@ DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats") DECLARE_LIST(thread_list, struct thread, threaditem) +static int thread_timer_cmp(const struct thread *a, const struct thread *b) +{ + if (a->u.sands.tv_sec < b->u.sands.tv_sec) + return -1; + if (a->u.sands.tv_sec > b->u.sands.tv_sec) + return 1; + if (a->u.sands.tv_usec < b->u.sands.tv_usec) + return -1; + if (a->u.sands.tv_usec > b->u.sands.tv_usec) + return 1; + return 0; +} + +DECLARE_HEAP(thread_timer_list, struct thread, timeritem, + thread_timer_cmp) + #if defined(__APPLE__) #include <mach/mach.h> #include <mach/mach_time.h> @@ -402,25 +417,6 @@ void thread_cmd_init(void) /* CLI end ------------------------------------------------------------------ */ -static int thread_timer_cmp(void *a, void *b) -{ - struct thread *thread_a = a; - struct thread *thread_b = b; - - if (timercmp(&thread_a->u.sands, &thread_b->u.sands, <)) - return -1; - if (timercmp(&thread_a->u.sands, &thread_b->u.sands, >)) - return 1; - return 0; -} - -static void thread_timer_update(void *node, int actual_position) -{ - struct thread *thread = node; - - thread->index = actual_position; -} - static void cancelreq_del(void *cr) { XFREE(MTYPE_TMP, cr); @@ -465,11 +461,7 @@ struct thread_master *thread_master_create(const char *name) thread_list_init(&rv->event); thread_list_init(&rv->ready); thread_list_init(&rv->unuse); - - /* Initialize the timer queues */ - rv->timer = pqueue_create(); - rv->timer->cmp = thread_timer_cmp; - rv->timer->update = thread_timer_update; + thread_timer_list_init(&rv->timer); /* Initialize thread_fetch() settings */ rv->spin = true; @@ -567,16 +559,6 @@ static void thread_array_free(struct thread_master *m, XFREE(MTYPE_THREAD_POLL, thread_array); } -static void thread_queue_free(struct thread_master *m, struct pqueue *queue) -{ - int i; - - for (i = 0; i < queue->size; i++) - thread_free(m, queue->array[i]); - - pqueue_delete(queue); -} - /* * thread_master_free_unused * @@ -599,6 +581,8 @@ void thread_master_free_unused(struct thread_master *m) /* Stop thread scheduler. */ void thread_master_free(struct thread_master *m) { + struct thread *t; + pthread_mutex_lock(&masters_mtx); { listnode_delete(masters, m); @@ -610,7 +594,8 @@ void thread_master_free(struct thread_master *m) thread_array_free(m, m->read); thread_array_free(m, m->write); - thread_queue_free(m, m->timer); + while ((t = thread_timer_list_pop(&m->timer))) + thread_free(m, t); thread_list_free(m, &m->event); thread_list_free(m, &m->ready); thread_list_free(m, &m->unuse); @@ -684,7 +669,6 @@ static struct thread *thread_get(struct thread_master *m, uint8_t type, thread->add_type = type; thread->master = m; thread->arg = arg; - thread->index = -1; thread->yield = THREAD_YIELD_TIME_SLOT; /* default */ thread->ref = NULL; @@ -860,7 +844,6 @@ funcname_thread_add_timer_timeval(struct thread_master *m, struct thread **t_ptr, debugargdef) { struct thread *thread; - struct pqueue *queue; assert(m != NULL); @@ -876,7 +859,6 @@ funcname_thread_add_timer_timeval(struct thread_master *m, return NULL; } - queue = m->timer; thread = thread_get(m, type, func, arg, debugargpass); pthread_mutex_lock(&thread->mtx); @@ -884,7 +866,7 @@ funcname_thread_add_timer_timeval(struct thread_master *m, monotime(&thread->u.sands); timeradd(&thread->u.sands, time_relative, &thread->u.sands); - pqueue_enqueue(thread, queue); + thread_timer_list_add(&m->timer, thread); if (t_ptr) { *t_ptr = thread; thread->ref = t_ptr; @@ -1061,7 +1043,6 @@ static void thread_cancel_rw(struct thread_master *master, int fd, short state) static void do_thread_cancel(struct thread_master *master) { struct thread_list_head *list = NULL; - struct pqueue *queue = NULL; struct thread **thread_array = NULL; struct thread *thread; @@ -1117,7 +1098,7 @@ static void do_thread_cancel(struct thread_master *master) thread_array = master->write; break; case THREAD_TIMER: - queue = master->timer; + thread_timer_list_del(&master->timer, thread); break; case THREAD_EVENT: list = &master->event; @@ -1130,16 +1111,10 @@ static void do_thread_cancel(struct thread_master *master) break; } - if (queue) { - assert(thread->index >= 0); - assert(thread == queue->array[thread->index]); - pqueue_remove_at(thread->index, queue); - } else if (list) { + if (list) { thread_list_del(list, thread); } else if (thread_array) { thread_array[thread->u.fd] = NULL; - } else { - assert(!"Thread should be either in queue or list or array!"); } if (thread->ref) @@ -1257,15 +1232,15 @@ void thread_cancel_async(struct thread_master *master, struct thread **thread, } /* ------------------------------------------------------------------------- */ -static struct timeval *thread_timer_wait(struct pqueue *queue, +static struct timeval *thread_timer_wait(struct thread_timer_list_head *timers, struct timeval *timer_val) { - if (queue->size) { - struct thread *next_timer = queue->array[0]; - monotime_until(&next_timer->u.sands, timer_val); - return timer_val; - } - return NULL; + if (!thread_timer_list_count(timers)) + return NULL; + + struct thread *next_timer = thread_timer_list_first(timers); + monotime_until(&next_timer->u.sands, timer_val); + return timer_val; } static struct thread *thread_run(struct thread_master *m, struct thread *thread, @@ -1375,17 +1350,16 @@ static void thread_process_io(struct thread_master *m, unsigned int num) } /* Add all timers that have popped to the ready list. */ -static unsigned int thread_process_timers(struct pqueue *queue, +static unsigned int thread_process_timers(struct thread_timer_list_head *timers, struct timeval *timenow) { struct thread *thread; unsigned int ready = 0; - while (queue->size) { - thread = queue->array[0]; + while ((thread = thread_timer_list_first(timers))) { if (timercmp(timenow, &thread->u.sands, <)) return ready; - pqueue_dequeue(queue); + thread_timer_list_pop(timers); thread->type = THREAD_READY; thread_list_add_tail(&thread->master->ready, thread); ready++; @@ -1467,7 +1441,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch) * once per loop to avoid starvation by events */ if (!thread_list_count(&m->ready)) - tw = thread_timer_wait(m->timer, &tv); + tw = thread_timer_wait(&m->timer, &tv); if (thread_list_count(&m->ready) || (tw && !timercmp(tw, &zerotime, >))) @@ -1512,7 +1486,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch) /* Post timers to ready queue. */ monotime(&now); - thread_process_timers(m->timer, &now); + thread_process_timers(&m->timer, &now); /* Post I/O to ready queue. */ if (num > 0) diff --git a/lib/thread.h b/lib/thread.h index 7897265120..412a4d93bf 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -41,8 +41,7 @@ struct rusage_t { #define GETRUSAGE(X) thread_getrusage(X) PREDECL_LIST(thread_list) - -struct pqueue; +PREDECL_HEAP(thread_timer_list) struct fd_handler { /* number of pfd that fit in the allocated space of pfds. This is a @@ -73,7 +72,7 @@ struct thread_master { struct thread **read; struct thread **write; - struct pqueue *timer; + struct thread_timer_list_head timer; struct thread_list_head event, ready, unuse; struct list *cancel_req; bool canceled; @@ -95,6 +94,7 @@ struct thread { uint8_t type; /* thread type */ uint8_t add_type; /* thread type */ struct thread_list_item threaditem; + struct thread_timer_list_item timeritem; struct thread **ref; /* external reference (if given) */ struct thread_master *master; /* pointer to the struct thread_master */ int (*func)(struct thread *); /* event function */ @@ -104,7 +104,6 @@ struct thread { int fd; /* file descriptor in case of r/w */ struct timeval sands; /* rest of time sands value. */ } u; - int index; /* queue position for timers */ struct timeval real; struct cpu_thread_history *hist; /* cache pointer to cpu_history */ unsigned long yield; /* yield time in microseconds */ diff --git a/lib/typerb.c b/lib/typerb.c index 4c48d6434f..3886fc678e 100644 --- a/lib/typerb.c +++ b/lib/typerb.c @@ -333,9 +333,10 @@ color: return (old); } -void typed_rb_remove(struct rbt_tree *rbt, struct rb_entry *rbe) +struct typed_rb_entry *typed_rb_remove(struct rbt_tree *rbt, + struct rb_entry *rbe) { - rbe_remove(rbt, rbe); + return rbe_remove(rbt, rbe); } struct typed_rb_entry *typed_rb_insert(struct rbt_tree *rbt, diff --git a/lib/typerb.h b/lib/typerb.h index ce8446f853..2d7b0ba637 100644 --- a/lib/typerb.h +++ b/lib/typerb.h @@ -38,29 +38,30 @@ struct typed_rb_root { size_t count; }; -struct typed_rb_entry *typed_rb_insert(struct typed_rb_root *, +struct typed_rb_entry *typed_rb_insert(struct typed_rb_root *rbt, struct typed_rb_entry *rbe, int (*cmpfn)( const struct typed_rb_entry *a, const struct typed_rb_entry *b)); -void typed_rb_remove(struct typed_rb_root *, struct typed_rb_entry *rbe); -struct typed_rb_entry *typed_rb_find(struct typed_rb_root *, +struct typed_rb_entry *typed_rb_remove(struct typed_rb_root *rbt, + struct typed_rb_entry *rbe); +struct typed_rb_entry *typed_rb_find(struct typed_rb_root *rbt, const struct typed_rb_entry *rbe, int (*cmpfn)( const struct typed_rb_entry *a, const struct typed_rb_entry *b)); -struct typed_rb_entry *typed_rb_find_gteq(struct typed_rb_root *, +struct typed_rb_entry *typed_rb_find_gteq(struct typed_rb_root *rbt, const struct typed_rb_entry *rbe, int (*cmpfn)( const struct typed_rb_entry *a, const struct typed_rb_entry *b)); -struct typed_rb_entry *typed_rb_find_lt(struct typed_rb_root *, +struct typed_rb_entry *typed_rb_find_lt(struct typed_rb_root *rbt, const struct typed_rb_entry *rbe, int (*cmpfn)( const struct typed_rb_entry *a, const struct typed_rb_entry *b)); -struct typed_rb_entry *typed_rb_min(struct typed_rb_root *); -struct typed_rb_entry *typed_rb_next(struct typed_rb_entry *); +struct typed_rb_entry *typed_rb_min(struct typed_rb_root *rbt); +struct typed_rb_entry *typed_rb_next(struct typed_rb_entry *rbe); #define _PREDECL_RBTREE(prefix) \ struct prefix ## _head { struct typed_rb_root rr; }; \ @@ -99,9 +100,11 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \ re = typed_rb_find_lt(&h->rr, &item->field.re, cmpfn_nuq); \ return container_of_null(re, type, field.re); \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ - typed_rb_remove(&h->rr, &item->field.re); \ + struct typed_rb_entry *re; \ + re = typed_rb_remove(&h->rr, &item->field.re); \ + return container_of_null(re, type, field.re); \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -130,7 +133,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ re = item ? typed_rb_next(&item->field.re) : NULL; \ return container_of_null(re, type, field.re); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->rr.count; \ } \ diff --git a/lib/typesafe.c b/lib/typesafe.c index f2ca67b7c6..7e5939d5b3 100644 --- a/lib/typesafe.c +++ b/lib/typesafe.c @@ -341,13 +341,14 @@ struct sskip_item *typesafe_skiplist_find_lt(struct sskip_head *head, return best; } -void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item, - int (*cmpfn)(const struct sskip_item *a, - const struct sskip_item *b)) +struct sskip_item *typesafe_skiplist_del( + struct sskip_head *head, struct sskip_item *item, + int (*cmpfn)(const struct sskip_item *a, const struct sskip_item *b)) { size_t level = SKIPLIST_MAXDEPTH; struct sskip_item *prev = &head->hitem, *next; int cmpval; + bool found = false; while (level) { next = sl_level_get(prev, level - 1); @@ -359,6 +360,7 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item, sl_level_set(prev, level - 1, sl_level_get(item, level - 1)); level--; + found = true; continue; } cmpval = cmpfn(next, item); @@ -369,6 +371,9 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item, level--; } + if (!found) + return NULL; + /* TBD: assert when trying to remove non-existing item? */ head->count--; @@ -379,6 +384,8 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item, XFREE(MTYPE_SKIPLIST_OFLOW, oflow); } memset(item, 0, sizeof(*item)); + + return item; } struct sskip_item *typesafe_skiplist_pop(struct sskip_head *head) diff --git a/lib/typesafe.h b/lib/typesafe.h index ee244c78ae..c30d73d1b3 100644 --- a/lib/typesafe.h +++ b/lib/typesafe.h @@ -109,17 +109,18 @@ macro_inline void prefix ## _add_after(struct prefix##_head *h, \ typesafe_list_add(&h->sh, nextp, &item->field.si); \ } \ /* TODO: del_hint */ \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ struct slist_item **iter = &h->sh.first; \ while (*iter && *iter != &item->field.si) \ iter = &(*iter)->next; \ if (!*iter) \ - return; \ + return NULL; \ h->sh.count--; \ *iter = item->field.si.next; \ if (!item->field.si.next) \ h->sh.last_next = iter; \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -149,7 +150,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ sitem = &item->field.si; \ return container_of_null(sitem->next, type, field.si); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->sh.count; \ } \ @@ -212,13 +213,14 @@ macro_inline void prefix ## _add_after(struct prefix##_head *h, \ prev = after ? &after->field.di : &h->dh.hitem; \ typesafe_dlist_add(&h->dh, prev, &item->field.di); \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ struct dlist_item *ditem = &item->field.di; \ ditem->prev->next = ditem->next; \ ditem->next->prev = ditem->prev; \ h->dh.count--; \ ditem->prev = ditem->next = NULL; \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -250,7 +252,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ return NULL; \ return prefix ## _next(h, item); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->dh.count; \ } \ @@ -308,7 +310,7 @@ macro_inline type *prefix ## _add(struct prefix##_head *h, type *item) \ h->hh.count++; \ return NULL; \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ struct heap_item *other; \ uint32_t index = item->field.hi.index; \ @@ -321,6 +323,7 @@ macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ typesafe_heap_pushdown(&h->hh, index, other, prefix ## __cmp); \ if (HEAP_RESIZE_TRESH_DN(h)) \ typesafe_heap_resize(&h->hh, false); \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -354,7 +357,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ return NULL; \ return prefix ## _next(h, item); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->hh.count; \ } \ @@ -449,15 +452,16 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \ return container_of_null(prev, type, field.si); \ } \ /* TODO: del_hint */ \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ struct ssort_item **iter = &h->sh.first; \ while (*iter && *iter != &item->field.si) \ iter = &(*iter)->next; \ if (!*iter) \ - return; \ + return NULL; \ h->sh.count--; \ *iter = item->field.si.next; \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -485,7 +489,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ sitem = &item->field.si; \ return container_of_null(sitem->next, type, field.si); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->sh.count; \ } \ @@ -617,10 +621,10 @@ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \ } \ return NULL; \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ if (!h->hh.tabshift) \ - return; \ + return NULL; \ uint32_t hval = item->field.hi.hashval, hbits = HASH_KEY(h->hh, hval); \ struct thash_item **np = &h->hh.entries[hbits]; \ while (*np && (*np)->hashval < hval) \ @@ -628,12 +632,13 @@ macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ while (*np && *np != &item->field.hi && (*np)->hashval == hval) \ np = &(*np)->next; \ if (*np != &item->field.hi) \ - return; \ + return NULL; \ *np = item->field.hi.next; \ item->field.hi.next = NULL; \ h->hh.count--; \ if (HASH_SHRINK_THRESHOLD(h->hh)) \ typesafe_hash_shrink(&h->hh); \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -675,7 +680,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ return NULL; \ return prefix ## _next(h, item); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->hh.count; \ } \ @@ -751,9 +756,11 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \ &item->field.si, cmpfn_nuq); \ return container_of_null(sitem, type, field.si); \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ - typesafe_skiplist_del(&h->sh, &item->field.si, cmpfn_uq); \ + struct sskip_item *sitem = typesafe_skiplist_del(&h->sh, \ + &item->field.si, cmpfn_uq); \ + return container_of_null(sitem, type, field.si); \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -776,7 +783,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ next = item ? item->field.si.next[0] : NULL; \ return container_of_null(next, type, field.si); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->sh.count; \ } \ @@ -848,8 +855,8 @@ extern struct sskip_item *typesafe_skiplist_find_lt(struct sskip_head *head, const struct sskip_item *item, int (*cmpfn)( const struct sskip_item *a, const struct sskip_item *b)); -extern void typesafe_skiplist_del(struct sskip_head *head, - struct sskip_item *item, int (*cmpfn)( +extern struct sskip_item *typesafe_skiplist_del( + struct sskip_head *head, struct sskip_item *item, int (*cmpfn)( const struct sskip_item *a, const struct sskip_item *b)); extern struct sskip_item *typesafe_skiplist_pop(struct sskip_head *head); @@ -337,7 +337,8 @@ void vty_hello(struct vty *vty) /* work backwards to ignore trailling isspace() */ for (s = buf + strlen(buf); - (s > buf) && isspace((int)*(s - 1)); s--) + (s > buf) && isspace((unsigned char)s[-1]); + s--) ; *s = '\0'; vty_out(vty, "%s\n", buf); @@ -468,7 +469,7 @@ static int vty_command(struct vty *vty, char *buf) cp = buf; if (cp != NULL) { /* Skip white spaces. */ - while (isspace((int)*cp) && *cp != '\0') + while (isspace((unsigned char)*cp) && *cp != '\0') cp++; } if (cp != NULL && *cp != '\0') { @@ -892,7 +893,7 @@ static void vty_complete_command(struct vty *vty) return; /* In case of 'help \t'. */ - if (isspace((int)vty->buf[vty->length - 1])) + if (isspace((unsigned char)vty->buf[vty->length - 1])) vector_set(vline, NULL); matched = cmd_complete_command(vline, vty, &ret); @@ -1006,7 +1007,7 @@ static void vty_describe_command(struct vty *vty) if (vline == NULL) { vline = vector_init(1); vector_set(vline, NULL); - } else if (isspace((int)vty->buf[vty->length - 1])) + } else if (isspace((unsigned char)vty->buf[vty->length - 1])) vector_set(vline, NULL); describe = cmd_describe_command(vline, vty, &ret); diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 6d1e44996e..1d85a04984 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -83,6 +83,9 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, struct as_external_lsa *al; struct prefix_ipv4 p; struct route_node *rn; + struct list *ext_list; + struct listnode *node; + struct ospf_external *ext; int type; al = (struct as_external_lsa *)lsa->data; @@ -91,7 +94,7 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, p.prefix = lsa->data->id; p.prefixlen = ip_masklen(al->mask); - for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { int redist_on = 0; redist_on = @@ -105,10 +108,6 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, ospf->vrf_id)); // Pending: check for MI above. if (redist_on) { - struct list *ext_list; - struct listnode *node; - struct ospf_external *ext; - ext_list = ospf->external[type]; if (!ext_list) continue; @@ -129,6 +128,22 @@ struct external_info *ospf_external_info_check(struct ospf *ospf, } } + if (is_prefix_default(&p) && ospf->external[DEFAULT_ROUTE]) { + ext_list = ospf->external[DEFAULT_ROUTE]; + + for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { + if (!ext->external_info) + continue; + + rn = route_node_lookup(ext->external_info, + (struct prefix *)&p); + if (!rn) + continue; + route_unlock_node(rn); + if (rn->info != NULL) + return (struct external_info *)rn->info; + } + } return NULL; } diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index bf46d22031..db41df7c47 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -1979,6 +1979,13 @@ struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf, */ + if (ospf->router_id.s_addr == 0) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("LSA[Type5:%pI4]: deferring AS-external-LSA origination, router ID is zero", + &ei->p.prefix); + return NULL; + } + /* Check the AS-external-LSA should be originated. */ if (!ospf_redistribute_check(ospf, ei, NULL)) return NULL; @@ -2019,50 +2026,6 @@ struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf, return new; } -/* Originate AS-external-LSA from external info with initial flag. */ -int ospf_external_lsa_originate_timer(struct thread *thread) -{ - struct ospf *ospf = THREAD_ARG(thread); - struct route_node *rn; - struct external_info *ei; - struct route_table *rt; - int type = THREAD_VAL(thread); - struct list *ext_list; - struct listnode *node; - struct ospf_external *ext; - - ospf->t_external_lsa = NULL; - - ext_list = ospf->external[type]; - if (!ext_list) - return 0; - - for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { - /* Originate As-external-LSA from all type of distribute source. - */ - rt = ext->external_info; - if (!rt) - continue; - - for (rn = route_top(rt); rn; rn = route_next(rn)) { - ei = rn->info; - - if (!ei) - continue; - - if (is_prefix_default((struct prefix_ipv4 *)&ei->p)) - continue; - - if (!ospf_external_lsa_originate(ospf, ei)) - flog_warn( - EC_OSPF_LSA_INSTALL_FAILURE, - "LSA: AS-external-LSA was not originated."); - } - } - - return 0; -} - static struct external_info *ospf_default_external_info(struct ospf *ospf) { int type; @@ -2102,31 +2065,52 @@ static struct external_info *ospf_default_external_info(struct ospf *ospf) return NULL; } -int ospf_default_originate_timer(struct thread *thread) +void ospf_external_lsa_rid_change(struct ospf *ospf) { - struct prefix_ipv4 p; - struct in_addr nexthop; struct external_info *ei; - struct ospf *ospf; + int type; - ospf = THREAD_ARG(thread); + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { + struct route_node *rn; + struct route_table *rt; + struct list *ext_list; + struct listnode *node; + struct ospf_external *ext; - p.family = AF_INET; - p.prefix.s_addr = 0; - p.prefixlen = 0; + ext_list = ospf->external[type]; + if (!ext_list) + continue; - if (ospf->default_originate == DEFAULT_ORIGINATE_ALWAYS) { - /* If there is no default route via redistribute, - then originate AS-external-LSA with nexthop 0 (self). */ - nexthop.s_addr = 0; - ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, p, 0, nexthop, - 0); - } + for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { + /* Originate As-external-LSA from all type of + * distribute source. + */ + rt = ext->external_info; + if (!rt) + continue; - if ((ei = ospf_default_external_info(ospf))) - ospf_external_lsa_originate(ospf, ei); + for (rn = route_top(rt); rn; rn = route_next(rn)) { + ei = rn->info; - return 0; + if (!ei) + continue; + + if (is_prefix_default( + (struct prefix_ipv4 *)&ei->p)) + continue; + + if (!ospf_external_lsa_originate(ospf, ei)) + flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, + "LSA: AS-external-LSA was not originated."); + } + } + } + + ei = ospf_default_external_info(ospf); + if (ei && !ospf_external_lsa_originate(ospf, ei)) { + flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, + "LSA: AS-external-LSA for default route was not originated."); + } } /* Flush any NSSA LSAs for given prefix */ @@ -2218,44 +2202,20 @@ void ospf_external_lsa_refresh_default(struct ospf *ospf) ei = ospf_default_external_info(ospf); lsa = ospf_external_info_find_lsa(ospf, &p); - if (ei) { - if (lsa) { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", - (void *)lsa); - ospf_external_lsa_refresh(ospf, lsa, ei, - LSA_REFRESH_FORCE); - } else { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "LSA[Type5:0.0.0.0]: Originate AS-external-LSA"); - ospf_external_lsa_originate(ospf, ei); - } - } else { - if (lsa) { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "LSA[Type5:0.0.0.0]: Flush AS-external-LSA"); - ospf_refresher_unregister_lsa(ospf, lsa); - ospf_lsa_flush_as(ospf, lsa); - } - } -} - -void ospf_default_originate_lsa_update(struct ospf *ospf) -{ - struct prefix_ipv4 p; - struct ospf_lsa *lsa; - - p.family = AF_INET; - p.prefixlen = 0; - p.prefix.s_addr = 0; - - lsa = ospf_external_info_find_lsa(ospf, &p); - if (lsa && IS_LSA_MAXAGE(lsa)) { - ospf_discard_from_db(ospf, lsa->lsdb, lsa); - ospf_lsdb_delete(lsa->lsdb, lsa); + if (ei && lsa) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", + (void *)lsa); + ospf_external_lsa_refresh(ospf, lsa, ei, LSA_REFRESH_FORCE); + } else if (ei && !lsa) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "LSA[Type5:0.0.0.0]: Originate AS-external-LSA"); + ospf_external_lsa_originate(ospf, ei); + } else if (lsa) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("LSA[Type5:0.0.0.0]: Flush AS-external-LSA"); + ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &p, 0); } } diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index 5e3dabc27a..4033659bff 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -275,8 +275,7 @@ extern struct in_addr ospf_get_ip_from_ifp(struct ospf_interface *); extern struct ospf_lsa *ospf_external_lsa_originate(struct ospf *, struct external_info *); -extern int ospf_external_lsa_originate_timer(struct thread *); -extern int ospf_default_originate_timer(struct thread *); +extern void ospf_external_lsa_rid_change(struct ospf *ospf); extern struct ospf_lsa *ospf_lsa_lookup(struct ospf *ospf, struct ospf_area *, uint32_t, struct in_addr, struct in_addr); @@ -301,7 +300,6 @@ extern int ospf_lsa_maxage_walker(struct thread *); extern struct ospf_lsa *ospf_lsa_refresh(struct ospf *, struct ospf_lsa *); extern void ospf_external_lsa_refresh_default(struct ospf *); -extern void ospf_default_originate_lsa_update(struct ospf *ospf); extern void ospf_external_lsa_refresh_type(struct ospf *, uint8_t, unsigned short, int); diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index f7c73fee33..ee27ec0942 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -616,8 +616,6 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) struct ospf_interface *oi = nbr->oi; struct ospf_area *vl_area = NULL; uint8_t old_state; - int x; - int force = 1; /* Preserve old status. */ old_state = nbr->state; @@ -664,32 +662,6 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area) if (++vl_area->full_vls == 1) ospf_schedule_abr_task(oi->ospf); - - /* kevinm: refresh any redistributions */ - for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++) { - struct list *red_list; - struct listnode *node; - struct ospf_redist *red; - - if (x == ZEBRA_ROUTE_OSPF6) - continue; - - red_list = oi->ospf->redist[x]; - if (!red_list) - continue; - - for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) - ospf_external_lsa_refresh_type( - oi->ospf, x, red->instance, - force); - } - /* XXX: Clearly some thing is wrong with refresh of - * external LSAs - * this added to hack around defaults not refreshing - * after a timer - * jump. - */ - ospf_external_lsa_refresh_default(oi->ospf); } else { oi->full_nbrs--; oi->area->full_nbrs--; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 98ddd6a79e..2564c6f330 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -8487,22 +8487,8 @@ DEFUN (no_ospf_default_information_originate, "Pointer to route-map entries\n") { VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - struct prefix_ipv4 p; - struct ospf_external *ext; struct ospf_redist *red; - p.family = AF_INET; - p.prefix.s_addr = 0; - p.prefixlen = 0; - - ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &p, 0); - - ext = ospf_external_lookup(ospf, DEFAULT_ROUTE, 0); - if (ext && EXTERNAL_INFO(ext)) { - ospf_external_info_delete(ospf, DEFAULT_ROUTE, 0, p); - ospf_external_del(ospf, DEFAULT_ROUTE, 0); - } - red = ospf_redist_lookup(ospf, DEFAULT_ROUTE, 0); if (!red) return CMD_SUCCESS; @@ -8510,7 +8496,8 @@ DEFUN (no_ospf_default_information_originate, ospf_routemap_unset(red); ospf_redist_del(ospf, DEFAULT_ROUTE, 0); - return ospf_redistribute_default_unset(ospf); + return ospf_redistribute_default_set(ospf, DEFAULT_ORIGINATE_NONE, + 0, 0); } DEFUN (ospf_default_metric, diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 951402f47f..47438b985e 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -744,10 +744,10 @@ int ospf_redistribute_unset(struct ospf *ospf, int type, int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype, int mvalue) { - struct ospf_external *ext; struct prefix_ipv4 p; struct in_addr nexthop; int cur_originate = ospf->default_originate; + const char *type_str = NULL; nexthop.s_addr = 0; p.family = AF_INET; @@ -756,41 +756,7 @@ int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype, ospf->default_originate = originate; - ospf_external_add(ospf, DEFAULT_ROUTE, 0); - - if (cur_originate == DEFAULT_ORIGINATE_NONE) { - /* First time configuration */ - if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug("Redistribute[DEFAULT]: Start Type[%d], Metric[%d]", - metric_type(ospf, DEFAULT_ROUTE, 0), - metric_value(ospf, DEFAULT_ROUTE, 0)); - - if (ospf->router_id.s_addr == 0) - ospf->external_origin |= (1 << DEFAULT_ROUTE); - if ((originate == DEFAULT_ORIGINATE_ALWAYS) - && (ospf->router_id.s_addr)) { - - /* always , so originate lsa even it doesn't - * exist in RIB. - */ - ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, - p, 0, nexthop, 0); - ospf_external_lsa_refresh_default(ospf); - - } else if (originate == DEFAULT_ORIGINATE_ZEBRA) { - /* Send msg to Zebra to validate default route - * existance. - */ - zclient_redistribute_default( - ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient, AFI_IP, - ospf->vrf_id); - } - - ospf_asbr_status_update(ospf, ++ospf->redistribute); - return CMD_SUCCESS; - - - } else if (originate == cur_originate) { + if (cur_originate == originate) { /* Refresh the lsa since metric might different */ if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) zlog_debug( @@ -800,67 +766,51 @@ int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype, metric_value(ospf, DEFAULT_ROUTE, 0)); ospf_external_lsa_refresh_default(ospf); - - } else { - /* "default-info originate always" configured now, - * where "default-info originate" configured previoulsly. - */ - if (originate == DEFAULT_ORIGINATE_ALWAYS) { - - zclient_redistribute_default( - ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, - zclient, AFI_IP, ospf->vrf_id); - /* here , ex-info should be added since ex-info might - * have not updated earlier if def route is not exist. - * If ex-iinfo ex-info already exist , it will return - * smoothly. - */ - ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, - p, 0, nexthop, 0); - ospf_external_lsa_refresh_default(ospf); - - } else { - /* "default-info originate" configured now,where - * "default-info originate always" configured - * previoulsy. - */ - - ospf_external_lsa_flush(ospf, DEFAULT_ROUTE, &p, 0); - - ext = ospf_external_lookup(ospf, DEFAULT_ROUTE, 0); - if (ext && EXTERNAL_INFO(ext)) - ospf_external_info_delete(ospf, - DEFAULT_ROUTE, 0, p); - - zclient_redistribute_default( - ZEBRA_REDISTRIBUTE_DEFAULT_ADD, - zclient, AFI_IP, ospf->vrf_id); - } + return CMD_SUCCESS; } - return CMD_SUCCESS; -} -int ospf_redistribute_default_unset(struct ospf *ospf) -{ - if (ospf->default_originate == DEFAULT_ORIGINATE_ZEBRA) { - if (!ospf_is_type_redistributed(ospf, DEFAULT_ROUTE, 0)) - return CMD_SUCCESS; + switch (cur_originate) { + case DEFAULT_ORIGINATE_NONE: + break; + case DEFAULT_ORIGINATE_ZEBRA: zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient, AFI_IP, ospf->vrf_id); + ospf->redistribute--; + break; + case DEFAULT_ORIGINATE_ALWAYS: + ospf_external_info_delete(ospf, DEFAULT_ROUTE, 0, p); + ospf_external_del(ospf, DEFAULT_ROUTE, 0); + ospf->redistribute--; + break; } - ospf->default_originate = DEFAULT_ORIGINATE_NONE; + switch (originate) { + case DEFAULT_ORIGINATE_NONE: + type_str = "none"; + break; + case DEFAULT_ORIGINATE_ZEBRA: + type_str = "normal"; + ospf->redistribute++; + zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, + zclient, AFI_IP, ospf->vrf_id); + break; + case DEFAULT_ORIGINATE_ALWAYS: + type_str = "always"; + ospf->redistribute++; + ospf_external_add(ospf, DEFAULT_ROUTE, 0); + ospf_external_info_add(ospf, DEFAULT_ROUTE, 0, p, 0, nexthop, + 0); + break; + } if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug("Redistribute[DEFAULT]: Stop"); - - // Pending: how does the external_info cleanup work in this case? - - ospf_asbr_status_update(ospf, --ospf->redistribute); - - /* clean up maxage default originate external lsa */ - ospf_default_originate_lsa_update(ospf); + zlog_debug("Redistribute[DEFAULT]: %s Type[%d], Metric[%d]", + type_str, + metric_type(ospf, DEFAULT_ROUTE, 0), + metric_value(ospf, DEFAULT_ROUTE, 0)); + ospf_external_lsa_refresh_default(ospf); + ospf_asbr_status_update(ospf, ospf->redistribute); return CMD_SUCCESS; } @@ -1067,11 +1017,7 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) /* Nothing has changed, so nothing to do; return */ return 0; } - if (ospf->router_id.s_addr == 0) - /* Set flags to generate AS-external-LSA originate event - for each redistributed protocols later. */ - ospf->external_origin |= (1 << rt_type); - else { + if (ospf->router_id.s_addr != 0) { if (ei) { if (is_prefix_default(&p)) ospf_external_lsa_refresh_default(ospf); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index a64ddbc3b7..b91a55f635 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -91,7 +91,6 @@ void ospf_router_id_update(struct ospf *ospf) struct ospf_interface *oi; struct interface *ifp; struct listnode *node; - int type; if (!ospf->oi_running) { if (IS_DEBUG_OSPF_EVENT) @@ -135,24 +134,6 @@ void ospf_router_id_update(struct ospf *ospf) ospf_nbr_self_reset(oi, router_id); } - /* If AS-external-LSA is queued, then flush those LSAs. */ - if (router_id_old.s_addr == 0 && ospf->external_origin) { - /* Originate each redistributed external route. */ - for (type = 0; type < ZEBRA_ROUTE_MAX; type++) - if (ospf->external_origin & (1 << type)) - thread_add_event( - master, - ospf_external_lsa_originate_timer, - ospf, type, NULL); - /* Originate Deafult. */ - if (ospf->external_origin & (1 << ZEBRA_ROUTE_MAX)) - thread_add_event(master, - ospf_default_originate_timer, - ospf, 0, NULL); - - ospf->external_origin = 0; - } - /* Flush (inline) all external LSAs based on the OSPF_LSA_SELF * flag */ if (ospf->lsdb) { @@ -196,20 +177,14 @@ void ospf_router_id_update(struct ospf *ospf) } } - /* Originate each redistributed external route. */ - for (type = 0; type < ZEBRA_ROUTE_MAX; type++) - thread_add_event(master, - ospf_external_lsa_originate_timer, - ospf, type, NULL); - thread_add_event(master, ospf_default_originate_timer, ospf, 0, - NULL); - /* 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); + + ospf_external_lsa_rid_change(ospf); } } @@ -633,7 +608,7 @@ static void ospf_finish_final(struct ospf *ospf) ospf_redist_del(ospf, i, red->instance); } } - ospf_redistribute_default_unset(ospf); + ospf_redistribute_default_set(ospf, DEFAULT_ORIGINATE_NONE, 0, 0); for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) ospf_remove_vls_through_area(ospf, area); @@ -702,7 +677,6 @@ static void ospf_finish_final(struct ospf *ospf) /* Cancel all timers. */ OSPF_TIMER_OFF(ospf->t_read); OSPF_TIMER_OFF(ospf->t_write); - OSPF_TIMER_OFF(ospf->t_external_lsa); OSPF_TIMER_OFF(ospf->t_spf_calc); OSPF_TIMER_OFF(ospf->t_ase_calc); OSPF_TIMER_OFF(ospf->t_maxage); diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index cbea033b73..b31ad30375 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -202,7 +202,6 @@ struct ospf { struct ospf_lsdb *lsdb; /* Flags. */ - int external_origin; /* AS-external-LSA origin flag. */ int ase_calc; /* ASE calculation flag. */ struct list *opaque_lsa_self; /* Type-11 Opaque-LSAs */ @@ -233,7 +232,6 @@ struct ospf { struct thread *t_distribute_update; /* Distirbute list update timer. */ struct thread *t_spf_calc; /* SPF calculation timer. */ struct thread *t_ase_calc; /* ASE calculation timer. */ - struct thread *t_external_lsa; /* AS-external-LSA origin timer. */ struct thread *t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */ struct thread *t_sr_update; /* Segment Routing update timer */ diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index a7552547e9..60cfb2e486 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -39,14 +39,15 @@ #endif DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, - "sharp watch [vrf NAME$name] <nexthop$n|import$import> X:X::X:X$nhop [connected$connected]", + "sharp watch [vrf NAME$name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" "The vrf we would like to watch if non-default\n" "The NAME of the vrf\n" "Watch for nexthop changes\n" - "Watch for import check changes\n" "The v6 nexthop to signal for watching\n" + "Watch for import check changes\n" + "The v6 prefix to signal for watching\n" "Should the route be connected\n") { struct vrf *vrf; @@ -62,16 +63,17 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, return CMD_WARNING; } - if (n) - type_import = false; - else - type_import = true; - memset(&p, 0, sizeof(p)); - p.prefixlen = 128; - memcpy(&p.u.prefix6, &nhop, 16); - p.family = AF_INET6; + if (n) { + type_import = false; + p.prefixlen = 128; + memcpy(&p.u.prefix6, &nhop, 16); + p.family = AF_INET6; + } else { + type_import = true; + p = *(const struct prefix *)inhop; + } sharp_nh_tracker_get(&p); sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, @@ -81,14 +83,15 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, } DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, - "sharp watch [vrf NAME$name] <nexthop$n|import$import> A.B.C.D$nhop [connected$connected]", + "sharp watch [vrf NAME$name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" "The vrf we would like to watch if non-default\n" "The NAME of the vrf\n" "Watch for nexthop changes\n" + "The v4 address to signal for watching\n" "Watch for import check changes\n" - "The v4 nexthop to signal for watching\n" + "The v4 prefix for import check to watch\n" "Should the route be connected\n") { struct vrf *vrf; @@ -106,14 +109,16 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, memset(&p, 0, sizeof(p)); - if (n) + if (n) { type_import = false; - else + p.prefixlen = 32; + p.u.prefix4 = nhop; + p.family = AF_INET; + } + else { type_import = true; - - p.prefixlen = 32; - p.u.prefix4 = nhop; - p.family = AF_INET; + p = *(const struct prefix *)inhop; + } sharp_nh_tracker_get(&p); sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index cd6f956580..6263f429ea 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -188,7 +188,7 @@ static void handle_repeated(bool installed) sg.r.inst, sg.r.total_routes); } - if (installed) { + if (!installed) { sg.r.installed_routes = 0; sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst, &sg.r.nhop_group, diff --git a/staticd/static_nht.c b/staticd/static_nht.c index 2aa0db59f1..1a2ddd7f05 100644 --- a/staticd/static_nht.c +++ b/staticd/static_nht.c @@ -23,18 +23,48 @@ #include "table.h" #include "vrf.h" #include "nexthop.h" +#include "srcdest_table.h" #include "static_vrf.h" #include "static_routes.h" #include "static_zebra.h" #include "static_nht.h" -static void static_nht_update_safi(struct prefix *p, uint32_t nh_num, - afi_t afi, safi_t safi, struct vrf *vrf, - vrf_id_t nh_vrf_id) +static void static_nht_update_rn(struct route_node *rn, + struct prefix *nhp, uint32_t nh_num, + vrf_id_t nh_vrf_id, struct vrf *vrf, + safi_t safi) { - struct route_table *stable; struct static_route *si; + + for (si = rn->info; si; si = si->next) { + if (si->nh_vrf_id != nh_vrf_id) + continue; + + if (si->type != STATIC_IPV4_GATEWAY + && si->type != STATIC_IPV4_GATEWAY_IFNAME + && si->type != STATIC_IPV6_GATEWAY + && si->type != STATIC_IPV6_GATEWAY_IFNAME) + continue; + + if (nhp->family == AF_INET + && nhp->u.prefix4.s_addr == si->addr.ipv4.s_addr) + si->nh_valid = !!nh_num; + + if (nhp->family == AF_INET6 + && memcmp(&nhp->u.prefix6, &si->addr.ipv6, 16) == 0) + si->nh_valid = !!nh_num; + + if (si->state == STATIC_START) + static_zebra_route_add(rn, si, vrf->vrf_id, safi, true); + } +} + +static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp, + uint32_t nh_num, afi_t afi, safi_t safi, + struct vrf *vrf, vrf_id_t nh_vrf_id) +{ + struct route_table *stable; struct static_vrf *svrf; struct route_node *rn; @@ -46,40 +76,129 @@ static void static_nht_update_safi(struct prefix *p, uint32_t nh_num, if (!stable) return; + if (sp) { + rn = srcdest_rnode_lookup(stable, sp, NULL); + if (rn) { + static_nht_update_rn(rn, nhp, nh_num, nh_vrf_id, + vrf, safi); + route_unlock_node(rn); + } + return; + } + + for (rn = route_top(stable); rn; rn = route_next(rn)) + static_nht_update_rn(rn, nhp, nh_num, nh_vrf_id, vrf, safi); + +} + +void static_nht_update(struct prefix *sp, struct prefix *nhp, + uint32_t nh_num, afi_t afi, vrf_id_t nh_vrf_id) +{ + + struct vrf *vrf; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + static_nht_update_safi(sp, nhp, nh_num, afi, SAFI_UNICAST, + vrf, nh_vrf_id); + static_nht_update_safi(sp, nhp, nh_num, afi, SAFI_MULTICAST, + vrf, nh_vrf_id); + } +} + +static void static_nht_reset_start_safi(struct prefix *nhp, afi_t afi, + safi_t safi, struct vrf *vrf, + vrf_id_t nh_vrf_id) +{ + struct static_vrf *svrf; + struct route_table *stable; + struct static_route *si; + struct route_node *rn; + + svrf = vrf->info; + if (!svrf) + return; + + stable = static_vrf_static_table(afi, safi, svrf); + if (!stable) + return; + for (rn = route_top(stable); rn; rn = route_next(rn)) { for (si = rn->info; si; si = si->next) { if (si->nh_vrf_id != nh_vrf_id) continue; - if (si->type != STATIC_IPV4_GATEWAY - && si->type != STATIC_IPV4_GATEWAY_IFNAME - && si->type != STATIC_IPV6_GATEWAY - && si->type != STATIC_IPV6_GATEWAY_IFNAME) + if (nhp->family == AF_INET + && nhp->u.prefix4.s_addr != si->addr.ipv4.s_addr) continue; - if (p->family == AF_INET - && p->u.prefix4.s_addr == si->addr.ipv4.s_addr) - si->nh_valid = !!nh_num; - - if (p->family == AF_INET6 - && memcmp(&p->u.prefix6, &si->addr.ipv6, 16) == 0) - si->nh_valid = !!nh_num; + if (nhp->family == AF_INET6 + && memcmp(&nhp->u.prefix6, &si->addr.ipv6, 16) != 0) + continue; - static_zebra_route_add(rn, si, vrf->vrf_id, safi, true); + /* + * We've been told that a nexthop we depend + * on has changed in some manner, so reset + * the state machine to allow us to start + * over. + */ + si->state = STATIC_START; } } } -void static_nht_update(struct prefix *p, uint32_t nh_num, afi_t afi, - vrf_id_t nh_vrf_id) +void static_nht_reset_start(struct prefix *nhp, afi_t afi, vrf_id_t nh_vrf_id) { - struct vrf *vrf; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - static_nht_update_safi(p, nh_num, afi, SAFI_UNICAST, - vrf, nh_vrf_id); - static_nht_update_safi(p, nh_num, afi, SAFI_MULTICAST, - vrf, nh_vrf_id); + static_nht_reset_start_safi(nhp, afi, SAFI_UNICAST, + vrf, nh_vrf_id); + static_nht_reset_start_safi(nhp, afi, SAFI_MULTICAST, + vrf, nh_vrf_id); } } + +static void static_nht_mark_state_safi(struct prefix *sp, afi_t afi, + safi_t safi, struct vrf *vrf, + enum static_install_states state) +{ + struct static_vrf *svrf; + struct route_table *stable; + struct static_route *si; + struct route_node *rn; + + svrf = vrf->info; + if (!svrf) + return; + + stable = static_vrf_static_table(afi, safi, svrf); + if (!stable) + return; + + rn = srcdest_rnode_lookup(stable, sp, NULL); + if (!rn) + return; + + for (si = rn->info; si; si = si->next) + si->state = state; + + route_unlock_node(rn); +} + +void static_nht_mark_state(struct prefix *sp, vrf_id_t vrf_id, + enum static_install_states state) +{ + struct vrf *vrf; + + afi_t afi = AFI_IP; + + if (sp->family == AF_INET6) + afi = AFI_IP6; + + vrf = vrf_lookup_by_id(vrf_id); + if (!vrf || !vrf->info) + return; + + static_nht_mark_state_safi(sp, afi, SAFI_UNICAST, vrf, state); + static_nht_mark_state_safi(sp, afi, SAFI_MULTICAST, vrf, state); +} diff --git a/staticd/static_nht.h b/staticd/static_nht.h index f273c71bba..18bb9e39ca 100644 --- a/staticd/static_nht.h +++ b/staticd/static_nht.h @@ -20,6 +20,31 @@ #ifndef __STATIC_NHT_H__ #define __STATIC_NHT_H__ -extern void static_nht_update(struct prefix *p, uint32_t nh_num, - afi_t afi, vrf_id_t vrf_id); +/* + * When we get notification that nexthop tracking has an answer for + * us call this function to find the nexthop we are tracking so it + * can be installed or removed. + * + * sp -> The route we are looking at. If NULL then look at all + * routes. + * nhp -> The nexthop that is being tracked. + * nh_num -> number of valid nexthops. + * afi -> The afi we are working in. + * vrf_id -> The vrf the nexthop is in. + */ +extern void static_nht_update(struct prefix *sp, struct prefix *nhp, + uint32_t nh_num, afi_t afi, vrf_id_t vrf_id); + +/* + * For the given tracked nexthop, nhp, mark all routes that use + * this route as in starting state again. + */ +extern void static_nht_reset_start(struct prefix *nhp, afi_t afi, + vrf_id_t nh_vrf_id); + +/* + * For the given prefix, sp, mark it as in a particular state + */ +extern void static_nht_mark_state(struct prefix *sp, vrf_id_t vrf_id, + enum static_install_states state); #endif diff --git a/staticd/static_routes.c b/staticd/static_routes.c index 5f9ecad694..b2c61bcbab 100644 --- a/staticd/static_routes.c +++ b/staticd/static_routes.c @@ -39,7 +39,7 @@ static void static_install_route(struct route_node *rn, struct static_route *si; for (si = rn->info; si; si = si->next) - static_zebra_nht_register(si, true); + static_zebra_nht_register(rn, si, true); si = rn->info; if (si) @@ -183,7 +183,7 @@ int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p, /* check whether interface exists in system & install if it does */ if (!ifname) - static_install_route(rn, si, safi); + static_zebra_nht_register(rn, si, true); else { struct interface *ifp; @@ -242,7 +242,7 @@ int static_delete_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p, return 0; } - static_zebra_nht_register(si, false); + static_zebra_nht_register(rn, si, false); /* Unlink static route from linked list. */ if (si->prev) diff --git a/staticd/static_routes.h b/staticd/static_routes.h index 6036bfe396..6414947b16 100644 --- a/staticd/static_routes.h +++ b/staticd/static_routes.h @@ -44,6 +44,26 @@ typedef enum { STATIC_IPV6_GATEWAY_IFNAME, } static_types; +/* + * Route Creation gives us: + * START -> Initial State, only exit is when we send the route to + * zebra for installation + * When we send the route to Zebra move to SENT_TO_ZEBRA + * SENT_TO_ZEBRA -> A way to notice that we've sent the route to zebra + * But have not received a response on it's status yet + * After The response from zebra we move to INSTALLED or FAILED + * INSTALLED -> Route was accepted + * FAILED -> Route was rejected + * When we receive notification about a nexthop that a route uses + * We move the route back to START and initiate the process again. + */ +enum static_install_states { + STATIC_START, + STATIC_SENT_TO_ZEBRA, + STATIC_INSTALLED, + STATIC_NOT_INSTALLED, +}; + /* Static route information. */ struct static_route { /* For linked list. */ @@ -55,6 +75,12 @@ struct static_route { vrf_id_t nh_vrf_id; char nh_vrfname[VRF_NAMSIZ + 1]; + /* + * States that we walk the route through + * To know where we are. + */ + enum static_install_states state; + /* Administrative distance. */ uint8_t distance; diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index c6da00418b..13c04259d7 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -43,6 +43,8 @@ #include "static_nht.h" #include "static_vty.h" +bool debug; + /* Zebra structure to hold current status. */ struct zclient *zclient; static struct hash *static_nht_hash; @@ -154,18 +156,23 @@ static int route_notify_owner(ZAPI_CALLBACK_ARGS) switch (note) { case ZAPI_ROUTE_FAIL_INSTALL: + static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED); zlog_warn("%s: Route %s failed to install for table: %u", __PRETTY_FUNCTION__, buf, table_id); break; case ZAPI_ROUTE_BETTER_ADMIN_WON: + static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED); zlog_warn("%s: Route %s over-ridden by better route for table: %u", __PRETTY_FUNCTION__, buf, table_id); break; case ZAPI_ROUTE_INSTALLED: + static_nht_mark_state(&p, vrf_id, STATIC_INSTALLED); break; case ZAPI_ROUTE_REMOVED: + static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED); break; case ZAPI_ROUTE_REMOVE_FAIL: + static_nht_mark_state(&p, vrf_id, STATIC_INSTALLED); zlog_warn("%s: Route %s failure to remove for table: %u", __PRETTY_FUNCTION__, buf, table_id); break; @@ -210,7 +217,8 @@ static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS) if (nhtd) { nhtd->nh_num = nhr.nexthop_num; - static_nht_update(&nhr.prefix, nhr.nexthop_num, afi, + static_nht_reset_start(&nhr.prefix, afi, nhtd->nh_vrf_id); + static_nht_update(NULL, &nhr.prefix, nhr.nexthop_num, afi, nhtd->nh_vrf_id); } else zlog_err("No nhtd?"); @@ -267,7 +275,8 @@ static void static_nht_hash_free(void *data) XFREE(MTYPE_TMP, nhtd); } -void static_zebra_nht_register(struct static_route *si, bool reg) +void static_zebra_nht_register(struct route_node *rn, + struct static_route *si, bool reg) { struct static_nht_data *nhtd, lookup; uint32_t cmd; @@ -315,8 +324,11 @@ void static_zebra_nht_register(struct static_route *si, bool reg) static_nht_hash_alloc); nhtd->refcount++; - if (nhtd->refcount > 1) { - static_nht_update(nhtd->nh, nhtd->nh_num, + if (debug) + zlog_debug("Registered nexthop(%pFX) for %pRN %d", &p, + rn, nhtd->nh_num); + if (nhtd->refcount > 1 && nhtd->nh_num) { + static_nht_update(&rn->p, nhtd->nh, nhtd->nh_num, afi, si->nh_vrf_id); return; } @@ -389,6 +401,8 @@ extern void static_zebra_route_add(struct route_node *rn, api_nh->vrf_id = si->nh_vrf_id; api_nh->onlink = si->onlink; + si->state = STATIC_SENT_TO_ZEBRA; + switch (si->type) { case STATIC_IFNAME: if (si->ifindex == IFINDEX_INTERNAL) diff --git a/staticd/static_zebra.h b/staticd/static_zebra.h index a82eb162e1..15f5410b81 100644 --- a/staticd/static_zebra.h +++ b/staticd/static_zebra.h @@ -21,7 +21,8 @@ extern struct thread_master *master; -extern void static_zebra_nht_register(struct static_route *si, bool reg); +extern void static_zebra_nht_register(struct route_node *rn, + struct static_route *si, bool reg); extern void static_zebra_route_add(struct route_node *rn, struct static_route *si_changed, diff --git a/tests/lib/cli/test_commands.c b/tests/lib/cli/test_commands.c index ba46bdcea9..bbdc8b238d 100644 --- a/tests/lib/cli/test_commands.c +++ b/tests/lib/cli/test_commands.c @@ -243,7 +243,8 @@ static void test_run(struct prng *prng, struct vty *vty, const char *cmd, (test_buf[0] != '\0') ? ", " : "", test_buf); - if (isspace((int)test_str[strlen(test_str) - 1])) { + if (isspace((unsigned char)test_str[ + strlen(test_str) - 1])) { vector_set(vline, NULL); appended_null = 1; } diff --git a/tests/lib/cxxcompat.c b/tests/lib/cxxcompat.c index 6624de7386..88126e84bc 100644 --- a/tests/lib/cxxcompat.c +++ b/tests/lib/cxxcompat.c @@ -55,7 +55,6 @@ #include "lib/libospf.h" #include "lib/linklist.h" #include "lib/log.h" -#include "lib/logicalrouter.h" #include "lib/md5.h" #include "lib/memory.h" #include "lib/memory_vty.h" @@ -73,7 +72,6 @@ #include "lib/openbsd-tree.h" #include "lib/pbr.h" #include "lib/plist.h" -#include "lib/pqueue.h" #include "lib/prefix.h" #include "lib/privs.h" #include "lib/ptm_lib.h" diff --git a/tests/lib/test_timer_correctness.c b/tests/lib/test_timer_correctness.c index 43e79ba9d0..cbf9b05546 100644 --- a/tests/lib/test_timer_correctness.c +++ b/tests/lib/test_timer_correctness.c @@ -28,7 +28,6 @@ #include <unistd.h> #include "memory.h" -#include "pqueue.h" #include "prng.h" #include "thread.h" diff --git a/tests/lib/test_timer_performance.c b/tests/lib/test_timer_performance.c index d5f4badc85..2960e0d81e 100644 --- a/tests/lib/test_timer_performance.c +++ b/tests/lib/test_timer_performance.c @@ -28,7 +28,6 @@ #include <unistd.h> #include "thread.h" -#include "pqueue.h" #include "prng.h" #define SCHEDULE_TIMERS 1000000 diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h index b288f0bd8e..7ff210cae3 100644 --- a/tests/lib/test_typelist.h +++ b/tests/lib/test_typelist.h @@ -209,7 +209,7 @@ static void concat(test_, TYPE)(void) assert(list_add(&head, &dummy) == &itm[j]); else { assert(list_add(&head, &dummy) == NULL); - list_del(&head, &dummy); + assert(list_del(&head, &dummy) != NULL); } } ts_hashx("add-dup", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838"); @@ -255,7 +255,7 @@ static void concat(test_, TYPE)(void) list_first(&head) == &dummy); } else if (list_next(&head, &dummy)) assert(list_next(&head, &dummy)->val > j); - list_del(&head, &dummy); + assert(list_del(&head, &dummy) != NULL); } ts_hash("add-dup+find_{lt,gteq}", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838"); #endif @@ -295,7 +295,7 @@ static void concat(test_, TYPE)(void) (void)prng_rand(prng); j = prng_rand(prng) % NITEM; if (itm[j].scratchpad == 1) { - list_del(&head, &itm[j]); + assert(list_del(&head, &itm[j]) != NULL); itm[j].scratchpad = 0; l++; } @@ -307,7 +307,7 @@ static void concat(test_, TYPE)(void) assert(item->scratchpad != 0); if (item->val & 1) { - list_del(&head, item); + assert(list_del(&head, item) != NULL); item->scratchpad = 0; l++; } @@ -333,7 +333,7 @@ static void concat(test_, TYPE)(void) for (i = 0; i < NITEM / 2; i++) { j = prng_rand(prng) % NITEM; if (itm[j].scratchpad == 1) { - list_del(&head, &itm[j]); + assert(list_del(&head, &itm[j]) != NULL); itm[j].scratchpad = 0; k--; } @@ -371,7 +371,7 @@ static void concat(test_, TYPE)(void) for (i = 0; i < NITEM / 2; i++) { j = prng_rand(prng) % NITEM; if (itm[j].scratchpad == 1) { - list_del(&head, &itm[j]); + assert(list_del(&head, &itm[j]) != NULL); itm[j].scratchpad = 0; k--; } @@ -424,7 +424,7 @@ static void concat(test_, TYPE)(void) item = &itm[j]; if (item->scratchpad == 0) continue; - list_del(&head, item); + assert(list_del(&head, item) != NULL); } item->scratchpad = 0; k--; @@ -469,7 +469,7 @@ static void concat(test_, TYPE)(void) item = &itm[j]; if (item->scratchpad == 0) continue; - list_del(&head, item); + assert(list_del(&head, item) != NULL); } item->scratchpad = 0; k--; diff --git a/tests/topotests/bgp_comm-list_delete/__init__.py b/tests/topotests/bgp_comm-list_delete/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_comm-list_delete/__init__.py diff --git a/tests/topotests/bgp_comm-list_delete/r1/bgpd.conf b/tests/topotests/bgp_comm-list_delete/r1/bgpd.conf new file mode 100644 index 0000000000..6e1273f464 --- /dev/null +++ b/tests/topotests/bgp_comm-list_delete/r1/bgpd.conf @@ -0,0 +1,9 @@ +router bgp 65000 + neighbor 192.168.255.2 remote-as 65001 + address-family ipv4 unicast + redistribute connected route-map r2-out + exit-address-family +! +route-map r2-out permit 10 + set community 111:111 222:222 333:333 444:444 +! diff --git a/tests/topotests/bgp_comm-list_delete/r1/zebra.conf b/tests/topotests/bgp_comm-list_delete/r1/zebra.conf new file mode 100644 index 0000000000..0a283c06d5 --- /dev/null +++ b/tests/topotests/bgp_comm-list_delete/r1/zebra.conf @@ -0,0 +1,9 @@ +! +interface lo + ip address 172.16.255.254/32 +! +interface r1-eth0 + ip address 192.168.255.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_comm-list_delete/r2/bgpd.conf b/tests/topotests/bgp_comm-list_delete/r2/bgpd.conf new file mode 100644 index 0000000000..3d354d56b1 --- /dev/null +++ b/tests/topotests/bgp_comm-list_delete/r2/bgpd.conf @@ -0,0 +1,11 @@ +router bgp 65001 + neighbor 192.168.255.1 remote-as 65000 + address-family ipv4 + neighbor 192.168.255.1 route-map r1-in in + exit-address-family +! +bgp community-list standard r1 permit 333:333 +! +route-map r1-in permit 10 + set comm-list r1 delete +! diff --git a/tests/topotests/bgp_comm-list_delete/r2/zebra.conf b/tests/topotests/bgp_comm-list_delete/r2/zebra.conf new file mode 100644 index 0000000000..606c17bec9 --- /dev/null +++ b/tests/topotests/bgp_comm-list_delete/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_comm-list_delete/test_bgp_comm-list_delete.py b/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py new file mode 100644 index 0000000000..de6c35ba8f --- /dev/null +++ b/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python + +# +# bgp_comm-list_delete.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2019 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. +# + +""" +bgp_comm-list_delete.py: + +Test if works the following commands: +route-map test permit 10 + set comm-list <arg> delete +""" + +import os +import sys +import json +import time +import pytest + +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, 3): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.iteritems(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) + + tgen.start_router() + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + +def test_bgp_maximum_prefix_invalid(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def _bgp_converge(router): + while True: + output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + if output['192.168.255.1']['bgpState'] == 'Established': + if output['192.168.255.1']['addressFamilyInfo']['IPv4 Unicast']['acceptedPrefixCounter'] == 2: + return True + + def _bgp_comm_list_delete(router): + output = json.loads(tgen.gears[router].vtysh_cmd("show ip bgp 172.16.255.254/32 json")) + if '333:333' in output['paths'][0]['community']['list']: + return False + return True + + if _bgp_converge('r2'): + assert _bgp_comm_list_delete('r2') == True + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 13f8824976..2613f45f1c 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -932,7 +932,7 @@ def clear_bgp_and_verify(tgen, topo, router): # Peer up time dictionary peer_uptime_before_clear_bgp[bgp_neighbor] = \ - ipv4_data[neighbor_ip]["peerUptime"] + ipv4_data[neighbor_ip]["peerUptimeEstablishedEpoch"] else: ipv6_data = show_bgp_json["ipv6Unicast"][ "peers"] @@ -940,7 +940,7 @@ def clear_bgp_and_verify(tgen, topo, router): # Peer up time dictionary peer_uptime_before_clear_bgp[bgp_neighbor] = \ - ipv6_data[neighbor_ip]["peerUptime"] + ipv6_data[neighbor_ip]["peerUptimeEstablishedEpoch"] if nh_state == "Established": no_of_peer += 1 @@ -953,6 +953,7 @@ def clear_bgp_and_verify(tgen, topo, router): logger.warning("BGP is not yet Converged for router %s " "before bgp clear", router) + logger.info(peer_uptime_before_clear_bgp) # Clearing BGP logger.info("Clearing BGP neighborship for router %s..", router) for addr_type in bgp_addr_type.keys(): @@ -1010,14 +1011,14 @@ def clear_bgp_and_verify(tgen, topo, router): "peers"] nh_state = ipv4_data[neighbor_ip]["state"] peer_uptime_after_clear_bgp[bgp_neighbor] = \ - ipv4_data[neighbor_ip]["peerUptime"] + ipv4_data[neighbor_ip]["peerUptimeEstablishedEpoch"] else: ipv6_data = show_bgp_json["ipv6Unicast"][ "peers"] nh_state = ipv6_data[neighbor_ip]["state"] # Peer up time dictionary peer_uptime_after_clear_bgp[bgp_neighbor] = \ - ipv6_data[neighbor_ip]["peerUptime"] + ipv6_data[neighbor_ip]["peerUptimeEstablishedEpoch"] if nh_state == "Established": no_of_peer += 1 @@ -1030,7 +1031,8 @@ def clear_bgp_and_verify(tgen, topo, router): logger.warning("BGP is not yet Converged for router %s after" " bgp clear", router) - # Compariung peerUptime dictionaries + logger.info(peer_uptime_after_clear_bgp) + # Comparing peerUptimeEstablishedEpoch dictionaries if peer_uptime_before_clear_bgp != peer_uptime_after_clear_bgp: logger.info("BGP neighborship is reset after clear BGP on router %s", router) diff --git a/tools/coccinelle/ctype_cast.cocci b/tools/coccinelle/ctype_cast.cocci new file mode 100644 index 0000000000..b0b00959da --- /dev/null +++ b/tools/coccinelle/ctype_cast.cocci @@ -0,0 +1,11 @@ + +@@ +identifier func =~ "^(to|is)(alnum|cntrl|print|xdigit|alpha|digit|punct|ascii|graph|space|blank|lower|upper)$"; +expression e; +@@ + + func( +- (int) ++ (unsigned char) + e) + diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c index f6c757f5d7..14f648e8da 100644 --- a/tools/gen_northbound_callbacks.c +++ b/tools/gen_northbound_callbacks.c @@ -28,7 +28,8 @@ static void __attribute__((noreturn)) usage(int status) { - fprintf(stderr, "usage: gen_northbound_callbacks [-h] MODULE\n"); + extern const char *__progname; + fprintf(stderr, "usage: %s [-h] [-p path] MODULE\n", __progname); exit(status); } @@ -152,6 +153,36 @@ static void generate_callback_name(struct lys_node *snode, replace_hyphens_by_underscores(buffer); } +static void generate_callback(const struct nb_callback_info *ncinfo, + const char *cb_name) +{ + printf("static %s%s(%s)\n{\n", + ncinfo->return_type, cb_name, ncinfo->arguments); + + switch (ncinfo->operation) { + case NB_OP_CREATE: + case NB_OP_MODIFY: + case NB_OP_DESTROY: + case NB_OP_MOVE: + printf("\tswitch (event) {\n" + "\tcase NB_EV_VALIDATE:\n" + "\tcase NB_EV_PREPARE:\n" + "\tcase NB_EV_ABORT:\n" + "\tcase NB_EV_APPLY:\n" + "\t\t/* TODO: implement me. */\n" + "\t\tbreak;\n" + "\t}\n\n" + ); + break; + + default: + printf("\t/* TODO: implement me. */\n"); + break; + } + + printf("\treturn %s;\n}\n\n", ncinfo->return_value); +} + static int generate_callbacks(const struct lys_node *snode, void *arg) { bool first = true; @@ -191,14 +222,7 @@ static int generate_callbacks(const struct lys_node *snode, void *arg) generate_callback_name((struct lys_node *)snode, cb->operation, cb_name, sizeof(cb_name)); - printf("static %s%s(%s)\n" - "{\n" - "\t/* TODO: implement me. */\n" - "\treturn %s;\n" - "}\n\n", - nb_callbacks[cb->operation].return_type, cb_name, - nb_callbacks[cb->operation].arguments, - nb_callbacks[cb->operation].return_value); + generate_callback(cb, cb_name); } return YANG_ITER_CONTINUE; @@ -237,32 +261,52 @@ static int generate_nb_nodes(const struct lys_node *snode, void *arg) printf("\t\t{\n" "\t\t\t.xpath = \"%s\",\n", xpath); + printf("\t\t\t.cbs = {\n"); first = false; } generate_callback_name((struct lys_node *)snode, cb->operation, cb_name, sizeof(cb_name)); - printf("\t\t\t.cbs.%s = %s,\n", - nb_operation_name(cb->operation), cb_name); + printf("\t\t\t\t.%s = %s,\n", nb_operation_name(cb->operation), + cb_name); } - if (!first) + if (!first) { + printf("\t\t\t}\n"); printf("\t\t},\n"); + } return YANG_ITER_CONTINUE; } int main(int argc, char *argv[]) { + const char *search_path = NULL; struct yang_module *module; char module_name_underscores[64]; + struct stat st; int opt; - while ((opt = getopt(argc, argv, "h")) != -1) { + while ((opt = getopt(argc, argv, "hp:")) != -1) { switch (opt) { case 'h': usage(EXIT_SUCCESS); /* NOTREACHED */ + case 'p': + if (stat(optarg, &st) == -1) { + fprintf(stderr, + "error: invalid search path '%s': %s\n", + optarg, strerror(errno)); + exit(EXIT_FAILURE); + } + if (S_ISDIR(st.st_mode) == 0) { + fprintf(stderr, + "error: search path is not directory"); + exit(EXIT_FAILURE); + } + + search_path = optarg; + break; default: usage(EXIT_FAILURE); /* NOTREACHED */ @@ -275,6 +319,9 @@ int main(int argc, char *argv[]) yang_init(); + if (search_path) + ly_ctx_set_searchdir(ly_native_ctx, search_path); + /* Load all FRR native models to ensure all augmentations are loaded. */ yang_module_load_all(); module = yang_module_find(argv[0]); diff --git a/tools/start-stop-daemon.c b/tools/start-stop-daemon.c index 5903f8732f..c75306a959 100644 --- a/tools/start-stop-daemon.c +++ b/tools/start-stop-daemon.c @@ -401,7 +401,7 @@ static void parse_schedule_item(const char *string, struct schedule_item *item) if (!strcmp(string, "forever")) { item->type = sched_forever; - } else if (isdigit((int)string[0])) { + } else if (isdigit((unsigned char)string[0])) { item->type = sched_timeout; if (parse_integer(string, &item->value) != 0) badusage("invalid timeout value in schedule"); diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index 5213b27d32..951ad3f58f 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -196,9 +196,20 @@ static struct vrrp_vrouter *vrrp_lookup_by_if_mvl(struct interface *mvl_ifp) { struct interface *p; - if (!mvl_ifp || !mvl_ifp->link_ifindex - || !vrrp_ifp_has_vrrp_mac(mvl_ifp)) + if (!mvl_ifp || mvl_ifp->link_ifindex == 0 + || !vrrp_ifp_has_vrrp_mac(mvl_ifp)) { + if (mvl_ifp && mvl_ifp->link_ifindex == 0) + DEBUGD(&vrrp_dbg_zebra, + VRRP_LOGPFX + "Interface %s has no parent ifindex; disregarding", + mvl_ifp->name); + if (mvl_ifp && !vrrp_ifp_has_vrrp_mac(mvl_ifp)) + DEBUGD(&vrrp_dbg_zebra, + VRRP_LOGPFX + "Interface %s has a non-VRRP MAC; disregarding", + mvl_ifp->name); return NULL; + } p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT); uint8_t vrid = mvl_ifp->hw_addr[5]; @@ -2028,9 +2039,19 @@ static void vrrp_bind_pending(struct interface *mvl_ifp) { struct vrrp_vrouter *vr; + DEBUGD(&vrrp_dbg_zebra, + VRRP_LOGPFX + "Searching for instances that could use interface %s", + mvl_ifp->name); + vr = vrrp_lookup_by_if_mvl(mvl_ifp); if (vr) { + DEBUGD(&vrrp_dbg_zebra, + VRRP_LOGPFX VRRP_LOGPFX_VRID + "<-- This instance can probably use interface %s", + vr->vrid, mvl_ifp->name); + if (mvl_ifp->hw_addr[4] == 0x01 && !vr->v4->mvl_ifp) vrrp_attach_interface(vr->v4); else if (mvl_ifp->hw_addr[4] == 0x02 && !vr->v6->mvl_ifp) @@ -2112,9 +2133,13 @@ void vrrp_if_down(struct interface *ifp) struct listnode *ln; struct list *vrs; + vrrp_bind_pending(ifp); + vrs = vrrp_lookup_by_if_any(ifp); for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) { + vrrp_check_start(vr); + if (vr->ifp == ifp || vr->v4->mvl_ifp == ifp || vr->v6->mvl_ifp == ifp) { DEBUGD(&vrrp_dbg_auto, diff --git a/vrrpd/vrrp_zebra.c b/vrrpd/vrrp_zebra.c index dbfcbe945e..72b77c1313 100644 --- a/vrrpd/vrrp_zebra.c +++ b/vrrpd/vrrp_zebra.c @@ -38,9 +38,11 @@ static void vrrp_zebra_debug_if_state(struct interface *ifp, vrf_id_t vrf_id, const char *func) { DEBUGD(&vrrp_dbg_zebra, - "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", - func, ifp->name, ifp->ifindex, vrf_id, (long)ifp->flags, - ifp->metric, ifp->mtu, if_is_operative(ifp)); + "%s: %s index %d(%u) parent %d mac %02x:%02x:%02x:%02x:%02x:%02x flags %ld metric %d mtu %d operative %d", + func, ifp->name, vrf_id, ifp->link_ifindex, ifp->ifindex, + ifp->hw_addr[0], ifp->hw_addr[1], ifp->hw_addr[2], + ifp->hw_addr[3], ifp->hw_addr[4], ifp->hw_addr[5], + (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } static void vrrp_zebra_debug_if_dump_address(struct interface *ifp, diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 4dc34d10ef..d0b0c701a7 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -96,18 +96,12 @@ sub scan_file { elsif ($file =~ /lib\/if\.c$/) { $protocol = "VTYSH_INTERFACE"; } - elsif ($file =~ /lib\/logicalrouter\.c$/) { - $protocol = "VTYSH_ALL"; - } elsif ($file =~ /lib\/filter\.c$/) { $protocol = "VTYSH_ALL"; } elsif ($file =~ /lib\/agentx\.c$/) { $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; } - elsif ($file =~ /lib\/ns\.c$/) { - $protocol = "VTYSH_ZEBRA"; - } elsif ($file =~ /lib\/nexthop_group\.c$/) { $protocol = "VTYSH_PBRD | VTYSH_SHARPD"; } diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 82dbe06a9c..cec5675e01 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -668,11 +668,11 @@ static char *trim(char *s) return s; end = s + size - 1; - while (end >= s && isspace((int)*end)) + while (end >= s && isspace((unsigned char)*end)) end--; *(end + 1) = '\0'; - while (*s && isspace((int)*s)) + while (*s && isspace((unsigned char)*s)) s++; return s; @@ -979,7 +979,7 @@ static int vtysh_process_questionmark(const char *input, int input_len) if (vline == NULL) { vline = vector_init(1); vector_set(vline, NULL); - } else if (input_len && isspace((int)input[input_len - 1])) + } else if (input_len && isspace((unsigned char)input[input_len - 1])) vector_set(vline, NULL); describe = cmd_describe_command(vline, vty, &ret); @@ -1127,7 +1127,8 @@ static char *command_generator(const char *text, int state) if (vline == NULL) return NULL; - if (rl_end && isspace((int)rl_line_buffer[rl_end - 1])) + if (rl_end && + isspace((unsigned char)rl_line_buffer[rl_end - 1])) vector_set(vline, NULL); matched = cmd_complete_command(vline, vty, &complete_status); @@ -1188,10 +1189,6 @@ static struct cmd_node pw_node = { PW_NODE, "%s(config-pw)# ", }; -static struct cmd_node logicalrouter_node = { - LOGICALROUTER_NODE, "%s(config-logical-router)# ", -}; - static struct cmd_node vrf_node = { VRF_NODE, "%s(config-vrf)# ", }; @@ -1798,7 +1795,6 @@ static int vtysh_exit(struct vty *vty) break; case INTERFACE_NODE: case PW_NODE: - case LOGICALROUTER_NODE: case VRF_NODE: case NH_GROUP_NODE: case ZEBRA_NODE: @@ -2128,24 +2124,6 @@ DEFUNSH(VTYSH_ZEBRA, vtysh_pseudowire, vtysh_pseudowire_cmd, return CMD_SUCCESS; } -DEFUNSH(VTYSH_ZEBRA, vtysh_logicalrouter, vtysh_logicalrouter_cmd, - "logical-router (1-65535) ns NAME", - "Enable a logical-router\n" - "Specify the logical-router indentifier\n" - "The Name Space\n" - "The file name in " NS_RUN_DIR ", or a full pathname\n") -{ - vty->node = LOGICALROUTER_NODE; - return CMD_SUCCESS; -} - -DEFSH(VTYSH_ZEBRA, vtysh_no_logicalrouter_cmd, - "no logical-router (1-65535) ns NAME", NO_STR - "Enable a Logical-Router\n" - "Specify the Logical-Router identifier\n" - "The Name Space\n" - "The file name in " NS_RUN_DIR ", or a full pathname\n") - DEFUNSH(VTYSH_PBRD | VTYSH_SHARPD, vtysh_nexthop_group, vtysh_nexthop_group_cmd, "nexthop-group NHGNAME", "Nexthop Group configuration\n" @@ -2180,20 +2158,6 @@ DEFSH(VTYSH_ZEBRA, vtysh_no_vrf_netns_cmd, "Detach VRF from a Namespace\n" "The file name in " NS_RUN_DIR ", or a full pathname\n") -DEFUNSH(VTYSH_NS, vtysh_exit_logicalrouter, - vtysh_exit_logicalrouter_cmd, "exit", - "Exit current mode and down to previous mode\n") -{ - return vtysh_exit(vty); -} - -DEFUNSH(VTYSH_NS, vtysh_quit_logicalrouter, - vtysh_quit_logicalrouter_cmd, "quit", - "Exit current mode and down to previous mode\n") -{ - return vtysh_exit_logicalrouter(self, vty, argc, argv); -} - DEFUNSH(VTYSH_VRF, vtysh_exit_vrf, vtysh_exit_vrf_cmd, "exit", "Exit current mode and down to previous mode\n") { @@ -3609,7 +3573,6 @@ void vtysh_init_vty(void) install_node(&interface_node, NULL); install_node(&pw_node, NULL); install_node(&link_params_node, NULL); - install_node(&logicalrouter_node, NULL); install_node(&vrf_node, NULL); install_node(&nh_group_node, NULL); install_node(&rmap_node, NULL); @@ -3819,13 +3782,6 @@ void vtysh_init_vty(void) install_element(PW_NODE, &vtysh_exit_interface_cmd); install_element(PW_NODE, &vtysh_quit_interface_cmd); - install_element(LOGICALROUTER_NODE, &vtysh_end_all_cmd); - - install_element(CONFIG_NODE, &vtysh_logicalrouter_cmd); - install_element(CONFIG_NODE, &vtysh_no_logicalrouter_cmd); - install_element(LOGICALROUTER_NODE, &vtysh_exit_logicalrouter_cmd); - install_element(LOGICALROUTER_NODE, &vtysh_quit_logicalrouter_cmd); - install_element(CONFIG_NODE, &vtysh_nexthop_group_cmd); install_element(NH_GROUP_NODE, &vtysh_end_all_cmd); install_element(NH_GROUP_NODE, &vtysh_exit_nexthop_group_cmd); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 3b0b570a56..b16761b41a 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -54,7 +54,6 @@ DECLARE_MGROUP(MVTYSH) #define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD #define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_SHARPD|VTYSH_FABRICD #define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD -#define VTYSH_NS VTYSH_ZEBRA #define VTYSH_VRF VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_STATICD #define VTYSH_KEYS VTYSH_RIPD|VTYSH_EIGRPD diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 1e45e6f972..3ec2eb239d 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -23,6 +23,7 @@ #include "command.h" #include "linklist.h" #include "memory.h" +#include "typesafe.h" #include "vtysh/vtysh.h" #include "vtysh/vtysh_user.h" @@ -33,6 +34,8 @@ DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line") vector configvec; +PREDECL_RBTREE_UNIQ(config_master); + struct config { /* Configuration node name. */ char *name; @@ -45,6 +48,9 @@ struct config { /* Index of this config. */ uint32_t index; + + /* Node entry for the typed Red-black tree */ + struct config_master_item rbt_item; }; struct list *config_top; @@ -66,7 +72,7 @@ static struct config *config_new(void) return config; } -static int config_cmp(struct config *c1, struct config *c2) +static int config_cmp(const struct config *c1, const struct config *c2) { return strcmp(c1->name, c2->name); } @@ -78,28 +84,23 @@ static void config_del(struct config *config) XFREE(MTYPE_VTYSH_CONFIG, config); } +DECLARE_RBTREE_UNIQ(config_master, struct config, rbt_item, config_cmp) + static struct config *config_get(int index, const char *line) { struct config *config; - struct config *config_loop; - struct list *master; - struct listnode *node, *nnode; - - config = config_loop = NULL; + struct config_master_head *master; master = vector_lookup_ensure(configvec, index); if (!master) { - master = list_new(); - master->del = (void (*)(void *))config_del; - master->cmp = (int (*)(void *, void *))config_cmp; + master = XMALLOC(MTYPE_VTYSH_CONFIG, sizeof(struct config_master_head)); + config_master_init(master); vector_set_index(configvec, index, master); } - for (ALL_LIST_ELEMENTS(master, node, nnode, config_loop)) { - if (strcmp(config_loop->name, line) == 0) - config = config_loop; - } + const struct config config_ref = { .name = (char *)line }; + config = config_master_find(master, &config_ref); if (!config) { config = config_new(); @@ -108,7 +109,7 @@ static struct config *config_get(int index, const char *line) config->line->cmp = (int (*)(void *, void *))line_cmp; config->name = XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line); config->index = index; - listnode_add(master, config); + config_master_add(master, config); } return config; } @@ -263,7 +264,6 @@ void vtysh_config_parse_line(void *arg, const char *line) config_add_line(config->line, line); } else if (config->index == RMAP_NODE || config->index == INTERFACE_NODE - || config->index == LOGICALROUTER_NODE || config->index == VTY_NODE || config->index == VRF_NODE || config->index == NH_GROUP_NODE) @@ -278,8 +278,6 @@ void vtysh_config_parse_line(void *arg, const char *line) config = config_get(INTERFACE_NODE, line); else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0) config = config_get(PW_NODE, line); - else if (strncmp(line, "logical-router", strlen("logical-router")) == 0) - config = config_get(LOGICALROUTER_NODE, line); else if (strncmp(line, "vrf", strlen("vrf")) == 0) config = config_get(VRF_NODE, line); else if (strncmp(line, "nexthop-group", strlen("nexthop-group")) @@ -435,7 +433,7 @@ void vtysh_config_dump(void) struct listnode *node, *nnode; struct listnode *mnode, *mnnode; struct config *config; - struct list *master; + struct config_master_head *master; char *line; unsigned int i; @@ -446,7 +444,7 @@ void vtysh_config_dump(void) for (i = 0; i < vector_active(configvec); i++) if ((master = vector_slot(configvec, i)) != NULL) { - for (ALL_LIST_ELEMENTS(master, node, nnode, config)) { + while ((config = config_master_pop(master))) { /* Don't print empty sections for interface. * Route maps on the * other hand could have a legitimate empty @@ -466,6 +464,8 @@ void vtysh_config_dump(void) vty_out(vty, "%s\n", line); if (!NO_DELIMITER(i)) vty_out(vty, "!\n"); + + config_del(config); } if (NO_DELIMITER(i)) vty_out(vty, "!\n"); @@ -473,7 +473,8 @@ void vtysh_config_dump(void) for (i = 0; i < vector_active(configvec); i++) if ((master = vector_slot(configvec, i)) != NULL) { - list_delete(&master); + config_master_fini(master); + XFREE(MTYPE_VTYSH_CONFIG, master); vector_slot(configvec, i) = NULL; } list_delete_all_node(config_top); diff --git a/yang/frr-eigrpd.yang b/yang/frr-eigrpd.yang index 26de7a71ae..853d823880 100644 --- a/yang/frr-eigrpd.yang +++ b/yang/frr-eigrpd.yang @@ -57,7 +57,7 @@ module frr-eigrpd { value 2; } - enum hmac-sha2 { + enum hmac-sha-256 { description "HMAC SHA256 algorithm"; value 3; } diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang new file mode 100644 index 0000000000..e79ede87b7 --- /dev/null +++ b/yang/frr-filter.yang @@ -0,0 +1,353 @@ +module frr-filter { + yang-version 1.1; + namespace "http://frrouting.org/yang/filter"; + prefix frr-filter; + + import ietf-inet-types { + prefix inet; + } + import ietf-yang-types { + prefix yang; + } + + organization "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description "This module defines filter settings"; + + revision 2019-07-04 { + description "Initial revision"; + } + + /* + * Types. + */ + typedef access-list-standard { + description "Standard IPv4 access list (any, host or a prefix)"; + type uint16 { + range "1..99 | 1300..1999"; + } + } + + typedef access-list-extended { + description + "Extended IPv4 access list (source / destination any, hosts or prefixes)"; + type uint16 { + range "100..199 | 2000..2699"; + } + } + + typedef access-list-legacy { + description "Standard/Extended IPv4 access list"; + type uint16 { + range "1..199 | 1300..2699"; + } + } + + typedef access-list-name { + description "Access list name formatting"; + type string; + } + + typedef access-list-sequence { + description "Access list sequence number"; + type uint32 { + range "1..4294967295"; + } + } + + typedef access-list-action { + description "Access list return action on match"; + type enumeration { + enum deny { + description "Deny an entry"; + value 0; + } + enum permit { + description "Accept an entry"; + value 1; + } + } + } + + /* + * Configuration data. + */ + container filter-list { + list access-list-legacy { + description "Access list legacy instance"; + + key "number sequence"; + + leaf number { + description "Access list sequence value"; + type access-list-legacy; + } + + leaf sequence { + description "Access list sequence value"; + type access-list-sequence; + } + + leaf action { + description "Access list action on match"; + type access-list-action; + mandatory true; + } + + leaf remark { + description "Access list remark"; + type string; + } + + choice value { + description + "Standard access list: value to match. + Extended access list: source value to match."; + mandatory true; + + leaf host { + description "Host to match"; + type inet:ipv4-address; + } + leaf network { + description "Network to match"; + type inet:ipv4-prefix; + } + leaf any { + description "Match any"; + type empty; + } + } + + choice extended-value { + when "./sequence >= 100 and ./sequence <= 199 or + ./sequence >= 2000 and ./sequence <= 2699"; + description "Destination value to match"; + + leaf destination-host { + description "Host to match"; + type inet:ipv4-address; + } + leaf destination-network { + description "Network to match"; + type inet:ipv4-prefix; + } + leaf destination-any { + description "Match any"; + type empty; + } + } + } + + list access-list { + description "Access list instance"; + + key "type identifier sequence"; + + leaf type { + description "Access list content type"; + type enumeration { + enum ipv4 { + description "Internet Protocol address version 4"; + value 0; + } + enum ipv6 { + description "Internet Protocol address version 6"; + value 1; + } + enum mac { + description "Media Access Control address"; + value 2; + } + + /* + * Protocol YANG models should augment the parent node to + * contain the routing protocol specific value. The protocol + * must also augment `value` leaf to include its specific + * values or expand the `when` statement on the existing cases. + */ + enum custom { + description "Custom data type"; + value 100; + } + } + } + + leaf identifier { + description "Access list identifier"; + type access-list-name; + } + + leaf sequence { + description "Access list sequence value"; + type access-list-sequence; + } + + leaf action { + description "Access list action on match"; + type access-list-action; + mandatory true; + } + + leaf remark { + description "Access list remark"; + type string; + } + + choice value { + description "Access list value to match"; + mandatory true; + + case ipv4-prefix { + when "./type = 'ipv4'"; + + leaf ipv4-prefix { + description "Configure IPv4 prefix to match"; + type inet:ipv4-prefix; + } + + leaf ipv4-exact-match { + description "Exact match of prefix"; + type boolean; + default false; + } + } + case ipv6-prefix { + when "./type = 'ipv6'"; + + leaf ipv6-prefix { + description "Configure IPv6 prefix to match"; + type inet:ipv6-prefix; + } + + leaf ipv6-exact-match { + description "Exact match of prefix"; + type boolean; + default false; + } + } + case mac { + when "./type = 'mac'"; + + leaf mac { + description "Configure MAC address to match"; + type yang:mac-address; + } + } + case any { + leaf any { + description "Match anything"; + type empty; + } + } + } + } + + list prefix-list { + description "Prefix list instance"; + + key "type name sequence"; + + leaf type { + description "Prefix list type"; + type enumeration { + enum ipv4 { + description "Internet Protocol address version 4"; + value 0; + } + enum ipv6 { + description "Internet Protocol address version 6"; + value 1; + } + } + } + + leaf name { + description "Prefix list name"; + type access-list-name; + } + + leaf sequence { + description "Access list sequence value"; + type access-list-sequence; + } + + leaf action { + description "Prefix list action on match"; + type access-list-action; + mandatory true; + } + + leaf description { + description "Prefix list user description"; + type string; + } + + choice value { + description "Prefix list value to match"; + mandatory true; + + case ipv4-prefix { + when "./type = 'ipv4'"; + + leaf ipv4-prefix { + description "Configure IPv4 prefix to match"; + type inet:ipv4-prefix; + } + + leaf ipv4-prefix-length-greater-or-equal { + description + "Specifies if matching prefixes with length greater than + or equal to value"; + type uint8 { + range "0..32"; + } + } + + leaf ipv4-prefix-length-lesser-or-equal { + description + "Specifies if matching prefixes with length lesser than + or equal to value"; + type uint8 { + range "0..32"; + } + } + } + case ipv6-prefix { + when "./type = 'ipv6'"; + + leaf ipv6-prefix { + description "Configure IPv6 prefix to match"; + type inet:ipv6-prefix; + } + + leaf ipv6-prefix-length-greater-or-equal { + description + "Specifies if matching prefixes with length greater than + or equal to value"; + type uint8 { + range "0..128"; + } + } + + leaf ipv6-prefix-length-lesser-or-equal { + description + "Specifies if matching prefixes with length lesser than + or equal to value"; + type uint8 { + range "0..128"; + } + } + } + case any { + leaf any { + description "Match anything"; + type empty; + } + } + } + } + } +} diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang new file mode 100644 index 0000000000..0ce40b474b --- /dev/null +++ b/yang/frr-route-map.yang @@ -0,0 +1,404 @@ +module frr-route-map { + yang-version 1.1; + namespace "http://frrouting.org/yang/route-map"; + prefix frr-route-map; + + import ietf-inet-types { + prefix inet; + } + import frr-filter { + prefix filter; + } + + organization "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description "This module defines route map settings"; + + revision 2019-07-01 { + description "Initial revision"; + } + + /* + * Types. + */ + typedef route-map-sequence { + description "Route map valid sequence numbers"; + type uint16 { + range "1..65535"; + } + } + + typedef route-map-name { + description "Route map name format"; + type string; + } + + /* + * Operational data. + */ + container route-map { + list instance { + description "Route map instance"; + + key "name sequence"; + + leaf name { + description "Route map instance name"; + type route-map-name; + } + + leaf sequence { + description + "Route map instance priority (low number means higher priority)"; + type route-map-sequence; + } + + leaf description { + description "Route map description"; + type string; + } + + leaf action { + description + "Route map actions: permit (executes action), deny (quits evaluation)"; + mandatory true; + type enumeration { + enum permit { + description + "Executes configured action and permits the prefix/route + if the conditions matched. An alternative exit action can + be configured to continue processing the route map list + or jump to process another route map."; + value 0; + } + enum deny { + description + "If all conditions are met the prefix/route is denied and + route map processing stops."; + value 1; + } + } + } + + list match-condition { + description "Route map match conditions"; + + key "condition"; + + leaf condition { + description "Match condition"; + type enumeration { + enum interface { + description "Match interface"; + value 0; + } + enum ipv4-address-list { + description "Match an IPv4 access-list"; + value 1; + } + enum ipv4-prefix-list { + description "Match an IPv4 prefix-list"; + value 2; + } + enum ipv4-prefix-length { + description "Match an IPv4 prefix length"; + value 3; + } + enum ipv4-next-hop-list { + description "Match an IPv4 next-hop"; + value 4; + } + enum ipv4-next-hop-prefix-list { + description "Match an IPv4 next-hop prefix list"; + value 5; + } + enum ipv4-next-hop-prefix-length { + description "Match an IPv4 next-hop prefix length"; + value 6; + } + enum ipv4-next-hop-type { + description "Match an IPv4 next-hop type"; + value 7; + } + enum ipv6-address-list { + description "Match an IPv6 access-list"; + value 8; + } + enum ipv6-prefix-list { + description "Match an IPv6 prefix-list"; + value 9; + } + enum ipv6-prefix-length { + description "Match an IPv6 prefix length"; + value 10; + } + enum ipv6-next-hop { + description "Match an IPv6 next-hop"; + value 11; + } + enum ipv6-next-hop-type { + description "Match an IPv6 next-hop type"; + value 12; + } + enum metric { + description "Match a route metric"; + value 13; + } + enum tag { + description "Match a route tag"; + value 14; + } + + /* + * Protocol YANG models should augment the parent node to + * contain the routing protocol specific value. The protocol + * must also augment `condition-value` to include its specific + * values or expand the `when` statement on the existing cases. + */ + enum routing-protocol-specific { + description "Match a routing protocol specific type"; + value 100; + } + } + } + + choice condition-value { + description + "Value to match (interpretation depends on condition type)"; + case access-list-num { + when "./condition = 'ipv4-address-list' or + ./condition = 'ipv4-next-hop-list'"; + leaf access-list-num { + type filter:access-list-standard; + } + } + case access-list-num-extended { + when "./condition = 'ipv4-address-list' or + ./condition = 'ipv4-next-hop-list'"; + leaf access-list-num-extended { + type filter:access-list-extended; + } + } + case list-name { + when "./condition = 'ipv4-address-list' or + ./condition = 'ipv4-prefix-list' or + ./condition = 'ipv4-next-hop-list' or + ./condition = 'ipv4-next-hop-prefix-list' or + ./condition = 'ipv6-address-list' or + ./condition = 'ipv6-prefix-list'"; + leaf list-name { + type filter:access-list-name; + } + } + case ipv6-address { + when "./condition = 'ipv6-next-hop'"; + leaf ipv6-address { + type inet:ipv6-address; + } + } + case ipv4-prefix-length { + when "./condition = 'ipv4-prefix-length' or + ./condition = 'ipv4-next-hop-prefix-length'"; + leaf ipv4-prefix-length { + type uint8 { + range "0..32"; + } + } + } + case ipv6-prefix-length { + when "./condition = 'ipv6-prefix-length'"; + leaf ipv6-prefix-length { + type uint8 { + range "0..128"; + } + } + } + case ipv4-next-hop-type { + when "./condition = 'ipv4-next-hop-type'"; + leaf ipv4-next-hop-type { + type enumeration { + enum blackhole { + value 0; + } + } + } + } + case ipv6-next-hop-type { + when "./condition = 'ipv6-next-hop-type'"; + leaf ipv6-next-hop-type { + type enumeration { + enum blackhole { + value 0; + } + } + } + } + case metric { + when "./condition = 'metric'"; + leaf metric { + type uint32 { + range "1..4294967295"; + } + } + } + case tag { + when "./condition = 'tag'"; + leaf tag { + type uint32 { + range "1..4294967295"; + } + } + } + } + } + + list set-action { + description "Route map set actions"; + + key "action"; + + leaf action { + description "Action to do when the route map matches"; + type enumeration { + enum ipv4-next-hop { + description "Set IPv4 address of the next hop"; + value 0; + } + enum ipv6-next-hop { + description "Set IPv6 address of the next hop"; + value 1; + } + enum metric { + description "Set prefix/route metric"; + value 2; + } + enum tag { + description "Set tag"; + value 3; + } + + /* + * Protocol YANG models should augment the parent node to + * contain the routing protocol specific value. The protocol + * must also augment `action-value` to include its specific + * values or expand the `when` statement on the existing cases. + */ + enum routing-protocol-specific { + description "Set a routing protocol specific action"; + value 100; + } + } + } + + choice action-value { + description + "Value to set (interpretation depends on action-type)"; + case ipv4-address { + when "./action = 'ipv4-next-hop'"; + leaf ipv4-address { + description "IPv4 address"; + type inet:ipv4-address; + } + } + case ipv6-address { + when "./action = 'ipv6-next-hop'"; + leaf ipv6-address { + description "IPv6 address"; + type inet:ipv6-address; + } + } + case metric { + when "./action = 'metric'"; + choice metric-value { + description "Metric to set or use"; + case value { + leaf value { + description "Use the following metric value"; + type uint32 { + range "0..4294967295"; + } + } + } + case add-metric { + leaf add-metric { + description "Add unit to metric"; + type boolean; + } + } + case subtract-metric { + leaf subtract-metric { + description "Subtract unit from metric"; + type boolean; + } + } + case use-round-trip-time { + leaf use-round-trip-time { + description "Use the round trip time as metric"; + type boolean; + } + } + case add-round-trip-time { + leaf add-round-trip-time { + description "Add round trip time to metric"; + type boolean; + } + } + case subtract-round-trip-time { + leaf subtract-round-trip-time { + description "Subtract round trip time to metric"; + type boolean; + } + } + } + } + case tag { + leaf tag { + description "Tag value"; + type uint32 { + range "0..4294967295"; + } + } + } + } + } + + leaf call { + description + "Call another route map before calling `exit-policy`. If the + called route map returns deny then this route map will also + return deny"; + type string; + } + + leaf exit-policy { + description "What do to after route map successful match, set and call"; + type enumeration { + enum permit-or-deny { + description "End route map evaluation and return"; + value 0; + } + enum next { + description + "Proceed evaluating next route map entry per sequence"; + value 1; + } + enum goto { + description + "Go to route map entry with the provided sequence number"; + value 2; + } + } + default "permit-or-deny"; + } + + leaf goto-value { + when "../exit-policy = 'goto'"; + description + "Sequence number to jump (when using `goto` exit policy)"; + type route-map-sequence; + } + } + } +} diff --git a/yang/subdir.am b/yang/subdir.am index 4b3baeea9d..18d2bf160c 100644 --- a/yang/subdir.am +++ b/yang/subdir.am @@ -28,6 +28,10 @@ if BFDD dist_yangmodels_DATA += yang/frr-bfdd.yang endif +if EIGRPD +dist_yangmodels_DATA += yang/frr-eigrpd.yang +endif + if RIPD dist_yangmodels_DATA += yang/frr-ripd.yang endif diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index df8d4bfe15..63e72fed00 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1347,6 +1347,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) "Intf %s(%u) has come UP", name, ifp->ifindex); if_up(ifp); + } else { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "Intf %s(%u) has gone DOWN", + name, ifp->ifindex); + if_down(ifp); } } diff --git a/zebra/main.c b/zebra/main.c index 84e83bc37e..657d1247e9 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -34,7 +34,6 @@ #include "privs.h" #include "sigevent.h" #include "vrf.h" -#include "logicalrouter.h" #include "libfrr.h" #include "routemap.h" #include "frr_pthread.h" @@ -262,7 +261,6 @@ int main(int argc, char **argv) graceful_restart = 0; vrf_configure_backend(VRF_BACKEND_VRF_LITE); - logicalrouter_configure_backend(LOGICALROUTER_BACKEND_NETNS); frr_preinit(&zebra_di, argc, argv); @@ -349,8 +347,6 @@ int main(int argc, char **argv) break; case 'n': vrf_configure_backend(VRF_BACKEND_NETNS); - logicalrouter_configure_backend( - LOGICALROUTER_BACKEND_OFF); break; case OPTION_V6_RR_SEMANTICS: v6_rr_semantics = true; diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index db4f9d0015..94918365a3 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -23,7 +23,6 @@ #include "lib/ns.h" #include "lib/vrf.h" -#include "lib/logicalrouter.h" #include "lib/prefix.h" #include "lib/memory.h" @@ -45,7 +44,6 @@ DEFINE_MTYPE(ZEBRA, ZEBRA_NS, "Zebra Name Space") static struct zebra_ns *dzns; -static int logicalrouter_config_write(struct vty *vty); static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete); struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id) @@ -188,8 +186,6 @@ int zebra_ns_init(const char *optional_default_name) ns_id_external = ns_map_nsid_with_external(ns_id, true); ns_init_management(ns_id_external, ns_id); - logicalrouter_init(logicalrouter_config_write); - /* Do any needed per-NS data structure allocation. */ dzns->if_table = route_table_init(); @@ -215,21 +211,6 @@ int zebra_ns_init(const char *optional_default_name) return 0; } -static int logicalrouter_config_write(struct vty *vty) -{ - struct ns *ns; - int write = 0; - - RB_FOREACH (ns, ns_head, &ns_tree) { - if (ns->ns_id == NS_DEFAULT || ns->name == NULL) - continue; - vty_out(vty, "logical-router %u netns %s\n", ns->ns_id, - ns->name); - write = 1; - } - return write; -} - int zebra_ns_config_write(struct vty *vty, struct ns *ns) { if (ns && ns->name != NULL) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index ca19971d64..3608b887ee 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1774,7 +1774,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) /* Redistribute */ redistribute_update(dest_pfx, src_pfx, - re, NULL); + re, old_re); } /* @@ -1926,6 +1926,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) goto done; } + /* Ensure we clear the QUEUED flag */ + UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); + /* Is this a notification that ... matters? We only really care about * the route that is currently selected for installation. */ @@ -1990,7 +1993,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) dplane_ctx_get_vrf(ctx), dest_str); /* We expect this to be the selected route, so we want - * to tell others about this transistion. + * to tell others about this transition. */ SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 0397b96983..da2fe4a30c 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -924,7 +924,7 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, } for (rn = route_top(table); rn; rn = route_next(rn)) { - if (p && prefix_cmp(&rn->p, p) != 0) + if (p && !prefix_match(&rn->p, p)) continue; if (rn->info) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 91edfab10f..99431e7e6d 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2444,7 +2444,7 @@ DEFPY (clear_evpn_dup_addr, zvrf = zebra_vrf_get_evpn(); if (vni_str) { - if (mac) { + if (!is_zero_mac(&mac->eth_addr)) { ret = zebra_vxlan_clear_dup_detect_vni_mac(vty, zvrf, vni, &mac->eth_addr); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 359585df73..2e8c81bddd 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3403,6 +3403,39 @@ static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac) return 0; } +static bool zvni_check_mac_del_from_db(struct mac_walk_ctx *wctx, + zebra_mac_t *mac) +{ + if ((wctx->flags & DEL_LOCAL_MAC) && + (mac->flags & ZEBRA_MAC_LOCAL)) + return true; + else if ((wctx->flags & DEL_REMOTE_MAC) && + (mac->flags & ZEBRA_MAC_REMOTE)) + return true; + else if ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP) && + (mac->flags & ZEBRA_MAC_REMOTE) && + IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip)) + return true; + else if ((wctx->flags & DEL_LOCAL_MAC) && + (mac->flags & ZEBRA_MAC_AUTO) && + !listcount(mac->neigh_list)) { + if (IS_ZEBRA_DEBUG_VXLAN) { + char buf[ETHER_ADDR_STRLEN]; + + zlog_debug("%s: Del MAC %s flags 0x%x", + __PRETTY_FUNCTION__, + prefix_mac2str(&mac->macaddr, + buf, sizeof(buf)), + mac->flags); + } + wctx->uninstall = 0; + + return true; + } + + return false; +} + /* * Free MAC hash entry (callback) */ @@ -3411,18 +3444,11 @@ static void zvni_mac_del_hash_entry(struct hash_bucket *bucket, void *arg) struct mac_walk_ctx *wctx = arg; zebra_mac_t *mac = bucket->data; - if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) - || ((wctx->flags & DEL_REMOTE_MAC) - && (mac->flags & ZEBRA_MAC_REMOTE)) - || ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP) - && (mac->flags & ZEBRA_MAC_REMOTE) - && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, - &wctx->r_vtep_ip))) { + if (zvni_check_mac_del_from_db(wctx, mac)) { if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) { zvni_mac_send_del_to_client(wctx->zvni->vni, &mac->macaddr); } - if (wctx->uninstall) zvni_mac_uninstall(wctx->zvni, mac); @@ -5332,8 +5358,6 @@ static void process_remote_macip_add(vni_t vni, if (ipa_len) SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); } else { - const char *mac_type; - /* When host moves but changes its (MAC,IP) * binding, BGP may install a MACIP entry that * corresponds to "older" location of the host @@ -5342,16 +5366,14 @@ static void process_remote_macip_add(vni_t vni, * the sequence number and ignore this update * if appropriate. */ - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) tmp_seq = mac->loc_seq; - mac_type = "local"; - } else { + else tmp_seq = mac->rem_seq; - mac_type = "remote"; - } + if (seq < tmp_seq) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s MAC has higher seq %u", + zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing MAC has higher seq %u flags 0x%x", vni, prefix_mac2str(macaddr, buf, sizeof(buf)), @@ -5359,8 +5381,7 @@ static void process_remote_macip_add(vni_t vni, ipa_len ? ipaddr2str(ipaddr, buf1, sizeof(buf1)) : "", - mac_type, - tmp_seq); + tmp_seq, mac->flags); return; } } @@ -7274,8 +7295,13 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp, * of a VxLAN bridge. */ zvni = zvni_from_svi(ifp, link_if); - if (!zvni) + if (!zvni) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%s: Del neighbor %s VNI is not present for interface %s", + __PRETTY_FUNCTION__, + ipaddr2str(ip, buf, sizeof(buf)), ifp->name); return 0; + } if (!zvni->vxlan_if) { zlog_debug( @@ -7672,9 +7698,10 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, return 0; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u flags 0x%x", + zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u seq %u flags 0x%x nbr count %u", prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, - ifp->ifindex, vid, zvni->vni, mac->flags); + ifp->ifindex, vid, zvni->vni, mac->loc_seq, + mac->flags, listcount(mac->neigh_list)); /* Update all the neigh entries associated with this mac */ zvni_process_neigh_on_local_mac_del(zvni, mac); |
