summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--babeld/message.c13
-rw-r--r--bgpd/bgp_route.c9
-rw-r--r--bgpd/bgp_rpki.c6
-rw-r--r--bgpd/bgp_vty.c4
-rw-r--r--debian/changelog4
-rw-r--r--doc/developer/workflow.rst55
-rw-r--r--doc/user/zebra.rst4
-rw-r--r--lib/command.c27
-rw-r--r--lib/command.h10
-rw-r--r--lib/hash.h13
-rw-r--r--lib/json.h9
-rw-r--r--ospf6d/ospf6_area.c5
-rw-r--r--ospf6d/ospf6_lsdb.c12
-rw-r--r--ospf6d/ospf6_lsdb.h1
-rw-r--r--pbrd/pbr_map.c6
-rw-r--r--pbrd/pbr_nht.c43
-rw-r--r--pbrd/pbr_nht.h5
-rw-r--r--pbrd/pbr_vty.c3
-rw-r--r--redhat/frr.spec.in2
-rwxr-xr-xtools/release_notes.py3
-rw-r--r--tools/releasedate.py18
-rw-r--r--zebra/interface.c10
-rw-r--r--zebra/interface.h6
-rw-r--r--zebra/kernel_netlink.c65
-rw-r--r--zebra/rt_netlink.c3
-rw-r--r--zebra/rtadv.c68
-rw-r--r--zebra/rtadv.h3
-rw-r--r--zebra/zebra_dplane.c16
-rw-r--r--zebra/zebra_dplane.h1
-rw-r--r--zebra/zebra_nhg.c31
-rw-r--r--zebra/zebra_router.h7
-rw-r--r--zebra/zebra_vty.c40
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");