diff options
| -rw-r--r-- | babeld/message.c | 13 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 9 | ||||
| -rw-r--r-- | bgpd/bgp_rpki.c | 6 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 4 | ||||
| -rw-r--r-- | debian/changelog | 4 | ||||
| -rw-r--r-- | doc/developer/workflow.rst | 55 | ||||
| -rw-r--r-- | doc/user/zebra.rst | 4 | ||||
| -rw-r--r-- | lib/command.c | 27 | ||||
| -rw-r--r-- | lib/command.h | 10 | ||||
| -rw-r--r-- | lib/hash.h | 13 | ||||
| -rw-r--r-- | lib/json.h | 9 | ||||
| -rw-r--r-- | ospf6d/ospf6_area.c | 5 | ||||
| -rw-r--r-- | ospf6d/ospf6_lsdb.c | 12 | ||||
| -rw-r--r-- | ospf6d/ospf6_lsdb.h | 1 | ||||
| -rw-r--r-- | pbrd/pbr_map.c | 6 | ||||
| -rw-r--r-- | pbrd/pbr_nht.c | 43 | ||||
| -rw-r--r-- | pbrd/pbr_nht.h | 5 | ||||
| -rw-r--r-- | pbrd/pbr_vty.c | 3 | ||||
| -rw-r--r-- | redhat/frr.spec.in | 2 | ||||
| -rwxr-xr-x | tools/release_notes.py | 3 | ||||
| -rw-r--r-- | tools/releasedate.py | 18 | ||||
| -rw-r--r-- | zebra/interface.c | 10 | ||||
| -rw-r--r-- | zebra/interface.h | 6 | ||||
| -rw-r--r-- | zebra/kernel_netlink.c | 65 | ||||
| -rw-r--r-- | zebra/rt_netlink.c | 3 | ||||
| -rw-r--r-- | zebra/rtadv.c | 68 | ||||
| -rw-r--r-- | zebra/rtadv.h | 3 | ||||
| -rw-r--r-- | zebra/zebra_dplane.c | 16 | ||||
| -rw-r--r-- | zebra/zebra_dplane.h | 1 | ||||
| -rw-r--r-- | zebra/zebra_nhg.c | 31 | ||||
| -rw-r--r-- | zebra/zebra_router.h | 7 | ||||
| -rw-r--r-- | zebra/zebra_vty.c | 40 |
32 files changed, 418 insertions, 84 deletions
diff --git a/babeld/message.c b/babeld/message.c index 5c2e29d8b3..3a29b6a60f 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -288,13 +288,18 @@ channels_len(unsigned char *channels) static int babel_packet_examin(const unsigned char *packet, int packetlen) { - unsigned i = 0, bodylen; + int i = 0, bodylen; const unsigned char *message; unsigned char type, len; if(packetlen < 4 || packet[0] != 42 || packet[1] != 2) return 1; DO_NTOHS(bodylen, packet + 2); + if(bodylen + 4 > packetlen) { + debugf(BABEL_DEBUG_COMMON, "Received truncated packet (%d + 4 > %d).", + bodylen, packetlen); + return 1; + } while (i < bodylen){ message = packet + 4 + i; type = message[0]; @@ -366,12 +371,6 @@ parse_packet(const unsigned char *from, struct interface *ifp, DO_NTOHS(bodylen, packet + 2); - if(bodylen + 4 > packetlen) { - flog_err(EC_BABEL_PACKET, "Received truncated packet (%d + 4 > %d).", - bodylen, packetlen); - bodylen = packetlen - 4; - } - i = 0; while(i < bodylen) { message = packet + 4 + i; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index fa83a457bf..e390ba5c75 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2200,10 +2200,11 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, if (ret == RMAP_DENYMATCH) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) zlog_debug( - "%s [Update:SEND] %pFX is filtered by route-map", - peer->host, p); + "%s [Update:SEND] %pFX is filtered by route-map '%s'", + peer->host, p, + ROUTE_MAP_OUT_NAME(filter)); - bgp_attr_flush(attr); + bgp_attr_flush(&dummy_attr); return false; } } @@ -12249,6 +12250,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, bool first = true; uint16_t show_flags = 0; enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED; + struct prefix p; if (uj) { argc--; @@ -12401,7 +12403,6 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, if (argv_find(argv, argc, "A.B.C.D/M", &idx) || argv_find(argv, argc, "X:X::X:X/M", &idx)) { const char *prefix_str = argv[idx]->arg; - struct prefix p; if (!str2prefix(prefix_str, &p)) { vty_out(vty, "%% Malformed Prefix\n"); diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index e5027359e7..b320e4e719 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -369,7 +369,7 @@ static int bgpd_sync_callback(struct thread *thread) thread_add_read(bm->master, bgpd_sync_callback, NULL, socket, &t_rpki); if (atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) { - while (read(socket, &rec, sizeof(rec) != -1)) + while (read(socket, &rec, sizeof(struct pfx_record) != -1)) ; atomic_store_explicit(&rtr_update_overflow, 0, @@ -378,8 +378,8 @@ static int bgpd_sync_callback(struct thread *thread) return 0; } - retval = read(socket, &rec, sizeof(rec)); - if (retval != sizeof(rec)) { + retval = read(socket, &rec, sizeof(struct pfx_record)); + if (retval != sizeof(struct pfx_record)) { RPKI_DEBUG("Could not read from socket"); return retval; } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 72b6049308..9a1991cd09 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -687,10 +687,10 @@ static bool peer_address_self_check(struct bgp *bgp, union sockunion *su) union sockunion all_su; if (su->sa.sa_family == AF_INET) { - str2sockunion("0.0.0.0", &all_su); + (void)str2sockunion("0.0.0.0", &all_su); ifp = if_lookup_by_ipv4_exact(&su->sin.sin_addr, bgp->vrf_id); } else if (su->sa.sa_family == AF_INET6) { - str2sockunion("::", &all_su); + (void)str2sockunion("::", &all_su); ifp = if_lookup_by_ipv6_exact(&su->sin6.sin6_addr, su->sin6.sin6_scope_id, bgp->vrf_id); diff --git a/debian/changelog b/debian/changelog index f5b392274a..2b28c4c6dc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,8 @@ -frr (8.2~dev-1) UNRELEASED; urgency=medium +frr (8.3~dev-1) UNRELEASED; urgency=medium * New upstream release... - -- Jafar Al-Gharaibeh <jafar@atcorp.com> Mon, 08 Nov 2021 10:00:00 +0500 + -- Donatas Abraitis <donatas.abraitis@gmail.com> Tue, 01 Feb 2022 11:00:00 +0200 frr (8.1-0) unstable; urgency=medium diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 54561d3b4b..5911fdb587 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -95,8 +95,8 @@ March/July/November. Walking backwards from this date: are considered lowest priority (regardless of when they were opened.) - 4 weeks earlier, the stable branch separates from master (named - ``dev/MAJOR.MINOR`` at this point) and a ``rc1`` release candidate is - tagged. Master is unfrozen and new features may again proceed. + ``dev/MAJOR.MINOR`` at this point) and tagged as ```base_X.Y``. + Master is unfrozen and new features may again proceed. Part of unfreezing master is editing the ``AC_INIT`` statement in :file:`configure.ac` to reflect the new development version that master @@ -108,7 +108,38 @@ March/July/November. Walking backwards from this date: (The :file:`configure.ac` edit and tag push are considered git housekeeping and are pushed directly to ``master``, not through a PR.) - - 2 weeks earlier, a ``rc2`` release candidate is tagged. + Below is the snippet of the commands to use in this step. + + .. code-block:: console + + % git remote --verbose + upstream git@github.com:frrouting/frr (fetch) + upstream git@github.com:frrouting/frr (push) + + % git checkout master + % git pull upstream master + % git checkout -b dev/8.2 + % git tag base_8.2 + % git push upstream base_8.2 + % git push upstream dev/8.2 + % git checkout master + % sed -i 's/8.2-dev/8.3-dev/' configure.ac + % git tag -a frr-8.3-dev -m "frr-8.3-dev" + % git push upstream frr-8.3-dev + % git add configure.ac + % git commit -s -m "build: FRR 8.3 development version" + % git push upstream master + + In this step, we also have to update package versions to reflect + the development version. Versions need to be updated using + a standard way of development (Pull Requests) based on master branch. + + Only change the version number with no other changes. This will produce + packages with the a version number that is higher than any previous + version. Once the release is done, whatever updates we make to changelog + files on the release branch need to be cherry-picked to the master branch. + + - 2 weeks earlier, a ``frr-X.Y-rc`` release candidate is tagged. - on release date, the branch is renamed to ``stable/MAJOR.MINOR``. @@ -121,15 +152,15 @@ as early as possible, i.e. the first 2-week window. For reference, the expected release schedule according to the above is: -+------------+------------+------------+------------+------------+------------+ -| Release | 2021-11-02 | 2022-03-01 | 2022-07-05 | 2022-11-01 | 2023-03-07 | -+------------+------------+------------+------------+------------+------------+ -| rc2 | 2021-10-19 | 2022-02-15 | 2022-06-21 | 2022-10-18 | 2023-02-21 | -+------------+------------+------------+------------+------------+------------+ -| rc1/branch | 2021-10-05 | 2022-02-01 | 2022-06-07 | 2022-10-04 | 2023-02-07 | -+------------+------------+------------+------------+------------+------------+ -| freeze | 2021-09-21 | 2022-01-18 | 2022-05-24 | 2022-09-20 | 2023-01-24 | -+------------+------------+------------+------------+------------+------------+ ++---------+------------+------------+------------+------------+------------+ +| Release | 2021-11-02 | 2022-03-01 | 2022-07-05 | 2022-11-01 | 2023-03-07 | ++---------+------------+------------+------------+------------+------------+ +| RC | 2021-10-19 | 2022-02-15 | 2022-06-21 | 2022-10-18 | 2023-02-21 | ++---------+------------+------------+------------+------------+------------+ +| dev/X.Y | 2021-10-05 | 2022-02-01 | 2022-06-07 | 2022-10-04 | 2023-02-07 | ++---------+------------+------------+------------+------------+------------+ +| freeze | 2021-09-21 | 2022-01-18 | 2022-05-24 | 2022-09-20 | 2023-01-24 | ++---------+------------+------------+------------+------------+------------+ Each release is managed by one or more volunteer release managers from the FRR community. To spread and distribute this workload, this should be rotated for diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 9ed6b6dd7f..7ca473ceb6 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -1155,7 +1155,9 @@ zebra Terminal Mode Commands .. clicmd:: show zebra Display various statistics related to the installation and deletion - of routes, neighbor updates, and LSP's into the kernel. + of routes, neighbor updates, and LSP's into the kernel. In addition + show various zebra state that is useful when debugging an operator's + setup. .. clicmd:: show zebra client [summary] diff --git a/lib/command.c b/lib/command.c index 9cf93ea192..ebdbf162d1 100644 --- a/lib/command.c +++ b/lib/command.c @@ -106,6 +106,21 @@ const char *cmd_domainname_get(void) return host.domainname; } +const char *cmd_system_get(void) +{ + return host.system; +} + +const char *cmd_release_get(void) +{ + return host.release; +} + +const char *cmd_version_get(void) +{ + return host.version; +} + static int root_on_exit(struct vty *vty); /* Standard command node structures. */ @@ -1398,8 +1413,9 @@ DEFUN (show_version, SHOW_STR "Displays zebra version\n") { - vty_out(vty, "%s %s (%s).\n", FRR_FULL_NAME, FRR_VERSION, - cmd_hostname_get() ? cmd_hostname_get() : ""); + vty_out(vty, "%s %s (%s) on %s(%s).\n", FRR_FULL_NAME, FRR_VERSION, + cmd_hostname_get() ? cmd_hostname_get() : "", cmd_system_get(), + cmd_release_get()); vty_out(vty, "%s%s\n", FRR_COPYRIGHT, GIT_INFO); #ifdef ENABLE_VERSION_BUILD_CONFIG vty_out(vty, "configured with:\n %s\n", FRR_CONFIG_ARGS); @@ -2445,6 +2461,10 @@ void cmd_init(int terminal) /* Default host value settings. */ host.name = XSTRDUP(MTYPE_HOST, names.nodename); + host.system = XSTRDUP(MTYPE_HOST, names.sysname); + host.release = XSTRDUP(MTYPE_HOST, names.release); + host.version = XSTRDUP(MTYPE_HOST, names.version); + #ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME if ((strcmp(names.domainname, "(none)") == 0)) host.domainname = NULL; @@ -2563,6 +2583,9 @@ void cmd_terminate(void) } XFREE(MTYPE_HOST, host.name); + XFREE(MTYPE_HOST, host.system); + XFREE(MTYPE_HOST, host.release); + XFREE(MTYPE_HOST, host.version); XFREE(MTYPE_HOST, host.domainname); XFREE(MTYPE_HOST, host.password); XFREE(MTYPE_HOST, host.password_encrypt); diff --git a/lib/command.h b/lib/command.h index c888356d61..a540bdc5c5 100644 --- a/lib/command.h +++ b/lib/command.h @@ -55,6 +55,13 @@ struct host { /* Domainname of this router */ char *domainname; + /* + * Some extra system data that is useful + */ + char *system; + char *release; + char *version; + /* Password for vty interface. */ char *password; char *password_encrypt; @@ -600,6 +607,9 @@ extern int cmd_domainname_set(const char *domainname); extern int cmd_hostname_set(const char *hostname); extern const char *cmd_hostname_get(void); extern const char *cmd_domainname_get(void); +extern const char *cmd_system_get(void); +extern const char *cmd_release_get(void); +extern const char *cmd_version_get(void); /* NOT safe for general use; call this only if DEV_BUILD! */ extern void grammar_sandbox_init(void); diff --git a/lib/hash.h b/lib/hash.h index f3b24f051b..91770d1813 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -235,9 +235,10 @@ extern void *hash_release(struct hash *hash, void *data); /* * Iterate over the elements in a hash table. * - * It is safe to delete items passed to the iteration function from the hash - * table during iteration. More than one item cannot be deleted during each - * iteration. Please note that adding entries to the hash + * The passed in arg to the handler function is the only safe + * item to delete from the hash. + * + * Please note that adding entries to the hash * during the walk will cause undefined behavior in that some new entries * will be walked and some will not. So do not do this. * @@ -258,8 +259,10 @@ extern void hash_iterate(struct hash *hash, /* * Iterate over the elements in a hash table, stopping on condition. * - * It is safe to delete items passed to the iteration function from the hash - * table during iteration. Please note that adding entries to the hash + * The passed in arg to the handler function is the only safe item + * to delete from the hash. + * + * Please note that adding entries to the hash * during the walk will cause undefined behavior in that some new entries * will be walked and some will not. So do not do this. * diff --git a/lib/json.h b/lib/json.h index 9d33ac7ae3..fcaa84c816 100644 --- a/lib/json.h +++ b/lib/json.h @@ -42,6 +42,15 @@ extern "C" { json_object_iter_equal(&(joi), &(join)) == 0; \ json_object_iter_next(&(joi))) +#define JSON_OBJECT_NEW_ARRAY(json_func, fields, n) \ + ({ \ + struct json_object *_json_array = json_object_new_array(); \ + for (int _i = 0; _i < (n); _i++) \ + json_object_array_add(_json_array, \ + (json_func)((fields)[_i])); \ + (_json_array); \ + }) + extern bool use_json(const int argc, struct cmd_token *argv[]); extern void json_object_string_add(struct json_object *obj, const char *key, const char *s); diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index a612f7d1b8..a0cb455798 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -455,6 +455,11 @@ void ospf6_area_show(struct vty *vty, struct ospf6_area *oa, json_object_int_add(json_area, "numberOfAreaScopedLsa", oa->lsdb->count); + json_object_object_add( + json_area, "lsaStatistics", + JSON_OBJECT_NEW_ARRAY(json_object_new_int, + oa->lsdb->stats, + OSPF6_LSTYPE_SIZE)); /* Interfaces Attached */ array_interfaces = json_object_new_array(); diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index 039c65d739..889ab16b11 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -92,6 +92,16 @@ static void _lsdb_count_assert(struct ospf6_lsdb *lsdb) #define ospf6_lsdb_count_assert(t) ((void) 0) #endif /*DEBUG*/ +static inline void ospf6_lsdb_stats_update(struct ospf6_lsa *lsa, + struct ospf6_lsdb *lsdb, int count) +{ + uint16_t stat = ntohs(lsa->header->type) & OSPF6_LSTYPE_FCODE_MASK; + + if (stat >= OSPF6_LSTYPE_SIZE) + stat = OSPF6_LSTYPE_UNKNOWN; + lsdb->stats[stat] += count; +} + void ospf6_lsdb_add(struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) { struct prefix_ipv6 key; @@ -112,6 +122,7 @@ void ospf6_lsdb_add(struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) if (!old) { lsdb->count++; + ospf6_lsdb_stats_update(lsa, lsdb, 1); if (OSPF6_LSA_IS_MAXAGE(lsa)) { if (lsdb->hook_remove) @@ -161,6 +172,7 @@ void ospf6_lsdb_remove(struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) node->info = NULL; lsdb->count--; + ospf6_lsdb_stats_update(lsa, lsdb, -1); if (lsdb->hook_remove) (*lsdb->hook_remove)(lsa); diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h index 9789e8c4e0..07c331af64 100644 --- a/ospf6d/ospf6_lsdb.h +++ b/ospf6d/ospf6_lsdb.h @@ -29,6 +29,7 @@ struct ospf6_lsdb { void *data; /* data structure that holds this lsdb */ struct route_table *table; uint32_t count; + uint32_t stats[OSPF6_LSTYPE_SIZE]; void (*hook_add)(struct ospf6_lsa *); void (*hook_remove)(struct ospf6_lsa *); }; diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index 03e6bacf1e..7710f3277d 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -792,6 +792,12 @@ void pbr_map_check_nh_group_change(const char *nh_group) if (found_name) { bool original = pbrm->valid; + /* Set data we were waiting on */ + if (pbrms->nhgrp_name) + pbr_nht_set_seq_nhg_data( + pbrms, + nhgc_find(pbrms->nhgrp_name)); + pbr_map_check_valid_internal(pbrm); if (pbrm->valid && (original != pbrm->valid)) diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index aaadad482e..fb0bd72585 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -522,6 +522,49 @@ char *pbr_nht_nexthop_make_name(char *name, size_t l, return buffer; } +/* Set data derived from nhg in pbrms */ +void pbr_nht_set_seq_nhg_data(struct pbr_map_sequence *pbrms, + const struct nexthop_group_cmd *nhgc) +{ + const struct nexthop_group *nhg; + + if (!nhgc) + return; + + nhg = &nhgc->nhg; + if (!nhg->nexthop) + return; + + switch (nhg->nexthop->type) { + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + pbrms->family = AF_INET6; + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + pbrms->family = AF_INET; + default: + break; + } +} + +/* Configure a routemap sequence to use a given nexthop group */ +void pbr_nht_set_seq_nhg(struct pbr_map_sequence *pbrms, const char *name) +{ + struct nexthop_group_cmd *nhgc; + + if (!name) + return; + + pbrms->nhgrp_name = XSTRDUP(MTYPE_TMP, name); + + nhgc = nhgc_find(name); + if (!nhgc) + return; + + pbr_nht_set_seq_nhg_data(pbrms, nhgc); +} + void pbr_nht_add_individual_nexthop(struct pbr_map_sequence *pbrms, const struct nexthop *nhop) { diff --git a/pbrd/pbr_nht.h b/pbrd/pbr_nht.h index 8d9edc6332..ecc92cc051 100644 --- a/pbrd/pbr_nht.h +++ b/pbrd/pbr_nht.h @@ -109,6 +109,11 @@ extern struct pbr_nexthop_group_cache *pbr_nht_add_group(const char *name); extern void pbr_nht_change_group(const char *name); extern void pbr_nht_delete_group(const char *name); +extern void pbr_nht_set_seq_nhg_data(struct pbr_map_sequence *pbrms, + const struct nexthop_group_cmd *nhgc); +extern void pbr_nht_set_seq_nhg(struct pbr_map_sequence *pbrms, + const char *name); + extern void pbr_nht_add_individual_nexthop(struct pbr_map_sequence *pbrms, const struct nexthop *nhop); extern void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms); diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index c9ec532bb9..21c1409e91 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -506,7 +506,8 @@ DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd, /* This is new/replacement config */ pbrms_clear_set_config(pbrms); - pbrms->nhgrp_name = XSTRDUP(MTYPE_TMP, name); + pbr_nht_set_seq_nhg(pbrms, name); + pbr_map_check(pbrms, true); return CMD_SUCCESS; diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 7f8e89de16..740cfe498a 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -775,6 +775,8 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons %changelog * Tue Nov 4 2021 Martin Winter <mwinter@opensourcerouting.org> - %{version} +* Tue Feb 1 2022 Donatas Abraitis <donatas.abraitis@gmail.com> - 8.2 + * Tue Nov 2 2021 Jafar Al-Gharaibeh <jafar@atcorp.com> - 8.1 - FRR 8.1 brings a long list of enhancements and fixes with 1200 commits from - 75 developers. Thanks to all contributers. diff --git a/tools/release_notes.py b/tools/release_notes.py index 7481cc18c3..973215b572 100755 --- a/tools/release_notes.py +++ b/tools/release_notes.py @@ -10,6 +10,7 @@ import os import getopt import subprocess + def run(cmd): proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) rv = proc.communicate("")[0].decode("UTF-8") @@ -45,7 +46,7 @@ def main(argv): tag = run(["git", "describe", "--abbrev=0"]).strip("\n") chnglog = run( - ["git", "log", "--no-merges", "--pretty=format:'%s%d'", tag + ".." + branch] + ["git", "log", "--no-merges", "--pretty=format:'%s'", tag + ".." + branch] ) chnglog = chnglog.split("\n") diff --git a/tools/releasedate.py b/tools/releasedate.py index 37780501c3..3df1ea48fb 100644 --- a/tools/releasedate.py +++ b/tools/releasedate.py @@ -36,21 +36,23 @@ if __name__ == "__main__": print("Last release was (scheduled) on %s" % last.isoformat()) rel = upcoming.pop(0) - freeze, rc1, rc2 = rel - w2 * 3, rel - w2 * 2, rel - w2 + freeze, stabilization, rc = rel - w2 * 3, rel - w2 * 2, rel - w2 if now == rel: print("It's release day! 🎉") - elif now >= rc2: + elif now >= rc: print( - "%d days until release! (rc2 since %s)" - % ((rel - now).days, rc2.isoformat()) + "%d days until release! (RC since %s)" % ((rel - now).days, rc.isoformat()) + ) + elif now >= stabilization: + print( + "%d days until RC. (stabilization branch created since %s)" + % ((rc - now).days, stabilization.isoformat()) ) - elif now >= rc1: - print("%d days until rc2. (rc1 since %s)" % ((rc2 - now).days, rc1.isoformat())) elif now >= freeze: print( - "%d days until rc1, master is frozen since %s" - % ((rc1 - now).days, freeze.isoformat()) + "%d days until stabilization branch, master is frozen since %s" + % ((stabilization - now).days, freeze.isoformat()) ) else: print( diff --git a/zebra/interface.c b/zebra/interface.c index e4e80ec4e9..2e13cfd55c 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -158,6 +158,16 @@ static int if_zebra_new_hook(struct interface *ifp) rtadv->AdvReachableTime = 0; rtadv->AdvRetransTimer = 0; rtadv->AdvCurHopLimit = RTADV_DEFAULT_HOPLIMIT; + memset(&rtadv->lastadvcurhoplimit, 0, + sizeof(rtadv->lastadvcurhoplimit)); + memset(&rtadv->lastadvmanagedflag, 0, + sizeof(rtadv->lastadvmanagedflag)); + memset(&rtadv->lastadvotherconfigflag, 0, + sizeof(rtadv->lastadvotherconfigflag)); + memset(&rtadv->lastadvreachabletime, 0, + sizeof(rtadv->lastadvreachabletime)); + memset(&rtadv->lastadvretranstimer, 0, + sizeof(rtadv->lastadvretranstimer)); rtadv->AdvDefaultLifetime = -1; /* derive from MaxRtrAdvInterval */ rtadv->HomeAgentPreference = 0; diff --git a/zebra/interface.h b/zebra/interface.h index 771398b547..413a67469a 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -81,6 +81,7 @@ struct rtadvconf { Default: false */ int AdvManagedFlag; + struct timeval lastadvmanagedflag; /* The true/false value to be placed in the "Other stateful @@ -89,6 +90,7 @@ struct rtadvconf { Default: false */ int AdvOtherConfigFlag; + struct timeval lastadvotherconfigflag; /* The value to be placed in MTU options sent by the router. A value of zero indicates that no MTU options are sent. @@ -105,6 +107,7 @@ struct rtadvconf { Default: 0 */ uint32_t AdvReachableTime; #define RTADV_MAX_REACHABLE_TIME 3600000 + struct timeval lastadvreachabletime; /* The value to be placed in the Retrans Timer field in the Router Advertisement messages sent by the router. The value zero means @@ -112,6 +115,7 @@ struct rtadvconf { Default: 0 */ int AdvRetransTimer; + struct timeval lastadvretranstimer; /* The default value to be placed in the Cur Hop Limit field in the Router Advertisement messages sent by the router. The value @@ -121,6 +125,8 @@ struct rtadvconf { Default: The value specified in the "Assigned Numbers" RFC [ASSIGNED] that was in effect at the time of implementation. */ int AdvCurHopLimit; + struct timeval lastadvcurhoplimit; + #define RTADV_DEFAULT_HOPLIMIT 64 /* 64 hops */ /* The value to be placed in the Router Lifetime field of Router diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index e7ef28d0f7..e3b2f9cb66 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -1125,8 +1125,25 @@ static int nl_batch_read_resp(struct nl_batch *bth) while (true) { status = netlink_recv_msg(nl, msg, nl_batch_rx_buf, sizeof(nl_batch_rx_buf)); - if (status == -1 || status == 0) + /* + * status == -1 is a full on failure somewhere + * since we don't know where the problem happened + * we must mark all as failed + * + * Else we mark everything as worked + * + */ + if (status == -1 || status == 0) { + while ((ctx = dplane_ctx_dequeue(&(bth->ctx_list))) != + NULL) { + if (status == -1) + dplane_ctx_set_status( + ctx, + ZEBRA_DPLANE_REQUEST_FAILURE); + dplane_ctx_enqueue_tail(bth->ctx_out_q, ctx); + } return status; + } h = (struct nlmsghdr *)nl_batch_rx_buf; ignore_msg = false; @@ -1138,15 +1155,18 @@ static int nl_batch_read_resp(struct nl_batch *bth) * requests at same time. */ while (true) { - ctx = dplane_ctx_dequeue(&(bth->ctx_list)); - if (ctx == NULL) - break; - - dplane_ctx_enqueue_tail(bth->ctx_out_q, ctx); - - /* We have found corresponding context object. */ - if (dplane_ctx_get_ns(ctx)->nls.seq == seq) + ctx = dplane_ctx_get_head(&(bth->ctx_list)); + if (ctx == NULL) { + /* + * This is a situation where we have gotten + * into a bad spot. We need to know that + * this happens( does it? ) + */ + zlog_err( + "%s:WARNING Received netlink Response for an error and no Contexts to associate with it", + __func__); break; + } /* * 'update' context objects take two consecutive @@ -1161,10 +1181,35 @@ static int nl_batch_read_resp(struct nl_batch *bth) ignore_msg = true; break; } + + ctx = dplane_ctx_dequeue(&(bth->ctx_list)); + dplane_ctx_enqueue_tail(bth->ctx_out_q, ctx); + + /* We have found corresponding context object. */ + if (dplane_ctx_get_ns(ctx)->nls.seq == seq) + break; + + if (dplane_ctx_get_ns(ctx)->nls.seq > seq) + zlog_warn( + "%s:WARNING Recieved %u is less than any context on the queue ctx->seq %u", + __func__, seq, + dplane_ctx_get_ns(ctx)->nls.seq); } - if (ignore_msg) + if (ignore_msg) { + /* + * If we ignore the message due to an update + * above we should still fricking decode the + * message for our operator to understand + * what is going on + */ + int err = netlink_parse_error(nl, h, bth->zns->is_cmd, + false); + + zlog_debug("%s: netlink error message seq=%d %d", + __func__, h->nlmsg_seq, err); continue; + } /* * We received a message with the sequence number that isn't diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 24c01b7f51..2d12ad4c8e 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -3027,11 +3027,12 @@ int netlink_nexthop_read(struct zebra_ns *zns) * this kernel must support them. */ supports_nh = true; - if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_NHG) zlog_debug("Nexthop objects %ssupported on this kernel", supports_nh ? "" : "not "); + zebra_router_set_supports_nhgs(supports_nh); + return ret; } diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 350b97cc5d..3bbee83d77 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -47,6 +47,8 @@ extern struct zebra_privs_t zserv_privs; +static uint32_t interfaces_configured_for_ra_from_bgp; + #if defined(HAVE_RTADV) #ifndef VTYSH_EXTRACT_PL @@ -632,45 +634,66 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len, radvert = (struct nd_router_advert *)msg; - if ((radvert->nd_ra_curhoplimit && zif->rtadv.AdvCurHopLimit) - && (radvert->nd_ra_curhoplimit != zif->rtadv.AdvCurHopLimit)) { +#define SIXHOUR2USEC (int64_t)6 * 60 * 60 * 1000000 + + if ((radvert->nd_ra_curhoplimit && zif->rtadv.AdvCurHopLimit) && + (radvert->nd_ra_curhoplimit != zif->rtadv.AdvCurHopLimit) && + (monotime_since(&zif->rtadv.lastadvcurhoplimit, NULL) > + SIXHOUR2USEC || + zif->rtadv.lastadvcurhoplimit.tv_sec == 0)) { flog_warn( EC_ZEBRA_RA_PARAM_MISMATCH, "%s(%u): Rx RA - our AdvCurHopLimit doesn't agree with %s", ifp->name, ifp->ifindex, addr_str); + monotime(&zif->rtadv.lastadvcurhoplimit); } - if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) - && !zif->rtadv.AdvManagedFlag) { + if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) && + !zif->rtadv.AdvManagedFlag && + (monotime_since(&zif->rtadv.lastadvmanagedflag, NULL) > + SIXHOUR2USEC || + zif->rtadv.lastadvmanagedflag.tv_sec == 0)) { flog_warn( EC_ZEBRA_RA_PARAM_MISMATCH, "%s(%u): Rx RA - our AdvManagedFlag doesn't agree with %s", ifp->name, ifp->ifindex, addr_str); + monotime(&zif->rtadv.lastadvmanagedflag); } - if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) - && !zif->rtadv.AdvOtherConfigFlag) { + if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) && + !zif->rtadv.AdvOtherConfigFlag && + (monotime_since(&zif->rtadv.lastadvotherconfigflag, NULL) > + SIXHOUR2USEC || + zif->rtadv.lastadvotherconfigflag.tv_sec == 0)) { flog_warn( EC_ZEBRA_RA_PARAM_MISMATCH, "%s(%u): Rx RA - our AdvOtherConfigFlag doesn't agree with %s", ifp->name, ifp->ifindex, addr_str); + monotime(&zif->rtadv.lastadvotherconfigflag); } - if ((radvert->nd_ra_reachable && zif->rtadv.AdvReachableTime) - && (ntohl(radvert->nd_ra_reachable) - != zif->rtadv.AdvReachableTime)) { + if ((radvert->nd_ra_reachable && zif->rtadv.AdvReachableTime) && + (ntohl(radvert->nd_ra_reachable) != zif->rtadv.AdvReachableTime) && + (monotime_since(&zif->rtadv.lastadvreachabletime, NULL) > + SIXHOUR2USEC || + zif->rtadv.lastadvreachabletime.tv_sec == 0)) { flog_warn( EC_ZEBRA_RA_PARAM_MISMATCH, "%s(%u): Rx RA - our AdvReachableTime doesn't agree with %s", ifp->name, ifp->ifindex, addr_str); + monotime(&zif->rtadv.lastadvreachabletime); } - if ((ntohl(radvert->nd_ra_retransmit) - != (unsigned int)zif->rtadv.AdvRetransTimer)) { + if ((ntohl(radvert->nd_ra_retransmit) != + (unsigned int)zif->rtadv.AdvRetransTimer) && + (monotime_since(&zif->rtadv.lastadvretranstimer, NULL) > + SIXHOUR2USEC || + zif->rtadv.lastadvretranstimer.tv_sec == 0)) { flog_warn( EC_ZEBRA_RA_PARAM_MISMATCH, "%s(%u): Rx RA - our AdvRetransTimer doesn't agree with %s", ifp->name, ifp->ifindex, addr_str); + monotime(&zif->rtadv.lastadvretranstimer); } /* Create entry for neighbor if not known. */ @@ -1282,6 +1305,9 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable) zif = ifp->info; if (enable) { + if (!CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED)) + interfaces_configured_for_ra_from_bgp++; + SET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED); ipv6_nd_suppress_ra_set(ifp, RA_ENABLE); if (ra_interval @@ -1290,6 +1316,9 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable) VTY_RA_INTERVAL_CONFIGURED)) zif->rtadv.MaxRtrAdvInterval = ra_interval * 1000; } else { + if (CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED)) + interfaces_configured_for_ra_from_bgp--; + UNSET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED); if (!CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED)) @@ -2766,6 +2795,8 @@ void rtadv_vrf_terminate(struct zebra_vrf *zvrf) void rtadv_cmd_init(void) { + interfaces_configured_for_ra_from_bgp = 0; + hook_register(zebra_if_extra_info, nd_dump_vty); hook_register(zebra_if_config_wr, rtadv_config_write); @@ -2865,6 +2896,11 @@ static int if_leave_all_router(int sock, struct interface *ifp) return 0; } +bool rtadv_compiled_in(void) +{ + return true; +} + #else void rtadv_vrf_init(struct zebra_vrf *zvrf) { @@ -2920,4 +2956,14 @@ void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS) return; } +bool rtadv_compiled_in(void) +{ + return false; +} + #endif /* HAVE_RTADV */ + +uint32_t rtadv_get_interfaces_configured_from_bgp(void) +{ + return interfaces_configured_for_ra_from_bgp; +} diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 7b71ee45a2..a95174b22b 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -22,6 +22,7 @@ #ifndef _ZEBRA_RTADV_H #define _ZEBRA_RTADV_H +#include "zebra.h" #include "vty.h" #include "zebra/interface.h" @@ -161,6 +162,8 @@ extern void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS); extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS); extern void rtadv_add_prefix(struct zebra_if *zif, const struct prefix_ipv6 *p); extern void rtadv_delete_prefix(struct zebra_if *zif, const struct prefix *p); +extern uint32_t rtadv_get_interfaces_configured_from_bgp(void); +extern bool rtadv_compiled_in(void); #ifdef __cplusplus } diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index bf34fb54a9..656ebcf3b7 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -833,6 +833,13 @@ void dplane_ctx_list_append(struct dplane_ctx_q *to_list, } } +struct zebra_dplane_ctx *dplane_ctx_get_head(struct dplane_ctx_q *q) +{ + struct zebra_dplane_ctx *ctx = TAILQ_FIRST(q); + + return ctx; +} + /* Dequeue a context block from the head of a list */ struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_q *q) { @@ -2296,6 +2303,8 @@ static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx, { dplane_info_from_zns(&(ctx->zd_ns_info), zns); + ctx->zd_is_update = is_update; + #if defined(HAVE_NETLINK) /* Increment message counter after copying to context struct - may need * two messages in some 'update' cases. @@ -2514,7 +2523,6 @@ int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, * it probably won't require two messages */ dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_NH_UPDATE)); - ctx->zd_is_update = (op == DPLANE_OP_NH_UPDATE); ret = AOK; @@ -2537,7 +2545,6 @@ int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, /* Capture namespace info */ dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), (op == DPLANE_OP_LSP_UPDATE)); - ctx->zd_is_update = (op == DPLANE_OP_LSP_UPDATE); memset(&ctx->u.lsp, 0, sizeof(ctx->u.lsp)); @@ -2813,7 +2820,6 @@ static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx, dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), op == DPLANE_OP_RULE_UPDATE); - ctx->zd_is_update = (op == DPLANE_OP_RULE_UPDATE); ctx->zd_vrf_id = new_rule->vrf_id; strlcpy(ctx->zd_ifname, new_rule->ifname, sizeof(ctx->zd_ifname)); @@ -2859,7 +2865,6 @@ static int dplane_ctx_iptable_init(struct zebra_dplane_ctx *ctx, ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false); - ctx->zd_is_update = false; ctx->zd_vrf_id = iptable->vrf_id; memcpy(&ctx->u.iptable, iptable, sizeof(struct zebra_pbr_iptable)); @@ -2899,7 +2904,6 @@ static int dplane_ctx_ipset_init(struct zebra_dplane_ctx *ctx, ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false); - ctx->zd_is_update = false; ctx->zd_vrf_id = ipset->vrf_id; @@ -2934,7 +2938,6 @@ dplane_ctx_ipset_entry_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false); - ctx->zd_is_update = false; ctx->zd_vrf_id = ipset->vrf_id; @@ -3015,7 +3018,6 @@ dplane_route_update_internal(struct route_node *rn, */ if ((op == DPLANE_OP_ROUTE_UPDATE) && old_re && (old_re != re)) { - ctx->zd_is_update = true; old_re->dplane_sequence = zebra_router_get_next_sequence(); diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 977f00bd2a..1d55181388 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -274,6 +274,7 @@ void dplane_ctx_list_append(struct dplane_ctx_q *to_list, /* Dequeue a context block from the head of caller's tailq */ struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_q *q); +struct zebra_dplane_ctx *dplane_ctx_get_head(struct dplane_ctx_q *q); /* * Accessors for information from the context object diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index aa015992d5..fac312cf7c 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -2995,7 +2995,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) dplane_ctx_fini(&ctx); } -static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg) +static int zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg) { struct nhg_hash_entry *nhe = NULL; @@ -3009,7 +3009,7 @@ static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg) * from an upper level proto. */ if (zrouter.startup_time < nhe->uptime) - return; + return HASHWALK_CONTINUE; /* * If it's proto-owned and not being used by a route, remove it since @@ -3019,20 +3019,41 @@ static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg) */ if (PROTO_OWNED(nhe) && nhe->refcnt == 1) { zebra_nhg_decrement_ref(nhe); - return; + return HASHWALK_ABORT; } /* * If its being ref'd by routes, just let it be uninstalled via a route * removal. */ - if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0) + if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0) { zebra_nhg_uninstall_kernel(nhe); + return HASHWALK_ABORT; + } + + return HASHWALK_CONTINUE; } void zebra_nhg_sweep_table(struct hash *hash) { - hash_iterate(hash, zebra_nhg_sweep_entry, NULL); + uint32_t count; + + /* + * Yes this is extremely odd. Effectively nhg's have + * other nexthop groups that depend on them and when you + * remove them, you can have other entries blown up. + * our hash code does not work with deleting multiple + * entries at a time and will possibly cause crashes + * So what to do? Whenever zebra_nhg_sweep_entry + * deletes an entry it will return HASHWALK_ABORT, + * cause that deletion might have triggered more. + * then we can just keep sweeping this table + * until nothing more is found to do. + */ + do { + count = hashcount(hash); + hash_walk(hash, zebra_nhg_sweep_entry, NULL); + } while (count != hashcount(hash)); } static void zebra_nhg_mark_keep_entry(struct hash_bucket *bucket, void *arg) diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index dd788216c7..dafe925c26 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -209,6 +209,8 @@ struct zebra_router { */ bool asic_offloaded; bool notify_on_ack; + + bool supports_nhgs; }; #define GRACEFUL_RESTART_TIME 60 @@ -256,6 +258,11 @@ extern enum multicast_mode multicast_mode_ipv4_get(void); extern bool zebra_router_notify_on_ack(void); +static inline void zebra_router_set_supports_nhgs(bool support) +{ + zrouter.supports_nhgs = support; +} + /* zebra_northbound.c */ extern const struct frr_yang_module_info frr_zebra_info; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index fab1e7b897..1d9ed4ddd9 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -33,6 +33,7 @@ #include "routemap.h" #include "srcdest_table.h" #include "vxlan.h" +#include "termtable.h" #include "zebra/zebra_router.h" #include "zebra/zserv.h" @@ -61,6 +62,7 @@ #include "zebra/kernel_netlink.h" #include "zebra/table_manager.h" #include "zebra/zebra_script.h" +#include "zebra/rtadv.h" extern int allow_delete; @@ -3969,9 +3971,43 @@ DEFUN (show_zebra, ZEBRA_STR) { struct vrf *vrf; + struct ttable *table = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + char *out; - if (zrouter.asic_offloaded) - vty_out(vty, "Asic Offload is being used\n"); + ttable_rowseps(table, 0, BOTTOM, true, '-'); + ttable_add_row(table, "OS|%s(%s)", cmd_system_get(), cmd_release_get()); + ttable_add_row(table, "v4 Forwarding|%s", ipforward() ? "On" : "Off"); + ttable_add_row(table, "v6 Forwarding|%s", + ipforward_ipv6() ? "On" : "Off"); + ttable_add_row(table, "MPLS|%s", mpls_enabled ? "On" : "Off"); + ttable_add_row(table, "EVPN|%s", is_evpn_enabled() ? "On" : "Off"); + + +#ifdef GNU_LINUX + if (!vrf_is_backend_netns()) + ttable_add_row(table, "VRF|l3mdev Available"); + else + ttable_add_row(table, "VRF|Namespaces"); +#else + ttable_add_row(table, "VRF|Not Available"); +#endif + + ttable_add_row(table, "ASIC offload|%s", + zrouter.asic_offloaded ? "Used" : "Unavailable"); + + ttable_add_row(table, "RA|%s", + rtadv_compiled_in() ? "Compiled in" : "Not Compiled in"); + ttable_add_row(table, "RFC 5549|%s", + rtadv_get_interfaces_configured_from_bgp() + ? "BGP is using" + : "BGP is not using"); + + ttable_add_row(table, "Kernel NHG|%s", + zrouter.supports_nhgs ? "Available" : "Unavailable"); + + out = ttable_dump(table, "\n"); + vty_out(vty, "%s\n", out); + XFREE(MTYPE_TMP, out); vty_out(vty, " Route Route Neighbor LSP LSP\n"); |
