summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_mplsvpn.c2
-rw-r--r--doc/developer/building-frr-for-openwrt.rst4
-rw-r--r--doc/developer/fuzzing.rst164
-rw-r--r--doc/developer/index.rst1
-rw-r--r--doc/user/basic.rst2
-rw-r--r--doc/user/ospf6d.rst7
-rw-r--r--doc/user/vrrp.rst2
-rw-r--r--lib/thread.c7
-rw-r--r--lib/thread.h4
-rw-r--r--lib/vrf.h2
-rw-r--r--nhrpd/nhrp_route.c12
-rw-r--r--ospf6d/ospf6_abr.c13
-rw-r--r--ospf6d/ospf6_bfd.c5
-rw-r--r--ospf6d/ospf6_bfd.h6
-rw-r--r--ospf6d/ospf6_interface.c2
-rw-r--r--ospf6d/ospf6_neighbor.c442
-rw-r--r--ospf6d/ospf6_neighbor.h2
-rw-r--r--ospfd/ospf_gr_helper.c16
-rw-r--r--ospfd/ospf_opaque.h2
-rw-r--r--tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py6
-rw-r--r--tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py6
-rw-r--r--tests/topotests/lib/common_config.py277
-rw-r--r--tests/topotests/route-scale/r1/installed.routes.json8
-rw-r--r--tests/topotests/route-scale/test_route_scale.py25
-rw-r--r--zebra/rt_netlink.c8
25 files changed, 610 insertions, 415 deletions
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 0c527efb8c..5877390377 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -265,7 +265,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
if (STREAM_READABLE(data) != 0) {
flog_err(
EC_BGP_UPDATE_RCV,
- "%s [Error] Update packet error / VPN (%td data remaining after parsing)",
+ "%s [Error] Update packet error / VPN (%zu data remaining after parsing)",
peer->host, STREAM_READABLE(data));
return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
}
diff --git a/doc/developer/building-frr-for-openwrt.rst b/doc/developer/building-frr-for-openwrt.rst
index 9bd1296dad..47cf2cbd43 100644
--- a/doc/developer/building-frr-for-openwrt.rst
+++ b/doc/developer/building-frr-for-openwrt.rst
@@ -51,7 +51,7 @@ to work and it may be needed to run a ``make`` for the entire build
environment. Add ``V=s`` to get more debugging output.
More information about OpenWrt buildsystem can be found `here
-<https://openwrt.org/docs/guide-developer/build-system/use-buildsystem>`_.
+<https://openwrt.org/docs/guide-developer/build-system/use-buildsystem>`__.
Work with sources
-----------------
@@ -59,7 +59,7 @@ Work with sources
To update to a newer version, or change other options, you need to edit the ``feeds/packages/frr/Makefile``.
More information about working with patches in OpenWrt buildsystem can be found `here
-<https://openwrt.org/docs/guide-developer/build-system/use-patches-with-buildsystem>`_.
+<https://openwrt.org/docs/guide-developer/build-system/use-patches-with-buildsystem>`__.
Usage
-----
diff --git a/doc/developer/fuzzing.rst b/doc/developer/fuzzing.rst
new file mode 100644
index 0000000000..8a3318745e
--- /dev/null
+++ b/doc/developer/fuzzing.rst
@@ -0,0 +1,164 @@
+.. _fuzzing:
+
+Fuzzing
+=======
+
+This page describes the fuzzing targets and supported fuzzers available in FRR
+and how to use them. Familiarity with fuzzing techniques and tools is assumed.
+
+Overview
+--------
+
+It is well known that networked applications tend to be difficult to fuzz on
+their network-facing attack surfaces. Approaches involving actual network
+transmission tend to be slow and are subject to intermediate devices and
+networking stacks which tend to drop fuzzed packets, especially if the fuzzing
+surface covers IP itself. Some time was spent on fuzzing FRR this way with some
+mediocre results but attention quickly turned towards skipping the actual
+networking and instead adding fuzzing targets directly in the packet processing
+code for use by more traditional in- and out-of-process fuzzers. Results from
+this approach have been very fruitful.
+
+The patches to add fuzzing targets are kept in a separate git branch. Typically
+it is better to keep them in the main branch so they are kept up to date and do
+not need to be constantly synchronized with the main codebase. Unfortunately,
+changes to FRR to support fuzzing necessarily extend far beyond the
+entrypoints. Checksums must be disarmed, interactions with the kernel must be
+skipped, sockets and files must be avoided, desired under/overflows must be
+marked, etc. There are the usual ``LD_PRELOAD`` libraries to emulate these
+things (preeny et al) but FRR is a very kernel-reliant program and these
+libraries tend to create annoying problems when used with FRR for whatever
+reason. Keeping this code in the main codebase is cluttering, difficult to work
+with / around, and runs the risk of accidentally introducing bugs even if
+``#ifdef``'d out. Consequently it's in a separate branch that is rebased on
+``master`` from time to time.
+
+
+Code
+----
+
+The git branch with fuzzing targets is located here:
+
+https://github.com/FRRouting/frr/tree/fuzz
+
+To build libFuzzer targets, pass ``--enable-libfuzzer`` to ``configure``.
+To build AFL targets, compile with ``afl-clang`` as usual.
+
+Fuzzing with sanitizers is strongly recommended, especially ASAN, which you can
+enable by passing ``--enable-address-sanitizer`` to ``configure``.
+
+Suggested UBSAN flags: ``-fsanitize-recover=unsigned-integer-overflow,implicit-conversion -fsanitize=unsigned-integer-overflow,implicit-conversion,nullability-arg,nullability-assign,nullability-return``
+Recommended cflags: ``-Wno-all -g3 -O3 -funroll-loops``
+
+Design
+------
+
+All fuzzing targets have support for libFuzzer and AFL. This is done by writing
+the target as a libFuzzer entrypoint (``LLVMFuzzerTestOneInput()``) and calling
+it from the AFL entrypoint in ``main()``. New targets should use this rule.
+
+When adding AFL entrypoints, it's a good idea to use AFL persistent mode for
+better performance. Grep ``bgpd/bgp_main.c`` for ``__AFL_INIT()`` for an
+example of how to do this in FRR. Typically it involves moving all internal
+daemon setup into a setup function. Then this setup function is called exactly
+once for the lifetime of the process. In ``LLVMFuzzerTestOneInput()`` this
+means you need to call it at the start of the function protected by a static
+boolean that is set to true, since that function is your entrypoint. You also
+need to call it prior to ``__AFL_INIT()`` in ``main()`` because ``main()`` is
+your entrypoint in the AFL case.
+
+Adding support to daemons
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This section describes how to add entrypoints to daemons that do not have any
+yet.
+
+Because libFuzzer has its own ``main()`` function, when adding fuzzing support
+to a daemon that doesn't have any targets already, ``main()`` needs to be
+``#ifdef``'d out like so:
+
+.. code:: c
+
+ #ifndef FUZZING_LIBFUZZER
+
+ int main(int argc, char **argv)
+ {
+ ...
+ }
+
+ #endif /* FUZZING_LIBFUZZER */
+
+
+The ``FUZZING_LIBFUZZER`` macro is set by ``--enable-libfuzzer``.
+
+Because libFuzzer can only be linked into daemons that have
+``LLVMFuzzerTestOneInput()`` implemented, we can't pass ``-fsanitize=fuzzer``
+to all daemons in ``AM_CFLAGS``. It needs to go into a variable specific to
+each daemon. Since it can be thought of as a kind of sanitizer, for daemons
+that have libFuzzer support there are now individual flags variables for those
+daemons named ``DAEMON_SAN_FLAGS`` (e.g. ``BGPD_SAN_FLAGS``,
+``ZEBRA_SAN_FLAGS``). This variable has the contents of the generic
+``SAN_FLAGS`` plus any fuzzing-related flags. It is used in daemons'
+``subdir.am`` in place of ``SAN_FLAGS``. Daemons that don't support libFuzzer
+still use ``SAN_FLAGS``. If you want to add fuzzing support to a daemon you
+need to do this flag variable conversion; look at ``configure.ac`` for
+examples, it is fairly straightforward. Remember to update ``subdir.am`` to use
+the new variable.
+
+Do note that when fuzzing is enabled, ``SAN_FLAGS`` gains
+``-fsanitize=fuzzer-no-link``; the result is that all daemons are instrumented
+for fuzzing but only the ones with ``LLVMFuzzerTestOneInput()`` actually get
+linked with libFuzzer.
+
+
+Targets
+-------
+
+A given daemon can have lots of different paths that are interesting to fuzz.
+There's not really a great way to handle this, most fuzzers assume the program
+has one entrypoint. The approach taken in FRR for multiple entrypoints is to
+control which path is taken within ``LLVMFuzzerTestOneInput()`` using
+``#ifdef`` and passing whatever controlling macro definition you want. Take a
+look at that function for the daemon you're interested in fuzzing, pick the
+target, add ``#define MY_TARGET 1`` somewhere before the ``#ifdef`` switch,
+recompile.
+
+.. list-table:: Fuzzing Targets
+
+ * - Daemon
+ - Target
+ - Fuzzers
+ * - bgpd
+ - packet parser
+ - libfuzzer, afl
+ * - ospfd
+ - packet parser
+ - libfuzzer, afl
+ * - pimd
+ - packet parser
+ - libfuzzer, afl
+ * - vrrpd
+ - packet parser
+ - libfuzzer, afl
+ * - vrrpd
+ - zapi parser
+ - libfuzzer, afl
+ * - zebra
+ - netlink
+ - libfuzzer, afl
+ * - zebra
+ - zserv / zapi
+ - libfuzzer, afl
+
+
+Fuzzer Notes
+------------
+
+Some interesting seed corpuses for various daemons are available `here
+<https://github.com/qlyoung/frr-fuzz/tree/master/samples>`_.
+
+For libFuzzer, you need to pass ``-rss_limit_mb=0`` if you are fuzzing with
+ASAN enabled, as you should.
+
+For AFL, afl++ is strongly recommended; afl proper isn't really maintained
+anymore.
diff --git a/doc/developer/index.rst b/doc/developer/index.rst
index 1ba0f31c8a..5a7da806ff 100644
--- a/doc/developer/index.rst
+++ b/doc/developer/index.rst
@@ -9,6 +9,7 @@ FRRouting Developer's Guide
packaging
process-architecture
library
+ fuzzing
tracing
testing
bgpd
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index 0bdcccaf74..7a450bec53 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -26,7 +26,7 @@ forms the initial command set for a routing beast as it is starting.
Config files are generally found in |INSTALL_PREFIX_ETC|.
Config Methods
-^^^^^^^^^^^^^^
+--------------
There are two ways of configuring FRR.
diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst
index 6295ba9293..dd53d8f8b4 100644
--- a/doc/user/ospf6d.rst
+++ b/doc/user/ospf6d.rst
@@ -179,10 +179,11 @@ Showing OSPF6 information
To see OSPF interface configuration like costs.
-.. index:: show ipv6 ospf6 neighbor
-.. clicmd:: show ipv6 ospf6 neighbor
+.. index:: show ipv6 ospf6 neighbor [json]
+.. clicmd:: show ipv6 ospf6 neighbor [json]
- Shows state and chosen (Backup) DR of neighbor.
+ Shows state and chosen (Backup) DR of neighbor. JSON output can be
+ obtained by appending 'json' at the end.
.. index:: show ipv6 ospf6 request-list A.B.C.D
.. clicmd:: show ipv6 ospf6 request-list A.B.C.D
diff --git a/doc/user/vrrp.rst b/doc/user/vrrp.rst
index 8ab050e9a0..cb70da3f3b 100644
--- a/doc/user/vrrp.rst
+++ b/doc/user/vrrp.rst
@@ -503,6 +503,7 @@ The following configuration is then generated for you:
vrrp 5 ip 10.0.2.16
vrrp 5 ipv6 2001:db8::370:7334
+
VRRP is automatically activated. Global defaults, if set, are applied.
You can then edit this configuration with **vtysh** as needed, and commit it by
@@ -516,6 +517,7 @@ My virtual routers are not seeing each others' advertisements
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Check:
+
- Is your kernel at least 5.1?
- Did you set the macvlan devices to ``bridge`` mode?
- If using IPv4 virtual addresses, does the parent of the macvlan devices have
diff --git a/lib/thread.c b/lib/thread.c
index db53e267f8..e71fd74bd9 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -115,10 +115,9 @@ static void vty_out_cpu_thread_history(struct vty *vty,
struct cpu_thread_history *a)
{
vty_out(vty, "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu",
- (size_t)a->total_active, a->cpu.total / 1000,
- a->cpu.total % 1000, (size_t)a->total_calls,
- (size_t)(a->cpu.total / a->total_calls), a->cpu.max,
- (size_t)(a->real.total / a->total_calls), a->real.max);
+ a->total_active, a->cpu.total / 1000, a->cpu.total % 1000,
+ a->total_calls, (a->cpu.total / a->total_calls), a->cpu.max,
+ (a->real.total / a->total_calls), a->real.max);
vty_out(vty, " %c%c%c%c%c %s\n",
a->types & (1 << THREAD_READ) ? 'R' : ' ',
a->types & (1 << THREAD_WRITE) ? 'W' : ' ',
diff --git a/lib/thread.h b/lib/thread.h
index 682a17b9f3..eb1b107e7b 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -115,8 +115,8 @@ struct thread {
struct cpu_thread_history {
int (*func)(struct thread *);
- atomic_uint_fast32_t total_calls;
- atomic_uint_fast32_t total_active;
+ atomic_size_t total_calls;
+ atomic_size_t total_active;
struct time_stats {
atomic_size_t total, max;
} real;
diff --git a/lib/vrf.h b/lib/vrf.h
index 2d2fbe4fef..c636b9ea7e 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -43,7 +43,7 @@ enum { IFLA_VRF_UNSPEC, IFLA_VRF_TABLE, __IFLA_VRF_MAX };
#endif
#define VRF_NAMSIZ 36
-#define NS_NAMSIZ 16
+#define NS_NAMSIZ 36
/*
* The command strings
diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c
index 2bc2d91597..e7d35b90ff 100644
--- a/nhrpd/nhrp_route.c
+++ b/nhrpd/nhrp_route.c
@@ -350,10 +350,22 @@ void nhrp_zebra_init(void)
zclient_init(zclient, ZEBRA_ROUTE_NHRP, 0, &nhrpd_privs);
}
+static void nhrp_table_node_cleanup(struct route_table *table,
+ struct route_node *node)
+{
+ if (!node->info)
+ return;
+
+ XFREE(MTYPE_NHRP_ROUTE, node->info);
+}
+
void nhrp_zebra_terminate(void)
{
zclient_stop(zclient);
zclient_free(zclient);
+
+ zebra_rib[AFI_IP]->cleanup = nhrp_table_node_cleanup;
+ zebra_rib[AFI_IP6]->cleanup = nhrp_table_node_cleanup;
route_table_finish(zebra_rib[AFI_IP]);
route_table_finish(zebra_rib[AFI_IP6]);
}
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index f087289df6..c71b30a2d4 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -196,7 +196,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
if (ADV_ROUTER_IN_PREFIX(&route->prefix)
== area->ospf6->router_id) {
zlog_debug(
- "%s: Skipping ASBR announcement for ABR (%pFX)",
+ "%s: Skipping ASBR announcement for ABR (%pI4)",
__func__,
&ADV_ROUTER_IN_PREFIX(&route->prefix));
return 0;
@@ -208,7 +208,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
|| IS_OSPF6_DEBUG_ORIGINATE(INTER_ROUTER)) {
is_debug++;
zlog_debug(
- "Originating summary in area %s for ASBR %pFX",
+ "Originating summary in area %s for ASBR %pI4",
area->name,
&ADV_ROUTER_IN_PREFIX(&route->prefix));
}
@@ -225,9 +225,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
if (is_debug)
zlog_debug(
"%s: route %pFX with cost %u is not best, ignore.",
- __func__,
- &ADV_ROUTER_IN_PREFIX(
- &route->prefix),
+ __func__, &route->prefix,
route->path.cost);
return 0;
}
@@ -405,8 +403,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
if (is_debug)
zlog_debug(
"prefix %pFX was denied by export list",
- &ADV_ROUTER_IN_PREFIX(
- &route->prefix));
+ &route->prefix);
return 0;
}
}
@@ -418,7 +415,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
if (is_debug)
zlog_debug(
"prefix %pFX was denied by filter-list out",
- &ADV_ROUTER_IN_PREFIX(&route->prefix));
+ &route->prefix);
return 0;
}
diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c
index 4e50ab5244..523ed7f181 100644
--- a/ospf6d/ospf6_bfd.c
+++ b/ospf6d/ospf6_bfd.c
@@ -55,12 +55,13 @@ void ospf6_bfd_info_free(void **bfd_info)
/*
* ospf6_bfd_show_info - Show BFD info structure
*/
-void ospf6_bfd_show_info(struct vty *vty, void *bfd_info, int param_only)
+void ospf6_bfd_show_info(struct vty *vty, void *bfd_info, int param_only,
+ json_object *json_obj, bool use_json)
{
if (param_only)
bfd_show_param(vty, bfd_info, 1, 0, 0, NULL);
else
- bfd_show_info(vty, bfd_info, 0, 1, 0, NULL);
+ bfd_show_info(vty, bfd_info, 0, 1, use_json, json_obj);
}
/*
diff --git a/ospf6d/ospf6_bfd.h b/ospf6d/ospf6_bfd.h
index 19dff1ff7c..b4e798e911 100644
--- a/ospf6d/ospf6_bfd.h
+++ b/ospf6d/ospf6_bfd.h
@@ -19,7 +19,7 @@
* 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 "lib/json.h"
#ifndef OSPF6_BFD_H
#define OSPF6_BFD_H
@@ -35,8 +35,8 @@ extern void ospf6_bfd_info_nbr_create(struct ospf6_interface *oi,
extern void ospf6_bfd_info_free(void **bfd_info);
-extern void ospf6_bfd_show_info(struct vty *vty, void *bfd_info,
- int param_only);
+extern void ospf6_bfd_show_info(struct vty *vty, void *bfd_info, int param_only,
+ json_object *json_obj, bool use_json);
extern void ospf6_bfd_reg_dereg_nbr(struct ospf6_neighbor *on, int command);
#endif /* OSPF6_BFD_H */
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 75917b9d85..2d1b5e7b5a 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -996,7 +996,7 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp)
(oi->thread_send_lsack ? "on" : "off"));
for (ALL_LSDB(oi->lsack_list, lsa, lsanext))
vty_out(vty, " %s\n", lsa->name);
- ospf6_bfd_show_info(vty, oi->bfd_info, 1);
+ ospf6_bfd_show_info(vty, oi->bfd_info, 1, NULL, false);
return 0;
}
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index 9f13ecffa1..c1905e8c1e 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -44,6 +44,7 @@
#include "ospf6_lsa.h"
#include "ospf6_spf.h"
#include "ospf6_zebra.h"
+#include "lib/json.h"
DEFINE_HOOK(ospf6_neighbor_change,
(struct ospf6_neighbor * on, int state, int next_state),
@@ -595,7 +596,8 @@ int inactivity_timer(struct thread *thread)
/* vty functions */
/* show neighbor structure */
-static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on)
+static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
+ json_object *json_array, bool use_json)
{
char router_id[16];
char duration[64];
@@ -603,6 +605,7 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on)
char nstate[16];
char deadtime[64];
long h, m, s;
+ json_object *json_route;
/* Router-ID (Name) */
inet_ntop(AF_INET, &on->router_id, router_id, sizeof(router_id));
@@ -641,23 +644,43 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on)
/*
vty_out (vty, "%-15s %3d %11s %6s/%-12s %11s %s[%s]\n",
- "Neighbor ID", "Pri", "DeadTime", "State", "", "Duration",
- "I/F", "State");
+ "Neighbor ID", "Pri", "DeadTime", "State", "IfState",
+ "Duration", "I/F", "State");
*/
-
- vty_out(vty, "%-15s %3d %11s %8s/%-12s %11s %s[%s]\n", router_id,
- on->priority, deadtime, ospf6_neighbor_state_str[on->state],
- nstate, duration, on->ospf6_if->interface->name,
- ospf6_interface_state_str[on->ospf6_if->state]);
+ if (use_json) {
+ json_route = json_object_new_object();
+
+ json_object_string_add(json_route, "neighborId", router_id);
+ json_object_int_add(json_route, "priority", on->priority);
+ json_object_string_add(json_route, "deadTime", deadtime);
+ json_object_string_add(json_route, "state",
+ ospf6_neighbor_state_str[on->state]);
+ json_object_string_add(json_route, "ifState", nstate);
+ json_object_string_add(json_route, "duration", duration);
+ json_object_string_add(json_route, "interfaceName",
+ on->ospf6_if->interface->name);
+ json_object_string_add(
+ json_route, "interfaceState",
+ ospf6_interface_state_str[on->ospf6_if->state]);
+
+ json_object_array_add(json_array, json_route);
+ } else
+ vty_out(vty, "%-15s %3d %11s %8s/%-12s %11s %s[%s]\n",
+ router_id, on->priority, deadtime,
+ ospf6_neighbor_state_str[on->state], nstate, duration,
+ on->ospf6_if->interface->name,
+ ospf6_interface_state_str[on->ospf6_if->state]);
}
static void ospf6_neighbor_show_drchoice(struct vty *vty,
- struct ospf6_neighbor *on)
+ struct ospf6_neighbor *on,
+ json_object *json_array, bool use_json)
{
char router_id[16];
char drouter[16], bdrouter[16];
char duration[64];
struct timeval now, res;
+ json_object *json_route;
/*
vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]\n",
@@ -673,19 +696,39 @@ static void ospf6_neighbor_show_drchoice(struct vty *vty,
timersub(&now, &on->last_changed, &res);
timerstring(&res, duration, sizeof(duration));
- vty_out(vty, "%-15s %8s/%-11s %-15s %-15s %s[%s]\n", router_id,
- ospf6_neighbor_state_str[on->state], duration, drouter,
- bdrouter, on->ospf6_if->interface->name,
- ospf6_interface_state_str[on->ospf6_if->state]);
+ if (use_json) {
+ json_route = json_object_new_object();
+ json_object_string_add(json_route, "routerId", router_id);
+ json_object_string_add(json_route, "state",
+ ospf6_neighbor_state_str[on->state]);
+ json_object_string_add(json_route, "duration", duration);
+ json_object_string_add(json_route, "dRouter", drouter);
+ json_object_string_add(json_route, "bdRouter", bdrouter);
+ json_object_string_add(json_route, "interfaceName",
+ on->ospf6_if->interface->name);
+ json_object_string_add(
+ json_route, "interfaceState",
+ ospf6_interface_state_str[on->ospf6_if->state]);
+
+ json_object_array_add(json_array, json_route);
+ } else
+ vty_out(vty, "%-15s %8s/%-11s %-15s %-15s %s[%s]\n", router_id,
+ ospf6_neighbor_state_str[on->state], duration, drouter,
+ bdrouter, on->ospf6_if->interface->name,
+ ospf6_interface_state_str[on->ospf6_if->state]);
}
static void ospf6_neighbor_show_detail(struct vty *vty,
- struct ospf6_neighbor *on)
+ struct ospf6_neighbor *on,
+ json_object *json, bool use_json)
{
char drouter[16], bdrouter[16];
char linklocal_addr[64], duration[32];
struct timeval now, res;
struct ospf6_lsa *lsa, *lsanext;
+ json_object *json_neighbor;
+ json_object *json_array;
+ char db_desc_str[20];
inet_ntop(AF_INET6, &on->linklocal_addr, linklocal_addr,
sizeof(linklocal_addr));
@@ -696,149 +739,333 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
timersub(&now, &on->last_changed, &res);
timerstring(&res, duration, sizeof(duration));
- vty_out(vty, " Neighbor %s\n", on->name);
- vty_out(vty, " Area %s via interface %s (ifindex %d)\n",
- on->ospf6_if->area->name, on->ospf6_if->interface->name,
- on->ospf6_if->interface->ifindex);
- vty_out(vty, " His IfIndex: %d Link-local address: %s\n",
- on->ifindex, linklocal_addr);
- vty_out(vty, " State %s for a duration of %s\n",
- ospf6_neighbor_state_str[on->state], duration);
- vty_out(vty, " His choice of DR/BDR %s/%s, Priority %d\n", drouter,
- bdrouter, on->priority);
- vty_out(vty, " DbDesc status: %s%s%s SeqNum: %#lx\n",
- (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT) ? "Initial "
- : ""),
- (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT) ? "More " : ""),
- (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT) ? "Master"
- : "Slave"),
- (unsigned long)ntohl(on->dbdesc_seqnum));
-
- vty_out(vty, " Summary-List: %d LSAs\n", on->summary_list->count);
- for (ALL_LSDB(on->summary_list, lsa, lsanext))
- vty_out(vty, " %s\n", lsa->name);
-
- vty_out(vty, " Request-List: %d LSAs\n", on->request_list->count);
- for (ALL_LSDB(on->request_list, lsa, lsanext))
- vty_out(vty, " %s\n", lsa->name);
-
- vty_out(vty, " Retrans-List: %d LSAs\n", on->retrans_list->count);
- for (ALL_LSDB(on->retrans_list, lsa, lsanext))
- vty_out(vty, " %s\n", lsa->name);
-
- timerclear(&res);
- if (on->thread_send_dbdesc)
- timersub(&on->thread_send_dbdesc->u.sands, &now, &res);
- timerstring(&res, duration, sizeof(duration));
- vty_out(vty, " %d Pending LSAs for DbDesc in Time %s [thread %s]\n",
- on->dbdesc_list->count, duration,
- (on->thread_send_dbdesc ? "on" : "off"));
- for (ALL_LSDB(on->dbdesc_list, lsa, lsanext))
- vty_out(vty, " %s\n", lsa->name);
-
- timerclear(&res);
- if (on->thread_send_lsreq)
- timersub(&on->thread_send_lsreq->u.sands, &now, &res);
- timerstring(&res, duration, sizeof(duration));
- vty_out(vty, " %d Pending LSAs for LSReq in Time %s [thread %s]\n",
- on->request_list->count, duration,
- (on->thread_send_lsreq ? "on" : "off"));
- for (ALL_LSDB(on->request_list, lsa, lsanext))
- vty_out(vty, " %s\n", lsa->name);
-
- timerclear(&res);
- if (on->thread_send_lsupdate)
- timersub(&on->thread_send_lsupdate->u.sands, &now, &res);
- timerstring(&res, duration, sizeof(duration));
- vty_out(vty,
- " %d Pending LSAs for LSUpdate in Time %s [thread %s]\n",
- on->lsupdate_list->count, duration,
- (on->thread_send_lsupdate ? "on" : "off"));
- for (ALL_LSDB(on->lsupdate_list, lsa, lsanext))
- vty_out(vty, " %s\n", lsa->name);
-
- timerclear(&res);
- if (on->thread_send_lsack)
- timersub(&on->thread_send_lsack->u.sands, &now, &res);
- timerstring(&res, duration, sizeof(duration));
- vty_out(vty, " %d Pending LSAs for LSAck in Time %s [thread %s]\n",
- on->lsack_list->count, duration,
- (on->thread_send_lsack ? "on" : "off"));
- for (ALL_LSDB(on->lsack_list, lsa, lsanext))
- vty_out(vty, " %s\n", lsa->name);
-
- ospf6_bfd_show_info(vty, on->bfd_info, 0);
+ if (use_json) {
+ json_neighbor = json_object_new_object();
+ json_object_string_add(json_neighbor, "area",
+ on->ospf6_if->area->name);
+ json_object_string_add(json_neighbor, "interface",
+ on->ospf6_if->interface->name);
+ json_object_int_add(json_neighbor, "interfaceIndex",
+ on->ospf6_if->interface->ifindex);
+ json_object_int_add(json_neighbor, "neighborInterfaceIndex",
+ on->ifindex);
+ json_object_string_add(json_neighbor, "linkLocalAddress",
+ linklocal_addr);
+ json_object_string_add(json_neighbor, "neighborState",
+ ospf6_neighbor_state_str[on->state]);
+ json_object_string_add(json_neighbor, "neighborStateDuration",
+ duration);
+ json_object_string_add(json_neighbor, "neighborDRouter",
+ drouter);
+ json_object_string_add(json_neighbor, "neighborBdRouter",
+ bdrouter);
+ snprintf(db_desc_str, sizeof(db_desc_str), "%s%s%s",
+ (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
+ ? "Initial "
+ : ""),
+ (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT)
+ ? "More"
+ : ""),
+ (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)
+ ? "Master"
+ : "Slave"));
+ json_object_string_add(json_neighbor, "dbDescStatus",
+ db_desc_str);
+
+ json_object_int_add(json_neighbor, "dbDescSeqNumber",
+ (unsigned long)ntohl(on->dbdesc_seqnum));
+
+ json_array = json_object_new_array();
+ json_object_int_add(json_neighbor, "summaryListCount",
+ on->summary_list->count);
+ for (ALL_LSDB(on->summary_list, lsa, lsanext))
+ json_object_array_add(
+ json_array, json_object_new_string(lsa->name));
+ json_object_object_add(json_neighbor, "summaryListLsa",
+ json_array);
+
+ json_array = json_object_new_array();
+ json_object_int_add(json_neighbor, "requestListCount",
+ on->request_list->count);
+ for (ALL_LSDB(on->request_list, lsa, lsanext))
+ json_object_array_add(
+ json_array, json_object_new_string(lsa->name));
+ json_object_object_add(json_neighbor, "requestListLsa",
+ json_array);
+
+ json_array = json_object_new_array();
+ json_object_int_add(json_neighbor, "reTransListCount",
+ on->retrans_list->count);
+ for (ALL_LSDB(on->retrans_list, lsa, lsanext))
+ json_object_array_add(
+ json_array, json_object_new_string(lsa->name));
+ json_object_object_add(json_neighbor, "reTransListLsa",
+ json_array);
+
+
+ timerclear(&res);
+ if (on->thread_send_dbdesc)
+ timersub(&on->thread_send_dbdesc->u.sands, &now, &res);
+ timerstring(&res, duration, sizeof(duration));
+ json_object_int_add(json_neighbor, "pendingLsaDbDescCount",
+ on->dbdesc_list->count);
+ json_object_string_add(json_neighbor, "pendingLsaDbDescTime",
+ duration);
+ json_object_string_add(json_neighbor, "dbDescSendThread",
+ (on->thread_send_dbdesc ? "on" : "off"));
+ json_array = json_object_new_array();
+ for (ALL_LSDB(on->dbdesc_list, lsa, lsanext))
+ json_object_array_add(
+ json_array, json_object_new_string(lsa->name));
+ json_object_object_add(json_neighbor, "pendingLsaDbDesc",
+ json_array);
+
+ timerclear(&res);
+ if (on->thread_send_lsreq)
+ timersub(&on->thread_send_lsreq->u.sands, &now, &res);
+ timerstring(&res, duration, sizeof(duration));
+ json_object_int_add(json_neighbor, "pendingLsaLsReqCount",
+ on->request_list->count);
+ json_object_string_add(json_neighbor, "pendingLsaLsReqTime",
+ duration);
+ json_object_string_add(json_neighbor, "lsReqSendThread",
+ (on->thread_send_lsreq ? "on" : "off"));
+ json_array = json_object_new_array();
+ for (ALL_LSDB(on->request_list, lsa, lsanext))
+ json_object_array_add(
+ json_array, json_object_new_string(lsa->name));
+ json_object_object_add(json_neighbor, "pendingLsaLsReq",
+ json_array);
+
+
+ timerclear(&res);
+ if (on->thread_send_lsupdate)
+ timersub(&on->thread_send_lsupdate->u.sands, &now,
+ &res);
+ timerstring(&res, duration, sizeof(duration));
+ json_object_int_add(json_neighbor, "pendingLsaLsUpdateCount",
+ on->lsupdate_list->count);
+ json_object_string_add(json_neighbor, "pendingLsaLsUpdateTime",
+ duration);
+ json_object_string_add(
+ json_neighbor, "lsUpdateSendThread",
+ (on->thread_send_lsupdate ? "on" : "off"));
+ json_array = json_object_new_array();
+ for (ALL_LSDB(on->lsupdate_list, lsa, lsanext))
+ json_object_array_add(
+ json_array, json_object_new_string(lsa->name));
+ json_object_object_add(json_neighbor, "pendingLsaLsUpdate",
+ json_array);
+
+ timerclear(&res);
+ if (on->thread_send_lsack)
+ timersub(&on->thread_send_lsack->u.sands, &now, &res);
+ timerstring(&res, duration, sizeof(duration));
+ json_object_int_add(json_neighbor, "pendingLsaLsAckCount",
+ on->lsack_list->count);
+ json_object_string_add(json_neighbor, "pendingLsaLsAckTime",
+ duration);
+ json_object_string_add(json_neighbor, "lsAckSendThread",
+ (on->thread_send_lsack ? "on" : "off"));
+ json_array = json_object_new_array();
+ for (ALL_LSDB(on->lsack_list, lsa, lsanext))
+ json_object_array_add(
+ json_array, json_object_new_string(lsa->name));
+ json_object_object_add(json_neighbor, "pendingLsaLsAck",
+ json_array);
+
+ ospf6_bfd_show_info(vty, on->bfd_info, 0, json_neighbor,
+ use_json);
+
+ json_object_object_add(json, on->name, json_neighbor);
+
+
+ } else {
+ vty_out(vty, " Neighbor %s\n", on->name);
+ vty_out(vty, " Area %s via interface %s (ifindex %d)\n",
+ on->ospf6_if->area->name, on->ospf6_if->interface->name,
+ on->ospf6_if->interface->ifindex);
+ vty_out(vty, " His IfIndex: %d Link-local address: %s\n",
+ on->ifindex, linklocal_addr);
+ vty_out(vty, " State %s for a duration of %s\n",
+ ospf6_neighbor_state_str[on->state], duration);
+ vty_out(vty, " His choice of DR/BDR %s/%s, Priority %d\n",
+ drouter, bdrouter, on->priority);
+ vty_out(vty, " DbDesc status: %s%s%s SeqNum: %#lx\n",
+ (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
+ ? "Initial "
+ : ""),
+ (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT)
+ ? "More "
+ : ""),
+ (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)
+ ? "Master"
+ : "Slave"),
+ (unsigned long)ntohl(on->dbdesc_seqnum));
+
+ vty_out(vty, " Summary-List: %d LSAs\n",
+ on->summary_list->count);
+ for (ALL_LSDB(on->summary_list, lsa, lsanext))
+ vty_out(vty, " %s\n", lsa->name);
+
+ vty_out(vty, " Request-List: %d LSAs\n",
+ on->request_list->count);
+ for (ALL_LSDB(on->request_list, lsa, lsanext))
+ vty_out(vty, " %s\n", lsa->name);
+
+ vty_out(vty, " Retrans-List: %d LSAs\n",
+ on->retrans_list->count);
+ for (ALL_LSDB(on->retrans_list, lsa, lsanext))
+ vty_out(vty, " %s\n", lsa->name);
+
+ timerclear(&res);
+ if (on->thread_send_dbdesc)
+ timersub(&on->thread_send_dbdesc->u.sands, &now, &res);
+ timerstring(&res, duration, sizeof(duration));
+ vty_out(vty,
+ " %d Pending LSAs for DbDesc in Time %s [thread %s]\n",
+ on->dbdesc_list->count, duration,
+ (on->thread_send_dbdesc ? "on" : "off"));
+ for (ALL_LSDB(on->dbdesc_list, lsa, lsanext))
+ vty_out(vty, " %s\n", lsa->name);
+
+ timerclear(&res);
+ if (on->thread_send_lsreq)
+ timersub(&on->thread_send_lsreq->u.sands, &now, &res);
+ timerstring(&res, duration, sizeof(duration));
+ vty_out(vty,
+ " %d Pending LSAs for LSReq in Time %s [thread %s]\n",
+ on->request_list->count, duration,
+ (on->thread_send_lsreq ? "on" : "off"));
+ for (ALL_LSDB(on->request_list, lsa, lsanext))
+ vty_out(vty, " %s\n", lsa->name);
+
+ timerclear(&res);
+ if (on->thread_send_lsupdate)
+ timersub(&on->thread_send_lsupdate->u.sands, &now,
+ &res);
+ timerstring(&res, duration, sizeof(duration));
+ vty_out(vty,
+ " %d Pending LSAs for LSUpdate in Time %s [thread %s]\n",
+ on->lsupdate_list->count, duration,
+ (on->thread_send_lsupdate ? "on" : "off"));
+ for (ALL_LSDB(on->lsupdate_list, lsa, lsanext))
+ vty_out(vty, " %s\n", lsa->name);
+
+ timerclear(&res);
+ if (on->thread_send_lsack)
+ timersub(&on->thread_send_lsack->u.sands, &now, &res);
+ timerstring(&res, duration, sizeof(duration));
+ vty_out(vty,
+ " %d Pending LSAs for LSAck in Time %s [thread %s]\n",
+ on->lsack_list->count, duration,
+ (on->thread_send_lsack ? "on" : "off"));
+ for (ALL_LSDB(on->lsack_list, lsa, lsanext))
+ vty_out(vty, " %s\n", lsa->name);
+
+ ospf6_bfd_show_info(vty, on->bfd_info, 0, NULL, use_json);
+ }
}
DEFUN (show_ipv6_ospf6_neighbor,
show_ipv6_ospf6_neighbor_cmd,
- "show ipv6 ospf6 neighbor [<detail|drchoice>]",
+ "show ipv6 ospf6 neighbor [<detail|drchoice>] [json]",
SHOW_STR
IP6_STR
OSPF6_STR
"Neighbor list\n"
"Display details\n"
- "Display DR choices\n")
+ "Display DR choices\n"
+ JSON_STR)
{
int idx_type = 4;
struct ospf6_neighbor *on;
struct ospf6_interface *oi;
struct ospf6_area *oa;
struct listnode *i, *j, *k;
- void (*showfunc)(struct vty *, struct ospf6_neighbor *);
struct ospf6 *ospf6;
+ json_object *json = NULL;
+ json_object *json_array = NULL;
+ bool uj = use_json(argc, argv);
+ void (*showfunc)(struct vty *, struct ospf6_neighbor *,
+ json_object *json, bool use_json);
ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
OSPF6_CMD_CHECK_RUNNING(ospf6);
showfunc = ospf6_neighbor_show;
- if (argc == 5) {
+ if ((uj && argc == 6) || (!uj && argc == 5)) {
if (!strncmp(argv[idx_type]->arg, "de", 2))
showfunc = ospf6_neighbor_show_detail;
else if (!strncmp(argv[idx_type]->arg, "dr", 2))
showfunc = ospf6_neighbor_show_drchoice;
}
- if (showfunc == ospf6_neighbor_show)
- vty_out(vty, "%-15s %3s %11s %8s/%-12s %11s %s[%s]\n",
- "Neighbor ID", "Pri", "DeadTime", "State", "IfState",
- "Duration", "I/F", "State");
- else if (showfunc == ospf6_neighbor_show_drchoice)
- vty_out(vty, "%-15s %8s/%-11s %-15s %-15s %s[%s]\n", "RouterID",
- "State", "Duration", "DR", "BDR", "I/F", "State");
+ if (uj) {
+ json = json_object_new_object();
+ json_array = json_object_new_array();
+ } else {
+ if (showfunc == ospf6_neighbor_show)
+ vty_out(vty, "%-15s %3s %11s %8s/%-12s %11s %s[%s]\n",
+ "Neighbor ID", "Pri", "DeadTime", "State",
+ "IfState", "Duration", "I/F", "State");
+ else if (showfunc == ospf6_neighbor_show_drchoice)
+ vty_out(vty, "%-15s %8s/%-11s %-15s %-15s %s[%s]\n",
+ "RouterID", "State", "Duration", "DR", "BDR",
+ "I/F", "State");
+ }
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi))
- for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, on))
- (*showfunc)(vty, on);
-
+ for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, on)) {
+ if (showfunc == ospf6_neighbor_show_detail)
+ (*showfunc)(vty, on, json, uj);
+ else
+ (*showfunc)(vty, on, json_array, uj);
+ }
+
+ if (uj) {
+ if (showfunc != ospf6_neighbor_show_detail)
+ json_object_object_add(json, "neighbors", json_array);
+ else
+ json_object_free(json_array);
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
return CMD_SUCCESS;
}
DEFUN (show_ipv6_ospf6_neighbor_one,
show_ipv6_ospf6_neighbor_one_cmd,
- "show ipv6 ospf6 neighbor A.B.C.D",
+ "show ipv6 ospf6 neighbor A.B.C.D [json]",
SHOW_STR
IP6_STR
OSPF6_STR
"Neighbor list\n"
"Specify Router-ID as IPv4 address notation\n"
- )
+ JSON_STR)
{
int idx_ipv4 = 4;
struct ospf6_neighbor *on;
struct ospf6_interface *oi;
struct ospf6_area *oa;
struct listnode *i, *j, *k;
- void (*showfunc)(struct vty *, struct ospf6_neighbor *);
+ void (*showfunc)(struct vty *, struct ospf6_neighbor *,
+ json_object *json, bool use_json);
uint32_t router_id;
struct ospf6 *ospf6;
+ json_object *json = NULL;
+ bool uj = use_json(argc, argv);
ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
OSPF6_CMD_CHECK_RUNNING(ospf6);
showfunc = ospf6_neighbor_show_detail;
+ if (uj)
+ json = json_object_new_object();
if ((inet_pton(AF_INET, argv[idx_ipv4]->arg, &router_id)) != 1) {
vty_out(vty, "Router-ID is not parsable: %s\n",
@@ -849,8 +1076,15 @@ DEFUN (show_ipv6_ospf6_neighbor_one,
for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi))
for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, on))
- (*showfunc)(vty, on);
+ (*showfunc)(vty, on, json, uj);
+
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
return CMD_SUCCESS;
}
diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h
index 1a45a1966a..94300ff2ba 100644
--- a/ospf6d/ospf6_neighbor.h
+++ b/ospf6d/ospf6_neighbor.h
@@ -64,7 +64,7 @@ struct ospf6_neighbor {
/* Options field (Capability) */
char options[3];
- /* IPaddr of I/F on our side link */
+ /* IPaddr of I/F on neighbour's link */
struct in6_addr linklocal_addr;
/* For Database Exchange */
diff --git a/ospfd/ospf_gr_helper.c b/ospfd/ospf_gr_helper.c
index 9c029a49ba..a86e1b8401 100644
--- a/ospfd/ospf_gr_helper.c
+++ b/ospfd/ospf_gr_helper.c
@@ -251,7 +251,7 @@ static int ospf_extract_grace_lsa_fields(struct ospf_lsa *lsa,
/* Check TLV len against overall LSA */
if (sum + TLV_SIZE(tlvh) > length) {
if (IS_DEBUG_OSPF_GR_HELPER)
- zlog_debug("%s: Malformed packet: Invalid TLV len:%zu",
+ zlog_debug("%s: Malformed packet: Invalid TLV len:%u",
__func__, TLV_SIZE(tlvh));
return OSPF_GR_FAILURE;
}
@@ -260,7 +260,7 @@ static int ospf_extract_grace_lsa_fields(struct ospf_lsa *lsa,
case GRACE_PERIOD_TYPE:
if (TLV_SIZE(tlvh) <
sizeof(struct grace_tlv_graceperiod)) {
- zlog_debug("%s: Malformed packet: Invalid grace TLV len:%zu",
+ zlog_debug("%s: Malformed packet: Invalid grace TLV len:%u",
__func__, TLV_SIZE(tlvh));
return OSPF_GR_FAILURE;
}
@@ -277,7 +277,7 @@ static int ospf_extract_grace_lsa_fields(struct ospf_lsa *lsa,
case RESTART_REASON_TYPE:
if (TLV_SIZE(tlvh) <
sizeof(struct grace_tlv_restart_reason)) {
- zlog_debug("%s: Malformed packet: Invalid reason TLV len:%zu",
+ zlog_debug("%s: Malformed packet: Invalid reason TLV len:%u",
__func__, TLV_SIZE(tlvh));
return OSPF_GR_FAILURE;
}
@@ -292,7 +292,7 @@ static int ospf_extract_grace_lsa_fields(struct ospf_lsa *lsa,
case RESTARTER_IP_ADDR_TYPE:
if (TLV_SIZE(tlvh) <
sizeof(struct grace_tlv_restart_addr)) {
- zlog_debug("%s: Malformed packet: Invalid addr TLV len:%zu",
+ zlog_debug("%s: Malformed packet: Invalid addr TLV len:%u",
__func__, TLV_SIZE(tlvh));
return OSPF_GR_FAILURE;
}
@@ -1018,7 +1018,7 @@ static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa)
tlvh = TLV_HDR_NEXT(tlvh)) {
/* Check TLV len */
if (sum + TLV_SIZE(tlvh) > length) {
- vty_out(vty, "%% Invalid TLV length: %zu\n",
+ vty_out(vty, "%% Invalid TLV length: %u\n",
TLV_SIZE(tlvh));
return;
}
@@ -1028,7 +1028,7 @@ static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa)
if (TLV_SIZE(tlvh) <
sizeof(struct grace_tlv_graceperiod)) {
vty_out(vty,
- "%% Invalid grace TLV length %zu\n",
+ "%% Invalid grace TLV length %u\n",
TLV_SIZE(tlvh));
return;
}
@@ -1043,7 +1043,7 @@ static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa)
if (TLV_SIZE(tlvh) <
sizeof(struct grace_tlv_restart_reason)) {
vty_out(vty,
- "%% Invalid reason TLV length %zu\n",
+ "%% Invalid reason TLV length %u\n",
TLV_SIZE(tlvh));
return;
}
@@ -1058,7 +1058,7 @@ static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa)
if (TLV_SIZE(tlvh) <
sizeof(struct grace_tlv_restart_addr)) {
vty_out(vty,
- "%% Invalid addr TLV length %zu\n",
+ "%% Invalid addr TLV length %u\n",
TLV_SIZE(tlvh));
return;
}
diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h
index f02f34c9af..c63b8ebdaf 100644
--- a/ospfd/ospf_opaque.h
+++ b/ospfd/ospf_opaque.h
@@ -94,7 +94,7 @@ struct tlv_header {
#define TLV_BODY_SIZE(tlvh) (ROUNDUP(ntohs((tlvh)->length), sizeof(uint32_t)))
-#define TLV_SIZE(tlvh) (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh))
+#define TLV_SIZE(tlvh) (uint32_t)(TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh))
#define TLV_HDR_TOP(lsah) \
(struct tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE)
diff --git a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
index 12069a12dc..54a3c699f3 100644
--- a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
+++ b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
@@ -292,6 +292,10 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
input_dict_1 = {"r3": {"static_routes": [{"network": NETWORK[addr_type]}]}}
logger.info("Verifying %s routes on r3", addr_type)
+
+ # Only test the count of nexthops; the actual nexthop addresses
+ # can vary and are not deterministic.
+ #
result = verify_rib(
tgen,
addr_type,
@@ -299,7 +303,9 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
input_dict_1,
next_hop=NEXT_HOPS[addr_type][: int(ecmp_num)],
protocol=protocol,
+ count_only=True
)
+
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
diff --git a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
index 50aa281d34..73724ac069 100644
--- a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
+++ b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
@@ -293,6 +293,10 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
input_dict_1 = {"r3": {"static_routes": [{"network": NETWORK[addr_type]}]}}
logger.info("Verifying %s routes on r3", addr_type)
+
+ # Test only the count of nexthops, not the specific nexthop addresses -
+ # they're not deterministic
+ #
result = verify_rib(
tgen,
addr_type,
@@ -300,7 +304,9 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
input_dict_1,
next_hop=NEXT_HOPS[addr_type][: int(ecmp_num)],
protocol=protocol,
+ count_only=True
)
+
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index d83f946c42..e42992e294 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -2559,6 +2559,7 @@ def verify_rib(
tag=None,
metric=None,
fib=None,
+ count_only=False
):
"""
Data will be read from input_dict or input JSON file, API will generate
@@ -2576,6 +2577,8 @@ def verify_rib(
* `next_hop`[optional]: next_hop which needs to be verified,
default: static
* `protocol`[optional]: protocol, default = None
+ * `count_only`[optional]: count of nexthops only, not specific addresses,
+ default = False
Usage
-----
@@ -2739,7 +2742,23 @@ def verify_rib(
for rib_r in rib_routes_json[st_rt][0]["nexthops"]
]
- if found_hops:
+ # Check only the count of nexthops
+ if count_only:
+ if len(next_hop) == len(found_hops):
+ nh_found = True
+ else:
+ errormsg = (
+ "Nexthops are missing for "
+ "route {} in RIB of router {}: "
+ "expected {}, found {}\n".format(
+ st_rt, dut, len(next_hop),
+ len(found_hops)
+ )
+ )
+ return errormsg
+
+ # Check the actual nexthops
+ elif found_hops:
missing_list_of_nexthops = set(
found_hops
).difference(next_hop)
@@ -3019,262 +3038,6 @@ def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None):
for st_rt in ip_list:
st_rt = str(ipaddress.ip_network(frr_unicode(st_rt)))
- # st_rt = str(ipaddr.IPNetwork(unicode(st_rt)))
-
- _addr_type = validate_ip_address(st_rt)
- if _addr_type != addr_type:
- continue
-
- if st_rt in rib_routes_json:
- st_found = True
- found_routes.append(st_rt)
-
- if next_hop:
- if type(next_hop) is not list:
- next_hop = [next_hop]
-
- count = 0
- for nh in next_hop:
- for nh_dict in rib_routes_json[st_rt][0][
- "nexthops"
- ]:
- if nh_dict["ip"] != nh:
- continue
- else:
- count += 1
-
- if count == len(next_hop):
- nh_found = True
- else:
- missing_routes.append(st_rt)
- errormsg = (
- "Nexthop {} is Missing"
- " for route {} in "
- "RIB of router {}\n".format(
- next_hop, st_rt, dut
- )
- )
- return errormsg
-
- else:
- missing_routes.append(st_rt)
-
- if len(missing_routes) > 0:
- errormsg = "[DUT: {}]: Missing route in FIB:" " {}".format(
- dut, missing_routes
- )
- return errormsg
-
- if nh_found:
- logger.info(
- "Found next_hop {} for all routes in RIB"
- " of router {}\n".format(next_hop, dut)
- )
-
- if found_routes:
- logger.info(
- "[DUT: %s]: Verified routes in FIB, found" " routes are: %s\n",
- dut,
- found_routes,
- )
-
- continue
-
- if "bgp" in input_dict[routerInput]:
- if (
- "advertise_networks"
- not in input_dict[routerInput]["bgp"]["address_family"][addr_type][
- "unicast"
- ]
- ):
- continue
-
- found_routes = []
- missing_routes = []
- advertise_network = input_dict[routerInput]["bgp"]["address_family"][
- addr_type
- ]["unicast"]["advertise_networks"]
-
- # Continue if there are no network advertise
- if len(advertise_network) == 0:
- continue
-
- for advertise_network_dict in advertise_network:
- if "vrf" in advertise_network_dict:
- cmd = "{} vrf {} json".format(command, static_route["vrf"])
- else:
- cmd = "{} json".format(command)
-
- rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
-
- # Verifying output dictionary rib_routes_json is not empty
- if bool(rib_routes_json) is False:
- errormsg = "No route found in rib of router {}..".format(router)
- return errormsg
-
- start_ip = advertise_network_dict["network"]
- if "no_of_network" in advertise_network_dict:
- no_of_network = advertise_network_dict["no_of_network"]
- else:
- no_of_network = 1
-
- # Generating IPs for verification
- ip_list = generate_ips(start_ip, no_of_network)
- st_found = False
- nh_found = False
-
- for st_rt in ip_list:
- # st_rt = str(ipaddr.IPNetwork(unicode(st_rt)))
- st_rt = str(ipaddress.ip_network(frr_unicode(st_rt)))
-
- _addr_type = validate_ip_address(st_rt)
- if _addr_type != addr_type:
- continue
-
- if st_rt in rib_routes_json:
- st_found = True
- found_routes.append(st_rt)
-
- if next_hop:
- if type(next_hop) is not list:
- next_hop = [next_hop]
-
- count = 0
- for nh in next_hop:
- for nh_dict in rib_routes_json[st_rt][0]["nexthops"]:
- if nh_dict["ip"] != nh:
- continue
- else:
- count += 1
-
- if count == len(next_hop):
- nh_found = True
- else:
- missing_routes.append(st_rt)
- errormsg = (
- "Nexthop {} is Missing"
- " for route {} in "
- "RIB of router {}\n".format(next_hop, st_rt, dut)
- )
- return errormsg
- else:
- missing_routes.append(st_rt)
-
- if len(missing_routes) > 0:
- errormsg = "[DUT: {}]: Missing route in FIB: " "{} \n".format(
- dut, missing_routes
- )
- return errormsg
-
- if nh_found:
- logger.info(
- "Found next_hop {} for all routes in RIB"
- " of router {}\n".format(next_hop, dut)
- )
-
- if found_routes:
- logger.info(
- "[DUT: {}]: Verified routes FIB"
- ", found routes are: {}\n".format(dut, found_routes)
- )
-
- logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
- return True
-
-
-@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
-def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None):
- """
- Data will be read from input_dict or input JSON file, API will generate
- same prefixes, which were redistributed by either create_static_routes() or
- advertise_networks_using_network_command() and will verify next_hop and
- each prefix/routes is present in "show ip/ipv6 fib json"
- command o/p.
-
- Parameters
- ----------
- * `tgen` : topogen object
- * `addr_type` : ip type, ipv4/ipv6
- * `dut`: Device Under Test, for which user wants to test the data
- * `input_dict` : input dict, has details of static routes
- * `next_hop`[optional]: next_hop which needs to be verified,
- default: static
-
- Usage
- -----
- input_routes_r1 = {
- "r1": {
- "static_routes": [{
- "network": ["1.1.1.1/32],
- "next_hop": "Null0",
- "vrf": "RED"
- }]
- }
- }
- result = result = verify_fib_routes(tgen, "ipv4, "r1", input_routes_r1)
-
- Returns
- -------
- errormsg(str) or True
- """
-
- logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
-
- router_list = tgen.routers()
- for routerInput in input_dict.keys():
- for router, rnode in router_list.items():
- if router != dut:
- continue
-
- logger.info("Checking router %s FIB routes:", router)
-
- # Verifying RIB routes
- if addr_type == "ipv4":
- command = "show ip fib"
- else:
- command = "show ipv6 fib"
-
- found_routes = []
- missing_routes = []
-
- if "static_routes" in input_dict[routerInput]:
- static_routes = input_dict[routerInput]["static_routes"]
-
- for static_route in static_routes:
- if "vrf" in static_route and static_route["vrf"] is not None:
-
- logger.info(
- "[DUT: {}]: Verifying routes for VRF:"
- " {}".format(router, static_route["vrf"])
- )
-
- cmd = "{} vrf {}".format(command, static_route["vrf"])
-
- else:
- cmd = "{}".format(command)
-
- cmd = "{} json".format(cmd)
-
- rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
-
- # Verifying output dictionary rib_routes_json is not empty
- if bool(rib_routes_json) is False:
- errormsg = "[DUT: {}]: No route found in fib".format(router)
- return errormsg
-
- network = static_route["network"]
- if "no_of_ip" in static_route:
- no_of_ip = static_route["no_of_ip"]
- else:
- no_of_ip = 1
-
- # Generating IPs for verification
- ip_list = generate_ips(network, no_of_ip)
- st_found = False
- nh_found = False
-
- for st_rt in ip_list:
- st_rt = str(ipaddress.ip_network(frr_unicode(st_rt)))
_addr_type = validate_ip_address(st_rt)
if _addr_type != addr_type:
diff --git a/tests/topotests/route-scale/r1/installed.routes.json b/tests/topotests/route-scale/r1/installed.routes.json
index 25d209f9eb..24a45dca81 100644
--- a/tests/topotests/route-scale/r1/installed.routes.json
+++ b/tests/topotests/route-scale/r1/installed.routes.json
@@ -6,11 +6,11 @@
"type":"connected"
},
{
- "fib":1000000,
- "rib":1000000,
+ "fib":200000,
+ "rib":200000,
"type":"sharp"
}
],
- "routesTotal":1000032,
- "routesTotalFib":1000032
+ "routesTotal":200032,
+ "routesTotalFib":200032
}
diff --git a/tests/topotests/route-scale/test_route_scale.py b/tests/topotests/route-scale/test_route_scale.py
index 8aedfc198c..bbd6ef8d60 100644
--- a/tests/topotests/route-scale/test_route_scale.py
+++ b/tests/topotests/route-scale/test_route_scale.py
@@ -122,15 +122,20 @@ def run_one_setup(r1, s):
expected_installed = s["expect_in"]
expected_removed = s["expect_rem"]
- count = s["count"]
+ retries = s["retries"]
wait = s["wait"]
- logger.info("Testing 1 million routes X {} ecmp".format(s["ecmp"]))
+ for d in expected_installed["routes"]:
+ if d["type"] == "sharp":
+ count = d["rib"]
+ break
+
+ logger.info("Testing {} routes X {} ecmp".format(count, s["ecmp"]))
r1.vtysh_cmd(
"sharp install route 1.0.0.0 \
- nexthop-group {} 1000000".format(
- s["nhg"]
+ nexthop-group {} {}".format(
+ s["nhg"], count
),
isjson=False,
)
@@ -138,21 +143,21 @@ def run_one_setup(r1, s):
test_func = partial(
topotest.router_json_cmp, r1, "show ip route summary json", expected_installed
)
- success, result = topotest.run_and_expect(test_func, None, count, wait)
+ success, result = topotest.run_and_expect(test_func, None, retries, wait)
assert success, "Route scale test install failed:\n{}".format(result)
output = r1.vtysh_cmd("sharp data route", isjson=False)
- logger.info("1 million routes X {} ecmp installed".format(s["ecmp"]))
+ logger.info("{} routes X {} ecmp installed".format(count, s["ecmp"]))
logger.info(output)
- r1.vtysh_cmd("sharp remove route 1.0.0.0 1000000", isjson=False)
+ r1.vtysh_cmd("sharp remove route 1.0.0.0 {}".format(count), isjson=False)
test_func = partial(
topotest.router_json_cmp, r1, "show ip route summary json", expected_removed
)
- success, result = topotest.run_and_expect(test_func, None, count, wait)
+ success, result = topotest.run_and_expect(test_func, None, retries, wait)
assert success, "Route scale test remove failed:\n{}".format(result)
output = r1.vtysh_cmd("sharp data route", isjson=False)
- logger.info("1 million routes x {} ecmp removed".format(s["ecmp"]))
+ logger.info("{} routes x {} ecmp removed".format(count, s["ecmp"]))
logger.info(output)
@@ -174,7 +179,7 @@ def test_route_install():
# dict keys of params: ecmp number, corresponding nhg name, timeout,
# number of times to wait
- scale_keys = ["ecmp", "nhg", "wait", "count", "expect_in", "expect_rem"]
+ scale_keys = ["ecmp", "nhg", "wait", "retries", "expect_in", "expect_rem"]
# Table of defaults, used for timeout values and 'expected' objects
scale_defaults = dict(
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index ef51989a0c..4dc8c2a6eb 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -3179,10 +3179,14 @@ ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data,
update_flags = dplane_ctx_mac_get_update_flags(ctx);
if (update_flags & DPLANE_MAC_REMOTE) {
flags |= NTF_SELF;
- if (dplane_ctx_mac_is_sticky(ctx))
+ if (dplane_ctx_mac_is_sticky(ctx)) {
+ /* NUD_NOARP prevents the entry from expiring */
+ state |= NUD_NOARP;
+ /* sticky the entry from moving */
flags |= NTF_STICKY;
- else
+ } else {
flags |= NTF_EXT_LEARNED;
+ }
/* if it was static-local previously we need to clear the
* notify flags on replace with remote
*/